From 8a10bb7d0dd0cc03353bb751af25a0eca1357c9d Mon Sep 17 00:00:00 2001 From: Clay John Date: Tue, 26 Oct 2021 08:18:39 -0700 Subject: Use OpenGL 3.3 core profile instead of compatibility profile - Rename OpenGL to GLES3 in the source code per community feedback. - The renderer is still exposed as "OpenGL 3" to the user. - Hide renderer selection dropdown until OpenGL support is more mature. - The renderer can still be changed in the Project Settings or using the `--rendering-driver opengl` command line argument. - Remove commented out exporter code. - Remove some OpenGL/DisplayServer-related debugging prints. --- SConstruct | 6 +- core/core_bind.cpp | 2 +- core/core_bind.h | 2 +- doc/classes/OS.xml | 6 +- doc/classes/ProjectSettings.xml | 42 + drivers/SCsub | 2 +- drivers/gles3/SCsub | 7 + drivers/gles3/rasterizer_array.h | 421 ++ drivers/gles3/rasterizer_asserts.h | 67 + drivers/gles3/rasterizer_canvas_base_gles3.cpp | 1354 ++++++ drivers/gles3/rasterizer_canvas_base_gles3.h | 213 + drivers/gles3/rasterizer_canvas_batcher.h | 1560 +++++++ drivers/gles3/rasterizer_canvas_gles3.cpp | 1709 +++++++ drivers/gles3/rasterizer_canvas_gles3.h | 71 + drivers/gles3/rasterizer_gles3.cpp | 378 ++ drivers/gles3/rasterizer_gles3.h | 92 + drivers/gles3/rasterizer_platforms.h | 48 + drivers/gles3/rasterizer_scene_gles3.cpp | 466 ++ drivers/gles3/rasterizer_scene_gles3.h | 229 + drivers/gles3/rasterizer_storage_common.h | 77 + drivers/gles3/rasterizer_storage_gles3.cpp | 4820 ++++++++++++++++++++ drivers/gles3/rasterizer_storage_gles3.h | 1453 ++++++ drivers/gles3/shader_compiler_gles3.cpp | 1120 +++++ drivers/gles3/shader_compiler_gles3.h | 106 + drivers/gles3/shader_gles3.cpp | 1116 +++++ drivers/gles3/shader_gles3.h | 277 ++ drivers/gles3/shaders/SCsub | 14 + drivers/gles3/shaders/canvas.glsl | 665 +++ drivers/gles3/shaders/canvas_shadow.glsl | 60 + drivers/gles3/shaders/copy.glsl | 193 + drivers/gles3/shaders/cube_to_dp.glsl | 100 + drivers/gles3/shaders/cubemap_filter.glsl | 214 + drivers/gles3/shaders/effect_blur.glsl | 291 ++ drivers/gles3/shaders/lens_distorted.glsl | 86 + drivers/gles3/shaders/scene.glsl | 2153 +++++++++ drivers/gles3/shaders/tonemap.glsl | 313 ++ drivers/gles3/texture_loader_gles3.cpp | 112 + drivers/gles3/texture_loader_gles3.h | 52 + drivers/opengl/SCsub | 7 - drivers/opengl/rasterizer_array.h | 421 -- drivers/opengl/rasterizer_asserts.h | 67 - drivers/opengl/rasterizer_canvas_base_opengl.cpp | 1252 ----- drivers/opengl/rasterizer_canvas_base_opengl.h | 196 - drivers/opengl/rasterizer_canvas_batcher.h | 1560 ------- drivers/opengl/rasterizer_canvas_opengl.cpp | 1708 ------- drivers/opengl/rasterizer_canvas_opengl.h | 71 - drivers/opengl/rasterizer_opengl.cpp | 377 -- drivers/opengl/rasterizer_opengl.h | 92 - drivers/opengl/rasterizer_platforms.h | 48 - drivers/opengl/rasterizer_scene_opengl.cpp | 439 -- drivers/opengl/rasterizer_scene_opengl.h | 220 - drivers/opengl/rasterizer_storage_common.h | 77 - drivers/opengl/rasterizer_storage_opengl.cpp | 4818 ------------------- drivers/opengl/rasterizer_storage_opengl.h | 1440 ------ drivers/opengl/shader_compiler_opengl.cpp | 1120 ----- drivers/opengl/shader_compiler_opengl.h | 106 - drivers/opengl/shader_opengl.cpp | 1128 ----- drivers/opengl/shader_opengl.h | 277 -- drivers/opengl/shaders/SCsub | 14 - drivers/opengl/shaders/canvas.glsl | 686 --- drivers/opengl/shaders/canvas_shadow.glsl | 60 - drivers/opengl/shaders/copy.glsl | 191 - drivers/opengl/shaders/cube_to_dp.glsl | 100 - drivers/opengl/shaders/cubemap_filter.glsl | 231 - drivers/opengl/shaders/effect_blur.glsl | 308 -- drivers/opengl/shaders/lens_distorted.glsl | 84 - drivers/opengl/shaders/scene.glsl | 2176 --------- drivers/opengl/shaders/stdlib.glsl | 420 -- drivers/opengl/shaders/tonemap.glsl | 343 -- drivers/opengl/texture_loader_opengl.cpp | 112 - drivers/opengl/texture_loader_opengl.h | 52 - editor/editor_export.cpp | 4 +- editor/editor_node.cpp | 61 +- editor/plugins/visual_shader_editor_plugin.cpp | 2 +- editor/project_manager.cpp | 2 +- gles3_builders.py | 528 +++ main/main.cpp | 2 - opengl_builders.py | 530 --- platform/android/display_server_android.cpp | 14 +- platform/android/export/export.cpp | 2827 ------------ platform/android/export/export_plugin.cpp | 2 +- platform/android/export/gradle_export_util.h | 45 - platform/android/os_android.cpp | 6 +- platform/android/os_android.h | 2 +- platform/iphone/app_delegate.h | 2 +- platform/iphone/display_layer.mm | 2 +- platform/iphone/display_server_iphone.mm | 12 +- platform/iphone/export/export.cpp | 1923 -------- platform/javascript/display_server_javascript.cpp | 6 +- platform/javascript/export/export.cpp | 672 --- platform/javascript/export/export_plugin.cpp | 2 +- platform/linuxbsd/detect.py | 2 +- platform/linuxbsd/detect_prime_x11.cpp | 2 +- platform/linuxbsd/detect_prime_x11.h | 2 +- platform/linuxbsd/display_server_x11.cpp | 51 +- platform/linuxbsd/display_server_x11.h | 6 +- platform/linuxbsd/gl_manager_x11.cpp | 8 +- platform/linuxbsd/gl_manager_x11.h | 6 +- platform/osx/context_gl_osx.h | 6 +- platform/osx/context_gl_osx.mm | 8 +- platform/osx/detect.py | 2 +- platform/osx/display_server_osx.h | 6 +- platform/osx/display_server_osx.mm | 28 +- platform/uwp/os_uwp.cpp | 8 +- platform/windows/context_gl_windows.cpp | 186 - platform/windows/detect.py | 4 +- platform/windows/display_server_windows.cpp | 69 +- platform/windows/display_server_windows.h | 4 +- platform/windows/gl_manager_windows.cpp | 74 +- platform/windows/gl_manager_windows.h | 5 +- .../forward_clustered/render_forward_clustered.cpp | 2 +- .../forward_mobile/render_forward_mobile.cpp | 2 +- servers/rendering/renderer_viewport.cpp | 2 +- servers/rendering_server.cpp | 37 + 114 files changed, 20615 insertions(+), 26647 deletions(-) create mode 100644 drivers/gles3/SCsub create mode 100644 drivers/gles3/rasterizer_array.h create mode 100644 drivers/gles3/rasterizer_asserts.h create mode 100644 drivers/gles3/rasterizer_canvas_base_gles3.cpp create mode 100644 drivers/gles3/rasterizer_canvas_base_gles3.h create mode 100644 drivers/gles3/rasterizer_canvas_batcher.h create mode 100644 drivers/gles3/rasterizer_canvas_gles3.cpp create mode 100644 drivers/gles3/rasterizer_canvas_gles3.h create mode 100644 drivers/gles3/rasterizer_gles3.cpp create mode 100644 drivers/gles3/rasterizer_gles3.h create mode 100644 drivers/gles3/rasterizer_platforms.h create mode 100644 drivers/gles3/rasterizer_scene_gles3.cpp create mode 100644 drivers/gles3/rasterizer_scene_gles3.h create mode 100644 drivers/gles3/rasterizer_storage_common.h create mode 100644 drivers/gles3/rasterizer_storage_gles3.cpp create mode 100644 drivers/gles3/rasterizer_storage_gles3.h create mode 100644 drivers/gles3/shader_compiler_gles3.cpp create mode 100644 drivers/gles3/shader_compiler_gles3.h create mode 100644 drivers/gles3/shader_gles3.cpp create mode 100644 drivers/gles3/shader_gles3.h create mode 100644 drivers/gles3/shaders/SCsub create mode 100644 drivers/gles3/shaders/canvas.glsl create mode 100644 drivers/gles3/shaders/canvas_shadow.glsl create mode 100644 drivers/gles3/shaders/copy.glsl create mode 100644 drivers/gles3/shaders/cube_to_dp.glsl create mode 100644 drivers/gles3/shaders/cubemap_filter.glsl create mode 100644 drivers/gles3/shaders/effect_blur.glsl create mode 100644 drivers/gles3/shaders/lens_distorted.glsl create mode 100644 drivers/gles3/shaders/scene.glsl create mode 100644 drivers/gles3/shaders/tonemap.glsl create mode 100644 drivers/gles3/texture_loader_gles3.cpp create mode 100644 drivers/gles3/texture_loader_gles3.h delete mode 100644 drivers/opengl/SCsub delete mode 100644 drivers/opengl/rasterizer_array.h delete mode 100644 drivers/opengl/rasterizer_asserts.h delete mode 100644 drivers/opengl/rasterizer_canvas_base_opengl.cpp delete mode 100644 drivers/opengl/rasterizer_canvas_base_opengl.h delete mode 100644 drivers/opengl/rasterizer_canvas_batcher.h delete mode 100644 drivers/opengl/rasterizer_canvas_opengl.cpp delete mode 100644 drivers/opengl/rasterizer_canvas_opengl.h delete mode 100644 drivers/opengl/rasterizer_opengl.cpp delete mode 100644 drivers/opengl/rasterizer_opengl.h delete mode 100644 drivers/opengl/rasterizer_platforms.h delete mode 100644 drivers/opengl/rasterizer_scene_opengl.cpp delete mode 100644 drivers/opengl/rasterizer_scene_opengl.h delete mode 100644 drivers/opengl/rasterizer_storage_common.h delete mode 100644 drivers/opengl/rasterizer_storage_opengl.cpp delete mode 100644 drivers/opengl/rasterizer_storage_opengl.h delete mode 100644 drivers/opengl/shader_compiler_opengl.cpp delete mode 100644 drivers/opengl/shader_compiler_opengl.h delete mode 100644 drivers/opengl/shader_opengl.cpp delete mode 100644 drivers/opengl/shader_opengl.h delete mode 100644 drivers/opengl/shaders/SCsub delete mode 100644 drivers/opengl/shaders/canvas.glsl delete mode 100644 drivers/opengl/shaders/canvas_shadow.glsl delete mode 100644 drivers/opengl/shaders/copy.glsl delete mode 100644 drivers/opengl/shaders/cube_to_dp.glsl delete mode 100644 drivers/opengl/shaders/cubemap_filter.glsl delete mode 100644 drivers/opengl/shaders/effect_blur.glsl delete mode 100644 drivers/opengl/shaders/lens_distorted.glsl delete mode 100644 drivers/opengl/shaders/scene.glsl delete mode 100644 drivers/opengl/shaders/stdlib.glsl delete mode 100644 drivers/opengl/shaders/tonemap.glsl delete mode 100644 drivers/opengl/texture_loader_opengl.cpp delete mode 100644 drivers/opengl/texture_loader_opengl.h create mode 100644 gles3_builders.py delete mode 100644 opengl_builders.py delete mode 100644 platform/windows/context_gl_windows.cpp diff --git a/SConstruct b/SConstruct index cd4657b20c..78e3d28337 100644 --- a/SConstruct +++ b/SConstruct @@ -15,7 +15,7 @@ from collections import OrderedDict # Local import methods import glsl_builders -import opengl_builders +import gles3_builders from platform_methods import run_in_subprocess # Scan possible build platforms @@ -711,8 +711,8 @@ if selected_platform in platform_list: if not env["platform"] == "server": env.Append( BUILDERS={ - "OpenGL_GLSL": env.Builder( - action=run_in_subprocess(opengl_builders.build_opengl_headers), + "GLES3_GLSL": env.Builder( + action=run_in_subprocess(gles3_builders.build_gles3_headers), suffix="glsl.gen.h", src_suffix=".glsl", ) diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 31e9237d56..afd82939ca 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -604,7 +604,7 @@ void OS::_bind_methods() { ADD_PROPERTY_DEFAULT("low_processor_usage_mode_sleep_usec", 6900); BIND_ENUM_CONSTANT(VIDEO_DRIVER_VULKAN); - BIND_ENUM_CONSTANT(VIDEO_DRIVER_OPENGL); + BIND_ENUM_CONSTANT(VIDEO_DRIVER_OPENGL_3); BIND_ENUM_CONSTANT(DAY_SUNDAY); BIND_ENUM_CONSTANT(DAY_MONDAY); diff --git a/core/core_bind.h b/core/core_bind.h index afbee4efaa..010d1e2419 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -120,7 +120,7 @@ protected: public: enum VideoDriver { VIDEO_DRIVER_VULKAN, - VIDEO_DRIVER_OPENGL, + VIDEO_DRIVER_OPENGL_3, }; enum Weekday { diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index cc845cc139..03a3ac053d 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -456,10 +456,10 @@ - The Vulkan rendering backend. + The Vulkan rendering backend. It requires Vulkan 1.0 support and automatically uses features from Vulkan 1.1 and 1.2 if available. - - The OpenGL rendering backend. It uses OpenGL ES 3.0 on mobile devices, OpenGL 3.3 on desktop platforms and WebGL 2.0 on the web. + + The OpenGL 3 rendering backend. It uses OpenGL 3.3 Core Profile on desktop platforms, OpenGL ES 3.0 on mobile devices, and WebGL 2.0 on HTML5. Sunday. diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index e67ccf9efd..5563695811 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1475,6 +1475,18 @@ The number of fixed iterations per second. This controls how often physics simulation and [method Node._physics_process] methods are run. [b]Note:[/b] This property is only read when the project starts. To change the physics FPS at runtime, set [member Engine.physics_ticks_per_second] instead. + + + + + + + + + + + + @@ -1504,6 +1516,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Sets the quality of the depth of field effect. Higher quality takes more samples, which is slower but looks smoother. @@ -1585,6 +1623,10 @@ Base size used to determine size of froxel buffer in the camera X-axis and Y-axis. The final size is scaled by the aspect ratio of the screen, so actual values may differ from what is set. Set a larger size for more detailed fog, set a smaller size for better performance. + + + + diff --git a/drivers/SCsub b/drivers/SCsub index ea6d4c9a47..714d4110de 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -25,7 +25,7 @@ SConscript("winmidi/SCsub") # Graphics drivers if env["vulkan"]: SConscript("vulkan/SCsub") - SConscript("opengl/SCsub") + SConscript("gles3/SCsub") SConscript("gl_context/SCsub") else: SConscript("dummy/SCsub") diff --git a/drivers/gles3/SCsub b/drivers/gles3/SCsub new file mode 100644 index 0000000000..987ddcd16e --- /dev/null +++ b/drivers/gles3/SCsub @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.drivers_sources, "*.cpp") + +SConscript("shaders/SCsub") diff --git a/drivers/gles3/rasterizer_array.h b/drivers/gles3/rasterizer_array.h new file mode 100644 index 0000000000..a321c9ed10 --- /dev/null +++ b/drivers/gles3/rasterizer_array.h @@ -0,0 +1,421 @@ +/*************************************************************************/ +/* rasterizer_array.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_ARRAY_H +#define RASTERIZER_ARRAY_H + +/** + * Fast single-threaded growable array for POD types. + * For use in render drivers, not for general use. + * TO BE REPLACED by local_vector. + */ + +#include "core/os/memory.h" +#include + +#include "core/templates/local_vector.h" +#include "core/templates/vector.h" + +// very simple non-growable array, that keeps track of the size of a 'unit' +// which can be cast to whatever vertex format FVF required, and is initially +// created with enough memory to hold the biggest FVF. +// This allows multiple FVFs to use the same array. +class RasterizerUnitArrayGLES3 { +public: + RasterizerUnitArrayGLES3() { + _list = nullptr; + free(); + } + ~RasterizerUnitArrayGLES3() { free(); } + + uint8_t *get_unit(unsigned int ui) { return &_list[ui * _unit_size_bytes]; } + const uint8_t *get_unit(unsigned int ui) const { return &_list[ui * _unit_size_bytes]; } + + int size() const { return _size; } + int max_size() const { return _max_size; } + + void free() { + if (_list) { + memdelete_arr(_list); + _list = 0; + } + _size = 0; + _max_size = 0; + _max_size_bytes = 0; + _unit_size_bytes = 0; + } + + void create(int p_max_size_units, int p_max_unit_size_bytes) { + free(); + + _max_unit_size_bytes = p_max_unit_size_bytes; + _max_size = p_max_size_units; + _max_size_bytes = p_max_size_units * p_max_unit_size_bytes; + + if (_max_size_bytes) { + _list = memnew_arr(uint8_t, _max_size_bytes); + } + } + + void prepare(int p_unit_size_bytes) { + _unit_size_bytes = p_unit_size_bytes; + _size = 0; + } + + // several items at a time + uint8_t *request(int p_num_items = 1) { + int old_size = _size; + _size += p_num_items; + + if (_size <= _max_size) { + return get_unit(old_size); + } + + // revert + _size = old_size; + return nullptr; + } + +private: + uint8_t *_list; + int _size; // in units + int _max_size; // in units + int _max_size_bytes; + int _unit_size_bytes; + int _max_unit_size_bytes; +}; + +template +class RasterizerArray { +public: + RasterizerArray() { + _list = 0; + _size = 0; + _max_size = 0; + } + ~RasterizerArray() { free(); } + + T &operator[](unsigned int ui) { return _list[ui]; } + const T &operator[](unsigned int ui) const { return _list[ui]; } + + void free() { + if (_list) { + memdelete_arr(_list); + _list = 0; + } + _size = 0; + _max_size = 0; + } + + void create(int p_size) { + free(); + if (p_size) { + _list = memnew_arr(T, p_size); + } + _size = 0; + _max_size = p_size; + } + + void reset() { _size = 0; } + + T *request_with_grow() { + T *p = request(); + if (!p) { + grow(); + return request_with_grow(); + } + return p; + } + + // none of that inefficient pass by value stuff here, thanks + T *request() { + if (_size < _max_size) { + return &_list[_size++]; + } + return 0; + } + + // several items at a time + T *request(int p_num_items) { + int old_size = _size; + _size += p_num_items; + + if (_size <= _max_size) { + return &_list[old_size]; + } + + // revert + _size = old_size; + return 0; + } + + int size() const { return _size; } + int max_size() const { return _max_size; } + const T *get_data() const { return _list; } + + bool copy_from(const RasterizerArray &o) { + // no resizing done here, it should be done manually + if (o.size() > _max_size) + return false; + + // pod types only please! + memcpy(_list, o.get_data(), o.size() * sizeof(T)); + _size = o.size(); + return true; + } + + // if you want this to be cheap, call reset before grow, + // to ensure there is no data to copy + void grow() { + unsigned int new_max_size = _max_size * 2; + if (!new_max_size) + new_max_size = 1; + + T *new_list = memnew_arr(T, new_max_size); + + // copy .. pod types only + if (_list) { + memcpy(new_list, _list, _size * sizeof(T)); + } + + unsigned int new_size = size(); + free(); + _list = new_list; + _size = new_size; + _max_size = new_max_size; + } + +private: + T *_list; + int _size; + int _max_size; +}; + +template +class RasterizerArray_non_pod { +public: + RasterizerArray_non_pod() { + _size = 0; + } + + const T &operator[](unsigned int ui) const { return _list[ui]; } + + void create(int p_size) { + _list.resize(p_size); + _size = 0; + } + void reset() { _size = 0; } + + void push_back(const T &val) { + while (true) { + if (_size < max_size()) { + _list.set(_size, val); + _size++; + return; + } + + grow(); + } + } + + int size() const { return _size; } + int max_size() const { return _list.size(); } + +private: + void grow() { + unsigned int new_max_size = _list.size() * 2; + if (!new_max_size) + new_max_size = 1; + _list.resize(new_max_size); + } + + Vector _list; + int _size; +}; + +// very simple non-growable array, that keeps track of the size of a 'unit' +// which can be cast to whatever vertex format FVF required, and is initially +// created with enough memory to hold the biggest FVF. +// This allows multiple FVFs to use the same array. +class RasterizerUnitArray { +public: + RasterizerUnitArray() { + _list = nullptr; + free(); + } + ~RasterizerUnitArray() { free(); } + + uint8_t *get_unit(unsigned int ui) { return &_list[ui * _unit_size_bytes]; } + const uint8_t *get_unit(unsigned int ui) const { return &_list[ui * _unit_size_bytes]; } + + int size() const { return _size; } + int max_size() const { return _max_size; } + int get_unit_size_bytes() const { return _unit_size_bytes; } + + void free() { + if (_list) { + memdelete_arr(_list); + _list = 0; + } + _size = 0; + _max_size = 0; + _max_size_bytes = 0; + _unit_size_bytes = 0; + } + + void create(int p_max_size_units, int p_max_unit_size_bytes) { + free(); + + _max_unit_size_bytes = p_max_unit_size_bytes; + _max_size = p_max_size_units; + _max_size_bytes = p_max_size_units * p_max_unit_size_bytes; + + if (_max_size_bytes) { + _list = memnew_arr(uint8_t, _max_size_bytes); + } + } + + void prepare(int p_unit_size_bytes) { + _unit_size_bytes = p_unit_size_bytes; + _size = 0; + } + + // several items at a time + uint8_t *request(int p_num_items = 1) { + int old_size = _size; + _size += p_num_items; + + if (_size <= _max_size) { + return get_unit(old_size); + } + + // revert + _size = old_size; + return nullptr; + } + +private: + uint8_t *_list; + int _size; // in units + int _max_size; // in units + int _max_size_bytes; + int _unit_size_bytes; + int _max_unit_size_bytes; +}; + +template +class RasterizerPooledList { + LocalVector list; + LocalVector freelist; + + // not all list members are necessarily used + int _used_size; + +public: + RasterizerPooledList() { + _used_size = 0; + } + + int estimate_memory_use() const { + return (list.size() * sizeof(T)) + (freelist.size() * sizeof(uint32_t)); + } + + const T &operator[](uint32_t p_index) const { + return list[p_index]; + } + T &operator[](uint32_t p_index) { + return list[p_index]; + } + + int size() const { return _used_size; } + + // returns the list id of the allocated item + uint32_t alloc() { + uint32_t id = 0; + _used_size++; + + if (freelist.size()) { + // pop from freelist + int new_size = freelist.size() - 1; + id = freelist[new_size]; + freelist.resize(new_size); + return id; + // return &list[r_id]; + } + + id = list.size(); + list.resize(id + 1); + return id; + // return &list[r_id]; + } + void free(const uint32_t &p_id) { + // should not be on free list already + CRASH_COND(p_id >= list.size()); + freelist.push_back(p_id); + _used_size--; + } +}; + +template +class RasterizerPooledIndirectList { +public: + const T &operator[](uint32_t p_index) const { + return *_list[p_index]; + } + T &operator[](uint32_t p_index) { + return *_list[p_index]; + } + + uint32_t alloc() { + uint32_t id = _list.alloc(); + _list[id] = memnew(T); + return id; + } + void free(const uint32_t &p_id) { + CRASH_COND(!_list[p_id]); + memdelete_notnull(_list[p_id]); + _list[p_id] = nullptr; + _list.free(p_id); + } + + ~RasterizerPooledIndirectList() { + // autodelete + for (int n = 0; n < _list.size(); n++) { + if (_list[n]) { + memdelete_notnull(_list[n]); + } + } + } + +private: + RasterizerPooledList _list; +}; + +#endif // RASTERIZER_ARRAY_H diff --git a/drivers/gles3/rasterizer_asserts.h b/drivers/gles3/rasterizer_asserts.h new file mode 100644 index 0000000000..dbc45035b2 --- /dev/null +++ b/drivers/gles3/rasterizer_asserts.h @@ -0,0 +1,67 @@ +/*************************************************************************/ +/* rasterizer_asserts.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_ASSERTS_H +#define RASTERIZER_ASSERTS_H + +// For flow control checking, we want an easy way to apply asserts that occur in debug development builds only. +// This is enforced by outputting a warning which will fail CI checks if the define is set in a PR. +#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) +// only uncomment this define for error checking in development, not in the main repository +// as these checks will slow things down in debug builds. +//#define RASTERIZER_EXTRA_CHECKS +#endif + +#ifdef RASTERIZER_EXTRA_CHECKS +#ifndef _MSC_VER +#warning do not define RASTERIZER_EXTRA_CHECKS in main repository builds +#endif +#define RAST_DEV_DEBUG_ASSERT(a) CRASH_COND(!(a)) +#else +#define RAST_DEV_DEBUG_ASSERT(a) +#endif + +// Also very useful, an assert check that only occurs in debug tools builds +#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) +#define RAST_DEBUG_ASSERT(a) CRASH_COND(!(a)) +#else +#define RAST_DEBUG_ASSERT(a) +#endif + +// Thin wrapper around ERR_FAIL_COND to allow us to make it debug only +#ifdef DEBUG_ENABLED +#define RAST_FAIL_COND(m_cond) ERR_FAIL_COND(m_cond) +#else +#define RAST_FAIL_COND(m_cond) \ + if (m_cond) { \ + } +#endif + +#endif // RASTERIZER_ASSERTS_H diff --git a/drivers/gles3/rasterizer_canvas_base_gles3.cpp b/drivers/gles3/rasterizer_canvas_base_gles3.cpp new file mode 100644 index 0000000000..ffa0bc30f5 --- /dev/null +++ b/drivers/gles3/rasterizer_canvas_base_gles3.cpp @@ -0,0 +1,1354 @@ +/*************************************************************************/ +/* rasterizer_canvas_base_gles3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "rasterizer_canvas_base_gles3.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/os/os.h" +#include "drivers/gles3/rasterizer_asserts.h" +#include "rasterizer_scene_gles3.h" + +#include "core/config/project_settings.h" +#include "servers/rendering/rendering_server_default.h" + +#ifndef GLES_OVER_GL +#define glClearDepth glClearDepthf +#endif + +static _FORCE_INLINE_ void store_transform3d(const Transform3D &p_mtx, float *p_array) { + p_array[0] = p_mtx.basis.elements[0][0]; + p_array[1] = p_mtx.basis.elements[1][0]; + p_array[2] = p_mtx.basis.elements[2][0]; + p_array[3] = 0; + p_array[4] = p_mtx.basis.elements[0][1]; + p_array[5] = p_mtx.basis.elements[1][1]; + p_array[6] = p_mtx.basis.elements[2][1]; + p_array[7] = 0; + p_array[8] = p_mtx.basis.elements[0][2]; + p_array[9] = p_mtx.basis.elements[1][2]; + p_array[10] = p_mtx.basis.elements[2][2]; + p_array[11] = 0; + p_array[12] = p_mtx.origin.x; + p_array[13] = p_mtx.origin.y; + p_array[14] = p_mtx.origin.z; + p_array[15] = 1; +} + +RID RasterizerCanvasBaseGLES3::light_internal_create() { + return RID(); +} + +void RasterizerCanvasBaseGLES3::light_internal_update(RID p_rid, Light *p_light) { +} + +void RasterizerCanvasBaseGLES3::light_internal_free(RID p_rid) { +} + +RID RasterizerCanvasBaseGLES3::light_create() { + return RID(); +} + +void RasterizerCanvasBaseGLES3::light_set_texture(RID p_rid, RID p_texture) { +} + +void RasterizerCanvasBaseGLES3::light_set_use_shadow(RID p_rid, bool p_enable) { +} + +void RasterizerCanvasBaseGLES3::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { +} + +void RasterizerCanvasBaseGLES3::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { +} + +void RasterizerCanvasBaseGLES3::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) { +} + +RID RasterizerCanvasBaseGLES3::occluder_polygon_create() { + return RID(); +} + +void RasterizerCanvasBaseGLES3::occluder_polygon_set_shape(RID p_occluder, const Vector &p_points, bool p_closed) { +} + +void RasterizerCanvasBaseGLES3::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { +} + +void RasterizerCanvasBaseGLES3::set_shadow_texture_size(int p_size) { +} + +bool RasterizerCanvasBaseGLES3::free(RID p_rid) { + return true; +} + +void RasterizerCanvasBaseGLES3::update() { +} + +void RasterizerCanvasBaseGLES3::canvas_begin() { + state.using_transparent_rt = false; + + // always start with light_angle unset + state.using_light_angle = false; + state.using_large_vertex = false; + state.using_modulate = false; + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LIGHT_ANGLE, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_MODULATE, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LARGE_VERTEX, false); + state.canvas_shader.bind(); + + int viewport_x, viewport_y, viewport_width, viewport_height; + + if (storage->frame.current_rt) { + storage->bind_framebuffer(storage->frame.current_rt->fbo); + state.using_transparent_rt = storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]; + + if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + // set Viewport and Scissor when rendering directly to screen + viewport_width = storage->_dims.rt_width; + viewport_height = storage->_dims.rt_height; + viewport_x = storage->frame.current_rt->x; + // FTODO + // viewport_y = OS::get_singleton()->get_window_size().height - viewport_height - storage->frame.current_rt->y; + viewport_y = storage->frame.current_rt->y; + + // viewport_x = 0; + // viewport_y = 0; + + glScissor(viewport_x, viewport_y, viewport_width, viewport_height); + glViewport(viewport_x, viewport_y, viewport_width, viewport_height); + glEnable(GL_SCISSOR_TEST); + } + } + + // FTODO .. this was commented out to try and get the clear color correct + //#ifdef GODOT3 + // OLD METHOD .. now done by render target rather than frame +#if 0 + if (storage->frame.clear_request) { + glClearColor(storage->frame.clear_request_color.r, + storage->frame.clear_request_color.g, + storage->frame.clear_request_color.b, + state.using_transparent_rt ? storage->frame.clear_request_color.a : 1.0); + glClear(GL_COLOR_BUFFER_BIT); + storage->frame.clear_request = false; + } +#endif + + // NEW METHOD + if (storage->frame.current_rt && storage->frame.current_rt->clear_requested) { + const Color &col = storage->frame.current_rt->clear_color; + glClearColor(col.r, col.g, col.b, col.a); + + // clear EVERYTHING. + // not clearing everything can be devastating on tiled renderers especially, + // because if anything is preserved, often the whole frame buffer needs to be preserved. + // Not sure if GL_ACCUM_BUFFER_BIT is needed or supported in GLES. + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + storage->frame.current_rt->clear_requested = false; + } + + //#endif + + /* + if (storage->frame.current_rt) { + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); + glColorMask(1, 1, 1, 1); + } + */ + + reset_canvas(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + + glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); + glDisableVertexAttribArray(RS::ARRAY_COLOR); + + // set up default uniforms + + Transform3D canvas_transform; + + if (storage->frame.current_rt) { + float csy = 1.0; + // FTODO + // if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_VFLIP]) { + // csy = -1.0; + // } + canvas_transform.translate(-(storage->frame.current_rt->width / 2.0f), -(storage->frame.current_rt->height / 2.0f), 0.0f); + canvas_transform.scale(Vector3(2.0f / storage->frame.current_rt->width, csy * -2.0f / storage->frame.current_rt->height, 1.0f)); + } else { + // FTODO + // Vector2 ssize = OS::get_singleton()->get_window_size(); + Vector2 ssize; + ssize.x = storage->_dims.win_width; + ssize.y = storage->_dims.win_height; + + canvas_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); + canvas_transform.scale(Vector3(2.0f / ssize.width, -2.0f / ssize.height, 1.0f)); + } + + state.uniforms.projection_matrix = canvas_transform; + + state.uniforms.final_modulate = Color(1, 1, 1, 1); + + state.uniforms.modelview_matrix = Transform2D(); + state.uniforms.extra_matrix = Transform2D(); + + _set_uniforms(); + _bind_quad_buffer(); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_item_ubo); + glBindVertexArray(data.canvas_quad_array); +} + +void RasterizerCanvasBaseGLES3::canvas_end() { + glBindBuffer(GL_ARRAY_BUFFER, 0); + + if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + //reset viewport to full window size + // int viewport_width = OS::get_singleton()->get_window_size().width; + // int viewport_height = OS::get_singleton()->get_window_size().height; + int viewport_width = storage->_dims.win_width; + int viewport_height = storage->_dims.win_height; + glViewport(0, 0, viewport_width, viewport_height); + glScissor(0, 0, viewport_width, viewport_height); + } + + state.using_texture_rect = false; + state.using_skeleton = false; + state.using_ninepatch = false; + state.using_transparent_rt = false; +} + +void RasterizerCanvasBaseGLES3::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) { + state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y)); + _bind_quad_buffer(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + +void RasterizerCanvasBaseGLES3::_set_texture_rect_mode(bool p_texture_rect, bool p_light_angle, bool p_modulate, bool p_large_vertex) { + // always set this directly (this could be state checked) + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_TEXTURE_RECT, p_texture_rect); + + if (state.using_light_angle != p_light_angle) { + state.using_light_angle = p_light_angle; + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LIGHT_ANGLE, p_light_angle); + } + + if (state.using_modulate != p_modulate) { + state.using_modulate = p_modulate; + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_MODULATE, p_modulate); + } + + if (state.using_large_vertex != p_large_vertex) { + state.using_large_vertex = p_large_vertex; + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_ATTRIB_LARGE_VERTEX, p_large_vertex); + } +} + +RasterizerStorageGLES3::Texture *RasterizerCanvasBaseGLES3::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map) { + RasterizerStorageGLES3::Texture *tex_return = NULL; + + if (p_texture.is_valid()) { + RasterizerStorageGLES3::Texture *texture = storage->texture_owner.get_or_null(p_texture); + + if (!texture) { + state.current_tex = RID(); + state.current_tex_ptr = NULL; + + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); + glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + + } else { + if (texture->redraw_if_visible) { + RenderingServerDefault::redraw_request(); + } + + texture = texture->get_ptr(); + + if (texture->render_target) { + texture->render_target->used_in_frame = true; + } + + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + + state.current_tex = p_texture; + state.current_tex_ptr = texture; + + // new for Godot 4. Set the texture min mag filter and repeat per item + // we use a wrapper to avoid noop GL state changes + texture->GLSetFilter(GL_TEXTURE_2D, state.current_filter); + + tex_return = texture; + } + } else { + state.current_tex = RID(); + state.current_tex_ptr = NULL; + + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); + glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + } + + if (p_normal_map == state.current_normal) { + //do none + state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, state.current_normal.is_valid()); + + } else if (p_normal_map.is_valid()) { + RasterizerStorageGLES3::Texture *normal_map = storage->texture_owner.get_or_null(p_normal_map); + + if (!normal_map) { + state.current_normal = RID(); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); + glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); + state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, false); + + } else { + if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies + RenderingServerDefault::redraw_request(); + } + + normal_map = normal_map->get_ptr(); + + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); + glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); + state.current_normal = p_normal_map; + state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, true); + } + + } else { + state.current_normal = RID(); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); + glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); + state.canvas_shader.set_uniform(CanvasShaderGLES3::USE_DEFAULT_NORMAL, false); + } + + return tex_return; +} + +/* +void RasterizerCanvasBaseGLES3::draw_window_margins(int *black_margin, RID *black_image) { + return; + + // FTODO + int window_w = storage->_dims.rt_width; + int window_h = storage->_dims.rt_height; + //Vector2 window_size = Vector2(window_w, window_h); + + // int window_h = window_size.height; + // int window_w = window_size.width; + + // glBindFramebuffer(GL_FRAMEBUFFER, storage->system_fbo); + // glViewport(0, 0, window_size.width, window_size.height); + + canvas_begin(); + + if (black_image[SIDE_LEFT].is_valid()) { + _bind_canvas_texture(black_image[SIDE_LEFT], RID()); + Size2 sz(storage->texture_get_width(black_image[SIDE_LEFT]), storage->texture_get_height(black_image[SIDE_LEFT])); + draw_generic_textured_rect(Rect2(0, 0, black_margin[SIDE_LEFT], window_h), + Rect2(0, 0, (float)black_margin[SIDE_LEFT] / sz.x, (float)(window_h) / sz.y)); + } else if (black_margin[SIDE_LEFT]) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + + draw_generic_textured_rect(Rect2(0, 0, black_margin[SIDE_LEFT], window_h), Rect2(0, 0, 1, 1)); + } + + if (black_image[SIDE_RIGHT].is_valid()) { + _bind_canvas_texture(black_image[SIDE_RIGHT], RID()); + Size2 sz(storage->texture_get_width(black_image[SIDE_RIGHT]), storage->texture_get_height(black_image[SIDE_RIGHT])); + draw_generic_textured_rect(Rect2(window_w - black_margin[SIDE_RIGHT], 0, black_margin[SIDE_RIGHT], window_h), + Rect2(0, 0, (float)black_margin[SIDE_RIGHT] / sz.x, (float)window_h / sz.y)); + } else if (black_margin[SIDE_RIGHT]) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + + draw_generic_textured_rect(Rect2(window_w - black_margin[SIDE_RIGHT], 0, black_margin[SIDE_RIGHT], window_h), Rect2(0, 0, 1, 1)); + } + + if (black_image[SIDE_TOP].is_valid()) { + _bind_canvas_texture(black_image[SIDE_TOP], RID()); + + Size2 sz(storage->texture_get_width(black_image[SIDE_TOP]), storage->texture_get_height(black_image[SIDE_TOP])); + draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[SIDE_TOP]), + Rect2(0, 0, (float)window_w / sz.x, (float)black_margin[SIDE_TOP] / sz.y)); + + } else if (black_margin[SIDE_TOP]) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + + draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[SIDE_TOP]), Rect2(0, 0, 1, 1)); + } + + if (black_image[SIDE_BOTTOM].is_valid()) { + _bind_canvas_texture(black_image[SIDE_BOTTOM], RID()); + + Size2 sz(storage->texture_get_width(black_image[SIDE_BOTTOM]), storage->texture_get_height(black_image[SIDE_BOTTOM])); + draw_generic_textured_rect(Rect2(0, window_h - black_margin[SIDE_BOTTOM], window_w, black_margin[SIDE_BOTTOM]), + Rect2(0, 0, (float)window_w / sz.x, (float)black_margin[SIDE_BOTTOM] / sz.y)); + + } else if (black_margin[SIDE_BOTTOM]) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + + draw_generic_textured_rect(Rect2(0, window_h - black_margin[SIDE_BOTTOM], window_w, black_margin[SIDE_BOTTOM]), Rect2(0, 0, 1, 1)); + } + + canvas_end(); +} +*/ + +void RasterizerCanvasBaseGLES3::_bind_quad_buffer() { + glBindVertexArray(data.canvas_quad_array); +} + +void RasterizerCanvasBaseGLES3::_set_uniforms() { + state.canvas_shader.set_uniform(CanvasShaderGLES3::PROJECTION_MATRIX, state.uniforms.projection_matrix); + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.uniforms.extra_matrix); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.uniforms.final_modulate); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::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(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, screen_pixel_size); + } + + if (state.using_skeleton) { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM, state.skeleton_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TEXTURE_SIZE, state.skeleton_texture_size); + } + + if (state.using_light) { + Light *light = state.using_light; + state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_MATRIX, light->light_shader_xform); + Transform2D basis_inverse = light->light_shader_xform.affine_inverse().orthonormalized(); + basis_inverse.elements[2] = Vector2(); + state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_MATRIX_INVERSE, basis_inverse); + state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_LOCAL_MATRIX, light->xform_cache.affine_inverse()); + state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_COLOR, light->color * light->energy); + // state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_POS, light->light_shader_pos); + // FTODO + state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_POS, light->light_shader_xform.elements[2]); + state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_HEIGHT, light->height); + + // FTODO + //state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_OUTSIDE_ALPHA, light->mode == RS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0); + state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_OUTSIDE_ALPHA, 0.0f); + + if (state.using_shadow) { + // FTODO +#if 0 + RasterizerStorageGLES3::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(light->shadow_buffer); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); + glBindTexture(GL_TEXTURE_2D, cls->distance); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SHADOW_MATRIX, light->shadow_matrix_cache); + state.canvas_shader.set_uniform(CanvasShaderGLES3::LIGHT_SHADOW_COLOR, light->shadow_color); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::SHADOWPIXEL_SIZE, (1.0 / light->shadow_buffer_size) * (1.0 + light->shadow_smooth)); + if (light->radius_cache == 0) { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SHADOW_GRADIENT, 0.0); + } else { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SHADOW_GRADIENT, light->shadow_gradient_length / (light->radius_cache * 1.1)); + } + state.canvas_shader.set_uniform(CanvasShaderGLES3::SHADOW_DISTANCE_MULT, light->radius_cache * 1.1); +#endif + } + } +} + +void RasterizerCanvasBaseGLES3::reset_canvas() { + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DITHER); + glEnable(GL_BLEND); + + if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::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); + } + + // bind the back buffer to a texture so shaders can use it. + // It should probably use texture unit -3 (as OpenGL does as well) but currently that's buggy. + // keeping this for now as there's nothing else that uses texture unit 2 + // TODO ^ + if (storage->frame.current_rt) { + // glActiveTexture(GL_TEXTURE0 + 2); + // glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void RasterizerCanvasBaseGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) { +} + +void RasterizerCanvasBaseGLES3::_copy_texscreen(const Rect2 &p_rect) { + state.canvas_texscreen_used = true; + + _copy_screen(p_rect); + + // back to canvas, force rebind + state.using_texture_rect = false; + state.canvas_shader.bind(); + _bind_canvas_texture(state.current_tex, state.current_normal); + _set_uniforms(); +} + +void RasterizerCanvasBaseGLES3::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights, const int *p_bones) { + glBindVertexArray(data.polygon_buffer_pointer_array); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + + uint32_t buffer_ofs = 0; + uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size); +#endif + + storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true); + + glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); + buffer_ofs = buffer_ofs_after; + + if (p_singlecolor) { + glDisableVertexAttribArray(RS::ARRAY_COLOR); + Color m = *p_colors; + glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); + } else if (!p_colors) { + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); + } else { + RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after)); + glEnableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs = buffer_ofs_after; + } + + if (p_uvs) { + RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after)); + glEnableVertexAttribArray(RS::ARRAY_TEX_UV); + glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs = buffer_ofs_after; + } else { + glDisableVertexAttribArray(RS::ARRAY_TEX_UV); + } + + if (p_weights && p_bones) { + RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights, buffer_ofs_after)); + glEnableVertexAttribArray(RS::ARRAY_WEIGHTS); + glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs = buffer_ofs_after; + + RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones, buffer_ofs_after)); + glEnableVertexAttribArray(RS::ARRAY_BONES); + glVertexAttribPointer(RS::ARRAY_BONES, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs = buffer_ofs_after; + + } else { + glDisableVertexAttribArray(RS::ARRAY_WEIGHTS); + glDisableVertexAttribArray(RS::ARRAY_BONES); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); + + if (storage->config.support_32_bits_indices) { //should check for +#ifdef DEBUG_ENABLED + ERR_FAIL_COND((sizeof(int) * p_index_count) > data.polygon_index_buffer_size); +#endif + storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(int) * p_index_count, p_indices, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true); + + glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); + storage->info.render._2d_draw_call_count++; + } else { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND((sizeof(uint16_t) * p_index_count) > data.polygon_index_buffer_size); +#endif + uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count); + for (int i = 0; i < p_index_count; i++) { + index16[i] = uint16_t(p_indices[i]); + } + storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(uint16_t) * p_index_count, index16, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true); + glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_SHORT, 0); + storage->info.render._2d_draw_call_count++; + } + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void RasterizerCanvasBaseGLES3::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { + glBindVertexArray(data.polygon_buffer_pointer_array); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + + uint32_t buffer_ofs = 0; + uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size); +#endif + storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true); + + glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); + buffer_ofs = buffer_ofs_after; + + if (p_singlecolor) { + glDisableVertexAttribArray(RS::ARRAY_COLOR); + Color m = *p_colors; + glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); + } else if (!p_colors) { + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); + } else { + RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after)); + glEnableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs = buffer_ofs_after; + } + + if (p_uvs) { + RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after)); + glEnableVertexAttribArray(RS::ARRAY_TEX_UV); + glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs = buffer_ofs_after; + } else { + glDisableVertexAttribArray(RS::ARRAY_TEX_UV); + } + + glDrawArrays(p_primitive, 0, p_vertex_count); + storage->info.render._2d_draw_call_count++; + + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void RasterizerCanvasBaseGLES3::_draw_generic_indices(GLuint p_primitive, 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) { + glBindVertexArray(data.polygon_buffer_pointer_array); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + + uint32_t buffer_ofs = 0; + uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count); +#ifdef DEBUG_ENABLED + ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size); +#endif + storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true); + + glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); + buffer_ofs = buffer_ofs_after; + + if (p_singlecolor) { + glDisableVertexAttribArray(RS::ARRAY_COLOR); + Color m = *p_colors; + glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); + } else if (!p_colors) { + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); + } else { + RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after)); + glEnableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs = buffer_ofs_after; + } + + if (p_uvs) { + RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after)); + glEnableVertexAttribArray(RS::ARRAY_TEX_UV); + glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs = buffer_ofs_after; + } else { + glDisableVertexAttribArray(RS::ARRAY_TEX_UV); + } + +#ifdef RASTERIZER_EXTRA_CHECKS + // very slow, do not enable in normal use + for (int n = 0; n < p_index_count; n++) { + RAST_DEV_DEBUG_ASSERT(p_indices[n] < p_vertex_count); + } +#endif + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); + + if (storage->config.support_32_bits_indices) { //should check for +#ifdef DEBUG_ENABLED + ERR_FAIL_COND((sizeof(int) * p_index_count) > data.polygon_index_buffer_size); +#endif + storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(int) * p_index_count, p_indices, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true); + glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_INT, 0); + storage->info.render._2d_draw_call_count++; + } else { +#ifdef DEBUG_ENABLED + ERR_FAIL_COND((sizeof(uint16_t) * p_index_count) > data.polygon_index_buffer_size); +#endif + uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count); + for (int i = 0; i < p_index_count; i++) { + index16[i] = uint16_t(p_indices[i]); + } + storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(uint16_t) * p_index_count, index16, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true); + glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_SHORT, 0); + storage->info.render._2d_draw_call_count++; + } + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void RasterizerCanvasBaseGLES3::_legacy_draw_poly_triangles(Item::CommandPolygon *p_poly, RasterizerStorageGLES3::Material *p_material) { + // return; + + const PolyData &pd = _polydata[p_poly->polygon.polygon_id]; + + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + // FTODO + //RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(p_poly->texture, RID()); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + _draw_polygon(pd.indices.ptr(), pd.indices.size(), pd.points.size(), pd.points.ptr(), pd.uvs.ptr(), pd.colors.ptr(), pd.colors.size() == 1, nullptr, nullptr); + +// _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->weights.ptr(), polygon->bones.ptr()); +#ifdef GLES_OVER_GL +#if 0 + if (polygon->antialiased) { + glEnable(GL_LINE_SMOOTH); + if (polygon->antialiasing_use_indices) { + _draw_generic_indices(GL_LINE_STRIP, polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); + } else { + _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); + } + glDisable(GL_LINE_SMOOTH); + } +#endif +#endif +} + +void RasterizerCanvasBaseGLES3::_legacy_draw_primitive(Item::CommandPrimitive *p_pr, RasterizerStorageGLES3::Material *p_material) { + // return; + + if (p_pr->point_count != 4) + return; // not sure if supported + + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + _bind_canvas_texture(RID(), RID()); + + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4fv(RS::ARRAY_COLOR, p_pr->colors[0].components); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); + + _draw_gui_primitive(p_pr->point_count, p_pr->points, NULL, NULL); +} + +void RasterizerCanvasBaseGLES3::_legacy_draw_line(Item::CommandPrimitive *p_pr, RasterizerStorageGLES3::Material *p_material) { + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + _bind_canvas_texture(RID(), RID()); + + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4fv(RS::ARRAY_COLOR, p_pr->colors[0].components); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); + +#ifdef GLES_OVER_GL +// if (line->antialiased) +// glEnable(GL_LINE_SMOOTH); +#endif + _draw_gui_primitive(2, p_pr->points, NULL, NULL); + +#ifdef GLES_OVER_GL +// if (line->antialiased) +// glDisable(GL_LINE_SMOOTH); +#endif +} + +void RasterizerCanvasBaseGLES3::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs, const float *p_light_angles) { + static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN }; + + int version = 0; + int color_offset = 0; + int uv_offset = 0; + int light_angle_offset = 0; + int stride = 2; + + if (p_colors) { + version |= 1; + color_offset = stride; + stride += 4; + } + + if (p_uvs) { + version |= 2; + uv_offset = stride; + stride += 2; + } + + if (p_light_angles) { //light_angles + version |= 4; + light_angle_offset = stride; + stride += 1; + } + + RAST_DEV_DEBUG_ASSERT(p_points <= 4); + float buffer_data[(2 + 2 + 4 + 1) * 4]; + + for (int i = 0; i < p_points; i++) { + buffer_data[stride * i + 0] = p_vertices[i].x; + buffer_data[stride * i + 1] = p_vertices[i].y; + } + + if (p_colors) { + for (int i = 0; i < p_points; i++) { + buffer_data[stride * i + color_offset + 0] = p_colors[i].r; + buffer_data[stride * i + color_offset + 1] = p_colors[i].g; + buffer_data[stride * i + color_offset + 2] = p_colors[i].b; + buffer_data[stride * i + color_offset + 3] = p_colors[i].a; + } + } + + if (p_uvs) { + for (int i = 0; i < p_points; i++) { + buffer_data[stride * i + uv_offset + 0] = p_uvs[i].x; + buffer_data[stride * i + uv_offset + 1] = p_uvs[i].y; + } + } + + if (p_light_angles) { + for (int i = 0; i < p_points; i++) { + buffer_data[stride * i + light_angle_offset + 0] = p_light_angles[i]; + } + } + + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, p_points * stride * 4 * sizeof(float), buffer_data, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true); + + glBindVertexArray(data.polygon_buffer_quad_arrays[version]); + + glDrawArrays(prim[p_points], 0, p_points); + storage->info.render._2d_draw_call_count++; + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void RasterizerCanvasBaseGLES3::_copy_screen(const Rect2 &p_rect) { + if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + ERR_PRINT_ONCE("Cannot use screen texture copying in render target set to render direct to screen."); + return; + } + + ERR_FAIL_COND_MSG(storage->frame.current_rt->copy_screen_effect.color == 0, "Can't use screen texture copying in a render target configured without copy buffers."); + + glDisable(GL_BLEND); + + Vector2 wh(storage->frame.current_rt->width, storage->frame.current_rt->height); + + Color copy_section(p_rect.position.x / wh.x, p_rect.position.y / wh.y, p_rect.size.x / wh.x, p_rect.size.y / wh.y); + + if (p_rect != Rect2()) { + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_COPY_SECTION, true); + } + + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_NO_ALPHA, !state.using_transparent_rt); + + storage->bind_framebuffer(storage->frame.current_rt->copy_screen_effect.fbo); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + + storage->shaders.copy.bind(); + storage->shaders.copy.set_uniform(CopyShaderGLES3::COPY_SECTION, copy_section); + + const Vector2 vertpos[4] = { + Vector2(-1, -1), + Vector2(-1, 1), + Vector2(1, 1), + Vector2(1, -1), + }; + + const Vector2 uvpos[4] = { + Vector2(0, 0), + Vector2(0, 1), + Vector2(1, 1), + Vector2(1, 0) + }; + + const int indexpos[6] = { + 0, 1, 2, + 2, 3, 0 + }; + + _draw_polygon(indexpos, 6, 4, vertpos, uvpos, NULL, false); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_COPY_SECTION, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_NO_ALPHA, false); + + storage->bind_framebuffer(storage->frame.current_rt->fbo); + glEnable(GL_BLEND); +} + +void RasterizerCanvasBaseGLES3::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) { +#if 0 + RasterizerStorageGLES3::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(p_buffer); + ERR_FAIL_COND(!cls); + + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DITHER); + glDisable(GL_CULL_FACE); + glDepthFunc(GL_LEQUAL); + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); + state.canvas_shadow_shader.bind(); + + glViewport(0, 0, cls->size, cls->height); + glClearDepth(1.0f); + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + RS::CanvasOccluderPolygonCullMode cull = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; + + for (int i = 0; i < 4; i++) { + //make sure it remains orthogonal, makes easy to read angle later + + Transform3D light; + light.origin[0] = p_light_xform[2][0]; + light.origin[1] = p_light_xform[2][1]; + light.basis[0][0] = p_light_xform[0][0]; + light.basis[0][1] = p_light_xform[1][0]; + light.basis[1][0] = p_light_xform[0][1]; + light.basis[1][1] = p_light_xform[1][1]; + + //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); + + //p_near=1; + CameraMatrix projection; + { + real_t fov = 90; + real_t nearp = p_near; + real_t farp = p_far; + real_t aspect = 1.0; + + real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5)); + real_t ymin = -ymax; + real_t xmin = ymin * aspect; + real_t xmax = ymax * aspect; + + projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); + } + + Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * (i / 4.0))).xform(Vector3(0, 1, 0)); + projection = projection * CameraMatrix(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); + + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::PROJECTION_MATRIX, projection); + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::LIGHT_MATRIX, light); + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::DISTANCE_NORM, 1.0 / p_far); + + if (i == 0) + *p_xform_cache = projection; + + glViewport(0, (cls->height / 4) * i, cls->size, cls->height / 4); + + LightOccluderInstance *instance = p_occluders; + + while (instance) { + RasterizerStorageGLES3::CanvasOccluder *cc = storage->canvas_occluder_owner.get_or_null(instance->polygon_buffer); + if (!cc || cc->len == 0 || !(p_light_mask & instance->light_mask)) { + instance = instance->next; + continue; + } + + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES3::WORLD_MATRIX, instance->xform_cache); + + RS::CanvasOccluderPolygonCullMode transformed_cull_cache = instance->cull_cache; + + if (transformed_cull_cache != RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED && + (p_light_xform.basis_determinant() * instance->xform_cache.basis_determinant()) < 0) { + transformed_cull_cache = + transformed_cull_cache == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? + RS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE : + RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE; + } + + if (cull != transformed_cull_cache) { + cull = transformed_cull_cache; + switch (cull) { + case RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: { + glDisable(GL_CULL_FACE); + + } break; + case RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: { + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + } break; + case RS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: { + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + } break; + } + } + + glBindBuffer(GL_ARRAY_BUFFER, cc->vertex_id); + glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cc->index_id); + + glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0); + + instance = instance->next; + } + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +#endif +} + +void RasterizerCanvasBaseGLES3::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + Vector2 half_size; + if (storage->frame.current_rt) { + half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height); + } else { + // half_size = OS::get_singleton()->get_window_size(); + half_size = Vector2(storage->_dims.win_width, storage->_dims.win_height); + } + half_size *= 0.5; + Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y); + Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y); + + float aspect_ratio = p_rect.size.x / p_rect.size.y; + + // setup our lens shader + state.lens_shader.bind(); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::OFFSET, offset); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::SCALE, scale); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::K1, p_k1); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::K2, p_k2); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::EYE_CENTER, p_eye_center); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::UPSCALE, p_oversample); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio); + + // bind our quad buffer + _bind_quad_buffer(); + + // and draw + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // and cleanup + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void RasterizerCanvasBaseGLES3::initialize() { + bool flag_stream = false; + //flag_stream = GLOBAL_GET("rendering/options/api_usage_legacy/flag_stream"); + if (flag_stream) + _buffer_upload_usage_flag = GL_STREAM_DRAW; + else + _buffer_upload_usage_flag = GL_DYNAMIC_DRAW; + + // quad buffer + { + glGenBuffers(1, &data.canvas_quad_vertices); + glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); + + const float qv[8] = { + 0, 0, + 0, 1, + 1, 1, + 1, 0 + }; + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, qv, GL_STATIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glGenVertexArrays(1, &data.canvas_quad_array); + glBindVertexArray(data.canvas_quad_array); + glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 2, nullptr); + glEnableVertexAttribArray(0); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + } + + { + //particle quad buffers + + glGenBuffers(1, &data.particle_quad_vertices); + glBindBuffer(GL_ARRAY_BUFFER, data.particle_quad_vertices); + { + //quad of size 1, with pivot on the center for particles, then regular UVS. Color is general plus fetched from particle + const float qv[16] = { + -0.5, -0.5, + 0.0, 0.0, + -0.5, 0.5, + 0.0, 1.0, + 0.5, 0.5, + 1.0, 1.0, + 0.5, -0.5, + 1.0, 0.0 + }; + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + + glGenVertexArrays(1, &data.particle_quad_array); + glBindVertexArray(data.particle_quad_array); + glBindBuffer(GL_ARRAY_BUFFER, data.particle_quad_vertices); + glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, nullptr); + glEnableVertexAttribArray(RS::ARRAY_TEX_UV); + glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); + glBindVertexArray(0); + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + } + + // polygon buffer + { + uint32_t poly_size = 128; //GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); + poly_size = MAX(poly_size, 2); // minimum 2k, may still see anomalies in editor + poly_size *= 1024; //kb + glGenBuffers(1, &data.polygon_buffer); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + glBufferData(GL_ARRAY_BUFFER, poly_size, nullptr, GL_DYNAMIC_DRAW); //allocate max size + glBindBuffer(GL_ARRAY_BUFFER, 0); + data.polygon_buffer_size = poly_size; + + //quad arrays + for (int i = 0; i < Data::NUM_QUAD_ARRAY_VARIATIONS; i++) { + glGenVertexArrays(1, &data.polygon_buffer_quad_arrays[i]); + glBindVertexArray(data.polygon_buffer_quad_arrays[i]); + glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); + + int uv_ofs = 0; + int color_ofs = 0; + int light_angle_ofs = 0; + int stride = 2 * 4; + + if (i & 1) { //color + color_ofs = stride; + stride += 4 * 4; + } + + if (i & 2) { //uv + uv_ofs = stride; + stride += 2 * 4; + } + + if (i & 4) { //light_angle + light_angle_ofs = stride; + stride += 1 * 4; + } + + glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride, nullptr); + + if (i & 1) { + glEnableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); + } + + if (i & 2) { + glEnableVertexAttribArray(RS::ARRAY_TEX_UV); + glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(uv_ofs)); + } + + if (i & 4) { + // reusing tangent for light_angle + glEnableVertexAttribArray(RS::ARRAY_TANGENT); + glVertexAttribPointer(RS::ARRAY_TANGENT, 1, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(light_angle_ofs)); + } + + glBindVertexArray(0); + } + + glGenVertexArrays(1, &data.polygon_buffer_pointer_array); + + uint32_t index_size = 128; //GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); + index_size = MAX(index_size, 2); + index_size *= 1024; //kb + glGenBuffers(1, &data.polygon_index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, nullptr, GL_DYNAMIC_DRAW); //allocate max size + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + data.polygon_index_buffer_size = index_size; + } + + // ninepatch buffers + { + // array buffer + glGenBuffers(1, &data.ninepatch_vertices); + glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); + + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, NULL, GL_DYNAMIC_DRAW); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // element buffer + glGenBuffers(1, &data.ninepatch_elements); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); + +#define _EIDX(y, x) (y * 4 + x) + uint8_t elems[3 * 2 * 9] = { + // first row + + _EIDX(0, 0), _EIDX(0, 1), _EIDX(1, 1), + _EIDX(1, 1), _EIDX(1, 0), _EIDX(0, 0), + + _EIDX(0, 1), _EIDX(0, 2), _EIDX(1, 2), + _EIDX(1, 2), _EIDX(1, 1), _EIDX(0, 1), + + _EIDX(0, 2), _EIDX(0, 3), _EIDX(1, 3), + _EIDX(1, 3), _EIDX(1, 2), _EIDX(0, 2), + + // second row + + _EIDX(1, 0), _EIDX(1, 1), _EIDX(2, 1), + _EIDX(2, 1), _EIDX(2, 0), _EIDX(1, 0), + + // the center one would be here, but we'll put it at the end + // so it's easier to disable the center and be able to use + // one draw call for both + + _EIDX(1, 2), _EIDX(1, 3), _EIDX(2, 3), + _EIDX(2, 3), _EIDX(2, 2), _EIDX(1, 2), + + // third row + + _EIDX(2, 0), _EIDX(2, 1), _EIDX(3, 1), + _EIDX(3, 1), _EIDX(3, 0), _EIDX(2, 0), + + _EIDX(2, 1), _EIDX(2, 2), _EIDX(3, 2), + _EIDX(3, 2), _EIDX(3, 1), _EIDX(2, 1), + + _EIDX(2, 2), _EIDX(2, 3), _EIDX(3, 3), + _EIDX(3, 3), _EIDX(3, 2), _EIDX(2, 2), + + // center field + + _EIDX(1, 1), _EIDX(1, 2), _EIDX(2, 2), + _EIDX(2, 2), _EIDX(2, 1), _EIDX(1, 1) + }; +#undef _EIDX + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + store_transform3d(Transform3D(), state.canvas_item_ubo_data.projection_matrix); + + glGenBuffers(1, &state.canvas_item_ubo); + glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); + glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); + glBindBuffer(GL_UNIFORM_BUFFER, 0); + + state.canvas_shadow_shader.init(); + state.canvas_shader.init(); + _set_texture_rect_mode(true); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); + + state.canvas_shader.bind(); + + state.lens_shader.init(); + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false)); + + state.using_light = NULL; + state.using_transparent_rt = false; + state.using_skeleton = false; +} + +RendererCanvasRender::PolygonID RasterizerCanvasBaseGLES3::request_polygon(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, const Vector &p_bones, const Vector &p_weights) { + uint32_t id = _polydata.alloc(); + PolyData &pd = _polydata[id]; + pd.indices = p_indices; + pd.points = p_points; + pd.colors = p_colors; + pd.uvs = p_uvs; + return id; +} +void RasterizerCanvasBaseGLES3::free_polygon(PolygonID p_polygon) { + _polydata.free(p_polygon); +} + +void RasterizerCanvasBaseGLES3::finalize() { + glDeleteBuffers(1, &data.canvas_quad_vertices); + glDeleteVertexArrays(1, &data.canvas_quad_array); + + glDeleteBuffers(1, &data.canvas_quad_vertices); + glDeleteVertexArrays(1, &data.canvas_quad_array); + + glDeleteVertexArrays(1, &data.polygon_buffer_pointer_array); +} + +RasterizerCanvasBaseGLES3::RasterizerCanvasBaseGLES3() { +} + +#endif // GLES3_BACKEND_ENABLED diff --git a/drivers/gles3/rasterizer_canvas_base_gles3.h b/drivers/gles3/rasterizer_canvas_base_gles3.h new file mode 100644 index 0000000000..3fa180539e --- /dev/null +++ b/drivers/gles3/rasterizer_canvas_base_gles3.h @@ -0,0 +1,213 @@ +/*************************************************************************/ +/* rasterizer_canvas_base_gles3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_CANVAS_BASE_OPENGL_H +#define RASTERIZER_CANVAS_BASE_OPENGL_H + +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "drivers/gles3/rasterizer_array.h" +#include "drivers/gles3/rasterizer_storage_common.h" +#include "rasterizer_scene_gles3.h" +#include "rasterizer_storage_gles3.h" +#include "servers/rendering/renderer_canvas_render.h" +#include "servers/rendering/renderer_compositor.h" + +#include "shaders/canvas.glsl.gen.h" +#include "shaders/canvas_shadow.glsl.gen.h" +#include "shaders/lens_distorted.glsl.gen.h" + +class RasterizerCanvasBaseGLES3 : public RendererCanvasRender { +public: + enum { + INSTANCE_ATTRIB_BASE = 8, + }; + + struct Uniforms { + Transform3D projection_matrix; + + Transform2D modelview_matrix; + Transform2D extra_matrix; + + Color final_modulate; + + float time; + }; + + struct CanvasItemUBO { + float projection_matrix[16]; + float time; + uint8_t padding[12]; + }; + + struct Data { + enum { NUM_QUAD_ARRAY_VARIATIONS = 8 }; + + GLuint canvas_quad_vertices; + GLuint canvas_quad_array; + + GLuint polygon_buffer; + GLuint polygon_buffer_quad_arrays[NUM_QUAD_ARRAY_VARIATIONS]; + GLuint polygon_buffer_pointer_array; + GLuint polygon_index_buffer; + + GLuint particle_quad_vertices; + GLuint particle_quad_array; + + uint32_t polygon_buffer_size; + uint32_t polygon_index_buffer_size; + + GLuint ninepatch_vertices; + GLuint ninepatch_elements; + } data; + + struct State { + Uniforms uniforms; + CanvasItemUBO canvas_item_ubo_data; + GLuint canvas_item_ubo; + bool canvas_texscreen_used; + CanvasShaderGLES3 canvas_shader; + CanvasShadowShaderGLES3 canvas_shadow_shader; + LensDistortedShaderGLES3 lens_shader; + + bool using_texture_rect; + + bool using_light_angle; + bool using_modulate; + bool using_large_vertex; + + bool using_ninepatch; + bool using_skeleton; + + Transform2D skeleton_transform; + Transform2D skeleton_transform_inverse; + Size2i skeleton_texture_size; + + RID current_tex; + RID current_normal; + RasterizerStorageGLES3::Texture *current_tex_ptr; + + Transform3D vp; + Light *using_light; + bool using_shadow; + bool using_transparent_rt; + + // new for Godot 4.0 + // min mag filter is per item, and repeat + RS::CanvasItemTextureFilter current_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; + RS::CanvasItemTextureRepeat current_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; + } state; + + typedef void Texture; + + RasterizerSceneGLES3 *scene_render; + + RasterizerStorageGLES3 *storage; + + // allow user to choose api usage + GLenum _buffer_upload_usage_flag; + + void _set_uniforms(); + + virtual RID light_internal_create(); + virtual void light_internal_update(RID p_rid, Light *p_light); + virtual void light_internal_free(RID p_rid); + + virtual void canvas_begin(); + virtual void canvas_end(); + +protected: + void _legacy_draw_primitive(Item::CommandPrimitive *p_pr, RasterizerStorageGLES3::Material *p_material); + void _legacy_draw_line(Item::CommandPrimitive *p_pr, RasterizerStorageGLES3::Material *p_material); + void _legacy_draw_poly_triangles(Item::CommandPolygon *p_poly, RasterizerStorageGLES3::Material *p_material); + +public: + void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs, const float *p_light_angles = nullptr); + void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights = NULL, const int *p_bones = NULL); + 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); + void _draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); + + void _bind_quad_buffer(); + void _copy_texscreen(const Rect2 &p_rect); + void _copy_screen(const Rect2 &p_rect); + + //virtual void draw_window_margins(int *black_margin, RID *black_image) override; + void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); + void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); + + virtual void reset_canvas(); + virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache); + + // Copied from RasterizerCanvasDummy: + virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override; + + RID light_create() override; + void light_set_texture(RID p_rid, RID p_texture) override; + void light_set_use_shadow(RID p_rid, bool p_enable) override; + void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) override; + void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) override; + + void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) override; + RID occluder_polygon_create() override; + void occluder_polygon_set_shape(RID p_occluder, const Vector &p_points, bool p_closed) override; + void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) override; + void set_shadow_texture_size(int p_size) override; + + bool free(RID p_rid) override; + void update() override; + // End copied from RasterizerCanvasDummy. + + RasterizerStorageGLES3::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map); + void _set_texture_rect_mode(bool p_texture_rect, bool p_light_angle = false, bool p_modulate = false, bool p_large_vertex = false); + + // NEW API + struct PolyData { + LocalVector indices; + LocalVector points; + LocalVector colors; + LocalVector uvs; + }; + + RendererCanvasRender::PolygonID request_polygon(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), const Vector &p_bones = Vector(), const Vector &p_weights = Vector()) override; + void free_polygon(PolygonID p_polygon) override; + + RasterizerPooledIndirectList _polydata; + + ////////////////////// + void initialize(); + void finalize(); + + RasterizerCanvasBaseGLES3(); +}; + +#endif // GLES3_BACKEND_ENABLED + +#endif // RASTERIZER_CANVAS_BASE_OPENGL_H diff --git a/drivers/gles3/rasterizer_canvas_batcher.h b/drivers/gles3/rasterizer_canvas_batcher.h new file mode 100644 index 0000000000..c7345824ab --- /dev/null +++ b/drivers/gles3/rasterizer_canvas_batcher.h @@ -0,0 +1,1560 @@ +/*************************************************************************/ +/* rasterizer_canvas_batcher.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_CANVAS_BATCHER_H +#define RASTERIZER_CANVAS_BATCHER_H + +#include "core/os/os.h" +#include "core/templates/local_vector.h" +#include "rasterizer_array.h" +#include "rasterizer_asserts.h" +#include "rasterizer_storage_common.h" + +#include "core/config/project_settings.h" +#include "servers/rendering/renderer_compositor.h" + +// We are using the curiously recurring template pattern +// https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern +// For static polymorphism. + +// This makes it super easy to access +// data / call funcs in the derived rasterizers from the base without writing and +// maintaining a boatload of virtual functions. +// In addition it assures that vtable will not be used and the function calls can be optimized, +// because it gives compile time static polymorphism. + +// These macros makes it simpler and less verbose to define (and redefine) the inline functions +// template preamble +#define T_PREAMBLE template +// class preamble +#define C_PREAMBLE RasterizerCanvasBatcher +// generic preamble +#define PREAMBLE(RET_T) \ + T_PREAMBLE \ + RET_T C_PREAMBLE + +template +class RasterizerCanvasBatcher { +public: + // used to determine whether we use hardware transform (none) + // software transform all verts, or software transform just a translate + // (no rotate or scale) + enum TransformMode { + TM_NONE, + TM_ALL, + TM_TRANSLATE, + }; + + // pod versions of vector and color and RID, need to be 32 bit for vertex format + struct BatchVector2 { + float x, y; + void set(float xx, float yy) { + x = xx; + y = yy; + } + void set(const Vector2 &p_o) { + x = p_o.x; + y = p_o.y; + } + void to(Vector2 &r_o) const { + r_o.x = x; + r_o.y = y; + } + }; + + struct BatchColor { + float r, g, b, a; + void set_white() { + r = 1.0f; + g = 1.0f; + b = 1.0f; + a = 1.0f; + } + void set(const Color &p_c) { + r = p_c.r; + g = p_c.g; + b = p_c.b; + a = p_c.a; + } + void set(float rr, float gg, float bb, float aa) { + r = rr; + g = gg; + b = bb; + a = aa; + } + bool operator==(const BatchColor &p_c) const { + return (r == p_c.r) && (g == p_c.g) && (b == p_c.b) && (a == p_c.a); + } + bool operator!=(const BatchColor &p_c) const { return (*this == p_c) == false; } + bool equals(const Color &p_c) const { + return (r == p_c.r) && (g == p_c.g) && (b == p_c.b) && (a == p_c.a); + } + const float *get_data() const { return &r; } + String to_string() const { + String sz = "{"; + const float *data = get_data(); + for (int c = 0; c < 4; c++) { + float f = data[c]; + int val = ((f * 255.0f) + 0.5f); + sz += String(Variant(val)) + " "; + } + sz += "}"; + return sz; + } + }; + + // simplest FVF - local or baked position + struct BatchVertex { + // must be 32 bit pod + BatchVector2 pos; + BatchVector2 uv; + }; + + // simple FVF but also incorporating baked color + struct BatchVertexColored : public BatchVertex { + // must be 32 bit pod + BatchColor col; + }; + + // if we are using normal mapping, we need light angles to be sent + struct BatchVertexLightAngled : public BatchVertexColored { + // must be pod + float light_angle; + }; + + // CUSTOM SHADER vertex formats. These are larger but will probably + // be needed with custom shaders in order to have the data accessible in the shader. + + // if we are using COLOR in vertex shader but not position (VERTEX) + struct BatchVertexModulated : public BatchVertexLightAngled { + BatchColor modulate; + }; + + struct BatchTransform { + BatchVector2 translate; + BatchVector2 basis[2]; + }; + + // last resort, specially for custom shader, we put everything possible into a huge FVF + // not very efficient, but better than no batching at all. + struct BatchVertexLarge : public BatchVertexModulated { + // must be pod + BatchTransform transform; + }; + + // Batch should be as small as possible, and ideally nicely aligned (is 32 bytes at the moment) + struct Batch { + RasterizerStorageCommon::BatchType type; // should be 16 bit + uint16_t batch_texture_id; + + // also item reference number + uint32_t first_command; + + // in the case of DEFAULT, this is num commands. + // with rects, is number of command and rects. + // with lines, is number of lines + uint32_t num_commands; + + // first vertex of this batch in the vertex lists + uint32_t first_vert; + + BatchColor color; + }; + + struct BatchTex { + enum TileMode : uint32_t { + TILE_OFF, + TILE_NORMAL, + TILE_FORCE_REPEAT, + }; + RID RID_texture; + RID RID_normal; + TileMode tile_mode; + BatchVector2 tex_pixel_size; + uint32_t flags; + }; + + // items in a list to be sorted prior to joining + struct BSortItem { + // have a function to keep as pod, rather than operator + void assign(const BSortItem &o) { + item = o.item; + z_index = o.z_index; + } + RendererCanvasRender::Item *item; + int z_index; + }; + + // batch item may represent 1 or more items + struct BItemJoined { + uint32_t first_item_ref; + uint32_t num_item_refs; + + Rect2 bounding_rect; + + // note the z_index may only be correct for the first of the joined item references + // this has implications for light culling with z ranged lights. + int16_t z_index; + + // these are defined in RasterizerStorageCommon::BatchFlags + uint16_t flags; + + // we are always splitting items with lots of commands, + // and items with unhandled primitives (default) + bool use_hardware_transform() const { return num_item_refs == 1; } + }; + + struct BItemRef { + RendererCanvasRender::Item *item; + Color final_modulate; + }; + + struct BLightRegion { + void reset() { + light_bitfield = 0; + shadow_bitfield = 0; + too_many_lights = false; + } + uint64_t light_bitfield; + uint64_t shadow_bitfield; + bool too_many_lights; // we can only do light region optimization if there are 64 or less lights + }; + + struct BatchData { + BatchData() { + reset_flush(); + reset_joined_item(); + + gl_vertex_buffer = 0; + gl_index_buffer = 0; + max_quads = 0; + vertex_buffer_size_units = 0; + vertex_buffer_size_bytes = 0; + index_buffer_size_units = 0; + index_buffer_size_bytes = 0; + + use_colored_vertices = false; + + settings_use_batching = false; + settings_max_join_item_commands = 0; + settings_colored_vertex_format_threshold = 0.0f; + settings_batch_buffer_num_verts = 0; + scissor_threshold_area = 0.0f; + joined_item_batch_flags = 0; + diagnose_frame = false; + next_diagnose_tick = 10000; + diagnose_frame_number = 9999999999; // some high number + join_across_z_indices = true; + settings_item_reordering_lookahead = 0; + + settings_use_batching_original_choice = false; + settings_flash_batching = false; + settings_diagnose_frame = false; + settings_scissor_lights = false; + settings_scissor_threshold = -1.0f; + settings_use_single_rect_fallback = false; + settings_use_software_skinning = true; + settings_ninepatch_mode = 0; // default + settings_light_max_join_items = 16; + + settings_uv_contract = false; + settings_uv_contract_amount = 0.0f; + + buffer_mode_batch_upload_send_null = true; + buffer_mode_batch_upload_flag_stream = false; + + stats_items_sorted = 0; + stats_light_items_joined = 0; + } + + // called for each joined item + void reset_joined_item() { + // noop but left in as a stub + } + + // called after each flush + void reset_flush() { + batches.reset(); + batch_textures.reset(); + + vertices.reset(); + light_angles.reset(); + vertex_colors.reset(); + vertex_modulates.reset(); + vertex_transforms.reset(); + + total_quads = 0; + total_verts = 0; + total_color_changes = 0; + + use_light_angles = false; + use_modulate = false; + use_large_verts = false; + fvf = RasterizerStorageCommon::FVF_REGULAR; + } + + unsigned int gl_vertex_buffer; + unsigned int gl_index_buffer; + + uint32_t max_quads; + uint32_t vertex_buffer_size_units; + uint32_t vertex_buffer_size_bytes; + uint32_t index_buffer_size_units; + uint32_t index_buffer_size_bytes; + + // small vertex FVF type - pos and UV. + // This will always be written to initially, but can be translated + // to larger FVFs if necessary. + RasterizerArray vertices; + + // extra data which can be stored during prefilling, for later translation to larger FVFs + RasterizerArray light_angles; + RasterizerArray vertex_colors; // these aren't usually used, but are for polys + RasterizerArray vertex_modulates; + RasterizerArray vertex_transforms; + + // instead of having a different buffer for each vertex FVF type + // we have a special array big enough for the biggest FVF + // which can have a changeable unit size, and reuse it. + RasterizerUnitArray unit_vertices; + + RasterizerArray batches; + RasterizerArray batches_temp; // used for translating to colored vertex batches + RasterizerArray_non_pod batch_textures; // the only reason this is non-POD is because of RIDs + + // SHOULD THESE BE IN FILLSTATE? + // flexible vertex format. + // all verts have pos and UV. + // some have color, some light angles etc. + RasterizerStorageCommon::FVF fvf; + bool use_colored_vertices; + bool use_light_angles; + bool use_modulate; + bool use_large_verts; + + // if the shader is using MODULATE, we prevent baking color so the final_modulate can + // be read in the shader. + // if the shader is reading VERTEX, we prevent baking vertex positions with extra matrices etc + // to prevent the read position being incorrect. + // These flags are defined in RasterizerStorageCommon::BatchFlags + uint32_t joined_item_batch_flags; + + RasterizerArray items_joined; + RasterizerArray item_refs; + + // items are sorted prior to joining + RasterizerArray sort_items; + + // new for Godot 4 .. the client outputs a linked list so we need to convert this + // to a linear array + LocalVector command_shortlist; + + // counts + int total_quads; + int total_verts; + + // we keep a record of how many color changes caused new batches + // if the colors are causing an excessive number of batches, we switch + // to alternate batching method and add color to the vertex format. + int total_color_changes; + + // measured in pixels, recalculated each frame + float scissor_threshold_area; + + // diagnose this frame, every nTh frame when settings_diagnose_frame is on + bool diagnose_frame; + String frame_string; + uint32_t next_diagnose_tick; + uint64_t diagnose_frame_number; + + // whether to join items across z_indices - this can interfere with z ranged lights, + // so has to be disabled in some circumstances + bool join_across_z_indices; + + // global settings + bool settings_use_batching; // the current use_batching (affected by flash) + bool settings_use_batching_original_choice; // the choice entered in project settings + bool settings_flash_batching; // for regression testing, flash between non-batched and batched renderer + bool settings_diagnose_frame; // print out batches to help optimize / regression test + int settings_max_join_item_commands; + float settings_colored_vertex_format_threshold; + int settings_batch_buffer_num_verts; + bool settings_scissor_lights; + float settings_scissor_threshold; // 0.0 to 1.0 + int settings_item_reordering_lookahead; + bool settings_use_single_rect_fallback; + bool settings_use_software_skinning; + int settings_light_max_join_items; + int settings_ninepatch_mode; + + // buffer orphaning modes + bool buffer_mode_batch_upload_send_null; + bool buffer_mode_batch_upload_flag_stream; + + // uv contraction + bool settings_uv_contract; + float settings_uv_contract_amount; + + // only done on diagnose frame + void reset_stats() { + stats_items_sorted = 0; + stats_light_items_joined = 0; + } + + // frame stats (just for monitoring and debugging) + int stats_items_sorted; + int stats_light_items_joined; + } bdata; + + struct FillState { + void reset_flush() { + // don't reset members that need to be preserved after flushing + // half way through a list of commands + curr_batch = 0; + batch_tex_id = -1; + texpixel_size = Vector2(1, 1); + contract_uvs = false; + + sequence_batch_type_flags = 0; + } + + void reset_joined_item(bool p_use_hardware_transform) { + reset_flush(); + use_hardware_transform = p_use_hardware_transform; + extra_matrix_sent = false; + } + + // for batching multiple types, we don't allow mixing RECTs / LINEs etc. + // using flags allows quicker rejection of sequences with different batch types + uint32_t sequence_batch_type_flags; + + Batch *curr_batch; + int batch_tex_id; + bool use_hardware_transform; + bool contract_uvs; + Vector2 texpixel_size; + Color final_modulate; + TransformMode transform_mode; + TransformMode orig_transform_mode; + + // support for extra matrices + bool extra_matrix_sent; // whether sent on this item (in which case sofware transform can't be used untl end of item) + int transform_extra_command_number_p1; // plus one to allow fast checking against zero + Transform2D transform_combined; // final * extra + }; + + // used during try_join + struct RenderItemState { + RenderItemState() { reset(); } + void reset() { + current_clip = nullptr; + shader_cache = nullptr; + rebind_shader = true; + prev_use_skeleton = false; + last_blend_mode = -1; + canvas_last_material = RID(); + item_group_z = 0; + item_group_light = nullptr; + final_modulate = Color(-1.0, -1.0, -1.0, -1.0); // just something unlikely + + joined_item_batch_type_flags_curr = 0; + joined_item_batch_type_flags_prev = 0; + + joined_item = nullptr; + } + + RendererCanvasRender::Item *current_clip; + typename T_STORAGE::Shader *shader_cache; + bool rebind_shader; + bool prev_use_skeleton; + bool prev_distance_field; + int last_blend_mode; + RID canvas_last_material; + Color final_modulate; + + // used for joining items only + BItemJoined *joined_item; + bool join_batch_break; + BLightRegion light_region; + + // we need some logic to prevent joining items that have vastly different batch types + // these are defined in RasterizerStorageCommon::BatchTypeFlags + uint32_t joined_item_batch_type_flags_curr; + uint32_t joined_item_batch_type_flags_prev; + + // 'item group' is data over a single call to canvas_render_items + int item_group_z; + Color item_group_modulate; + RendererCanvasRender::Light *item_group_light; + Transform2D item_group_base_transform; + } _render_item_state; + + bool use_nvidia_rect_workaround; + + ////////////////////////////////////////////////////////////////////////////// + // End of structs used by the batcher. Beginning of funcs. +private: + // curiously recurring template pattern - allows access to functions in the DERIVED class + // this is kind of like using virtual functions but more efficient as they are resolved at compile time + T_STORAGE *get_storage() { return static_cast(this)->storage; } + const T_STORAGE *get_storage() const { return static_cast(this)->storage; } + T *get_this() { return static_cast(this); } + const T *get_this() const { return static_cast(this); } + +protected: + // main functions called from the rasterizer canvas + void batch_constructor(); + void batch_initialize(); + + void batch_canvas_begin(); + void batch_canvas_end(); + void batch_canvas_render_items_begin(const Color &p_modulate, RendererCanvasRender::Light *p_light, const Transform2D &p_base_transform); + void batch_canvas_render_items_end(); + void batch_canvas_render_items(RendererCanvasRender::Item *p_item_list, int p_z, const Color &p_modulate, RendererCanvasRender::Light *p_light, const Transform2D &p_base_transform); + + // recording and sorting items from the initial pass + void record_items(RendererCanvasRender::Item *p_item_list, int p_z); + void join_sorted_items(); + void sort_items(); + bool _sort_items_match(const BSortItem &p_a, const BSortItem &p_b) const; + bool sort_items_from(int p_start); + + // joining logic + bool _disallow_item_join_if_batch_types_too_different(RenderItemState &r_ris, uint32_t btf_allowed); + bool _detect_item_batch_break(RenderItemState &r_ris, RendererCanvasRender::Item *p_ci, bool &r_batch_break); + + // drives the loop filling batches and flushing + void render_joined_item_commands(const BItemJoined &p_bij, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material, bool p_lit); + +private: + // flush once full or end of joined item + void flush_render_batches(RendererCanvasRender::Item *p_first_item, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material, uint32_t p_sequence_batch_type_flags); + + // a single joined item can contain multiple itemrefs, and thus create lots of batches + // command start given a separate name to make easier to tell apart godot 3 and 4 + bool prefill_joined_item(FillState &r_fill_state, RendererCanvasRender::Item::Command **r_first_command, RendererCanvasRender::Item *p_item, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material); + + // prefilling different types of batch + + // default batch is an 'unhandled' legacy type batch that will be drawn with the legacy path, + // all other batches are accelerated. + void _prefill_default_batch(FillState &r_fill_state, int p_command_num, const RendererCanvasRender::Item &p_item); + + // accelerated batches + bool _prefill_rect(RendererCanvasRender::Item::CommandRect *rect, FillState &r_fill_state, int &r_command_start, int command_num, int command_count, RendererCanvasRender::Item::Command *const *commands, RendererCanvasRender::Item *p_item, bool multiply_final_modulate); + + // dealing with textures + int _batch_find_or_create_tex(const RID &p_texture, const RID &p_normal, bool p_tile, int p_previous_match); + +protected: + // legacy support for non batched mode + void _legacy_canvas_item_render_commands(RendererCanvasRender::Item *p_item, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material); + + // light scissoring + bool _light_scissor_begin(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect) const; + bool _light_find_intersection(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect, Rect2 &r_cliprect) const; + void _calculate_scissor_threshold_area(); + +private: + // translating vertex formats prior to rendering + void _translate_batches_to_vertex_colored_FVF(); + template + void _translate_batches_to_larger_FVF(uint32_t p_sequence_batch_type_flags); + +protected: + // accessory funcs + void _software_transform_vertex(BatchVector2 &r_v, const Transform2D &p_tr) const; + void _software_transform_vertex(Vector2 &r_v, const Transform2D &p_tr) const; + TransformMode _find_transform_mode(const Transform2D &p_tr) const { + // decided whether to do translate only for software transform + if ((p_tr.elements[0].x == 1.0f) && + (p_tr.elements[0].y == 0.0f) && + (p_tr.elements[1].x == 0.0f) && + (p_tr.elements[1].y == 1.0f)) { + return TM_TRANSLATE; + } + + return TM_ALL; + } + + typename T_STORAGE::Texture *_get_canvas_texture(const RID &p_texture) const { + if (p_texture.is_valid()) { + typename T_STORAGE::Texture *texture = get_storage()->texture_owner.get_or_null(p_texture); + + if (texture) { + return texture->get_ptr(); + } + } + + return 0; + } + +public: + Batch *_batch_request_new(bool p_blank = true) { + Batch *batch = bdata.batches.request(); + if (!batch) { + // grow the batches + bdata.batches.grow(); + + // and the temporary batches (used for color verts) + bdata.batches_temp.reset(); + bdata.batches_temp.grow(); + + // this should always succeed after growing + batch = bdata.batches.request(); + RAST_DEBUG_ASSERT(batch); + } + + if (p_blank) + memset(batch, 0, sizeof(Batch)); + + return batch; + } + + BatchVertex *_batch_vertex_request_new() { + return bdata.vertices.request(); + } + +protected: + int godot4_commands_count(RendererCanvasRender::Item::Command *p_comm) const { + int count = 0; + while (p_comm) { + count++; + p_comm = p_comm->next; + } + return count; + } + + unsigned int godot4_commands_to_vector(RendererCanvasRender::Item::Command *p_comm, LocalVector &p_list) { + p_list.clear(); + while (p_comm) { + p_list.push_back(p_comm); + p_comm = p_comm->next; + } + return p_list.size(); + } +}; + +PREAMBLE(void)::batch_canvas_begin() { + // diagnose_frame? + bdata.frame_string = ""; // just in case, always set this as we don't want a string leak in release... +#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) + if (bdata.settings_diagnose_frame) { + bdata.diagnose_frame = false; + + uint32_t tick = OS::get_singleton()->get_ticks_msec(); + uint64_t frame = Engine::get_singleton()->get_frames_drawn(); + + if (tick >= bdata.next_diagnose_tick) { + bdata.next_diagnose_tick = tick + 10000; + + // the plus one is prevent starting diagnosis half way through frame + bdata.diagnose_frame_number = frame + 1; + } + + if (frame == bdata.diagnose_frame_number) { + bdata.diagnose_frame = true; + bdata.reset_stats(); + } + + if (bdata.diagnose_frame) { + bdata.frame_string = "canvas_begin FRAME " + itos(frame) + "\n"; + } + } +#endif +} + +PREAMBLE(void)::batch_canvas_end() { +#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) + if (bdata.diagnose_frame) { + bdata.frame_string += "canvas_end\n"; + if (bdata.stats_items_sorted) { + bdata.frame_string += "\titems reordered: " + itos(bdata.stats_items_sorted) + "\n"; + } + if (bdata.stats_light_items_joined) { + bdata.frame_string += "\tlight items joined: " + itos(bdata.stats_light_items_joined) + "\n"; + } + + print_line(bdata.frame_string); + } +#endif +} + +PREAMBLE(void)::batch_canvas_render_items_begin(const Color &p_modulate, RendererCanvasRender::Light *p_light, const Transform2D &p_base_transform) { + // if we are debugging, flash each frame between batching renderer and old version to compare for regressions + if (bdata.settings_flash_batching) { + if ((Engine::get_singleton()->get_frames_drawn() % 2) == 0) + bdata.settings_use_batching = true; + else + bdata.settings_use_batching = false; + } + + if (!bdata.settings_use_batching) { + return; + } + + // this only needs to be done when screen size changes, but this should be + // infrequent enough + _calculate_scissor_threshold_area(); + + // set up render item state for all the z_indexes (this is common to all z_indexes) + _render_item_state.reset(); + _render_item_state.item_group_modulate = p_modulate; + _render_item_state.item_group_light = p_light; + _render_item_state.item_group_base_transform = p_base_transform; + _render_item_state.light_region.reset(); + + // batch break must be preserved over the different z indices, + // to prevent joining to an item on a previous index if not allowed + _render_item_state.join_batch_break = false; + + // whether to join across z indices depends on whether there are z ranged lights. + // joined z_index items can be wrongly classified with z ranged lights. + bdata.join_across_z_indices = true; + + int light_count = 0; + while (p_light) { + light_count++; + + if ((p_light->z_min != RS::CANVAS_ITEM_Z_MIN) || (p_light->z_max != RS::CANVAS_ITEM_Z_MAX)) { + // prevent joining across z indices. This would have caused visual regressions + bdata.join_across_z_indices = false; + } + + p_light = p_light->next_ptr; + } + + // can't use the light region bitfield if there are too many lights + // hopefully most games won't blow this limit.. + // if they do they will work but it won't batch join items just in case + if (light_count > 64) { + _render_item_state.light_region.too_many_lights = true; + } +} + +PREAMBLE(void)::batch_canvas_render_items_end() { + if (!bdata.settings_use_batching) { + return; + } + + join_sorted_items(); + +#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) + if (bdata.diagnose_frame) { + bdata.frame_string += "items\n"; + } +#endif + + // batching render is deferred until after going through all the z_indices, joining all the items + get_this()->canvas_render_items_implementation(0, 0, _render_item_state.item_group_modulate, + _render_item_state.item_group_light, + _render_item_state.item_group_base_transform); + + bdata.items_joined.reset(); + bdata.item_refs.reset(); + bdata.sort_items.reset(); +} + +PREAMBLE(void)::batch_canvas_render_items(RendererCanvasRender::Item *p_item_list, int p_z, const Color &p_modulate, RendererCanvasRender::Light *p_light, const Transform2D &p_base_transform) { + // stage 1 : join similar items, so that their state changes are not repeated, + // and commands from joined items can be batched together + if (bdata.settings_use_batching) { + record_items(p_item_list, p_z); + return; + } + + // only legacy renders at this stage, batched renderer doesn't render until canvas_render_items_end() + get_this()->canvas_render_items_implementation(p_item_list, p_z, p_modulate, p_light, p_base_transform); +} + +// Default batches will not occur in software transform only items +// EXCEPT IN THE CASE OF SINGLE RECTS (and this may well not occur, check the logic in prefill_join_item TYPE_RECT) +// but can occur where transform commands have been sent during hardware batch +PREAMBLE(void)::_prefill_default_batch(FillState &r_fill_state, int p_command_num, const RendererCanvasRender::Item &p_item) { + if (r_fill_state.curr_batch->type == RasterizerStorageCommon::BT_DEFAULT) { + // don't need to flush an extra transform command? + if (!r_fill_state.transform_extra_command_number_p1) { + // another default command, just add to the existing batch + r_fill_state.curr_batch->num_commands++; + } else { +#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) + if (r_fill_state.transform_extra_command_number_p1 != p_command_num) { + WARN_PRINT_ONCE("_prefill_default_batch : transform_extra_command_number_p1 != p_command_num"); + } +#endif + // if the first member of the batch is a transform we have to be careful + if (!r_fill_state.curr_batch->num_commands) { + // there can be leading useless extra transforms (sometimes happens with debug collision polys) + // we need to rejig the first_command for the first useful transform + r_fill_state.curr_batch->first_command += r_fill_state.transform_extra_command_number_p1 - 1; + } + + // we do have a pending extra transform command to flush + // either the extra transform is in the prior command, or not, in which case we need 2 batches + r_fill_state.curr_batch->num_commands += 2; + + r_fill_state.transform_extra_command_number_p1 = 0; // mark as sent + r_fill_state.extra_matrix_sent = true; + + // the original mode should always be hardware transform .. + // test this assumption + //CRASH_COND(r_fill_state.orig_transform_mode != TM_NONE); + r_fill_state.transform_mode = r_fill_state.orig_transform_mode; + + // do we need to restore anything else? + } + } else { + // end of previous different type batch, so start new default batch + + // first consider whether there is a dirty extra matrix to send + if (r_fill_state.transform_extra_command_number_p1) { + // get which command the extra is in, and blank all the records as it no longer is stored CPU side + int extra_command = r_fill_state.transform_extra_command_number_p1 - 1; // plus 1 based + r_fill_state.transform_extra_command_number_p1 = 0; + r_fill_state.extra_matrix_sent = true; + + // send the extra to the GPU in a batch + r_fill_state.curr_batch = _batch_request_new(); + r_fill_state.curr_batch->type = RasterizerStorageCommon::BT_DEFAULT; + r_fill_state.curr_batch->first_command = extra_command; + r_fill_state.curr_batch->num_commands = 1; + + // revert to the original transform mode + // e.g. go back to NONE if we were in hardware transform mode + r_fill_state.transform_mode = r_fill_state.orig_transform_mode; + + // reset the original transform if we are going back to software mode, + // because the extra is now done on the GPU... + // (any subsequent extras are sent directly to the GPU, no deferring) + if (r_fill_state.orig_transform_mode != TM_NONE) { + r_fill_state.transform_combined = p_item.final_transform; + } + + // can possibly combine batch with the next one in some cases + // this is more efficient than having an extra batch especially for the extra + if ((extra_command + 1) == p_command_num) { + r_fill_state.curr_batch->num_commands = 2; + return; + } + } + + // start default batch + r_fill_state.curr_batch = _batch_request_new(); + r_fill_state.curr_batch->type = RasterizerStorageCommon::BT_DEFAULT; + r_fill_state.curr_batch->first_command = p_command_num; + r_fill_state.curr_batch->num_commands = 1; + } +} + +PREAMBLE(int)::_batch_find_or_create_tex(const RID &p_texture, const RID &p_normal, bool p_tile, int p_previous_match) { + // optimization .. in 99% cases the last matched value will be the same, so no need to traverse the list + if (p_previous_match > 0) // if it is zero, it will get hit first in the linear search anyway + { + const BatchTex &batch_texture = bdata.batch_textures[p_previous_match]; + + // note for future reference, if RID implementation changes, this could become more expensive + if ((batch_texture.RID_texture == p_texture) && (batch_texture.RID_normal == p_normal)) { + // tiling mode must also match + bool tiles = batch_texture.tile_mode != BatchTex::TILE_OFF; + + if (tiles == p_tile) + // match! + return p_previous_match; + } + } + + // not the previous match .. we will do a linear search ... slower, but should happen + // not very often except with non-batchable runs, which are going to be slow anyway + // n.b. could possibly be replaced later by a fast hash table + for (int n = 0; n < bdata.batch_textures.size(); n++) { + const BatchTex &batch_texture = bdata.batch_textures[n]; + if ((batch_texture.RID_texture == p_texture) && (batch_texture.RID_normal == p_normal)) { + // tiling mode must also match + bool tiles = batch_texture.tile_mode != BatchTex::TILE_OFF; + + if (tiles == p_tile) + // match! + return n; + } + } + + // pushing back from local variable .. not ideal but has to use a Vector because non pod + // due to RIDs + BatchTex new_batch_tex; + new_batch_tex.RID_texture = p_texture; + new_batch_tex.RID_normal = p_normal; + + // get the texture + typename T_STORAGE::Texture *texture = _get_canvas_texture(p_texture); + + if (texture) { + // special case, there can be textures with no width or height + int w = texture->width; + int h = texture->height; + + if (!w || !h) { + w = 1; + h = 1; + } + + new_batch_tex.tex_pixel_size.x = 1.0 / w; + new_batch_tex.tex_pixel_size.y = 1.0 / h; + new_batch_tex.flags = texture->flags; + } else { + // maybe doesn't need doing... + new_batch_tex.tex_pixel_size.x = 1.0f; + new_batch_tex.tex_pixel_size.y = 1.0f; + new_batch_tex.flags = 0; + } + + if (p_tile) { + if (texture) { + // default + new_batch_tex.tile_mode = BatchTex::TILE_NORMAL; + + // no hardware support for non power of 2 tiling + if (!get_storage()->config.support_npot_repeat_mipmap) { + if (next_power_of_2(texture->alloc_width) != (unsigned int)texture->alloc_width && next_power_of_2(texture->alloc_height) != (unsigned int)texture->alloc_height) { + new_batch_tex.tile_mode = BatchTex::TILE_FORCE_REPEAT; + } + } + } else { + // this should not happen? + new_batch_tex.tile_mode = BatchTex::TILE_OFF; + } + } else { + new_batch_tex.tile_mode = BatchTex::TILE_OFF; + } + + // push back + bdata.batch_textures.push_back(new_batch_tex); + + return bdata.batch_textures.size() - 1; +} + +PREAMBLE(void)::batch_constructor() { + bdata.settings_use_batching = false; + +#ifdef GLES_OVER_GL + use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/use_nvidia_rect_flicker_workaround"); +#else + // Not needed (a priori) on GLES devices + use_nvidia_rect_workaround = false; +#endif +} + +PREAMBLE(void)::batch_initialize() { +#define BATCHING_LOAD_PROJECT_SETTINGS + +#ifdef BATCHING_LOAD_PROJECT_SETTINGS + bdata.settings_use_batching = GLOBAL_GET("rendering/batching/options/use_batching"); + bdata.settings_max_join_item_commands = GLOBAL_GET("rendering/batching/parameters/max_join_item_commands"); + bdata.settings_colored_vertex_format_threshold = GLOBAL_GET("rendering/batching/parameters/colored_vertex_format_threshold"); + bdata.settings_item_reordering_lookahead = GLOBAL_GET("rendering/batching/parameters/item_reordering_lookahead"); + bdata.settings_light_max_join_items = GLOBAL_GET("rendering/batching/lights/max_join_items"); + bdata.settings_use_single_rect_fallback = GLOBAL_GET("rendering/batching/options/single_rect_fallback"); + bdata.settings_use_software_skinning = GLOBAL_GET("rendering/quality/2d/use_software_skinning"); + bdata.settings_ninepatch_mode = GLOBAL_GET("rendering/quality/2d/ninepatch_mode"); + + // alternatively only enable uv contract if pixel snap in use, + // but with this enable bool, it should not be necessary + bdata.settings_uv_contract = GLOBAL_GET("rendering/batching/precision/uv_contract"); + bdata.settings_uv_contract_amount = (float)GLOBAL_GET("rendering/batching/precision/uv_contract_amount") / 1000000.0f; + + // we can use the threshold to determine whether to turn scissoring off or on + bdata.settings_scissor_threshold = GLOBAL_GET("rendering/batching/lights/scissor_area_threshold"); +#endif + + if (bdata.settings_scissor_threshold > 0.999f) { + bdata.settings_scissor_lights = false; + } else { + bdata.settings_scissor_lights = true; + + // apply power of 4 relationship for the area, as most of the important changes + // will be happening at low values of scissor threshold + bdata.settings_scissor_threshold *= bdata.settings_scissor_threshold; + bdata.settings_scissor_threshold *= bdata.settings_scissor_threshold; + } + + // The sweet spot on my desktop for cache is actually smaller than the max, and this + // is the default. This saves memory too so we will use it for now, needs testing to see whether this varies according + // to device / platform. +#ifdef BATCHING_LOAD_PROJECT_SETTINGS + bdata.settings_batch_buffer_num_verts = GLOBAL_GET("rendering/batching/parameters/batch_buffer_size"); + + // override the use_batching setting in the editor + // (note that if the editor can't start, you can't change the use_batching project setting!) + if (Engine::get_singleton()->is_editor_hint()) { + bool use_in_editor = GLOBAL_GET("rendering/batching/options/use_batching_in_editor"); + bdata.settings_use_batching = use_in_editor; + + // fix some settings in the editor, as the performance not worth the risk + bdata.settings_use_single_rect_fallback = false; + } +#endif + + // if we are using batching, we will purposefully disable the nvidia workaround. + // This is because the only reason to use the single rect fallback is the approx 2x speed + // of the uniform drawing technique. If we used nvidia workaround, speed would be + // approx equal to the batcher drawing technique (indexed primitive + VB). + if (bdata.settings_use_batching) { + use_nvidia_rect_workaround = false; + } + + // For debugging, if flash is set in project settings, it will flash on alternate frames + // between the non-batched renderer and the batched renderer, + // in order to find regressions. + // This should not be used except during development. + // make a note of the original choice in case we are flashing on and off the batching + bdata.settings_use_batching_original_choice = bdata.settings_use_batching; + +#ifdef BATCHING_LOAD_PROJECT_SETTINGS + bdata.settings_flash_batching = GLOBAL_GET("rendering/batching/debug/flash_batching"); +#endif + if (!bdata.settings_use_batching) { + // no flash when batching turned off + bdata.settings_flash_batching = false; + } + + // frame diagnosis. print out the batches every nth frame + bdata.settings_diagnose_frame = false; + if (!Engine::get_singleton()->is_editor_hint() && bdata.settings_use_batching) { +#ifdef BATCHING_LOAD_PROJECT_SETTINGS + bdata.settings_diagnose_frame = GLOBAL_GET("rendering/batching/debug/diagnose_frame"); +#endif + } + + // the maximum num quads in a batch is limited by GLES2. We can have only 16 bit indices, + // which means we can address a vertex buffer of max size 65535. 4 vertices are needed per quad. + + // Note this determines the memory use by the vertex buffer vector. max quads (65536/4)-1 + // but can be reduced to save memory if really required (will result in more batches though) + const int max_possible_quads = (65536 / 4) - 1; + const int min_possible_quads = 8; // some reasonable small value + + // value from project settings + int max_quads = bdata.settings_batch_buffer_num_verts / 4; + + // sanity checks + max_quads = CLAMP(max_quads, min_possible_quads, max_possible_quads); + bdata.settings_max_join_item_commands = CLAMP(bdata.settings_max_join_item_commands, 0, 65535); + bdata.settings_colored_vertex_format_threshold = CLAMP(bdata.settings_colored_vertex_format_threshold, 0.0f, 1.0f); + bdata.settings_scissor_threshold = CLAMP(bdata.settings_scissor_threshold, 0.0f, 1.0f); + bdata.settings_light_max_join_items = CLAMP(bdata.settings_light_max_join_items, 0, 65535); + bdata.settings_item_reordering_lookahead = CLAMP(bdata.settings_item_reordering_lookahead, 0, 65535); + + // allow user to override the api usage techniques using project settings + // bdata.buffer_mode_batch_upload_send_null = GLOBAL_GET("rendering/options/api_usage_batching/send_null"); + // bdata.buffer_mode_batch_upload_flag_stream = GLOBAL_GET("rendering/options/api_usage_batching/flag_stream"); + + // for debug purposes, output a string with the batching options + String batching_options_string = "OpenGL ES Batching: "; + if (bdata.settings_use_batching) { + batching_options_string += "ON"; + + if (OS::get_singleton()->is_stdout_verbose()) { + batching_options_string += "\n\tOPTIONS\n"; + batching_options_string += "\tmax_join_item_commands " + itos(bdata.settings_max_join_item_commands) + "\n"; + batching_options_string += "\tcolored_vertex_format_threshold " + String(Variant(bdata.settings_colored_vertex_format_threshold)) + "\n"; + batching_options_string += "\tbatch_buffer_size " + itos(bdata.settings_batch_buffer_num_verts) + "\n"; + batching_options_string += "\tlight_scissor_area_threshold " + String(Variant(bdata.settings_scissor_threshold)) + "\n"; + + batching_options_string += "\titem_reordering_lookahead " + itos(bdata.settings_item_reordering_lookahead) + "\n"; + batching_options_string += "\tlight_max_join_items " + itos(bdata.settings_light_max_join_items) + "\n"; + batching_options_string += "\tsingle_rect_fallback " + String(Variant(bdata.settings_use_single_rect_fallback)) + "\n"; + + batching_options_string += "\tdebug_flash " + String(Variant(bdata.settings_flash_batching)) + "\n"; + batching_options_string += "\tdiagnose_frame " + String(Variant(bdata.settings_diagnose_frame)); + } + + print_line(batching_options_string); + } + + // special case, for colored vertex format threshold. + // as the comparison is >=, we want to be able to totally turn on or off + // conversion to colored vertex format at the extremes, so we will force + // 1.0 to be just above 1.0 + if (bdata.settings_colored_vertex_format_threshold > 0.995f) { + bdata.settings_colored_vertex_format_threshold = 1.01f; + } + + // save memory when batching off + if (!bdata.settings_use_batching) { + max_quads = 0; + } + + uint32_t sizeof_batch_vert = sizeof(BatchVertex); + + bdata.max_quads = max_quads; + + // 4 verts per quad + bdata.vertex_buffer_size_units = max_quads * 4; + + // the index buffer can be longer than 65535, only the indices need to be within this range + bdata.index_buffer_size_units = max_quads * 6; + + const int max_verts = bdata.vertex_buffer_size_units; + + // this comes out at approx 64K for non-colored vertex buffer, and 128K for colored vertex buffer + bdata.vertex_buffer_size_bytes = max_verts * sizeof_batch_vert; + bdata.index_buffer_size_bytes = bdata.index_buffer_size_units * 2; // 16 bit inds + + // create equal number of normal and (max) unit sized verts (as the normal may need to be translated to a larger FVF) + bdata.vertices.create(max_verts); // 512k + bdata.unit_vertices.create(max_verts, sizeof(BatchVertexLarge)); + + // extra data per vert needed for larger FVFs + bdata.light_angles.create(max_verts); + bdata.vertex_colors.create(max_verts); + bdata.vertex_modulates.create(max_verts); + bdata.vertex_transforms.create(max_verts); + + // num batches will be auto increased dynamically if required + bdata.batches.create(1024); + bdata.batches_temp.create(bdata.batches.max_size()); + + // batch textures can also be increased dynamically + bdata.batch_textures.create(32); +} + +PREAMBLE(bool)::_light_scissor_begin(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect) const { + float area_item = p_item_rect.size.x * p_item_rect.size.y; // double check these are always positive + + // quick reject .. the area of pixels saved can never be more than the area of the item + if (area_item < bdata.scissor_threshold_area) { + return false; + } + + Rect2 cliprect; + if (!_light_find_intersection(p_item_rect, p_light_xform, p_light_rect, cliprect)) { + // should not really occur .. but just in case + cliprect = Rect2(0, 0, 0, 0); + } else { + // some conditions not to scissor + // determine the area (fill rate) that will be saved + float area_cliprect = cliprect.size.x * cliprect.size.y; + float area_saved = area_item - area_cliprect; + + // if area saved is too small, don't scissor + if (area_saved < bdata.scissor_threshold_area) { + return false; + } + } + + int rh = get_storage()->frame.current_rt->height; + + int y = rh - (cliprect.position.y + cliprect.size.y); + get_this()->gl_enable_scissor(cliprect.position.x, y, cliprect.size.width, cliprect.size.height); + + return true; +} + +PREAMBLE(bool)::_light_find_intersection(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect, Rect2 &r_cliprect) const { + // transform light to world space (note this is done in the earlier intersection test, so could + // be made more efficient) + Vector2 pts[4] = { + p_light_xform.xform(p_light_rect.position), + p_light_xform.xform(Vector2(p_light_rect.position.x + p_light_rect.size.x, p_light_rect.position.y)), + p_light_xform.xform(Vector2(p_light_rect.position.x, p_light_rect.position.y + p_light_rect.size.y)), + p_light_xform.xform(Vector2(p_light_rect.position.x + p_light_rect.size.x, p_light_rect.position.y + p_light_rect.size.y)), + }; + + // calculate the light bound rect in world space + Rect2 lrect(pts[0].x, pts[0].y, 0, 0); + for (int n = 1; n < 4; n++) { + lrect.expand_to(pts[n]); + } + + // intersection between the 2 rects + // they should probably always intersect, because of earlier check, but just in case... + if (!p_item_rect.intersects(lrect)) + return false; + + // note this does almost the same as Rect2.clip but slightly more efficient for our use case + r_cliprect.position.x = MAX(p_item_rect.position.x, lrect.position.x); + r_cliprect.position.y = MAX(p_item_rect.position.y, lrect.position.y); + + Point2 item_rect_end = p_item_rect.position + p_item_rect.size; + Point2 lrect_end = lrect.position + lrect.size; + + r_cliprect.size.x = MIN(item_rect_end.x, lrect_end.x) - r_cliprect.position.x; + r_cliprect.size.y = MIN(item_rect_end.y, lrect_end.y) - r_cliprect.position.y; + + return true; +} + +PREAMBLE(void)::_calculate_scissor_threshold_area() { + if (!bdata.settings_scissor_lights) { + return; + } + + // scissor area threshold is 0.0 to 1.0 in the settings for ease of use. + // we need to translate to an absolute area to determine quickly whether + // to scissor. + if (bdata.settings_scissor_threshold < 0.0001f) { + bdata.scissor_threshold_area = -1.0f; // will always pass + } else { + // in pixels + int w = get_storage()->frame.current_rt->width; + int h = get_storage()->frame.current_rt->height; + + int screen_area = w * h; + + bdata.scissor_threshold_area = bdata.settings_scissor_threshold * screen_area; + } +} + +PREAMBLE(void)::render_joined_item_commands(const BItemJoined &p_bij, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material, bool p_lit) { + RendererCanvasRender::Item *item = 0; + RendererCanvasRender::Item *first_item = bdata.item_refs[p_bij.first_item_ref].item; + + // fill_state and bdata have once off setup per joined item, and a smaller reset on flush + FillState fill_state; + fill_state.reset_joined_item(p_bij.use_hardware_transform()); + + bdata.reset_joined_item(); + + // should this joined item be using large FVF? + if (p_bij.flags & RasterizerStorageCommon::USE_MODULATE_FVF) { + bdata.use_modulate = true; + bdata.fvf = RasterizerStorageCommon::FVF_MODULATED; + } + if (p_bij.flags & RasterizerStorageCommon::USE_LARGE_FVF) { + bdata.use_modulate = true; + bdata.use_large_verts = true; + bdata.fvf = RasterizerStorageCommon::FVF_LARGE; + } + + // in the special case of custom shaders that read from VERTEX (i.e. vertex position) + // we want to disable software transform of extra matrix + if (bdata.joined_item_batch_flags & RasterizerStorageCommon::PREVENT_VERTEX_BAKING) { + fill_state.extra_matrix_sent = true; + } + + for (unsigned int i = 0; i < p_bij.num_item_refs; i++) { + const BItemRef &ref = bdata.item_refs[p_bij.first_item_ref + i]; + item = ref.item; + + if (!p_lit) { + // if not lit we use the complex calculated final modulate + fill_state.final_modulate = ref.final_modulate; + } else { + // if lit we ignore canvas modulate and just use the item modulate + fill_state.final_modulate = item->final_modulate; + } + + // ONCE OFF fill state setup, that will be retained over multiple calls to + // prefill_joined_item() + fill_state.transform_combined = item->final_transform; + + // decide the initial transform mode, and make a backup + // in orig_transform_mode in case we need to switch back + if (!fill_state.use_hardware_transform) { + fill_state.transform_mode = _find_transform_mode(fill_state.transform_combined); + } else { + fill_state.transform_mode = TM_NONE; + } + fill_state.orig_transform_mode = fill_state.transform_mode; + + // keep track of when we added an extra matrix + // so we can defer sending until we see a default command + fill_state.transform_extra_command_number_p1 = 0; + + RendererCanvasRender::Item::Command *current_command = item->commands; + while (current_command) { + // fill as many batches as possible (until all done, or the vertex buffer is full) + bool bFull = get_this()->prefill_joined_item(fill_state, current_command, item, p_current_clip, r_reclip, p_material); + + if (bFull) { + // always pass first item (commands for default are always first item) + flush_render_batches(first_item, p_current_clip, r_reclip, p_material, fill_state.sequence_batch_type_flags); + + // zero all the batch data ready for a new run + bdata.reset_flush(); + + // don't zero all the fill state, some may need to be preserved + fill_state.reset_flush(); + } + } + } + + // flush if any left + flush_render_batches(first_item, p_current_clip, r_reclip, p_material, fill_state.sequence_batch_type_flags); + + // zero all the batch data ready for a new run + bdata.reset_flush(); +} + +PREAMBLE(void)::_legacy_canvas_item_render_commands(RendererCanvasRender::Item *p_item, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material) { + // reuse the same list each time to prevent needless dynamic allocations + unsigned int command_count = godot4_commands_to_vector(p_item->commands, bdata.command_shortlist); + RendererCanvasRender::Item::Command *const *commands = nullptr; + if (command_count) { + commands = &bdata.command_shortlist[0]; + } + + // legacy .. just create one massive batch and render everything as before + bdata.batches.reset(); + Batch *batch = _batch_request_new(); + batch->type = RasterizerStorageCommon::BT_DEFAULT; + batch->num_commands = command_count; + + get_this()->render_batches(commands, p_current_clip, r_reclip, p_material); + bdata.reset_flush(); +} + +PREAMBLE(void)::record_items(RendererCanvasRender::Item *p_item_list, int p_z) { + while (p_item_list) { + BSortItem *s = bdata.sort_items.request_with_grow(); + + s->item = p_item_list; + s->z_index = p_z; + + p_item_list = p_item_list->next; + } +} + +PREAMBLE(void)::join_sorted_items() { +} + +PREAMBLE(void)::_software_transform_vertex(BatchVector2 &r_v, const Transform2D &p_tr) const { + Vector2 vc(r_v.x, r_v.y); + vc = p_tr.xform(vc); + r_v.set(vc); +} + +PREAMBLE(void)::_software_transform_vertex(Vector2 &r_v, const Transform2D &p_tr) const { + r_v = p_tr.xform(r_v); +} + +PREAMBLE(void)::_translate_batches_to_vertex_colored_FVF() { + // zeros the size and sets up how big each unit is + bdata.unit_vertices.prepare(sizeof(BatchVertexColored)); + + const BatchColor *source_vertex_colors = &bdata.vertex_colors[0]; + RAST_DEBUG_ASSERT(bdata.vertex_colors.size() == bdata.vertices.size()); + + int num_verts = bdata.vertices.size(); + + for (int n = 0; n < num_verts; n++) { + const BatchVertex &bv = bdata.vertices[n]; + + BatchVertexColored *cv = (BatchVertexColored *)bdata.unit_vertices.request(); + + cv->pos = bv.pos; + cv->uv = bv.uv; + cv->col = *source_vertex_colors++; + } +} + +// Translation always involved adding color to the FVF, which enables +// joining of batches that have different colors. +// There is a trade off. Non colored verts are smaller so work faster, but +// there comes a point where it is better to just use colored verts to avoid lots of +// batches. +// In addition this can optionally add light angles to the FVF, necessary for normal mapping. +T_PREAMBLE +template +void C_PREAMBLE::_translate_batches_to_larger_FVF(uint32_t p_sequence_batch_type_flags) { + bool include_poly_color = false; + + // we ONLY want to include the color verts in translation when using polys, + // as rects do not write vertex colors, only colors per batch. + if (p_sequence_batch_type_flags & RasterizerStorageCommon::BTF_POLY) { + include_poly_color = INCLUDE_LIGHT_ANGLES | INCLUDE_MODULATE | INCLUDE_LARGE; + } + + // zeros the size and sets up how big each unit is + bdata.unit_vertices.prepare(sizeof(BATCH_VERTEX_TYPE)); + bdata.batches_temp.reset(); + + // As the vertices_colored and batches_temp are 'mirrors' of the non-colored version, + // the sizes should be equal, and allocations should never fail. Hence the use of debug + // asserts to check program flow, these should not occur at runtime unless the allocation + // code has been altered. + RAST_DEBUG_ASSERT(bdata.unit_vertices.max_size() == bdata.vertices.max_size()); + RAST_DEBUG_ASSERT(bdata.batches_temp.max_size() == bdata.batches.max_size()); + + Color curr_col(-1.0f, -1.0f, -1.0f, -1.0f); + + Batch *dest_batch = nullptr; + + const BatchColor *source_vertex_colors = &bdata.vertex_colors[0]; + const float *source_light_angles = &bdata.light_angles[0]; + const BatchColor *source_vertex_modulates = &bdata.vertex_modulates[0]; + const BatchTransform *source_vertex_transforms = &bdata.vertex_transforms[0]; + + // translate the batches into vertex colored batches + for (int n = 0; n < bdata.batches.size(); n++) { + const Batch &source_batch = bdata.batches[n]; + + // does source batch use light angles? + const BatchTex &btex = bdata.batch_textures[source_batch.batch_texture_id]; + bool source_batch_uses_light_angles = btex.RID_normal != RID(); + + bool needs_new_batch = true; + + if (dest_batch) { + if (dest_batch->type == source_batch.type) { + if (source_batch.type == RasterizerStorageCommon::BT_RECT) { + if (dest_batch->batch_texture_id == source_batch.batch_texture_id) { + // add to previous batch + dest_batch->num_commands += source_batch.num_commands; + needs_new_batch = false; + + // create the colored verts (only if not default) + //int first_vert = source_batch.first_quad * 4; + //int end_vert = 4 * (source_batch.first_quad + source_batch.num_commands); + int first_vert = source_batch.first_vert; + int end_vert = first_vert + (4 * source_batch.num_commands); + + for (int v = first_vert; v < end_vert; v++) { + RAST_DEV_DEBUG_ASSERT(bdata.vertices.size()); + const BatchVertex &bv = bdata.vertices[v]; + BATCH_VERTEX_TYPE *cv = (BATCH_VERTEX_TYPE *)bdata.unit_vertices.request(); + RAST_DEBUG_ASSERT(cv); + cv->pos = bv.pos; + cv->uv = bv.uv; + cv->col = source_batch.color; + + if (INCLUDE_LIGHT_ANGLES) { + RAST_DEV_DEBUG_ASSERT(bdata.light_angles.size()); + // this is required to allow compilation with non light angle vertex. + // it should be compiled out. + BatchVertexLightAngled *lv = (BatchVertexLightAngled *)cv; + if (source_batch_uses_light_angles) + lv->light_angle = *source_light_angles++; + else + lv->light_angle = 0.0f; // dummy, unused in vertex shader (could possibly be left uninitialized, but probably bad idea) + } // if including light angles + + if (INCLUDE_MODULATE) { + RAST_DEV_DEBUG_ASSERT(bdata.vertex_modulates.size()); + BatchVertexModulated *mv = (BatchVertexModulated *)cv; + mv->modulate = *source_vertex_modulates++; + } // including modulate + + if (INCLUDE_LARGE) { + RAST_DEV_DEBUG_ASSERT(bdata.vertex_transforms.size()); + BatchVertexLarge *lv = (BatchVertexLarge *)cv; + lv->transform = *source_vertex_transforms++; + } // if including large + } + } // textures match + } else { + // default + // we can still join, but only under special circumstances + // does this ever happen? not sure at this stage, but left for future expansion + uint32_t source_last_command = source_batch.first_command + source_batch.num_commands; + if (source_last_command == dest_batch->first_command) { + dest_batch->num_commands += source_batch.num_commands; + needs_new_batch = false; + } // if the commands line up exactly + } + } // if both batches are the same type + + } // if dest batch is valid + + if (needs_new_batch) { + dest_batch = bdata.batches_temp.request(); + RAST_DEBUG_ASSERT(dest_batch); + + *dest_batch = source_batch; + + // create the colored verts (only if not default) + if (source_batch.type != RasterizerStorageCommon::BT_DEFAULT) { + // int first_vert = source_batch.first_quad * 4; + // int end_vert = 4 * (source_batch.first_quad + source_batch.num_commands); + int first_vert = source_batch.first_vert; + int end_vert = first_vert + (4 * source_batch.num_commands); + + for (int v = first_vert; v < end_vert; v++) { + RAST_DEV_DEBUG_ASSERT(bdata.vertices.size()); + const BatchVertex &bv = bdata.vertices[v]; + BATCH_VERTEX_TYPE *cv = (BATCH_VERTEX_TYPE *)bdata.unit_vertices.request(); + RAST_DEBUG_ASSERT(cv); + cv->pos = bv.pos; + cv->uv = bv.uv; + + // polys are special, they can have per vertex colors + if (!include_poly_color) { + cv->col = source_batch.color; + } else { + RAST_DEV_DEBUG_ASSERT(bdata.vertex_colors.size()); + cv->col = *source_vertex_colors++; + } + + if (INCLUDE_LIGHT_ANGLES) { + RAST_DEV_DEBUG_ASSERT(bdata.light_angles.size()); + // this is required to allow compilation with non light angle vertex. + // it should be compiled out. + BatchVertexLightAngled *lv = (BatchVertexLightAngled *)cv; + if (source_batch_uses_light_angles) + lv->light_angle = *source_light_angles++; + else + lv->light_angle = 0.0f; // dummy, unused in vertex shader (could possibly be left uninitialized, but probably bad idea) + } // if using light angles + + if (INCLUDE_MODULATE) { + RAST_DEV_DEBUG_ASSERT(bdata.vertex_modulates.size()); + BatchVertexModulated *mv = (BatchVertexModulated *)cv; + mv->modulate = *source_vertex_modulates++; + } // including modulate + + if (INCLUDE_LARGE) { + RAST_DEV_DEBUG_ASSERT(bdata.vertex_transforms.size()); + BatchVertexLarge *lv = (BatchVertexLarge *)cv; + lv->transform = *source_vertex_transforms++; + } // if including large + } + } + } + } + + // copy the temporary batches to the master batch list (this could be avoided but it makes the code cleaner) + bdata.batches.copy_from(bdata.batches_temp); +} + +PREAMBLE(bool)::_disallow_item_join_if_batch_types_too_different(RenderItemState &r_ris, uint32_t btf_allowed) { + r_ris.joined_item_batch_type_flags_curr |= btf_allowed; + + bool disallow = false; + + if (r_ris.joined_item_batch_type_flags_prev & (~btf_allowed)) + disallow = true; + + return disallow; +} + +#undef PREAMBLE +#undef T_PREAMBLE +#undef C_PREAMBLE + +#endif // RASTERIZER_CANVAS_BATCHER_H diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp new file mode 100644 index 0000000000..7cd90ea1de --- /dev/null +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -0,0 +1,1709 @@ +/*************************************************************************/ +/* rasterizer_canvas_gles3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "rasterizer_canvas_gles3.h" +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/os/os.h" +#include "drivers/gles3/rasterizer_asserts.h" +#include "rasterizer_scene_gles3.h" +#include "rasterizer_storage_gles3.h" + +#include "core/config/project_settings.h" +#include "servers/rendering/rendering_server_default.h" + +//static const GLenum gl_primitive[] = { +// GL_POINTS, +// GL_LINES, +// GL_LINE_STRIP, +// GL_LINE_LOOP, +// GL_TRIANGLES, +// GL_TRIANGLE_STRIP, +// GL_TRIANGLE_FAN +//}; + +#if 0 +void RasterizerCanvasGLES3::_batch_upload_buffers() { + // noop? + if (!bdata.vertices.size()) + return; + + glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); + + // usage flag is a project setting + GLenum buffer_usage_flag = GL_DYNAMIC_DRAW; + if (bdata.buffer_mode_batch_upload_flag_stream) { + buffer_usage_flag = GL_STREAM_DRAW; + } + + // orphan the old (for now) + if (bdata.buffer_mode_batch_upload_send_null) { + glBufferData(GL_ARRAY_BUFFER, 0, 0, buffer_usage_flag); // GL_DYNAMIC_DRAW); + } + + switch (bdata.fvf) { + case RasterizerStorageCommon::FVF_UNBATCHED: // should not happen + break; + case RasterizerStorageCommon::FVF_REGULAR: // no change + glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertex) * bdata.vertices.size(), bdata.vertices.get_data(), buffer_usage_flag); + break; + case RasterizerStorageCommon::FVF_COLOR: + glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertexColored) * bdata.unit_vertices.size(), bdata.unit_vertices.get_unit(0), buffer_usage_flag); + break; + case RasterizerStorageCommon::FVF_LIGHT_ANGLE: + glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertexLightAngled) * bdata.unit_vertices.size(), bdata.unit_vertices.get_unit(0), buffer_usage_flag); + break; + case RasterizerStorageCommon::FVF_MODULATED: + glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertexModulated) * bdata.unit_vertices.size(), bdata.unit_vertices.get_unit(0), buffer_usage_flag); + break; + case RasterizerStorageCommon::FVF_LARGE: + glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertexLarge) * bdata.unit_vertices.size(), bdata.unit_vertices.get_unit(0), buffer_usage_flag); + break; + } + + // might not be necessary + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + +void RasterizerCanvasGLES3::_batch_render_lines(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material, bool p_anti_alias) { + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + _bind_canvas_texture(RID(), RID()); + + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4fv(RS::ARRAY_COLOR, (float *)&p_batch.color); + +#ifdef GLES_OVER_GL + if (p_anti_alias) + glEnable(GL_LINE_SMOOTH); +#endif + + int sizeof_vert = sizeof(BatchVertex); + + // bind the index and vertex buffer + glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bdata.gl_index_buffer); + + uint64_t pointer = 0; + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof_vert, (const void *)pointer); + + glDisableVertexAttribArray(RS::ARRAY_TEX_UV); + + int64_t offset = p_batch.first_vert; // 6 inds per quad at 2 bytes each + + int num_elements = p_batch.num_commands * 2; + glDrawArrays(GL_LINES, offset, num_elements); + + storage->info.render._2d_draw_call_count++; + + // may not be necessary .. state change optimization still TODO + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + +#ifdef GLES_OVER_GL + if (p_anti_alias) + glDisable(GL_LINE_SMOOTH); +#endif +} + +void RasterizerCanvasGLES3::_batch_render_generic(const Batch &p_batch, RasterizerStorageGLES3::Material *p_material) { + ERR_FAIL_COND(p_batch.num_commands <= 0); + + const bool &use_light_angles = bdata.use_light_angles; + const bool &use_modulate = bdata.use_modulate; + const bool &use_large_verts = bdata.use_large_verts; + const bool &colored_verts = bdata.use_colored_vertices | use_light_angles | use_modulate | use_large_verts; + + int sizeof_vert; + + switch (bdata.fvf) { + default: + sizeof_vert = 0; // prevent compiler warning - this should never happen + break; + case RasterizerStorageCommon::FVF_UNBATCHED: { + sizeof_vert = 0; // prevent compiler warning - this should never happen + return; + } break; + case RasterizerStorageCommon::FVF_REGULAR: // no change + sizeof_vert = sizeof(BatchVertex); + break; + case RasterizerStorageCommon::FVF_COLOR: + sizeof_vert = sizeof(BatchVertexColored); + break; + case RasterizerStorageCommon::FVF_LIGHT_ANGLE: + sizeof_vert = sizeof(BatchVertexLightAngled); + break; + case RasterizerStorageCommon::FVF_MODULATED: + sizeof_vert = sizeof(BatchVertexModulated); + break; + case RasterizerStorageCommon::FVF_LARGE: + sizeof_vert = sizeof(BatchVertexLarge); + break; + } + + // make sure to set all conditionals BEFORE binding the shader + _set_texture_rect_mode(false, use_light_angles, use_modulate, use_large_verts); + + // batch tex + const BatchTex &tex = bdata.batch_textures[p_batch.batch_texture_id]; + //VSG::rasterizer->gl_check_for_error(); + + // force repeat is set if non power of 2 texture, and repeat is needed if hardware doesn't support npot + if (tex.tile_mode == BatchTex::TILE_FORCE_REPEAT) { + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_FORCE_REPEAT, true); + } + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + _bind_canvas_texture(tex.RID_texture, tex.RID_normal); + + // bind the index and vertex buffer + glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bdata.gl_index_buffer); + + uint64_t pointer = 0; + glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof_vert, (const void *)pointer); + + // always send UVs, even within a texture specified because a shader can still use UVs + glEnableVertexAttribArray(RS::ARRAY_TEX_UV); + glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (2 * 4))); + + // color + if (!colored_verts) { + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4fv(RS::ARRAY_COLOR, p_batch.color.get_data()); + } else { + glEnableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (4 * 4))); + } + + if (use_light_angles) { + glEnableVertexAttribArray(RS::ARRAY_TANGENT); + glVertexAttribPointer(RS::ARRAY_TANGENT, 1, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (8 * 4))); + } + + if (use_modulate) { + glEnableVertexAttribArray(RS::ARRAY_TEX_UV2); + glVertexAttribPointer(RS::ARRAY_TEX_UV2, 4, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (9 * 4))); + } + + if (use_large_verts) { + glEnableVertexAttribArray(RS::ARRAY_BONES); + glVertexAttribPointer(RS::ARRAY_BONES, 2, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (13 * 4))); + glEnableVertexAttribArray(RS::ARRAY_WEIGHTS); + glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (15 * 4))); + } + + // We only want to set the GL wrapping mode if the texture is not already tiled (i.e. set in Import). + // This is an optimization left over from the legacy renderer. + // If we DID set tiling in the API, and reverted to clamped, then the next draw using this texture + // may use clamped mode incorrectly. + bool tex_is_already_tiled = tex.flags & RasterizerStorageGLES3::TEXTURE_FLAG_REPEAT; + + if (tex.tile_mode == BatchTex::TILE_NORMAL) { + // if the texture is imported as tiled, no need to set GL state, as it will already be bound with repeat + if (!tex_is_already_tiled) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + } + + // we need to convert explicitly from pod Vec2 to Vector2 ... + // could use a cast but this might be unsafe in future + Vector2 tps; + tex.tex_pixel_size.to(tps); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, tps); + + switch (p_batch.type) { + default: { + // prevent compiler warning + } break; + case RasterizerStorageCommon::BT_RECT: { + int64_t offset = p_batch.first_vert * 3; + + int num_elements = p_batch.num_commands * 6; + glDrawElements(GL_TRIANGLES, num_elements, GL_UNSIGNED_SHORT, (void *)offset); + } break; + case RasterizerStorageCommon::BT_POLY: { + int64_t offset = p_batch.first_vert; + + int num_elements = p_batch.num_commands; + glDrawArrays(GL_TRIANGLES, offset, num_elements); + } break; + } + + storage->info.render._2d_draw_call_count++; + + switch (tex.tile_mode) { + case BatchTex::TILE_FORCE_REPEAT: { + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_FORCE_REPEAT, false); + } break; + case BatchTex::TILE_NORMAL: { + // if the texture is imported as tiled, no need to revert GL state + if (!tex_is_already_tiled) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + } break; + default: { + } break; + } + + // could these have ifs? + glDisableVertexAttribArray(RS::ARRAY_TEX_UV); + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glDisableVertexAttribArray(RS::ARRAY_TANGENT); + glDisableVertexAttribArray(RS::ARRAY_TEX_UV2); + glDisableVertexAttribArray(RS::ARRAY_BONES); + glDisableVertexAttribArray(RS::ARRAY_WEIGHTS); + + // may not be necessary .. state change optimization still TODO + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} +#endif +void RasterizerCanvasGLES3::render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES3::Material *p_material) { + int num_batches = bdata.batches.size(); + + for (int batch_num = 0; batch_num < num_batches; batch_num++) { + const Batch &batch = bdata.batches[batch_num]; + + switch (batch.type) { + case RasterizerStorageCommon::BT_RECT: { + //_batch_render_generic(batch, p_material); + } break; + case RasterizerStorageCommon::BT_POLY: { + //_batch_render_generic(batch, p_material); + } break; + case RasterizerStorageCommon::BT_LINE: { + //_batch_render_lines(batch, p_material, false); + } break; + case RasterizerStorageCommon::BT_LINE_AA: { + //_batch_render_lines(batch, p_material, true); + } break; + default: { + int end_command = batch.first_command + batch.num_commands; + + for (int i = batch.first_command; i < end_command; i++) { + Item::Command *command = p_commands[i]; + + switch (command->type) { +#if 0 + case Item::Command::TYPE_LINE: { + Item::CommandLine *line = static_cast(command); + + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + _bind_canvas_texture(RID(), RID()); + + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4fv(RS::ARRAY_COLOR, line->color.components); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); + + if (line->width <= 1) { + Vector2 verts[2] = { + Vector2(line->from.x, line->from.y), + Vector2(line->to.x, line->to.y) + }; + +#ifdef GLES_OVER_GL + if (line->antialiased) + glEnable(GL_LINE_SMOOTH); +#endif + _draw_gui_primitive(2, verts, NULL, NULL); + +#ifdef GLES_OVER_GL + if (line->antialiased) + glDisable(GL_LINE_SMOOTH); +#endif + } else { + Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; + + Vector2 verts[4] = { + line->from - t, + line->from + t, + line->to + t, + line->to - t + }; + + _draw_gui_primitive(4, verts, NULL, NULL); +#ifdef GLES_OVER_GL + if (line->antialiased) { + glEnable(GL_LINE_SMOOTH); + for (int j = 0; j < 4; j++) { + Vector2 vertsl[2] = { + verts[j], + verts[(j + 1) % 4], + }; + _draw_gui_primitive(2, vertsl, NULL, NULL); + } + glDisable(GL_LINE_SMOOTH); + } +#endif + } + } break; +#endif + case Item::Command::TYPE_PRIMITIVE: { + Item::CommandPrimitive *pr = static_cast(command); + + switch (pr->point_count) { + case 2: { + _legacy_draw_line(pr, p_material); + } break; + default: { + _legacy_draw_primitive(pr, p_material); + } break; + } + + } break; + + case Item::Command::TYPE_RECT: { + Item::CommandRect *r = static_cast(command); + _bind_quad_buffer(); + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4fv(RS::ARRAY_COLOR, r->modulate.components); + + bool can_tile = true; + + // we will take account of render target textures which need to be drawn upside down + // quirk of opengl + bool upside_down = r->flags & CANVAS_RECT_FLIP_V; + + // very inefficient, improve this + if (r->texture.is_valid()) { + RasterizerStorageGLES3::Texture *texture = storage->texture_owner.get_or_null(r->texture); + + if (texture) { + if (texture->is_upside_down()) + upside_down = true; + } + } + + if (r->texture.is_valid() && r->flags & CANVAS_RECT_TILE && !storage->config.support_npot_repeat_mipmap) { + // workaround for when setting tiling does not work due to hardware limitation + + RasterizerStorageGLES3::Texture *texture = storage->texture_owner.get_or_null(r->texture); + + if (texture) { + texture = texture->get_ptr(); + + if (next_power_of_2(texture->alloc_width) != (unsigned int)texture->alloc_width && next_power_of_2(texture->alloc_height) != (unsigned int)texture->alloc_height) { + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_FORCE_REPEAT, true); + can_tile = false; + } + } + } + + // On some widespread Nvidia cards, the normal draw method can produce some + // flickering in draw_rect and especially TileMap rendering (tiles randomly flicker). + // See GH-9913. + // To work it around, we use a simpler draw method which does not flicker, but gives + // a non negligible performance hit, so it's opt-in (GH-24466). + if (use_nvidia_rect_workaround) { + // are we using normal maps, if so we want to use light angle + bool send_light_angles = false; + + // only need to use light angles when normal mapping + // otherwise we can use the default shader + if (state.current_normal != RID()) { + send_light_angles = true; + } + + _set_texture_rect_mode(false, send_light_angles); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + Vector2 points[4] = { + r->rect.position, + r->rect.position + Vector2(r->rect.size.x, 0.0), + r->rect.position + r->rect.size, + r->rect.position + Vector2(0.0, r->rect.size.y), + }; + + if (r->rect.size.x < 0) { + SWAP(points[0], points[1]); + SWAP(points[2], points[3]); + } + if (r->rect.size.y < 0) { + SWAP(points[0], points[3]); + SWAP(points[1], points[2]); + } + + // FTODO + //RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(r->texture, r->normal_map); + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(r->texture, RID()); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + + Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); + + Vector2 uvs[4] = { + src_rect.position, + src_rect.position + Vector2(src_rect.size.x, 0.0), + src_rect.position + src_rect.size, + src_rect.position + Vector2(0.0, src_rect.size.y), + }; + + // for encoding in light angle + bool flip_h = false; + bool flip_v = false; + + if (r->flags & CANVAS_RECT_TRANSPOSE) { + SWAP(uvs[1], uvs[3]); + } + + if (r->flags & CANVAS_RECT_FLIP_H) { + SWAP(uvs[0], uvs[1]); + SWAP(uvs[2], uvs[3]); + flip_h = true; + flip_v = !flip_v; + } + if (upside_down) { + SWAP(uvs[0], uvs[3]); + SWAP(uvs[1], uvs[2]); + flip_v = !flip_v; + } + + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + + bool untile = false; + + if (can_tile && r->flags & CANVAS_RECT_TILE && !(texture->flags & RasterizerStorageGLES3::TEXTURE_FLAG_REPEAT)) { + texture->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + untile = true; + } + + if (send_light_angles) { + // for single rects, there is no need to fully utilize the light angle, + // we only need it to encode flips (horz and vert). But the shader can be reused with + // batching in which case the angle encodes the transform as well as + // the flips. + // Note transpose is NYI. I don't think it worked either with the non-nvidia method. + + // if horizontal flip, angle is 180 + float angle = 0.0f; + if (flip_h) + angle = Math_PI; + + // add 1 (to take care of zero floating point error with sign) + angle += 1.0f; + + // flip if necessary + if (flip_v) + angle *= -1.0f; + + // light angle must be sent for each vert, instead as a single uniform in the uniform draw method + // this has the benefit of enabling batching with light angles. + float light_angles[4] = { angle, angle, angle, angle }; + + _draw_gui_primitive(4, points, NULL, uvs, light_angles); + } else { + _draw_gui_primitive(4, points, NULL, uvs); + } + + if (untile) { + texture->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + } + } else { + static const Vector2 uvs[4] = { + Vector2(0.0, 0.0), + Vector2(0.0, 1.0), + Vector2(1.0, 1.0), + Vector2(1.0, 0.0), + }; + + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2()); + _draw_gui_primitive(4, points, NULL, uvs); + } + + } else { + // This branch is better for performance, but can produce flicker on Nvidia, see above comment. + + _set_texture_rect_mode(true); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + _bind_quad_buffer(); + + // FTODO + //RasterizerStorageGLES3::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map); + RasterizerStorageGLES3::Texture *tex = _bind_canvas_texture(r->texture, RID()); + + if (!tex) { + Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); + + if (dst_rect.size.width < 0) { + dst_rect.position.x += dst_rect.size.width; + dst_rect.size.width *= -1; + } + if (dst_rect.size.height < 0) { + dst_rect.position.y += dst_rect.size.height; + dst_rect.size.height *= -1; + } + + state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(0, 0, 1, 1)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + storage->info.render._2d_draw_call_count++; + } else { + bool untile = false; + + if (can_tile && r->flags & CANVAS_RECT_TILE && !(tex->flags & RasterizerStorageGLES3::TEXTURE_FLAG_REPEAT)) { + tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + untile = true; + } + + Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); + Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); + + Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); + + if (dst_rect.size.width < 0) { + dst_rect.position.x += dst_rect.size.width; + dst_rect.size.width *= -1; + } + if (dst_rect.size.height < 0) { + dst_rect.position.y += dst_rect.size.height; + dst_rect.size.height *= -1; + } + + if (r->flags & CANVAS_RECT_FLIP_H) { + src_rect.size.x *= -1; + } + + if (upside_down) { + src_rect.size.y *= -1; + } + + if (r->flags & CANVAS_RECT_TRANSPOSE) { + dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform + } + + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + storage->info.render._2d_draw_call_count++; + + if (untile) { + tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + } + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_FORCE_REPEAT, false); + + } break; + case Item::Command::TYPE_NINEPATCH: { + Item::CommandNinePatch *np = static_cast(command); + + _set_texture_rect_mode(false); + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + _bind_quad_buffer(); + + glDisableVertexAttribArray(RS::ARRAY_COLOR); + glVertexAttrib4fv(RS::ARRAY_COLOR, np->color.components); + + // FTODO + //RasterizerStorageGLES3::Texture *tex = _bind_canvas_texture(np->texture, np->normal_map); + RasterizerStorageGLES3::Texture *tex = _bind_canvas_texture(np->texture, RID()); + + if (!tex) { + // FIXME: Handle textureless ninepatch gracefully + WARN_PRINT("NinePatch without texture not supported yet in OpenGL backend, skipping."); + continue; + } + if (tex->width == 0 || tex->height == 0) { + WARN_PRINT("Cannot set empty texture to NinePatch."); + continue; + } + + Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); + + // state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); + state.canvas_shader.set_uniform(CanvasShaderGLES3::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; + } + + float screen_scale = 1.0; + + if ((bdata.settings_ninepatch_mode == 1) && (source.size.x != 0) && (source.size.y != 0)) { + screen_scale = MIN(np->rect.size.x / source.size.x, np->rect.size.y / source.size.y); + screen_scale = MIN(1.0, screen_scale); + } + + // prepare vertex buffer + + // this buffer contains [ POS POS UV UV ] * + + float buffer[16 * 2 + 16 * 2]; + + { + // first row + + buffer[(0 * 4 * 4) + 0] = np->rect.position.x; + buffer[(0 * 4 * 4) + 1] = np->rect.position.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[SIDE_LEFT] * screen_scale; + buffer[(0 * 4 * 4) + 5] = np->rect.position.y; + + buffer[(0 * 4 * 4) + 6] = (source.position.x + np->margin[SIDE_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[SIDE_RIGHT] * screen_scale; + buffer[(0 * 4 * 4) + 9] = np->rect.position.y; + + buffer[(0 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[SIDE_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] = (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[SIDE_TOP] * screen_scale; + + buffer[(1 * 4 * 4) + 2] = source.position.x * texpixel_size.x; + buffer[(1 * 4 * 4) + 3] = (source.position.y + np->margin[SIDE_TOP]) * texpixel_size.y; + + buffer[(1 * 4 * 4) + 4] = np->rect.position.x + np->margin[SIDE_LEFT] * screen_scale; + buffer[(1 * 4 * 4) + 5] = np->rect.position.y + np->margin[SIDE_TOP] * screen_scale; + + buffer[(1 * 4 * 4) + 6] = (source.position.x + np->margin[SIDE_LEFT]) * texpixel_size.x; + buffer[(1 * 4 * 4) + 7] = (source.position.y + np->margin[SIDE_TOP]) * texpixel_size.y; + + buffer[(1 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[SIDE_RIGHT] * screen_scale; + buffer[(1 * 4 * 4) + 9] = np->rect.position.y + np->margin[SIDE_TOP] * screen_scale; + + buffer[(1 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[SIDE_RIGHT]) * texpixel_size.x; + buffer[(1 * 4 * 4) + 11] = (source.position.y + np->margin[SIDE_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[SIDE_TOP] * screen_scale; + + buffer[(1 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; + buffer[(1 * 4 * 4) + 15] = (source.position.y + np->margin[SIDE_TOP]) * texpixel_size.y; + + // third row + + buffer[(2 * 4 * 4) + 0] = np->rect.position.x; + buffer[(2 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y - np->margin[SIDE_BOTTOM] * screen_scale; + + buffer[(2 * 4 * 4) + 2] = source.position.x * texpixel_size.x; + buffer[(2 * 4 * 4) + 3] = (source.position.y + source.size.y - np->margin[SIDE_BOTTOM]) * texpixel_size.y; + + buffer[(2 * 4 * 4) + 4] = np->rect.position.x + np->margin[SIDE_LEFT] * screen_scale; + buffer[(2 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y - np->margin[SIDE_BOTTOM] * screen_scale; + + buffer[(2 * 4 * 4) + 6] = (source.position.x + np->margin[SIDE_LEFT]) * texpixel_size.x; + buffer[(2 * 4 * 4) + 7] = (source.position.y + source.size.y - np->margin[SIDE_BOTTOM]) * texpixel_size.y; + + buffer[(2 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[SIDE_RIGHT] * screen_scale; + buffer[(2 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y - np->margin[SIDE_BOTTOM] * screen_scale; + + buffer[(2 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[SIDE_RIGHT]) * texpixel_size.x; + buffer[(2 * 4 * 4) + 11] = (source.position.y + source.size.y - np->margin[SIDE_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[SIDE_BOTTOM] * screen_scale; + + 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[SIDE_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] = 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[SIDE_LEFT] * screen_scale; + buffer[(3 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y; + + buffer[(3 * 4 * 4) + 6] = (source.position.x + np->margin[SIDE_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[SIDE_RIGHT] * screen_scale; + buffer[(3 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y; + + buffer[(3 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[SIDE_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] = (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); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, buffer, _buffer_upload_usage_flag); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); + + //glEnableVertexAttribArray(RS::ARRAY_VERTEX); + glEnableVertexAttribArray(RS::ARRAY_TEX_UV); + + //glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); + glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), CAST_INT_TO_UCHAR_PTR((sizeof(float) * 2))); + + //glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_SHORT, NULL); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + storage->info.render._2d_draw_call_count++; + + } break; +#if 0 + case Item::Command::TYPE_CIRCLE: { + Item::CommandCircle *circle = static_cast(command); + + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + static const int num_points = 32; + + Vector2 points[num_points + 1]; + points[num_points] = circle->pos; + + int indices[num_points * 3]; + + for (int j = 0; j < num_points; j++) { + points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / num_points), Math::cos(j * Math_PI * 2.0 / num_points)) * circle->radius; + indices[j * 3 + 0] = j; + indices[j * 3 + 1] = (j + 1) % num_points; + indices[j * 3 + 2] = num_points; + } + + _bind_canvas_texture(RID(), RID()); + + _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true); + } break; +#endif + case Item::Command::TYPE_POLYGON: { + Item::CommandPolygon *polygon = static_cast(command); + //const PolyData &pd = _polydata[polygon->polygon.polygon_id]; + + switch (polygon->primitive) { + case RS::PRIMITIVE_TRIANGLES: { + _legacy_draw_poly_triangles(polygon, p_material); + } break; + default: + break; + } + + } break; +#if 0 + case Item::Command::TYPE_MESH: { + Item::CommandMesh *mesh = static_cast(command); + + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.get_or_null(mesh->mesh); + if (mesh_data) { + 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 + + glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); + + if (s->index_array_len > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); + } + + for (int k = 0; k < RS::ARRAY_MAX - 1; k++) { + if (s->attribs[k].enabled) { + glEnableVertexAttribArray(k); + glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset)); + } else { + glDisableVertexAttribArray(k); + switch (k) { + case RS::ARRAY_NORMAL: { + glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); + } break; + case RS::ARRAY_COLOR: { + glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); + + } break; + default: { + } + } + } + } + + if (s->index_array_len > 0) { + glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); + } else { + glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); + } + } + + for (int j = 1; j < RS::ARRAY_MAX - 1; j++) { + glDisableVertexAttribArray(j); + } + } + + storage->info.render._2d_draw_call_count++; + } break; + case Item::Command::TYPE_MULTIMESH: { + Item::CommandMultiMesh *mmesh = static_cast(command); + + RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.get_or_null(mmesh->multimesh); + + if (!multi_mesh) + break; + + RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.get_or_null(multi_mesh->mesh); + + if (!mesh_data) + break; + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != RS::MULTIMESH_CUSTOM_DATA_NONE); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true); + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + //reset shader and force rebind + + int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); + + if (amount == -1) { + amount = multi_mesh->size; + } + + int stride = multi_mesh->color_floats + multi_mesh->custom_data_floats + multi_mesh->xform_floats; + + int color_ofs = multi_mesh->xform_floats; + int custom_data_ofs = color_ofs + multi_mesh->color_floats; + + // drawing + + const float *base_buffer = multi_mesh->data.ptr(); + + for (int j = 0; j < mesh_data->surfaces.size(); j++) { + 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 + + //bind buffers for mesh surface + glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); + + if (s->index_array_len > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); + } + + for (int k = 0; k < RS::ARRAY_MAX - 1; k++) { + if (s->attribs[k].enabled) { + glEnableVertexAttribArray(k); + glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset)); + } else { + glDisableVertexAttribArray(k); + switch (k) { + case RS::ARRAY_NORMAL: { + glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); + } break; + case RS::ARRAY_COLOR: { + glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); + + } break; + default: { + } + } + } + } + + for (int k = 0; k < amount; k++) { + const float *buffer = base_buffer + k * stride; + + { + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]); + if (multi_mesh->transform_format == RS::MULTIMESH_TRANSFORM_3D) { + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]); + } else { + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 2, 0.0, 0.0, 1.0, 0.0); + } + } + + if (multi_mesh->color_floats) { + if (multi_mesh->color_format == RS::MULTIMESH_COLOR_8BIT) { + uint8_t *color_data = (uint8_t *)(buffer + color_ofs); + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); + } else { + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); + } + } else { + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, 1.0, 1.0, 1.0, 1.0); + } + + if (multi_mesh->custom_data_floats) { + if (multi_mesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) { + uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); + } else { + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 4, buffer + custom_data_ofs); + } + } + + if (s->index_array_len > 0) { + glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); + } else { + glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); + } + } + } + + // LIGHT ANGLE PR replaced USE_INSTANCE_CUSTOM line with below .. think it was a typo, + // but just in case, made this note. + //_set_texture_rect_mode(false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); + + storage->info.render._2d_draw_call_count++; + } break; + case Item::Command::TYPE_POLYLINE: { + Item::CommandPolyLine *pline = static_cast(command); + + _set_texture_rect_mode(false); + + 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); +#ifdef GLES_OVER_GL + glEnable(GL_LINE_SMOOTH); + if (pline->multiline) { + //needs to be different + } else { + _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); + } + glDisable(GL_LINE_SMOOTH); +#endif + } else { +#ifdef GLES_OVER_GL + if (pline->antialiased) + glEnable(GL_LINE_SMOOTH); +#endif + + if (pline->multiline) { + int todo = pline->lines.size() / 2; + int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); + int offset = 0; + + while (todo) { + int to_draw = MIN(max_per_call, todo); + _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1); + todo -= to_draw; + offset += to_draw * 2; + } + } else { + _draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); + } + +#ifdef GLES_OVER_GL + if (pline->antialiased) + glDisable(GL_LINE_SMOOTH); +#endif + } + } break; + + case Item::Command::TYPE_PRIMITIVE: { + Item::CommandPrimitive *primitive = static_cast(command); + _set_texture_rect_mode(false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + ERR_CONTINUE(primitive->points.size() < 1); + + RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + // we need a temporary because this must be nulled out + // if only a single color specified + const Color *colors = primitive->colors.ptr(); + if (primitive->colors.size() == 1 && primitive->points.size() > 1) { + Color c = primitive->colors[0]; + glVertexAttrib4f(RS::ARRAY_COLOR, c.r, c.g, c.b, c.a); + colors = nullptr; + } else if (primitive->colors.empty()) { + glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); + } +#ifdef RASTERIZER_EXTRA_CHECKS + else { + RAST_DEV_DEBUG_ASSERT(primitive->colors.size() == primitive->points.size()); + } + + if (primitive->uvs.ptr()) { + RAST_DEV_DEBUG_ASSERT(primitive->uvs.size() == primitive->points.size()); + } +#endif + + _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), colors, primitive->uvs.ptr()); + } break; +#endif + case Item::Command::TYPE_TRANSFORM: { + Item::CommandTransform *transform = static_cast(command); + state.uniforms.extra_matrix = transform->xform; + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, state.uniforms.extra_matrix); + } break; + + case Item::Command::TYPE_PARTICLES: { + } break; + case Item::Command::TYPE_CLIP_IGNORE: { + Item::CommandClipIgnore *ci = static_cast(command); + if (p_current_clip) { + if (ci->ignore != r_reclip) { + if (ci->ignore) { + glDisable(GL_SCISSOR_TEST); + r_reclip = true; + } else { + glEnable(GL_SCISSOR_TEST); + + int x = p_current_clip->final_clip_rect.position.x; + int y = storage->frame.current_rt->height - (p_current_clip->final_clip_rect.position.y + p_current_clip->final_clip_rect.size.y); + int w = p_current_clip->final_clip_rect.size.x; + int h = p_current_clip->final_clip_rect.size.y; + + // FTODO + // if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_VFLIP]) + // y = p_current_clip->final_clip_rect.position.y; + + glScissor(x, y, w, h); + + r_reclip = false; + } + } + } + + } break; + default: { + // FIXME: Proper error handling if relevant + //print_line("other"); + } break; + } + } + + } // default + break; + } + } +} + +void RasterizerCanvasGLES3::canvas_end() { + batch_canvas_end(); + RasterizerCanvasBaseGLES3::canvas_end(); +} + +void RasterizerCanvasGLES3::canvas_begin() { + batch_canvas_begin(); + RasterizerCanvasBaseGLES3::canvas_begin(); +} + +void RasterizerCanvasGLES3::canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { + batch_canvas_render_items_begin(p_modulate, p_light, p_base_transform); +} + +void RasterizerCanvasGLES3::canvas_render_items_end() { + batch_canvas_render_items_end(); +} + +void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) { + storage->frame.current_rt = nullptr; + + // first set the current render target + storage->_set_current_render_target(p_to_render_target); + + // binds the render target (framebuffer) + canvas_begin(); + + canvas_render_items_begin(p_modulate, p_light_list, p_canvas_transform); + canvas_render_items_internal(p_item_list, 0, p_modulate, p_light_list, p_canvas_transform); + canvas_render_items_end(); + + canvas_end(); + + // not sure why these are needed to get frame to render? + storage->_set_current_render_target(RID()); + // storage->frame.current_rt = nullptr; + // canvas_begin(); + // canvas_end(); +} + +void RasterizerCanvasGLES3::canvas_render_items_internal(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { + batch_canvas_render_items(p_item_list, p_z, p_modulate, p_light, p_base_transform); + + //glClearColor(Math::randf(), 0, 1, 1); +} + +void RasterizerCanvasGLES3::canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { + // parameters are easier to pass around in a structure + RenderItemState ris; + ris.item_group_z = p_z; + ris.item_group_modulate = p_modulate; + ris.item_group_light = p_light; + ris.item_group_base_transform = p_base_transform; + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false); + + state.current_tex = RID(); + state.current_tex_ptr = NULL; + state.current_normal = RID(); + state.canvas_texscreen_used = false; + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + + while (p_item_list) { + Item *ci = p_item_list; + _legacy_canvas_render_item(ci, ris); + p_item_list = p_item_list->next; + } + + if (ris.current_clip) { + glDisable(GL_SCISSOR_TEST); + } + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false); +} + +// Legacy non-batched implementation for regression testing. +// Should be removed after testing phase to avoid duplicate codepaths. +void RasterizerCanvasGLES3::_legacy_canvas_render_item(Item *p_ci, RenderItemState &r_ris) { + storage->info.render._2d_item_count++; + + // defaults + state.current_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; + state.current_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; + + if (p_ci->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) { + state.current_filter = p_ci->texture_filter; + } + + if (p_ci->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) { + state.current_repeat = p_ci->texture_repeat; + } + + if (r_ris.current_clip != p_ci->final_clip_owner) { + r_ris.current_clip = p_ci->final_clip_owner; + + if (r_ris.current_clip) { + glEnable(GL_SCISSOR_TEST); + int y = storage->_dims.rt_height - (r_ris.current_clip->final_clip_rect.position.y + r_ris.current_clip->final_clip_rect.size.y); + // int y = storage->frame.current_rt->height - (r_ris.current_clip->final_clip_rect.position.y + r_ris.current_clip->final_clip_rect.size.y); + // FTODO + // if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_VFLIP]) + // y = r_ris.current_clip->final_clip_rect.position.y; + glScissor(r_ris.current_clip->final_clip_rect.position.x, y, r_ris.current_clip->final_clip_rect.size.width, r_ris.current_clip->final_clip_rect.size.height); + + // debug VFLIP + // if ((r_ris.current_clip->final_clip_rect.position.x == 223) + // && (y == 54) + // && (r_ris.current_clip->final_clip_rect.size.width == 1383)) + // { + // glScissor(r_ris.current_clip->final_clip_rect.position.x, y, r_ris.current_clip->final_clip_rect.size.width, r_ris.current_clip->final_clip_rect.size.height); + // } + + } else { + glDisable(GL_SCISSOR_TEST); + } + } + + // TODO: copy back buffer + + if (p_ci->copy_back_buffer) { + if (p_ci->copy_back_buffer->full) { + _copy_texscreen(Rect2()); + } else { + _copy_texscreen(p_ci->copy_back_buffer->rect); + } + } + +#if 0 + RasterizerStorageGLES3::Skeleton *skeleton = NULL; + + { + //skeleton handling + if (p_ci->skeleton.is_valid() && storage->skeleton_owner.owns(p_ci->skeleton)) { + skeleton = storage->skeleton_owner.get(p_ci->skeleton); + if (!skeleton->use_2d) { + skeleton = NULL; + } else { + state.skeleton_transform = r_ris.item_group_base_transform * skeleton->base_transform_2d; + state.skeleton_transform_inverse = state.skeleton_transform.affine_inverse(); + state.skeleton_texture_size = Vector2(skeleton->size * 2, 0); + } + } + + bool use_skeleton = skeleton != NULL; + if (r_ris.prev_use_skeleton != use_skeleton) { + r_ris.rebind_shader = true; + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, use_skeleton); + r_ris.prev_use_skeleton = use_skeleton; + } + + if (skeleton) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); + state.using_skeleton = true; + } else { + state.using_skeleton = false; + } + } +#endif + + Item *material_owner = p_ci->material_owner ? p_ci->material_owner : p_ci; + + RID material = material_owner->material; + RasterizerStorageGLES3::Material *material_ptr = storage->material_owner.get_or_null(material); + + if (material != r_ris.canvas_last_material || r_ris.rebind_shader) { + RasterizerStorageGLES3::Shader *shader_ptr = NULL; + + if (material_ptr) { + shader_ptr = material_ptr->shader; + + if (shader_ptr && shader_ptr->mode != RS::SHADER_CANVAS_ITEM) { + shader_ptr = NULL; // not a canvas item shader, don't use. + } + } + + if (shader_ptr) { + if (shader_ptr->canvas_item.uses_screen_texture) { + if (!state.canvas_texscreen_used) { + //copy if not copied before + _copy_texscreen(Rect2()); + + // blend mode will have been enabled so make sure we disable it again later on + //last_blend_mode = last_blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED ? last_blend_mode : -1; + } + + if (storage->frame.current_rt->copy_screen_effect.color) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); + } + } + + if (shader_ptr != r_ris.shader_cache) { + if (shader_ptr->canvas_item.uses_time) { + RenderingServerDefault::redraw_request(); + } + + state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); + state.canvas_shader.bind(); + } + + int tc = material_ptr->textures.size(); + Pair *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_TEXTURE0 + i); + + RasterizerStorageGLES3::Texture *t = storage->texture_owner.get_or_null(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; + } + + if (t->redraw_if_visible) { + RenderingServerDefault::redraw_request(); + } + + t = t->get_ptr(); + +#ifdef TOOLS_ENABLED + if (t->detect_normal && texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL) { + t->detect_normal(t->detect_normal_ud); + } +#endif + if (t->render_target) + t->render_target->used_in_frame = true; + + glBindTexture(t->target, t->tex_id); + } + + } else { + state.canvas_shader.set_custom_shader(0); + state.canvas_shader.bind(); + } + state.canvas_shader.use_material((void *)material_ptr); + + r_ris.shader_cache = shader_ptr; + + r_ris.canvas_last_material = material; + + r_ris.rebind_shader = false; + } + + int blend_mode = r_ris.shader_cache ? r_ris.shader_cache->canvas_item.blend_mode : RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX; + bool unshaded = r_ris.shader_cache && (r_ris.shader_cache->canvas_item.light_mode == RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA)); + bool reclip = false; + + if (r_ris.last_blend_mode != blend_mode) { + switch (blend_mode) { + case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } + + } break; + case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_ADD: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + } + + } break; + case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_SUB: { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + } + } break; + case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); + } else { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); + } + } break; + case RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } + } break; + } + } + + state.uniforms.final_modulate = unshaded ? p_ci->final_modulate : Color(p_ci->final_modulate.r * r_ris.item_group_modulate.r, p_ci->final_modulate.g * r_ris.item_group_modulate.g, p_ci->final_modulate.b * r_ris.item_group_modulate.b, p_ci->final_modulate.a * r_ris.item_group_modulate.a); + + state.uniforms.modelview_matrix = p_ci->final_transform; + state.uniforms.extra_matrix = Transform2D(); + + _set_uniforms(); + + if (unshaded || (state.uniforms.final_modulate.a > 0.001 && (!r_ris.shader_cache || r_ris.shader_cache->canvas_item.light_mode != RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !p_ci->light_masked)) + _legacy_canvas_item_render_commands(p_ci, NULL, reclip, material_ptr); + + r_ris.rebind_shader = true; // hacked in for now. + + if ((blend_mode == RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX || blend_mode == RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA) && r_ris.item_group_light && !unshaded) { + Light *light = r_ris.item_group_light; + bool light_used = false; + RS::CanvasLightBlendMode bmode = RS::CANVAS_LIGHT_BLEND_MODE_ADD; + state.uniforms.final_modulate = p_ci->final_modulate; // remove the canvas modulate + + while (light) { + if (p_ci->light_mask & light->item_mask && r_ris.item_group_z >= light->z_min && r_ris.item_group_z <= light->z_max && p_ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) { + //intersects this light + + if (!light_used || bmode != light->blend_mode) { + bmode = light->blend_mode; + + switch (bmode) { + case RS::CANVAS_LIGHT_BLEND_MODE_ADD: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + } break; + case RS::CANVAS_LIGHT_BLEND_MODE_SUB: { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } break; + case RS::CANVAS_LIGHT_BLEND_MODE_MIX: { + // case RS::CANVAS_LIGHT_MODE_MASK: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + } break; + } + } + + if (!light_used) { + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, true); + light_used = true; + } + + // FTODO + //bool has_shadow = light->shadow_buffer.is_valid() && p_ci->light_mask & light->item_shadow_mask; + bool has_shadow = light->use_shadow && p_ci->light_mask & light->item_shadow_mask; + + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, has_shadow); + if (has_shadow) { + // FTODO + //state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_USE_GRADIENT, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_NONE); + //state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF3); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF5); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, false); + //state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF7); + //state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF9); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF13); + } + + state.canvas_shader.bind(); + state.using_light = light; + state.using_shadow = has_shadow; + + //always re-set uniforms, since light parameters changed + _set_uniforms(); + state.canvas_shader.use_material((void *)material_ptr); + + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6); + RasterizerStorageGLES3::Texture *t = storage->texture_owner.get_or_null(light->texture); + if (!t) { + glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + } else { + t = t->get_ptr(); + + glBindTexture(t->target, t->tex_id); + } + + glActiveTexture(GL_TEXTURE0); + _legacy_canvas_item_render_commands(p_ci, NULL, reclip, material_ptr); //redraw using light + + state.using_light = NULL; + } + + light = light->next_ptr; + } + + if (light_used) { + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, false); + + state.canvas_shader.bind(); + + r_ris.last_blend_mode = -1; + +#if 0 + //this is set again, so it should not be needed anyway? + state.canvas_item_modulate = unshaded ? ci->final_modulate : Color(ci->final_modulate.r * p_modulate.r, ci->final_modulate.g * p_modulate.g, ci->final_modulate.b * p_modulate.b, ci->final_modulate.a * p_modulate.a); + + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, Transform2D()); + state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.canvas_item_modulate); + + glBlendEquation(GL_FUNC_ADD); + + if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + //@TODO RESET canvas_blend_mode +#endif + } + } + + if (reclip) { + glEnable(GL_SCISSOR_TEST); + int y = storage->frame.current_rt->height - (r_ris.current_clip->final_clip_rect.position.y + r_ris.current_clip->final_clip_rect.size.y); + // FTODO + // if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_VFLIP]) + // y = r_ris.current_clip->final_clip_rect.position.y; + glScissor(r_ris.current_clip->final_clip_rect.position.x, y, r_ris.current_clip->final_clip_rect.size.width, r_ris.current_clip->final_clip_rect.size.height); + } +} + +void RasterizerCanvasGLES3::gl_enable_scissor(int p_x, int p_y, int p_width, int p_height) const { + glEnable(GL_SCISSOR_TEST); + glScissor(p_x, p_y, p_width, p_height); +} + +void RasterizerCanvasGLES3::gl_disable_scissor() const { + glDisable(GL_SCISSOR_TEST); +} + +void RasterizerCanvasGLES3::initialize() { + RasterizerCanvasBaseGLES3::initialize(); + + batch_initialize(); + + // just reserve some space (may not be needed as we are orphaning, but hey ho) + glGenBuffers(1, &bdata.gl_vertex_buffer); + + if (bdata.vertex_buffer_size_bytes) { + glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); + glBufferData(GL_ARRAY_BUFFER, bdata.vertex_buffer_size_bytes, NULL, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // pre fill index buffer, the indices never need to change so can be static + glGenBuffers(1, &bdata.gl_index_buffer); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bdata.gl_index_buffer); + + Vector indices; + indices.resize(bdata.index_buffer_size_units); + + for (unsigned int q = 0; q < bdata.max_quads; q++) { + int i_pos = q * 6; // 6 inds per quad + int q_pos = q * 4; // 4 verts per quad + indices.set(i_pos, q_pos); + indices.set(i_pos + 1, q_pos + 1); + indices.set(i_pos + 2, q_pos + 2); + indices.set(i_pos + 3, q_pos); + indices.set(i_pos + 4, q_pos + 2); + indices.set(i_pos + 5, q_pos + 3); + + // we can only use 16 bit indices in OpenGL! +#ifdef DEBUG_ENABLED + CRASH_COND((q_pos + 3) > 65535); +#endif + } + + glBufferData(GL_ELEMENT_ARRAY_BUFFER, bdata.index_buffer_size_bytes, &indices[0], GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + } // only if there is a vertex buffer (batching is on) +} + +RasterizerCanvasGLES3::RasterizerCanvasGLES3() { + batch_constructor(); +} + +#endif // GLES3_BACKEND_ENABLED diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h new file mode 100644 index 0000000000..3d5cd705b7 --- /dev/null +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* rasterizer_canvas_gles3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_CANVAS_OPENGL_H +#define RASTERIZER_CANVAS_OPENGL_H + +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "drivers/gles3/rasterizer_canvas_batcher.h" +#include "rasterizer_canvas_base_gles3.h" + +class RasterizerSceneGLES3; + +class RasterizerCanvasGLES3 : public RasterizerCanvasBaseGLES3, public RasterizerCanvasBatcher { + friend class RasterizerCanvasBatcher; + +private: + // legacy codepath .. to remove after testing + void _legacy_canvas_render_item(Item *p_ci, RenderItemState &r_ris); + + // high level batch funcs + void canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); + void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageGLES3::Material *p_material); + + // funcs used from rasterizer_canvas_batcher template + void gl_enable_scissor(int p_x, int p_y, int p_width, int p_height) const; + void gl_disable_scissor() const; + +public: + void canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); + void canvas_render_items_end(); + void canvas_render_items_internal(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); + void canvas_begin() override; + void canvas_end() override; + + void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override; + + void initialize(); + RasterizerCanvasGLES3(); +}; + +#endif // GLES3_BACKEND_ENABLED +#endif // RASTERIZER_CANVAS_OPENGL_H diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp new file mode 100644 index 0000000000..10093d42a3 --- /dev/null +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -0,0 +1,378 @@ +/*************************************************************************/ +/* rasterizer_gles3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "rasterizer_gles3.h" + +#ifdef GLES3_BACKEND_ENABLED +#include "shader_gles3.h" + +#include "core/config/project_settings.h" +#include "core/os/os.h" + +#define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 +#define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 +#define _EXT_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 +#define _EXT_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 +#define _EXT_DEBUG_SOURCE_API_ARB 0x8246 +#define _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 +#define _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 +#define _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 +#define _EXT_DEBUG_SOURCE_APPLICATION_ARB 0x824A +#define _EXT_DEBUG_SOURCE_OTHER_ARB 0x824B +#define _EXT_DEBUG_TYPE_ERROR_ARB 0x824C +#define _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D +#define _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E +#define _EXT_DEBUG_TYPE_PORTABILITY_ARB 0x824F +#define _EXT_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 +#define _EXT_DEBUG_TYPE_OTHER_ARB 0x8251 +#define _EXT_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 +#define _EXT_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 +#define _EXT_DEBUG_LOGGED_MESSAGES_ARB 0x9145 +#define _EXT_DEBUG_SEVERITY_HIGH_ARB 0x9146 +#define _EXT_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 +#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 +#define _EXT_DEBUG_OUTPUT 0x92E0 + +#ifndef GLAPIENTRY +#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED) +#define GLAPIENTRY APIENTRY +#else +#define GLAPIENTRY +#endif +#endif + +#ifndef IPHONE_ENABLED +// We include EGL below to get debug callback on GLES2 platforms, +// but EGL is not available on iOS. +#define CAN_DEBUG +#endif + +#if !defined(GLES_OVER_GL) && defined(CAN_DEBUG) +#include +#include +#include + +#include +#include +#endif + +#if defined(MINGW_ENABLED) || defined(_MSC_VER) +#define strcpy strcpy_s +#endif + +void RasterizerGLES3::begin_frame(double frame_step) { + frame++; + delta = frame_step; + + // from 3.2 + time_total += frame_step * time_scale; + + if (frame_step == 0) { + //to avoid hiccups + frame_step = 0.001; + } + + double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs"); + time_total = Math::fmod(time_total, time_roll_over); + + storage.frame.time[0] = time_total; + storage.frame.time[1] = Math::fmod(time_total, 3600); + storage.frame.time[2] = Math::fmod(time_total, 900); + storage.frame.time[3] = Math::fmod(time_total, 60); + storage.frame.count++; + storage.frame.delta = frame_step; + + storage.update_dirty_resources(); + + storage.info.render_final = storage.info.render; + storage.info.render.reset(); + + //scene->iteration(); +} + +void RasterizerGLES3::end_frame(bool p_swap_buffers) { + // if (OS::get_singleton()->is_layered_allowed()) { + // if (!OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { + //clear alpha + // glColorMask(false, false, false, true); + // glClearColor(0.5, 0, 0, 1); + // glClear(GL_COLOR_BUFFER_BIT); + // glColorMask(true, true, true, true); + // } + // } + + // glClearColor(1, 0, 0, 1); + // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + if (p_swap_buffers) + DisplayServer::get_singleton()->swap_buffers(); + else + glFinish(); +} + +#ifdef CAN_DEBUG +static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) { + if (type == _EXT_DEBUG_TYPE_OTHER_ARB) + return; + + if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB) + return; //these are ultimately annoying, so removing for now + + char debSource[256], debType[256], debSev[256]; + + if (source == _EXT_DEBUG_SOURCE_API_ARB) + strcpy(debSource, "OpenGL"); + else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB) + strcpy(debSource, "Windows"); + else if (source == _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB) + strcpy(debSource, "Shader Compiler"); + else if (source == _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB) + strcpy(debSource, "Third Party"); + else if (source == _EXT_DEBUG_SOURCE_APPLICATION_ARB) + strcpy(debSource, "Application"); + else if (source == _EXT_DEBUG_SOURCE_OTHER_ARB) + strcpy(debSource, "Other"); + + if (type == _EXT_DEBUG_TYPE_ERROR_ARB) + strcpy(debType, "Error"); + else if (type == _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB) + strcpy(debType, "Deprecated behavior"); + else if (type == _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB) + strcpy(debType, "Undefined behavior"); + else if (type == _EXT_DEBUG_TYPE_PORTABILITY_ARB) + strcpy(debType, "Portability"); + else if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB) + strcpy(debType, "Performance"); + else if (type == _EXT_DEBUG_TYPE_OTHER_ARB) + strcpy(debType, "Other"); + + if (severity == _EXT_DEBUG_SEVERITY_HIGH_ARB) + strcpy(debSev, "High"); + else if (severity == _EXT_DEBUG_SEVERITY_MEDIUM_ARB) + strcpy(debSev, "Medium"); + else if (severity == _EXT_DEBUG_SEVERITY_LOW_ARB) + strcpy(debSev, "Low"); + + String output = String() + "GL ERROR: Source: " + debSource + "\tType: " + debType + "\tID: " + itos(id) + "\tSeverity: " + debSev + "\tMessage: " + message; + + ERR_PRINT(output); +} +#endif + +typedef void (*DEBUGPROCARB)(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const char *message, + const void *userParam); + +typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam); + +void RasterizerGLES3::initialize() { + print_verbose("Using OpenGL video driver"); + + storage._main_thread_id = Thread::get_caller_id(); + +#ifdef GLAD_ENABLED + if (!gladLoadGL()) { + ERR_PRINT("Error initializing GLAD"); + return; + } +#endif + +#ifdef GLAD_ENABLED + if (OS::get_singleton()->is_stdout_verbose()) { + if (GLAD_GL_ARB_debug_output) { + glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + glDebugMessageCallbackARB(_gl_debug_print, NULL); + glEnable(_EXT_DEBUG_OUTPUT); + } else { + print_line("OpenGL debugging not supported!"); + } + } +#endif // GLAD_ENABLED + + // For debugging +#ifdef CAN_DEBUG +#ifdef GLES_OVER_GL + if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) { + glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); + glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); + glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); + glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PORTABILITY_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); + glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PERFORMANCE_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); + glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_OTHER_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); + // glDebugMessageInsertARB( + // GL_DEBUG_SOURCE_API_ARB, + // GL_DEBUG_TYPE_OTHER_ARB, 1, + // GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello"); + } +#else + if (OS::get_singleton()->is_stdout_verbose()) { + DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback"); + if (!callback) { + callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR"); + } + + if (callback) { + print_line("godot: ENABLING GL DEBUG"); + glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + callback(_gl_debug_print, NULL); + glEnable(_EXT_DEBUG_OUTPUT); + } + } +#endif // GLES_OVER_GL +#endif // CAN_DEBUG + + print_line("OpenGL Renderer: " + RS::get_singleton()->get_video_adapter_name()); + storage.initialize(); + canvas.initialize(); + // scene.initialize(); + + // make sure the OS knows to only access the renderer from the main thread + OS::get_singleton()->set_render_main_thread_mode(OS::RENDER_MAIN_THREAD_ONLY); +} + +RasterizerGLES3::RasterizerGLES3() { + canvas.storage = &storage; + canvas.scene_render = &scene; + storage.canvas = &canvas; + //scene.storage = &storage; + storage.scene = &scene; +} + +void RasterizerGLES3::prepare_for_blitting_render_targets() { +} + +void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect) { + ERR_FAIL_COND(storage.frame.current_rt); + + // print_line("_blit_render_target_to_screen " + itos (p_screen) + ", rect " + String(Variant(p_screen_rect))); + + RasterizerStorageGLES3::RenderTarget *rt = storage.render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + canvas._set_texture_rect_mode(true); + canvas.state.canvas_shader.set_custom_shader(0); + canvas.state.canvas_shader.bind(); + + canvas.canvas_begin(); + + glDisable(GL_BLEND); + storage.bind_framebuffer_system(); + glActiveTexture(GL_TEXTURE0 + storage.config.max_texture_image_units - 1); + if (rt->external.fbo != 0) { + glBindTexture(GL_TEXTURE_2D, rt->external.color); + } else { + glBindTexture(GL_TEXTURE_2D, rt->color); + } + canvas.draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1)); + glBindTexture(GL_TEXTURE_2D, 0); + + canvas.canvas_end(); +} + +// is this p_screen useless in a multi window environment? +void RasterizerGLES3::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) { + // do this once off for all blits + storage.bind_framebuffer_system(); + + storage.frame.current_rt = nullptr; + + for (int i = 0; i < p_amount; i++) { + const BlitToScreen &blit = p_render_targets[i]; + + RID rid_rt = blit.render_target; + + Rect2 dst_rect = blit.dst_rect; + _blit_render_target_to_screen(rid_rt, dst_rect); + } +} + +void RasterizerGLES3::set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { + if (p_image.is_null() || p_image->is_empty()) + return; + + int window_w = 640; //OS::get_singleton()->get_video_mode(0).width; + int window_h = 480; //OS::get_singleton()->get_video_mode(0).height; + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, window_w, window_h); + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + if (false) { + // if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { + glClearColor(0.0, 0.0, 0.0, 0.0); + } else { + glClearColor(p_color.r, p_color.g, p_color.b, 1.0); + } + glClear(GL_COLOR_BUFFER_BIT); + + canvas.canvas_begin(); + + RID texture = storage.texture_create(); + //storage.texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0); + storage._texture_allocate_internal(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D); + 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(); + } + + RasterizerStorageGLES3::Texture *t = storage.texture_owner.get_or_null(texture); + 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); + canvas.canvas_end(); + + storage.free(texture); + + end_frame(true); +} + +#endif // GLES3_BACKEND_ENABLED diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h new file mode 100644 index 0000000000..8976b88522 --- /dev/null +++ b/drivers/gles3/rasterizer_gles3.h @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* rasterizer_gles3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_OPENGL_H +#define RASTERIZER_OPENGL_H + +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "rasterizer_canvas_gles3.h" +#include "rasterizer_scene_gles3.h" +#include "rasterizer_storage_gles3.h" +#include "servers/rendering/renderer_compositor.h" + +class RasterizerGLES3 : public RendererCompositor { +private: + uint64_t frame = 1; + float delta = 0; + + double time_total = 0.0; + double time_scale = 1.0; + +protected: + RasterizerCanvasGLES3 canvas; + RasterizerStorageGLES3 storage; + RasterizerSceneGLES3 scene; + + void _blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect); + +public: + RendererStorage *get_storage() { return &storage; } + RendererCanvasRender *get_canvas() { return &canvas; } + RendererSceneRender *get_scene() { return &scene; } + + void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); + + void initialize(); + void begin_frame(double frame_step); + + void prepare_for_blitting_render_targets(); + void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount); + + void end_frame(bool p_swap_buffers); + + void finalize() {} + + static RendererCompositor *_create_current() { + return memnew(RasterizerGLES3); + } + + static void make_current() { + _create_func = _create_current; + } + + virtual bool is_low_end() const { return true; } + uint64_t get_frame_number() const { return frame; } + double get_frame_delta_time() const { return delta; } + + RasterizerGLES3(); + ~RasterizerGLES3() {} +}; + +#endif // GLES3_BACKEND_ENABLED + +#endif diff --git a/drivers/gles3/rasterizer_platforms.h b/drivers/gles3/rasterizer_platforms.h new file mode 100644 index 0000000000..5d520c4d98 --- /dev/null +++ b/drivers/gles3/rasterizer_platforms.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* rasterizer_platforms.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_PLATFORMS_H +#define RASTERIZER_PLATFORMS_H + +///////////////////////////////////////////////////// +// override for intellisense .. ONLY FOR DEVELOPMENT +//#ifndef X11_ENABLED +//#define X11_ENABLED +//#endif +//#define GLES3_BACKEND_ENABLED +///////////////////////////////////////////////////// + +#if defined(GLES3_ENABLED) || defined(GLES_ENABLED) + +#define GLES3_BACKEND_ENABLED + +#endif // defined(GLES3_ENABLED) || defined(GLES_ENABLED) + +#endif // RASTERIZER_PLATFORMS_H diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp new file mode 100644 index 0000000000..e66bde90fe --- /dev/null +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -0,0 +1,466 @@ +/*************************************************************************/ +/* rasterizer_scene_gles3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "rasterizer_scene_gles3.h" +#ifdef GLES3_BACKEND_ENABLED + +// TODO: 3D support not implemented yet. + +RasterizerSceneGLES3::GeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_base) { + return nullptr; +} + +void RasterizerSceneGLES3::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { +} + +void RasterizerSceneGLES3::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { +} + +void RasterizerSceneGLES3::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_material) { +} + +void RasterizerSceneGLES3::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { +} + +void RasterizerSceneGLES3::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) { +} + +void RasterizerSceneGLES3::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { +} + +void RasterizerSceneGLES3::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { +} + +void RasterizerSceneGLES3::geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) { +} + +void RasterizerSceneGLES3::geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) { +} + +void RasterizerSceneGLES3::geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) { +} + +void RasterizerSceneGLES3::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { +} + +void RasterizerSceneGLES3::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { +} + +void RasterizerSceneGLES3::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { +} + +void RasterizerSceneGLES3::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { +} + +void RasterizerSceneGLES3::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { +} + +void RasterizerSceneGLES3::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { +} + +uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() { + return 0; +} + +void RasterizerSceneGLES3::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { +} + +void RasterizerSceneGLES3::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { +} + +void RasterizerSceneGLES3::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { +} + +void RasterizerSceneGLES3::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) { +} + +void RasterizerSceneGLES3::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) { +} + +void RasterizerSceneGLES3::geometry_instance_free(GeometryInstance *p_geometry_instance) { +} + +/* SHADOW ATLAS API */ + +RID RasterizerSceneGLES3::shadow_atlas_create() { + return RID(); +} + +void RasterizerSceneGLES3::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) { +} + +void RasterizerSceneGLES3::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { +} + +bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { + return false; +} + +void RasterizerSceneGLES3::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { +} + +int RasterizerSceneGLES3::get_directional_light_shadow_size(RID p_light_intance) { + return 0; +} + +void RasterizerSceneGLES3::set_directional_shadow_count(int p_count) { +} + +/* SDFGI UPDATE */ + +void RasterizerSceneGLES3::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) { +} + +int RasterizerSceneGLES3::sdfgi_get_pending_region_count(RID p_render_buffers) const { + return 0; +} + +AABB RasterizerSceneGLES3::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const { + return AABB(); +} + +uint32_t RasterizerSceneGLES3::sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const { + return 0; +} + +/* SKY API */ + +RID RasterizerSceneGLES3::sky_allocate() { + return RID(); +} + +void RasterizerSceneGLES3::sky_initialize(RID p_rid) { +} + +void RasterizerSceneGLES3::sky_set_radiance_size(RID p_sky, int p_radiance_size) { +} + +void RasterizerSceneGLES3::sky_set_mode(RID p_sky, RS::SkyMode p_samples) { +} + +void RasterizerSceneGLES3::sky_set_material(RID p_sky, RID p_material) { +} + +Ref RasterizerSceneGLES3::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { + return Ref(); +} + +/* ENVIRONMENT API */ + +RID RasterizerSceneGLES3::environment_allocate() { + return RID(); +} + +void RasterizerSceneGLES3::environment_initialize(RID p_rid) { +} + +void RasterizerSceneGLES3::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { +} + +void RasterizerSceneGLES3::environment_set_sky(RID p_env, RID p_sky) { +} + +void RasterizerSceneGLES3::environment_set_sky_custom_fov(RID p_env, float p_scale) { +} + +void RasterizerSceneGLES3::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { +} + +void RasterizerSceneGLES3::environment_set_bg_color(RID p_env, const Color &p_color) { +} + +void RasterizerSceneGLES3::environment_set_bg_energy(RID p_env, float p_energy) { +} + +void RasterizerSceneGLES3::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { +} + +void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source) { +} + +void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, Vector p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { +} + +void RasterizerSceneGLES3::environment_glow_set_use_bicubic_upscale(bool p_enable) { +} + +void RasterizerSceneGLES3::environment_glow_set_use_high_quality(bool p_enable) { +} + +void RasterizerSceneGLES3::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) { +} + +void RasterizerSceneGLES3::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { +} + +void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { +} + +void RasterizerSceneGLES3::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { +} + +void RasterizerSceneGLES3::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { +} + +void RasterizerSceneGLES3::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) { +} + +void RasterizerSceneGLES3::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) { +} + +void RasterizerSceneGLES3::environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) { +} + +void RasterizerSceneGLES3::environment_set_tonemap(RID p_env, RS::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) { +} + +void RasterizerSceneGLES3::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) { +} + +void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) { +} + +void RasterizerSceneGLES3::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) { +} + +void RasterizerSceneGLES3::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { +} + +void RasterizerSceneGLES3::environment_set_volumetric_fog_filter_active(bool p_enable) { +} + +Ref RasterizerSceneGLES3::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { + return Ref(); +} + +bool RasterizerSceneGLES3::is_environment(RID p_env) const { + return false; +} + +RS::EnvironmentBG RasterizerSceneGLES3::environment_get_background(RID p_env) const { + return RS::ENV_BG_KEEP; +} + +int RasterizerSceneGLES3::environment_get_canvas_max_layer(RID p_env) const { + return 0; +} + +RID RasterizerSceneGLES3::camera_effects_allocate() { + return RID(); +} + +void RasterizerSceneGLES3::camera_effects_initialize(RID p_rid) { +} + +void RasterizerSceneGLES3::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) { +} + +void RasterizerSceneGLES3::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) { +} + +void RasterizerSceneGLES3::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) { +} + +void RasterizerSceneGLES3::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) { +} + +void RasterizerSceneGLES3::shadows_quality_set(RS::ShadowQuality p_quality) { +} + +void RasterizerSceneGLES3::directional_shadow_quality_set(RS::ShadowQuality p_quality) { +} + +RID RasterizerSceneGLES3::light_instance_create(RID p_light) { + return RID(); +} + +void RasterizerSceneGLES3::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) { +} + +void RasterizerSceneGLES3::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { +} + +void RasterizerSceneGLES3::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { +} + +void RasterizerSceneGLES3::light_instance_mark_visible(RID p_light_instance) { +} + +RID RasterizerSceneGLES3::fog_volume_instance_create(RID p_fog_volume) { + return RID(); +} + +void RasterizerSceneGLES3::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) { +} + +void RasterizerSceneGLES3::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) { +} + +RID RasterizerSceneGLES3::fog_volume_instance_get_volume(RID p_fog_volume_instance) const { + return RID(); +} + +Vector3 RasterizerSceneGLES3::fog_volume_instance_get_position(RID p_fog_volume_instance) const { + return Vector3(); +} + +RID RasterizerSceneGLES3::reflection_atlas_create() { + return RID(); +} + +int RasterizerSceneGLES3::reflection_atlas_get_size(RID p_ref_atlas) const { + return 0; +} + +void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { +} + +RID RasterizerSceneGLES3::reflection_probe_instance_create(RID p_probe) { + return RID(); +} + +void RasterizerSceneGLES3::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) { +} + +void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance) { +} + +bool RasterizerSceneGLES3::reflection_probe_instance_needs_redraw(RID p_instance) { + return false; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_has_reflection(RID p_instance) { + return false; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { + return false; +} + +bool RasterizerSceneGLES3::reflection_probe_instance_postprocess_step(RID p_instance) { + return true; +} + +RID RasterizerSceneGLES3::decal_instance_create(RID p_decal) { + return RID(); +} + +void RasterizerSceneGLES3::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) { +} + +RID RasterizerSceneGLES3::lightmap_instance_create(RID p_lightmap) { + return RID(); +} + +void RasterizerSceneGLES3::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) { +} + +RID RasterizerSceneGLES3::voxel_gi_instance_create(RID p_voxel_gi) { + return RID(); +} + +void RasterizerSceneGLES3::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) { +} + +bool RasterizerSceneGLES3::voxel_gi_needs_update(RID p_probe) const { + return false; +} + +void RasterizerSceneGLES3::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector &p_light_instances, const PagedArray &p_dynamic_objects) { +} + +void RasterizerSceneGLES3::voxel_gi_set_quality(RS::VoxelGIQuality) { +} + +void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) { +} + +void RasterizerSceneGLES3::render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) { +} + +void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray &p_instances) { +} + +void RasterizerSceneGLES3::set_scene_pass(uint64_t p_pass) { +} + +void RasterizerSceneGLES3::set_time(double p_time, double p_step) { +} + +void RasterizerSceneGLES3::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) { +} + +RID RasterizerSceneGLES3::render_buffers_create() { + return RID(); +} + +void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { +} + +void RasterizerSceneGLES3::gi_set_use_half_resolution(bool p_enable) { +} + +void RasterizerSceneGLES3::screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) { +} + +bool RasterizerSceneGLES3::screen_space_roughness_limiter_is_active() const { + return false; +} + +void RasterizerSceneGLES3::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { +} + +void RasterizerSceneGLES3::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { +} + +TypedArray RasterizerSceneGLES3::bake_render_uv2(RID p_base, const Vector &p_material_overrides, const Size2i &p_image_size) { + return TypedArray(); +} + +bool RasterizerSceneGLES3::free(RID p_rid) { + return false; +} + +void RasterizerSceneGLES3::update() { +} + +void RasterizerSceneGLES3::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { +} + +void RasterizerSceneGLES3::decals_set_filter(RS::DecalFilter p_filter) { +} + +void RasterizerSceneGLES3::light_projectors_set_filter(RS::LightProjectorFilter p_filter) { +} + +RasterizerSceneGLES3::RasterizerSceneGLES3() { +} + +#endif // GLES3_BACKEND_ENABLED diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h new file mode 100644 index 0000000000..e8d257087f --- /dev/null +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -0,0 +1,229 @@ +/*************************************************************************/ +/* rasterizer_scene_gles3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_SCENE_OPENGL_H +#define RASTERIZER_SCENE_OPENGL_H + +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/math/camera_matrix.h" +#include "core/templates/rid_owner.h" +#include "core/templates/self_list.h" +#include "scene/resources/mesh.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_scene_render.h" +#include "servers/rendering_server.h" +#include "shaders/scene.glsl.gen.h" + +class RasterizerSceneGLES3 : public RendererSceneRender { +public: + struct State { + SceneShaderGLES3 scene_shader; + } state; + + GeometryInstance *geometry_instance_create(RID p_base) override; + void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; + void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; + void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_material) override; + void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override; + void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override; + void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override; + void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override; + void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) override; + void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override; + void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) override; + void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override; + void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override; + void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; + void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override; + void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override; + void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override; + + uint32_t geometry_instance_get_pair_mask() override; + void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override; + void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; + void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override; + void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override; + void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) override; + + void geometry_instance_free(GeometryInstance *p_geometry_instance) override; + + /* SHADOW ATLAS API */ + + RID shadow_atlas_create() override; + void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) override; + void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; + bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override; + + void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) override; + int get_directional_light_shadow_size(RID p_light_intance) override; + void set_directional_shadow_count(int p_count) override; + + /* SDFGI UPDATE */ + + void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override; + int sdfgi_get_pending_region_count(RID p_render_buffers) const override; + AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override; + uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override; + + /* SKY API */ + + RID sky_allocate() override; + void sky_initialize(RID p_rid) override; + void sky_set_radiance_size(RID p_sky, int p_radiance_size) override; + void sky_set_mode(RID p_sky, RS::SkyMode p_samples) override; + void sky_set_material(RID p_sky, RID p_material) override; + Ref sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) override; + + /* ENVIRONMENT API */ + + RID environment_allocate() override; + void environment_initialize(RID p_rid) override; + void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) override; + void environment_set_sky(RID p_env, RID p_sky) override; + void environment_set_sky_custom_fov(RID p_env, float p_scale) override; + void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) override; + void environment_set_bg_color(RID p_env, const Color &p_color) override; + void environment_set_bg_energy(RID p_env, float p_energy) override; + void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override; + void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) override; + + void environment_set_glow(RID p_env, bool p_enable, Vector p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override; + void environment_glow_set_use_bicubic_upscale(bool p_enable) override; + void environment_glow_set_use_high_quality(bool p_enable) override; + + 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) override; + void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override; + void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override; + void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; + + void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override; + + void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override; + void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override; + void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override; + + void environment_set_tonemap(RID p_env, RS::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) override; + + void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) override; + + void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) override; + void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) override; + void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override; + void environment_set_volumetric_fog_filter_active(bool p_enable) override; + + Ref environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override; + + bool is_environment(RID p_env) const override; + RS::EnvironmentBG environment_get_background(RID p_env) const override; + int environment_get_canvas_max_layer(RID p_env) const override; + + RID camera_effects_allocate() override; + void camera_effects_initialize(RID p_rid) override; + void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override; + void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override; + + void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override; + void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override; + + void shadows_quality_set(RS::ShadowQuality p_quality) override; + void directional_shadow_quality_set(RS::ShadowQuality p_quality) override; + + RID light_instance_create(RID p_light) override; + void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; + void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; + void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; + void light_instance_mark_visible(RID p_light_instance) override; + + RID fog_volume_instance_create(RID p_fog_volume) override; + void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override; + void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override; + RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override; + Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override; + + RID reflection_atlas_create() override; + int reflection_atlas_get_size(RID p_ref_atlas) const override; + void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override; + + RID reflection_probe_instance_create(RID p_probe) override; + void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; + void reflection_probe_release_atlas_index(RID p_instance) override; + bool reflection_probe_instance_needs_redraw(RID p_instance) override; + bool reflection_probe_instance_has_reflection(RID p_instance) override; + bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; + bool reflection_probe_instance_postprocess_step(RID p_instance) override; + + RID decal_instance_create(RID p_decal) override; + void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override; + + RID lightmap_instance_create(RID p_lightmap) override; + void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override; + + RID voxel_gi_instance_create(RID p_voxel_gi) override; + void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override; + bool voxel_gi_needs_update(RID p_probe) const override; + void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector &p_light_instances, const PagedArray &p_dynamic_objects) override; + + void voxel_gi_set_quality(RS::VoxelGIQuality) override; + + void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, const PagedArray &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; + void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) override; + void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray &p_instances) override; + + void set_scene_pass(uint64_t p_pass) override; + void set_time(double p_time, double p_step) override; + void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override; + + RID render_buffers_create() override; + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; + void gi_set_use_half_resolution(bool p_enable) override; + + void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override; + bool screen_space_roughness_limiter_is_active() const override; + + void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override; + void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override; + + TypedArray bake_render_uv2(RID p_base, const Vector &p_material_overrides, const Size2i &p_image_size) override; + + bool free(RID p_rid) override; + void update() override; + void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override; + + void decals_set_filter(RS::DecalFilter p_filter) override; + void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override; + + RasterizerSceneGLES3(); +}; + +#endif // GLES3_BACKEND_ENABLED + +#endif // RASTERIZER_SCENE_OPENGL_H diff --git a/drivers/gles3/rasterizer_storage_common.h b/drivers/gles3/rasterizer_storage_common.h new file mode 100644 index 0000000000..ed64b8c50a --- /dev/null +++ b/drivers/gles3/rasterizer_storage_common.h @@ -0,0 +1,77 @@ +/*************************************************************************/ +/* rasterizer_storage_common.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_STORAGE_COMMON_H +#define RASTERIZER_STORAGE_COMMON_H + +class RasterizerStorageCommon { +public: + enum FVF { + FVF_UNBATCHED, + FVF_REGULAR, + FVF_COLOR, + FVF_LIGHT_ANGLE, + FVF_MODULATED, + FVF_LARGE, + }; + + // these flags are specifically for batching + // some of the logic is thus in rasterizer_storage.cpp + // we could alternatively set bitflags for each 'uses' and test on the fly + enum BatchFlags { + PREVENT_COLOR_BAKING = 1 << 0, + PREVENT_VERTEX_BAKING = 1 << 1, + + // custom vertex shaders using BUILTINS that vary per item + PREVENT_ITEM_JOINING = 1 << 2, + + USE_MODULATE_FVF = 1 << 3, + USE_LARGE_FVF = 1 << 4, + }; + + enum BatchType : uint16_t { + BT_DEFAULT = 0, + BT_RECT = 1, + BT_LINE = 2, + BT_LINE_AA = 3, + BT_POLY = 4, + BT_DUMMY = 5, // dummy batch is just used to keep the batch creation loop simple + }; + + enum BatchTypeFlags { + BTF_DEFAULT = 1 << BT_DEFAULT, + BTF_RECT = 1 << BT_RECT, + BTF_LINE = 1 << BT_LINE, + BTF_LINE_AA = 1 << BT_LINE_AA, + BTF_POLY = 1 << BT_POLY, + }; +}; + +#endif // RASTERIZER_STORAGE_COMMON_H diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp new file mode 100644 index 0000000000..1feb2c224e --- /dev/null +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -0,0 +1,4820 @@ +/*************************************************************************/ +/* rasterizer_storage_gles3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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. */ +/*************************************************************************/ + +//#define OPENGL_DISABLE_RENDER_TARGETS + +#include "rasterizer_storage_gles3.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/config/project_settings.h" +#include "core/math/transform_3d.h" +#include "drivers/gles3/rasterizer_storage_common.h" +#include "rasterizer_canvas_gles3.h" +#include "rasterizer_scene_gles3.h" +#include "servers/rendering/shader_language.h" + +GLuint RasterizerStorageGLES3::system_fbo = 0; + +/* TEXTURE API */ + +#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_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB +#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define _EXT_COMPRESSED_RG_RGTC2 0x8DBD +#define _EXT_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define _EXT_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE +#define _EXT_ETC1_RGB8_OES 0x8D64 + +#define _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#define _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#define _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#define _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 + +#define _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 +#define _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 +#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 +#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 + +#define _EXT_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D +#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E +#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F + +#define _GL_TEXTURE_EXTERNAL_OES 0x8D65 + +#ifdef GLES_OVER_GL +#define _GL_HALF_FLOAT_OES 0x140B +#else +#define _GL_HALF_FLOAT_OES 0x8D61 +#endif + +#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F + +#define _RED_OES 0x1903 + +#define _DEPTH_COMPONENT24_OES 0x81A6 + +#ifndef GLES_OVER_GL +#define glClearDepth glClearDepthf +#endif //!GLES_OVER_GL + +void RasterizerStorageGLES3::bind_quad_array() const { + //glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); + //glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); + //glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); + + //glEnableVertexAttribArray(RS::ARRAY_VERTEX); + //glEnableVertexAttribArray(RS::ARRAY_TEX_UV); +} + +bool RasterizerStorageGLES3::can_create_resources_async() const { + return false; +} + +Ref RasterizerStorageGLES3::_get_gl_image_and_format(const Ref &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const { + r_gl_format = 0; + Ref image = p_image; + r_compressed = false; + r_real_format = p_format; + + bool need_decompress = false; + + switch (p_format) { + case Image::FORMAT_L8: { +#ifdef GLES_OVER_GL + r_gl_internal_format = GL_R8; + r_gl_format = GL_RED; + r_gl_type = GL_UNSIGNED_BYTE; +#else + r_gl_internal_format = GL_LUMINANCE; + r_gl_format = GL_LUMINANCE; + r_gl_type = GL_UNSIGNED_BYTE; +#endif + } break; + case Image::FORMAT_LA8: { +#ifdef GLES_OVER_GL + r_gl_internal_format = GL_RG8; + r_gl_format = GL_RG; + r_gl_type = GL_UNSIGNED_BYTE; +#else + r_gl_internal_format = GL_LUMINANCE_ALPHA; + r_gl_format = GL_LUMINANCE_ALPHA; + r_gl_type = GL_UNSIGNED_BYTE; +#endif + } break; + case Image::FORMAT_R8: { + r_gl_internal_format = GL_R8; + r_gl_format = GL_RED; + r_gl_type = GL_UNSIGNED_BYTE; + + } break; + case Image::FORMAT_RG8: { + r_gl_internal_format = GL_RG8; + r_gl_format = GL_RG; + r_gl_type = GL_UNSIGNED_BYTE; + + } break; + case Image::FORMAT_RGB8: { + r_gl_internal_format = GL_RGB8; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + //r_srgb = true; + + } break; + case Image::FORMAT_RGBA8: { + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA8; + r_gl_type = GL_UNSIGNED_BYTE; + //r_srgb = true; + + } break; + case Image::FORMAT_RGBA4444: { + r_gl_internal_format = GL_RGBA4; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4; + + } break; + //case Image::FORMAT_RGBA5551: { + // r_gl_internal_format = GL_RGB5_A1; + // r_gl_format = GL_RGBA; + // r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1; + // + //} break; + case Image::FORMAT_RF: { + r_gl_internal_format = GL_R32F; + r_gl_format = GL_RED; + r_gl_type = GL_FLOAT; + + } break; + case Image::FORMAT_RGF: { + r_gl_internal_format = GL_RG32F; + r_gl_format = GL_RG; + r_gl_type = GL_FLOAT; + + } break; + case Image::FORMAT_RGBF: { + r_gl_internal_format = GL_RGB32F; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + + } break; + case Image::FORMAT_RGBAF: { + r_gl_internal_format = GL_RGBA32F; + r_gl_format = GL_RGBA; + r_gl_type = GL_FLOAT; + + } break; + case Image::FORMAT_RH: { + r_gl_internal_format = GL_R16F; + r_gl_format = GL_RED; + r_gl_type = GL_HALF_FLOAT; + } break; + case Image::FORMAT_RGH: { + r_gl_internal_format = GL_RG16F; + r_gl_format = GL_RG; + r_gl_type = GL_HALF_FLOAT; + + } break; + case Image::FORMAT_RGBH: { + r_gl_internal_format = GL_RGB16F; + r_gl_format = GL_RGB; + r_gl_type = GL_HALF_FLOAT; + + } break; + case Image::FORMAT_RGBAH: { + r_gl_internal_format = GL_RGBA16F; + r_gl_format = GL_RGBA; + r_gl_type = GL_HALF_FLOAT; + + } break; + case Image::FORMAT_RGBE9995: { + r_gl_internal_format = GL_RGB9_E5; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_INT_5_9_9_9_REV; + + } break; + case Image::FORMAT_DXT1: { + 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; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_DXT3: { + 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; + //r_srgb = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_DXT5: { + 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; + //r_srgb = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_RGTC_R: { + if (config.rgtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_RGTC_RG: { + if (config.rgtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_BPTC_RGBA: { + if (config.bptc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_BPTC_UNORM; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_BPTC_RGBF: { + if (config.bptc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + r_compressed = true; + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_BPTC_RGBFU: { + if (config.bptc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + r_compressed = true; + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_PVRTC1_2: { + if (config.pvrtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_PVRTC1_2A: { + if (config.pvrtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_PVRTC1_4: { + if (config.pvrtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_PVRTC1_4A: { + if (config.pvrtc_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + + } break; + case Image::FORMAT_ETC: { + if (config.etc_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: { + if (config.etc2_supported) { + r_gl_internal_format = _EXT_COMPRESSED_R11_EAC; + r_gl_format = GL_RED; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_ETC2_R11S: { + if (config.etc2_supported) { + r_gl_internal_format = _EXT_COMPRESSED_SIGNED_R11_EAC; + r_gl_format = GL_RED; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_ETC2_RG11: { + if (config.etc2_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RG11_EAC; + r_gl_format = GL_RG; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_ETC2_RG11S: { + if (config.etc2_supported) { + r_gl_internal_format = _EXT_COMPRESSED_SIGNED_RG11_EAC; + r_gl_format = GL_RG; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_ETC2_RGB8: { + if (config.etc2_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB8_ETC2; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_ETC2_RGBA8: { + if (config.etc2_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGBA8_ETC2_EAC; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + } break; + case Image::FORMAT_ETC2_RGB8A1: { + if (config.etc2_supported) { + r_gl_internal_format = _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + //r_srgb = true; + + } else { + need_decompress = true; + } + } break; + */ + default: { + ERR_FAIL_V(Ref()); + } + } + + if (need_decompress || p_force_decompress) { + if (!image.is_null()) { + image = image->duplicate(); + image->decompress(); + ERR_FAIL_COND_V(image->is_compressed(), image); + switch (image->get_format()) { + case Image::FORMAT_RGB8: { + r_gl_format = GL_RGB; + r_gl_internal_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGB8; + r_compressed = false; + } break; + case Image::FORMAT_RGBA8: { + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGBA8; + r_compressed = false; + } break; + default: { + image->convert(Image::FORMAT_RGBA8); + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGBA8; + r_compressed = false; + + } break; + } + } + + return image; + } + + return p_image; +} + +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, +}; + +RID RasterizerStorageGLES3::texture_allocate() { + RID id = texture_create(); + ERR_FAIL_COND_V(id == RID(), id); + return id; +} + +void RasterizerStorageGLES3::texture_2d_initialize(RID p_texture, const Ref &p_image) { + Texture *tex = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!tex); + + int w = p_image->get_width(); + int h = p_image->get_height(); + + _texture_allocate_internal(p_texture, w, h, 1, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D, 0); + texture_set_data(p_texture, p_image); +} + +void RasterizerStorageGLES3::texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) { +} + +void RasterizerStorageGLES3::texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector> &p_data) { +} + +void RasterizerStorageGLES3::texture_proxy_initialize(RID p_texture, RID p_base) { + texture_set_proxy(p_texture, p_base); +} + +//RID RasterizerStorageGLES3::texture_2d_create(const Ref &p_image) { +// RID id = texture_create(); +// ERR_FAIL_COND_V(id == RID(), id); + +// int w = p_image->get_width(); +// int h = p_image->get_height(); + +// texture_allocate(id, w, h, 1, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D, 0); + +// texture_set_data(id, p_image); + +// return id; +//} + +//RID RasterizerStorageGLES3::texture_2d_layered_create(const Vector> &p_layers, RS::TextureLayeredType p_layered_type) { +// return RID(); +//} + +//void RasterizerStorageGLES3::texture_2d_update_immediate(RID p_texture, const Ref &p_image, int p_layer) { +// // only 1 layer so far +// texture_set_data(p_texture, p_image); +//} +void RasterizerStorageGLES3::texture_2d_update(RID p_texture, const Ref &p_image, int p_layer) { + // only 1 layer so far + texture_set_data(p_texture, p_image); +} + +void RasterizerStorageGLES3::texture_2d_placeholder_initialize(RID p_texture) { +} + +void RasterizerStorageGLES3::texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) { +} + +void RasterizerStorageGLES3::texture_3d_placeholder_initialize(RID p_texture) { +} + +Ref RasterizerStorageGLES3::texture_2d_get(RID p_texture) const { + Texture *tex = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND_V(!tex, Ref()); + + /* +#ifdef TOOLS_ENABLED + if (tex->image_cache_2d.is_valid()) { + return tex->image_cache_2d; + } +#endif + Vector data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0); + ERR_FAIL_COND_V(data.size() == 0, Ref()); + Ref image; + image.instance(); + image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); + ERR_FAIL_COND_V(image->empty(), Ref()); + if (tex->format != tex->validated_format) { + image->convert(tex->format); + } + +#ifdef TOOLS_ENABLED + if (Engine::get_singleton()->is_editor_hint()) { + tex->image_cache_2d = image; + } +#endif +*/ + ERR_FAIL_COND_V(!tex->images.size(), Ref()); + + return tex->images[0]; + + // return image; + + // return Ref(); +} + +void RasterizerStorageGLES3::texture_replace(RID p_texture, RID p_by_texture) { + Texture *tex_to = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!tex_to); + Texture *tex_from = texture_owner.get_or_null(p_by_texture); + ERR_FAIL_COND(!tex_from); + + tex_to->destroy(); + tex_to->copy_from(*tex_from); + + // copy image data and upload to GL + tex_to->images.resize(tex_from->images.size()); + + for (int n = 0; n < tex_from->images.size(); n++) { + texture_set_data(p_texture, tex_from->images[n], n); + } +} + +bool RasterizerStorageGLES3::_is_main_thread() { + //#if defined DEBUG_ENABLED && defined TOOLS_ENABLED + // must be called from main thread in OpenGL + bool is_main_thread = _main_thread_id == Thread::get_caller_id(); + //#endif + return is_main_thread; +} + +RID RasterizerStorageGLES3::texture_create() { + ERR_FAIL_COND_V(!_is_main_thread(), RID()); + + Texture *texture = memnew(Texture); + ERR_FAIL_COND_V(!texture, RID()); + glGenTextures(1, &texture->tex_id); + texture->active = false; + texture->total_data_size = 0; + + return texture_owner.make_rid(texture); +} + +void RasterizerStorageGLES3::_texture_allocate_internal(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags) { + // GLenum format; + // GLenum internal_format; + // GLenum type; + + // bool compressed = false; + + if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) { + p_flags &= ~TEXTURE_FLAG_MIPMAPS; // no mipies for video + } + + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!texture); + texture->width = p_width; + texture->height = p_height; + texture->format = p_format; + texture->flags = p_flags; + texture->stored_cube_sides = 0; + texture->type = p_type; + + switch (p_type) { + case RenderingDevice::TEXTURE_TYPE_2D: { + texture->target = GL_TEXTURE_2D; + texture->images.resize(1); + } break; + // case RenderingDevice::TEXTURE_TYPE_EXTERNAL: { + //#ifdef ANDROID_ENABLED + // texture->target = _GL_TEXTURE_EXTERNAL_OES; + //#else + // texture->target = GL_TEXTURE_2D; + //#endif + // texture->images.resize(0); + // } break; + case RenderingDevice::TEXTURE_TYPE_CUBE: { + texture->target = GL_TEXTURE_CUBE_MAP; + texture->images.resize(6); + } break; + case RenderingDevice::TEXTURE_TYPE_2D_ARRAY: + case RenderingDevice::TEXTURE_TYPE_3D: { + texture->target = GL_TEXTURE_3D; + ERR_PRINT("3D textures and Texture Arrays are not supported in OpenGL. Please switch to the Vulkan backend."); + return; + } break; + default: { + ERR_PRINT("Unknown texture type!"); + return; + } + } + +#if 0 + // if (p_type != RS::TEXTURE_TYPE_EXTERNAL) { + if (p_type == RenderingDevice::TEXTURE_TYPE_2D) { + texture->alloc_width = texture->width; + texture->alloc_height = texture->height; + texture->resize_to_po2 = false; + if (!config.support_npot_repeat_mipmap) { + int po2_width = next_power_of_2(p_width); + int po2_height = next_power_of_2(p_height); + + bool is_po2 = p_width == po2_width && p_height == po2_height; + + if (!is_po2 && (p_flags & TEXTURE_FLAG_REPEAT || p_flags & TEXTURE_FLAG_MIPMAPS)) { + if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) { + //not supported + ERR_PRINT("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled."); + texture->flags &= ~(TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS); + } else { + texture->alloc_height = po2_height; + texture->alloc_width = po2_width; + texture->resize_to_po2 = true; + } + } + } + + GLenum format; + GLenum internal_format; + GLenum type; + bool compressed = false; + + Image::Format real_format; + _get_gl_image_and_format(Ref(), + texture->format, + texture->flags, + real_format, + format, + internal_format, + type, + compressed, + texture->resize_to_po2); + + texture->gl_format_cache = format; + texture->gl_type_cache = type; + texture->gl_internal_format_cache = internal_format; + texture->data_size = 0; + texture->mipmaps = 1; + + texture->compressed = compressed; + } +#endif + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + // if (p_type == RS::TEXTURE_TYPE_EXTERNAL) { + // glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + // glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // } else if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) { + // //prealloc if video + // glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL); + // } + + texture->active = true; +} + +void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref &p_image, int p_layer) { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND(!_is_main_thread()); + + ERR_FAIL_COND(!texture); + if (texture->target == GL_TEXTURE_3D) { + // Target is set to a 3D texture or array texture, exit early to avoid spamming errors + return; + } + ERR_FAIL_COND(!texture->active); + ERR_FAIL_COND(texture->render_target); + ERR_FAIL_COND(p_image.is_null()); + ERR_FAIL_COND(texture->format != p_image->get_format()); + + ERR_FAIL_COND(!p_image->get_width()); + ERR_FAIL_COND(!p_image->get_height()); + + // ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL); + + GLenum type; + GLenum format; + GLenum internal_format; + bool compressed = false; + + if (config.keep_original_textures && !(texture->flags & TEXTURE_FLAG_USED_FOR_STREAMING)) { + texture->images.write[p_layer] = p_image; + } + + // print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height())); + + Image::Format real_format; + Ref img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); + + if (texture->resize_to_po2) { + if (p_image->is_compressed()) { + ERR_PRINT("Texture '" + texture->path + "' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage."); + } + + if (img == p_image) { + img = img->duplicate(); + } + img->resize_to_po2(false); + } + + if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & TEXTURE_FLAG_USED_FOR_STREAMING)) { + texture->alloc_height = MAX(1, texture->alloc_height / 2); + texture->alloc_width = MAX(1, texture->alloc_width / 2); + + if (texture->alloc_width == img->get_width() / 2 && texture->alloc_height == img->get_height() / 2) { + img->shrink_x2(); + } else if (img->get_format() <= Image::FORMAT_RGBA8) { + img->resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR); + } + } + + GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D; + + texture->data_size = img->get_data().size(); + Vector read = img->get_data(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + texture->ignore_mipmaps = compressed && !img->has_mipmaps(); + + // set filtering and repeat state + _texture_set_state_from_flags(texture); + + //set swizle for older format compatibility +#ifdef GLES_OVER_GL + switch (texture->format) { + case Image::FORMAT_L8: { + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ONE); + + } break; + case Image::FORMAT_LA8: { + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN); + } break; + default: { + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_GREEN); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_BLUE); + glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); + + } break; + } +#endif + + int mipmaps = ((texture->flags & TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; + + int w = img->get_width(); + int h = img->get_height(); + + int tsize = 0; + + for (int i = 0; i < mipmaps; i++) { + int size, ofs; + img->get_mipmap_offset_and_size(i, ofs, size); + + if (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 { + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + if (texture->flags & 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; + + w = MAX(1, w >> 1); + h = MAX(1, h >> 1); + } + + info.texture_mem -= texture->total_data_size; + texture->total_data_size = tsize; + info.texture_mem += texture->total_data_size; + + // printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem); + + texture->stored_cube_sides |= (1 << p_layer); + + if ((texture->flags & TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RenderingDevice::TEXTURE_TYPE_CUBE || texture->stored_cube_sides == (1 << 6) - 1)) { + //generate mipmaps if they were requested and the image does not contain them + glGenerateMipmap(texture->target); + } + + texture->mipmaps = mipmaps; +} + +void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref &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 RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) const { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND_V(!texture, Ref()); + ERR_FAIL_COND_V(!texture->active, Ref()); + ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref()); + + if (texture->type == RS::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(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, false); + + PoolVector data; + + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); + + data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers + PoolVector::Write wb = data.write(); + + glActiveTexture(GL_TEXTURE0); + + glBindTexture(texture->target, texture->tex_id); + + glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); + + for (int i = 0; i < texture->mipmaps; i++) { + int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i); + + 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.release(); + + data.resize(data_size); + + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, real_format, data)); + + return Ref(img); +#else + + Image::Format real_format; + GLenum gl_format; + GLenum gl_internal_format; + GLenum gl_type; + bool compressed; + _get_gl_image_and_format(Ref(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, texture->resize_to_po2); + + PoolVector data; + + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); + + data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers + PoolVector::Write wb = data.write(); + + GLuint temp_framebuffer; + glGenFramebuffers(1, &temp_framebuffer); + + GLuint temp_color_texture; + glGenTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + + glBindTexture(GL_TEXTURE_2D, temp_color_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1, 1, 1, 1); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + + glViewport(0, 0, texture->alloc_width, texture->alloc_height); + + shaders.copy.bind(); + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + bind_quad_array(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); + + glDeleteTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &temp_framebuffer); + + wb.release(); + + data.resize(data_size); + + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); + if (!texture->compressed) { + img->convert(real_format); + } + + return Ref(img); + +#endif +} +*/ + +void RasterizerStorageGLES3::_texture_set_state_from_flags(Texture *p_tex) { + if ((p_tex->flags & TEXTURE_FLAG_MIPMAPS) && !p_tex->ignore_mipmaps) + if (p_tex->flags & TEXTURE_FLAG_FILTER) { + // these do not exactly correspond ... + p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS); + //texture->glTexParam_MinFilter(texture->target, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); + } else { + p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS); + //texture->glTexParam_MinFilter(texture->target, config.use_fast_texture_filter ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_LINEAR); + } + else { + if (p_tex->flags & TEXTURE_FLAG_FILTER) { + p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR); + //texture->glTexParam_MinFilter(texture->target, GL_LINEAR); + } else { + p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST); + // texture->glTexParam_MinFilter(texture->target, GL_NEAREST); + } + } + + if (((p_tex->flags & TEXTURE_FLAG_REPEAT) || (p_tex->flags & TEXTURE_FLAG_MIRRORED_REPEAT)) && p_tex->target != GL_TEXTURE_CUBE_MAP) { + if (p_tex->flags & TEXTURE_FLAG_MIRRORED_REPEAT) { + p_tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR); + } else { + p_tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + } + } else { + p_tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + } +} + +void RasterizerStorageGLES3::texture_set_flags(RID p_texture, uint32_t p_flags) { + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!texture); + + bool had_mipmaps = texture->flags & TEXTURE_FLAG_MIPMAPS; + + texture->flags = p_flags; + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + // set filtering and repeat state + _texture_set_state_from_flags(texture); + + if ((texture->flags & TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) { + if (!had_mipmaps && texture->mipmaps == 1) { + glGenerateMipmap(texture->target); + } + } +} + +uint32_t RasterizerStorageGLES3::texture_get_flags(RID p_texture) const { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND_V(!texture, 0); + + return texture->flags; +} + +Image::Format RasterizerStorageGLES3::texture_get_format(RID p_texture) const { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND_V(!texture, Image::FORMAT_L8); + + return texture->format; +} + +RenderingDevice::TextureType RasterizerStorageGLES3::texture_get_type(RID p_texture) const { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND_V(!texture, RenderingDevice::TEXTURE_TYPE_2D); + + return texture->type; +} + +uint32_t RasterizerStorageGLES3::texture_get_texid(RID p_texture) const { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND_V(!texture, 0); + + return texture->tex_id; +} + +void RasterizerStorageGLES3::texture_bind(RID p_texture, uint32_t p_texture_no) { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND(!texture); + + glActiveTexture(GL_TEXTURE0 + p_texture_no); + glBindTexture(texture->target, texture->tex_id); +} + +uint32_t RasterizerStorageGLES3::texture_get_width(RID p_texture) const { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND_V(!texture, 0); + + return texture->width; +} + +uint32_t RasterizerStorageGLES3::texture_get_height(RID p_texture) const { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND_V(!texture, 0); + + return texture->height; +} + +uint32_t RasterizerStorageGLES3::texture_get_depth(RID p_texture) const { + Texture *texture = texture_owner.get_or_null(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) { + Texture *texture = texture_owner.get_or_null(p_texture); + + ERR_FAIL_COND(!texture); + ERR_FAIL_COND(texture->render_target); + + ERR_FAIL_COND(p_width <= 0 || p_width > 16384); + ERR_FAIL_COND(p_height <= 0 || p_height > 16384); + //real texture size is in alloc width and height + texture->width = p_width; + texture->height = p_height; +} + +void RasterizerStorageGLES3::texture_set_path(RID p_texture, const String &p_path) { + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!texture); + + texture->path = p_path; +} + +String RasterizerStorageGLES3::texture_get_path(RID p_texture) const { + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND_V(!texture, ""); + + return texture->path; +} + +void RasterizerStorageGLES3::texture_debug_usage(List *r_info) { + List textures; + texture_owner.get_owned_list(&textures); + + for (List::Element *E = textures.front(); E; E = E->next()) { + Texture *t = texture_owner.get_or_null(E->get()); + if (!t) + continue; + RS::TextureInfo tinfo; + tinfo.path = t->path; + tinfo.format = t->format; + tinfo.width = t->alloc_width; + tinfo.height = t->alloc_height; + tinfo.depth = 0; + tinfo.bytes = t->total_data_size; + r_info->push_back(tinfo); + } +} + +void RasterizerStorageGLES3::texture_set_shrink_all_x2_on_set_data(bool p_enable) { + config.shrink_textures_x2 = p_enable; +} + +void RasterizerStorageGLES3::textures_keep_original(bool p_enable) { + config.keep_original_textures = p_enable; +} + +Size2 RasterizerStorageGLES3::texture_size_with_proxy(RID p_texture) { + const Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND_V(!texture, Size2()); + if (texture->proxy) { + return Size2(texture->proxy->width, texture->proxy->height); + } else { + return Size2(texture->width, texture->height); + } +} + +// example use in 3.2 +// VS::get_singleton()->texture_set_proxy(default_texture->proxy, texture_rid); + +// p_proxy is the source (pre-existing) texture? +// and p_texture is the one that is being made into a proxy? +//This naming is confusing. Comments!!! + +// The naming of the parameters seemed to be reversed? +// The p_proxy is the source texture +// and p_texture is actually the proxy???? + +void RasterizerStorageGLES3::texture_set_proxy(RID p_texture, RID p_proxy) { + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!texture); + + if (texture->proxy) { + texture->proxy->proxy_owners.erase(texture); + texture->proxy = NULL; + } + + if (p_proxy.is_valid()) { + Texture *proxy = texture_owner.get_or_null(p_proxy); + ERR_FAIL_COND(!proxy); + ERR_FAIL_COND(proxy == texture); + proxy->proxy_owners.insert(texture); + texture->proxy = proxy; + } +} + +void RasterizerStorageGLES3::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!texture); + + texture->redraw_if_visible = p_enable; +} + +void RasterizerStorageGLES3::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!texture); + + texture->detect_3d = p_callback; + texture->detect_3d_ud = p_userdata; +} + +void RasterizerStorageGLES3::texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!texture); + + texture->detect_srgb = p_callback; + texture->detect_srgb_ud = p_userdata; +} + +void RasterizerStorageGLES3::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { + Texture *texture = texture_owner.get_or_null(p_texture); + ERR_FAIL_COND(!texture); + + texture->detect_normal = p_callback; + texture->detect_normal_ud = p_userdata; +} + +RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_resolution) const { + return RID(); +} + +RID RasterizerStorageGLES3::canvas_texture_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::canvas_texture_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { +} + +void RasterizerStorageGLES3::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) { +} + +void RasterizerStorageGLES3::canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) { +} +void RasterizerStorageGLES3::canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) { +} + +RID RasterizerStorageGLES3::sky_create() { + Sky *sky = memnew(Sky); + sky->radiance = 0; + return sky_owner.make_rid(sky); +} + +void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size) { + Sky *sky = sky_owner.get_or_null(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.get_or_null(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 < RS::ARRAY_MAX - 1; i++) { + //glDisableVertexAttribArray(i); + } + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(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); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // 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); + + int size = p_radiance_size / 2; //divide by two because its a cubemap (this is an approximation because GLES3 uses a dual paraboloid) + + GLenum internal_format = GL_RGB; + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; + + // Set the initial (empty) mipmaps + // Mobile hardware (PowerVR specially) prefers this approach, + // the previous approach with manual lod levels kills the game. + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL); + } + + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + + // No filters for now + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + 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); + + // Framebuffer + + bind_framebuffer(resources.mipmap_blur_fbo); + + int mipmaps = 6; + int lod = 0; + int mm_level = mipmaps; + size = p_radiance_size / 2; + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, true); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, true); + shaders.cubemap_filter.bind(); + + // third, render to the framebuffer using separate textures, then copy to mipmaps + while (size >= 1) { + //make framebuffer size the texture size, need to use a separate texture for compatibility + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, resources.mipmap_blur_color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resources.mipmap_blur_color, 0); + + if (lod == 1) { + //bind panorama for smaller lods + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, false); + shaders.cubemap_filter.bind(); + } + glViewport(0, 0, size, size); + bind_quad_array(); + + glActiveTexture(GL_TEXTURE2); //back to panorama + + for (int i = 0; i < 6; i++) { + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::FACE_ID, i); + + float roughness = mm_level >= 0 ? lod / (float)(mipmaps - 1) : 1; + roughness = MIN(1.0, roughness); //keep max at 1 + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::ROUGHNESS, roughness); + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES3::Z_FLIP, false); + + //glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glCopyTexSubImage2D(_cube_side_enum[i], lod, 0, 0, 0, 0, size, size); + } + + size >>= 1; + + mm_level--; + + lod++; + } + + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_SOURCE_PANORAMA, false); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::USE_DIRECT_WRITE, false); + + // restore ranges + glActiveTexture(GL_TEXTURE2); //back to panorama + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + 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); + + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE3); //back to panorama + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + + //reset flags on Sky Texture that may have changed + texture_set_flags(sky->panorama, texture->flags); + + // Framebuffer did its job. thank mr framebuffer + glActiveTexture(GL_TEXTURE0); //back to panorama + bind_framebuffer_system(); +} + +/* SHADER API */ + +RID RasterizerStorageGLES3::shader_allocate() { + Shader *shader = memnew(Shader); + shader->mode = RS::SHADER_SPATIAL; + shader->shader = &scene->state.scene_shader; + RID rid = shader_owner.make_rid(shader); + _shader_make_dirty(shader); + shader->self = rid; + + return rid; +} + +void RasterizerStorageGLES3::shader_initialize(RID p_rid) { + // noop +} + +//RID RasterizerStorageGLES3::shader_create() { +// Shader *shader = memnew(Shader); +// shader->mode = RS::SHADER_SPATIAL; +// shader->shader = &scene->state.scene_shader; +// RID rid = shader_owner.make_rid(shader); +// _shader_make_dirty(shader); +// shader->self = rid; + +// return rid; +//} + +void RasterizerStorageGLES3::_shader_make_dirty(Shader *p_shader) { + if (p_shader->dirty_list.in_list()) + return; + + _shader_dirty_list.add(&p_shader->dirty_list); +} + +void RasterizerStorageGLES3::shader_set_code(RID p_shader, const String &p_code) { + Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_COND(!shader); + + shader->code = p_code; + + String mode_string = ShaderLanguage::get_shader_type(p_code); + RS::ShaderMode mode; + + if (mode_string == "canvas_item") + mode = RS::SHADER_CANVAS_ITEM; + else if (mode_string == "particles") + mode = RS::SHADER_PARTICLES; + else + mode = RS::SHADER_SPATIAL; + + if (shader->custom_code_id && mode != shader->mode) { + shader->shader->free_custom_shader(shader->custom_code_id); + shader->custom_code_id = 0; + } + + shader->mode = mode; + + // TODO handle all shader types + if (mode == RS::SHADER_CANVAS_ITEM) { + shader->shader = &canvas->state.canvas_shader; + + } else if (mode == RS::SHADER_SPATIAL) { + shader->shader = &scene->state.scene_shader; + } else { + return; + } + + if (shader->custom_code_id == 0) { + shader->custom_code_id = shader->shader->create_custom_shader(); + } + + _shader_make_dirty(shader); +} + +String RasterizerStorageGLES3::shader_get_code(RID p_shader) const { + const Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_COND_V(!shader, ""); + + return shader->code; +} + +void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { + _shader_dirty_list.remove(&p_shader->dirty_list); + + p_shader->valid = false; + + p_shader->uniforms.clear(); + + if (p_shader->code == String()) { + return; //just invalid, but no error + } + + ShaderCompilerGLES3::GeneratedCode gen_code; + ShaderCompilerGLES3::IdentifierActions *actions = NULL; + + switch (p_shader->mode) { + case RS::SHADER_CANVAS_ITEM: { + p_shader->canvas_item.light_mode = Shader::CanvasItem::LIGHT_MODE_NORMAL; + p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX; + + p_shader->canvas_item.uses_screen_texture = false; + p_shader->canvas_item.uses_screen_uv = false; + p_shader->canvas_item.uses_time = false; + p_shader->canvas_item.uses_modulate = false; + p_shader->canvas_item.uses_color = false; + p_shader->canvas_item.uses_vertex = false; + p_shader->canvas_item.batch_flags = 0; + + p_shader->canvas_item.uses_world_matrix = false; + p_shader->canvas_item.uses_extra_matrix = false; + p_shader->canvas_item.uses_projection_matrix = false; + p_shader->canvas_item.uses_instance_custom = false; + + shaders.actions_canvas.render_mode_values["blend_add"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD); + shaders.actions_canvas.render_mode_values["blend_mix"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX); + shaders.actions_canvas.render_mode_values["blend_sub"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_SUB); + shaders.actions_canvas.render_mode_values["blend_mul"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MUL); + shaders.actions_canvas.render_mode_values["blend_premul_alpha"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_PMALPHA); + + shaders.actions_canvas.render_mode_values["unshaded"] = Pair(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED); + shaders.actions_canvas.render_mode_values["light_only"] = Pair(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY); + + shaders.actions_canvas.usage_flag_pointers["SCREEN_UV"] = &p_shader->canvas_item.uses_screen_uv; + shaders.actions_canvas.usage_flag_pointers["SCREEN_PIXEL_SIZE"] = &p_shader->canvas_item.uses_screen_uv; + shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture; + shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time; + shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate; + shaders.actions_canvas.usage_flag_pointers["COLOR"] = &p_shader->canvas_item.uses_color; + + shaders.actions_canvas.usage_flag_pointers["VERTEX"] = &p_shader->canvas_item.uses_vertex; + + shaders.actions_canvas.usage_flag_pointers["WORLD_MATRIX"] = &p_shader->canvas_item.uses_world_matrix; + shaders.actions_canvas.usage_flag_pointers["EXTRA_MATRIX"] = &p_shader->canvas_item.uses_extra_matrix; + shaders.actions_canvas.usage_flag_pointers["PROJECTION_MATRIX"] = &p_shader->canvas_item.uses_projection_matrix; + shaders.actions_canvas.usage_flag_pointers["INSTANCE_CUSTOM"] = &p_shader->canvas_item.uses_instance_custom; + + actions = &shaders.actions_canvas; + actions->uniforms = &p_shader->uniforms; + } break; + + case RS::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.uses_tangent = false; + p_shader->spatial.uses_ensure_correct_normals = 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(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_ADD); + shaders.actions_scene.render_mode_values["blend_mix"] = Pair(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MIX); + shaders.actions_scene.render_mode_values["blend_sub"] = Pair(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_SUB); + shaders.actions_scene.render_mode_values["blend_mul"] = Pair(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MUL); + + shaders.actions_scene.render_mode_values["depth_draw_opaque"] = Pair(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_OPAQUE); + shaders.actions_scene.render_mode_values["depth_draw_always"] = Pair(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALWAYS); + shaders.actions_scene.render_mode_values["depth_draw_never"] = Pair(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_NEVER); + shaders.actions_scene.render_mode_values["depth_draw_alpha_prepass"] = Pair(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS); + + shaders.actions_scene.render_mode_values["cull_front"] = Pair(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_FRONT); + shaders.actions_scene.render_mode_values["cull_back"] = Pair(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_BACK); + shaders.actions_scene.render_mode_values["cull_disabled"] = Pair(&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.render_mode_flags["ensure_correct_normals"] = &p_shader->spatial.uses_ensure_correct_normals; + + 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; + + // Use of any of these BUILTINS indicate the need for transformed tangents. + // This is needed to know when to transform tangents in software skinning. + shaders.actions_scene.usage_flag_pointers["TANGENT"] = &p_shader->spatial.uses_tangent; + shaders.actions_scene.usage_flag_pointers["NORMALMAP"] = &p_shader->spatial.uses_tangent; + + 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; + + if (p_shader->spatial.uses_screen_texture && p_shader->spatial.uses_depth_texture) { + ERR_PRINT_ONCE("Using both SCREEN_TEXTURE and DEPTH_TEXTURE is not supported in OpenGL"); + } + + if (p_shader->spatial.uses_depth_texture && !config.support_depth_texture) { + ERR_PRINT_ONCE("Using DEPTH_TEXTURE is not permitted on this hardware, operation will fail."); + } + } break; + + default: { + return; + } break; + } + + Error err = shaders.compiler.compile(p_shader->mode, p_shader->code, actions, p_shader->path, gen_code); + if (err != OK) { + return; + } + + p_shader->shader->set_custom_shader_code(p_shader->custom_code_id, gen_code.vertex, gen_code.vertex_global, gen_code.fragment, gen_code.light, gen_code.fragment_global, gen_code.uniforms, gen_code.texture_uniforms, gen_code.custom_defines); + + p_shader->texture_count = gen_code.texture_uniforms.size(); + p_shader->texture_hints = gen_code.texture_hints; + + p_shader->uses_vertex_time = gen_code.uses_vertex_time; + p_shader->uses_fragment_time = gen_code.uses_fragment_time; + + // some logic for batching + if (p_shader->mode == RS::SHADER_CANVAS_ITEM) { + if (p_shader->canvas_item.uses_modulate | p_shader->canvas_item.uses_color) { + p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_COLOR_BAKING; + } + if (p_shader->canvas_item.uses_vertex) { + p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_VERTEX_BAKING; + } + if (p_shader->canvas_item.uses_world_matrix | p_shader->canvas_item.uses_extra_matrix | p_shader->canvas_item.uses_projection_matrix | p_shader->canvas_item.uses_instance_custom) { + p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_ITEM_JOINING; + } + } + + p_shader->shader->set_custom_shader(p_shader->custom_code_id); + p_shader->shader->bind(); + + // cache uniform locations + + for (SelfList *E = p_shader->materials.first(); E; E = E->next()) { + _material_make_dirty(E->self()); + } + + p_shader->valid = true; + p_shader->version++; +} + +void RasterizerStorageGLES3::update_dirty_shaders() { + while (_shader_dirty_list.first()) { + _update_shader(_shader_dirty_list.first()->self()); + } +} + +void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List *p_param_list) const { + Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_COND(!shader); + + if (shader->dirty_list.in_list()) { + _update_shader(shader); + } + + Map order; + + for (Map::Element *E = shader->uniforms.front(); E; E = E->next()) { + if (E->get().texture_order >= 0) { + order[E->get().texture_order + 100000] = E->key(); + } else { + order[E->get().order] = E->key(); + } + } + + for (Map::Element *E = order.front(); E; E = E->next()) { + PropertyInfo pi; + ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[E->get()]; + + pi.name = E->get(); + + switch (u.type) { + case ShaderLanguage::TYPE_VOID: { + pi.type = Variant::NIL; + } break; + + case ShaderLanguage::TYPE_BOOL: { + pi.type = Variant::BOOL; + } break; + + // bool vectors + case ShaderLanguage::TYPE_BVEC2: { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y"; + } break; + case ShaderLanguage::TYPE_BVEC3: { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y,z"; + } break; + case ShaderLanguage::TYPE_BVEC4: { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y,z,w"; + } break; + + // int stuff + case ShaderLanguage::TYPE_UINT: + case ShaderLanguage::TYPE_INT: { + pi.type = Variant::INT; + + if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { + pi.hint = PROPERTY_HINT_RANGE; + pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); + } + } break; + + case ShaderLanguage::TYPE_IVEC2: + case ShaderLanguage::TYPE_UVEC2: + case ShaderLanguage::TYPE_IVEC3: + case ShaderLanguage::TYPE_UVEC3: + case ShaderLanguage::TYPE_IVEC4: + case ShaderLanguage::TYPE_UVEC4: { + // not sure what this should be in godot 4 + // pi.type = Variant::POOL_INT_ARRAY; + pi.type = Variant::PACKED_INT32_ARRAY; + } break; + + case ShaderLanguage::TYPE_FLOAT: { + pi.type = Variant::FLOAT; + if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { + pi.hint = PROPERTY_HINT_RANGE; + pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); + } + } break; + + case ShaderLanguage::TYPE_VEC2: { + pi.type = Variant::VECTOR2; + } break; + case ShaderLanguage::TYPE_VEC3: { + pi.type = Variant::VECTOR3; + } break; + + case ShaderLanguage::TYPE_VEC4: { + if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + pi.type = Variant::COLOR; + } else { + pi.type = Variant::PLANE; + } + } break; + + case ShaderLanguage::TYPE_MAT2: { + pi.type = Variant::TRANSFORM2D; + } break; + + case ShaderLanguage::TYPE_MAT3: { + pi.type = Variant::BASIS; + } break; + + case ShaderLanguage::TYPE_MAT4: { + pi.type = Variant::TRANSFORM3D; + } break; + + case ShaderLanguage::TYPE_SAMPLER2D: + // case ShaderLanguage::TYPE_SAMPLEREXT: + case ShaderLanguage::TYPE_ISAMPLER2D: + case ShaderLanguage::TYPE_USAMPLER2D: { + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "Texture"; + } break; + + case ShaderLanguage::TYPE_SAMPLERCUBE: { + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "CubeMap"; + } break; + + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in OpenGL + } break; + // new for godot 4 + case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: + case ShaderLanguage::TYPE_STRUCT: + case ShaderLanguage::TYPE_MAX: { + } break; + } + + p_param_list->push_back(pi); + } +} + +void RasterizerStorageGLES3::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { + Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_COND(!shader); + ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture)); + + if (p_texture.is_valid()) { + shader->default_textures[p_name] = p_texture; + } else { + shader->default_textures.erase(p_name); + } + + _shader_make_dirty(shader); +} + +RID RasterizerStorageGLES3::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { + const Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_COND_V(!shader, RID()); + + const Map::Element *E = shader->default_textures.find(p_name); + + if (!E) { + return RID(); + } + + return E->get(); +} + +void RasterizerStorageGLES3::shader_add_custom_define(RID p_shader, const String &p_define) { + Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_COND(!shader); + + shader->shader->add_custom_define(p_define); + + _shader_make_dirty(shader); +} + +void RasterizerStorageGLES3::shader_get_custom_defines(RID p_shader, Vector *p_defines) const { + Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_COND(!shader); + + shader->shader->get_custom_defines(p_defines); +} + +void RasterizerStorageGLES3::shader_remove_custom_define(RID p_shader, const String &p_define) { + Shader *shader = shader_owner.get_or_null(p_shader); + ERR_FAIL_COND(!shader); + + shader->shader->remove_custom_define(p_define); + + _shader_make_dirty(shader); +} + +/* COMMON MATERIAL API */ + +void RasterizerStorageGLES3::_material_make_dirty(Material *p_material) const { + if (p_material->dirty_list.in_list()) + return; + + _material_dirty_list.add(&p_material->dirty_list); +} + +RID RasterizerStorageGLES3::material_allocate() { + Material *material = memnew(Material); + return material_owner.make_rid(material); +} + +void RasterizerStorageGLES3::material_initialize(RID p_rid) { +} + +//RID RasterizerStorageGLES3::material_create() { +// Material *material = memnew(Material); + +// return material_owner.make_rid(material); +//} + +void RasterizerStorageGLES3::material_set_shader(RID p_material, RID p_shader) { + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + Shader *shader = shader_owner.get_or_null(p_shader); + + if (material->shader) { + // if a shader is present, remove the old shader + material->shader->materials.remove(&material->list); + } + + material->shader = shader; + + if (shader) { + shader->materials.add(&material->list); + } + + _material_make_dirty(material); +} + +RID RasterizerStorageGLES3::material_get_shader(RID p_material) const { + const Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND_V(!material, RID()); + + if (material->shader) { + return material->shader->self; + } + + return RID(); +} + +void RasterizerStorageGLES3::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + if (p_value.get_type() == Variant::NIL) { + material->params.erase(p_param); + } else { + material->params[p_param] = p_value; + } + + _material_make_dirty(material); +} + +Variant RasterizerStorageGLES3::material_get_param(RID p_material, const StringName &p_param) const { + const Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND_V(!material, RID()); + + if (material->params.has(p_param)) { + return material->params[p_param]; + } + + return material_get_param_default(p_material, p_param); +} + +Variant RasterizerStorageGLES3::material_get_param_default(RID p_material, const StringName &p_param) const { + const Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND_V(!material, Variant()); + + if (material->shader) { + if (material->shader->uniforms.has(p_param)) { + ShaderLanguage::ShaderNode::Uniform uniform = material->shader->uniforms[p_param]; + Vector default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + } + } + return Variant(); +} + +void RasterizerStorageGLES3::material_set_line_width(RID p_material, float p_width) { + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + material->line_width = p_width; +} + +void RasterizerStorageGLES3::material_set_next_pass(RID p_material, RID p_next_material) { + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + material->next_pass = p_next_material; +} + +bool RasterizerStorageGLES3::material_is_animated(RID p_material) { + Material *material = material_owner.get_or_null(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 RasterizerStorageGLES3::material_casts_shadows(RID p_material) { + Material *material = material_owner.get_or_null(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; +} + +bool RasterizerStorageGLES3::material_uses_tangents(RID p_material) { + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND_V(!material, false); + + if (!material->shader) { + return false; + } + + if (material->shader->dirty_list.in_list()) { + _update_shader(material->shader); + } + + return material->shader->spatial.uses_tangent; +} + +bool RasterizerStorageGLES3::material_uses_ensure_correct_normals(RID p_material) { + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND_V(!material, false); + + if (!material->shader) { + return false; + } + + if (material->shader->dirty_list.in_list()) { + _update_shader(material->shader); + } + + return material->shader->spatial.uses_ensure_correct_normals; +} + +void RasterizerStorageGLES3::material_add_instance_owner(RID p_material, DependencyTracker *p_instance) { + /* + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + Map::Element *E = material->instance_owners.find(p_instance); + if (E) { + E->get()++; + } else { + material->instance_owners[p_instance] = 1; + } +*/ +} + +void RasterizerStorageGLES3::material_remove_instance_owner(RID p_material, DependencyTracker *p_instance) { + /* + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + Map::Element *E = material->instance_owners.find(p_instance); + ERR_FAIL_COND(!E); + + E->get()--; + + if (E->get() == 0) { + material->instance_owners.erase(E); + } +*/ +} + +void RasterizerStorageGLES3::material_set_render_priority(RID p_material, int priority) { + ERR_FAIL_COND(priority < RS::MATERIAL_RENDER_PRIORITY_MIN); + ERR_FAIL_COND(priority > RS::MATERIAL_RENDER_PRIORITY_MAX); + + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + material->render_priority = priority; +} + +void RasterizerStorageGLES3::_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 == RS::SHADER_SPATIAL) { + if (p_material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX && + (!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::Element *E = p_material->geometry_owners.front(); E; E = E->next()) { + E->key()->material_changed_notify(); + } + + for (Map::Element *E = p_material->instance_owners.front(); E; E = E->next()) { + E->key()->base_changed(false, true); + } + */ + } + } + } + + // uniforms and other things will be set in the use_material method in ShaderGLES3 + + if (p_material->shader && p_material->shader->texture_count > 0) { + p_material->textures.resize(p_material->shader->texture_count); + + for (Map::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::Element *V = p_material->params.find(E->key()); + + if (V) { + texture = V->get(); + } + + if (!texture.is_valid()) { + Map::Element *W = p_material->shader->default_textures.find(E->key()); + + if (W) { + texture = W->get(); + } + } + + p_material->textures.write[E->get().texture_order] = Pair(E->key(), texture); + } + } else { + p_material->textures.clear(); + } +} +/* +void RasterizerStorageGLES3::_material_add_geometry(RID p_material, Geometry *p_geometry) { + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + Map::Element *I = material->geometry_owners.find(p_geometry); + + if (I) { + I->get()++; + } else { + material->geometry_owners[p_geometry] = 1; + } +} + +void RasterizerStorageGLES3::_material_remove_geometry(RID p_material, Geometry *p_geometry) { + Material *material = material_owner.get_or_null(p_material); + ERR_FAIL_COND(!material); + + Map::Element *I = material->geometry_owners.find(p_geometry); + ERR_FAIL_COND(!I); + + I->get()--; + + if (I->get() == 0) { + material->geometry_owners.erase(I); + } +} +*/ +void RasterizerStorageGLES3::update_dirty_materials() { + while (_material_dirty_list.first()) { + Material *material = _material_dirty_list.first()->self(); + _update_material(material); + } +} + +/* MESH API */ + +RID RasterizerStorageGLES3::mesh_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::mesh_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) { +} + +bool RasterizerStorageGLES3::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) { + return false; +} + +RID RasterizerStorageGLES3::mesh_instance_create(RID p_base) { + return RID(); +} + +void RasterizerStorageGLES3::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) { +} + +void RasterizerStorageGLES3::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) { +} + +void RasterizerStorageGLES3::mesh_instance_check_for_update(RID p_mesh_instance) { +} + +void RasterizerStorageGLES3::update_mesh_instances() { +} + +void RasterizerStorageGLES3::reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) { +} + +float RasterizerStorageGLES3::reflection_probe_get_lod_threshold(RID p_probe) const { + return 0.0; +} + +void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) { +} + +int RasterizerStorageGLES3::mesh_get_blend_shape_count(RID p_mesh) const { + return 0; +} + +void RasterizerStorageGLES3::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { +} + +RS::BlendShapeMode RasterizerStorageGLES3::mesh_get_blend_shape_mode(RID p_mesh) const { + return RS::BLEND_SHAPE_MODE_NORMALIZED; +} + +void RasterizerStorageGLES3::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) { +} + +void RasterizerStorageGLES3::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) { +} + +void RasterizerStorageGLES3::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) { +} + +void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { +} + +RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const { + return RID(); +} + +RS::SurfaceData RasterizerStorageGLES3::mesh_get_surface(RID p_mesh, int p_surface) const { + return RS::SurfaceData(); +} + +int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const { + return 0; +} + +void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { +} + +AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const { + return AABB(); +} + +AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) { + return AABB(); +} + +void RasterizerStorageGLES3::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) { +} + +void RasterizerStorageGLES3::mesh_clear(RID p_mesh) { +} + +/* MULTIMESH API */ + +RID RasterizerStorageGLES3::multimesh_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::multimesh_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) { +} + +int RasterizerStorageGLES3::multimesh_get_instance_count(RID p_multimesh) const { + return 0; +} + +void RasterizerStorageGLES3::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { +} + +void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) { +} + +void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { +} + +void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { +} + +void RasterizerStorageGLES3::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) { +} + +RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const { + return RID(); +} + +AABB RasterizerStorageGLES3::multimesh_get_aabb(RID p_multimesh) const { + return AABB(); +} + +Transform3D RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { + return Transform3D(); +} + +Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { + return Transform2D(); +} + +Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int p_index) const { + return Color(); +} + +Color RasterizerStorageGLES3::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { + return Color(); +} + +void RasterizerStorageGLES3::multimesh_set_buffer(RID p_multimesh, const Vector &p_buffer) { +} + +Vector RasterizerStorageGLES3::multimesh_get_buffer(RID p_multimesh) const { + return Vector(); +} + +void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { +} + +int RasterizerStorageGLES3::multimesh_get_visible_instances(RID p_multimesh) const { + return 0; +} + +/* SKELETON API */ + +RID RasterizerStorageGLES3::skeleton_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::skeleton_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) { +} + +void RasterizerStorageGLES3::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { +} + +int RasterizerStorageGLES3::skeleton_get_bone_count(RID p_skeleton) const { + return 0; +} + +void RasterizerStorageGLES3::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) { +} + +Transform3D RasterizerStorageGLES3::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { + return Transform3D(); +} + +void RasterizerStorageGLES3::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { +} + +Transform2D RasterizerStorageGLES3::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { + return Transform2D(); +} + +/* Light API */ + +RID RasterizerStorageGLES3::directional_light_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::directional_light_initialize(RID p_rid) { +} + +RID RasterizerStorageGLES3::omni_light_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::omni_light_initialize(RID p_rid) { +} + +RID RasterizerStorageGLES3::spot_light_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::spot_light_initialize(RID p_rid) { +} + +RID RasterizerStorageGLES3::reflection_probe_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::reflection_probe_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::light_set_color(RID p_light, const Color &p_color) { +} + +void RasterizerStorageGLES3::light_set_param(RID p_light, RS::LightParam p_param, float p_value) { +} + +void RasterizerStorageGLES3::light_set_shadow(RID p_light, bool p_enabled) { +} + +void RasterizerStorageGLES3::light_set_shadow_color(RID p_light, const Color &p_color) { +} + +void RasterizerStorageGLES3::light_set_projector(RID p_light, RID p_texture) { +} + +void RasterizerStorageGLES3::light_set_negative(RID p_light, bool p_enable) { +} + +void RasterizerStorageGLES3::light_set_cull_mask(RID p_light, uint32_t p_mask) { +} + +void RasterizerStorageGLES3::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { +} + +void RasterizerStorageGLES3::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { +} + +void RasterizerStorageGLES3::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) { +} + +void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { +} + +void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) { +} + +void RasterizerStorageGLES3::light_directional_set_blend_splits(RID p_light, bool p_enable) { +} + +bool RasterizerStorageGLES3::light_directional_get_blend_splits(RID p_light) const { + return false; +} + +void RasterizerStorageGLES3::light_directional_set_sky_only(RID p_light, bool p_sky_only) { +} + +bool RasterizerStorageGLES3::light_directional_is_sky_only(RID p_light) const { + return false; +} + +RS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_shadow_mode(RID p_light) { + return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; +} + +RS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) { + return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; +} + +bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const { + return false; +} + +bool RasterizerStorageGLES3::light_has_projector(RID p_light) const { + return false; +} + +RS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const { + return RS::LIGHT_OMNI; +} + +AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { + return AABB(); +} + +float RasterizerStorageGLES3::light_get_param(RID p_light, RS::LightParam p_param) { + return 0.0; +} + +Color RasterizerStorageGLES3::light_get_color(RID p_light) { + return Color(); +} + +RS::LightBakeMode RasterizerStorageGLES3::light_get_bake_mode(RID p_light) { + return RS::LIGHT_BAKE_DISABLED; +} + +uint32_t RasterizerStorageGLES3::light_get_max_sdfgi_cascade(RID p_light) { + return 0; +} + +uint64_t RasterizerStorageGLES3::light_get_version(RID p_light) const { + return 0; +} + +/* PROBE API */ + +void RasterizerStorageGLES3::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) { +} + +void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity) { +} + +void RasterizerStorageGLES3::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) { +} + +void RasterizerStorageGLES3::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) { +} + +void RasterizerStorageGLES3::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) { +} + +void RasterizerStorageGLES3::reflection_probe_set_max_distance(RID p_probe, float p_distance) { +} + +void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { +} + +void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { +} + +void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { +} + +void RasterizerStorageGLES3::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { +} + +void RasterizerStorageGLES3::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { +} + +void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { +} + +void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution) { +} + +AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const { + return AABB(); +} + +RS::ReflectionProbeUpdateMode RasterizerStorageGLES3::reflection_probe_get_update_mode(RID p_probe) const { + return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; +} + +uint32_t RasterizerStorageGLES3::reflection_probe_get_cull_mask(RID p_probe) const { + return 0; +} + +Vector3 RasterizerStorageGLES3::reflection_probe_get_extents(RID p_probe) const { + return Vector3(); +} + +Vector3 RasterizerStorageGLES3::reflection_probe_get_origin_offset(RID p_probe) const { + return Vector3(); +} + +float RasterizerStorageGLES3::reflection_probe_get_origin_max_distance(RID p_probe) const { + return 0.0; +} + +bool RasterizerStorageGLES3::reflection_probe_renders_shadows(RID p_probe) const { + return false; +} + +void RasterizerStorageGLES3::base_update_dependency(RID p_base, DependencyTracker *p_instance) { +} + +void RasterizerStorageGLES3::skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) { +} + +/* DECAL API */ + +RID RasterizerStorageGLES3::decal_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::decal_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::decal_set_extents(RID p_decal, const Vector3 &p_extents) { +} + +void RasterizerStorageGLES3::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { +} + +void RasterizerStorageGLES3::decal_set_emission_energy(RID p_decal, float p_energy) { +} + +void RasterizerStorageGLES3::decal_set_albedo_mix(RID p_decal, float p_mix) { +} + +void RasterizerStorageGLES3::decal_set_modulate(RID p_decal, const Color &p_modulate) { +} + +void RasterizerStorageGLES3::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { +} + +void RasterizerStorageGLES3::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { +} + +void RasterizerStorageGLES3::decal_set_fade(RID p_decal, float p_above, float p_below) { +} + +void RasterizerStorageGLES3::decal_set_normal_fade(RID p_decal, float p_fade) { +} + +AABB RasterizerStorageGLES3::decal_get_aabb(RID p_decal) const { + return AABB(); +} + +/* VOXEL GI API */ + +RID RasterizerStorageGLES3::voxel_gi_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::voxel_gi_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector &p_octree_cells, const Vector &p_data_cells, const Vector &p_distance_field, const Vector &p_level_counts) { +} + +AABB RasterizerStorageGLES3::voxel_gi_get_bounds(RID p_voxel_gi) const { + return AABB(); +} + +Vector3i RasterizerStorageGLES3::voxel_gi_get_octree_size(RID p_voxel_gi) const { + return Vector3i(); +} + +Vector RasterizerStorageGLES3::voxel_gi_get_octree_cells(RID p_voxel_gi) const { + return Vector(); +} + +Vector RasterizerStorageGLES3::voxel_gi_get_data_cells(RID p_voxel_gi) const { + return Vector(); +} + +Vector RasterizerStorageGLES3::voxel_gi_get_distance_field(RID p_voxel_gi) const { + return Vector(); +} + +Vector RasterizerStorageGLES3::voxel_gi_get_level_counts(RID p_voxel_gi) const { + return Vector(); +} + +Transform3D RasterizerStorageGLES3::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const { + return Transform3D(); +} + +void RasterizerStorageGLES3::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) { +} + +float RasterizerStorageGLES3::voxel_gi_get_dynamic_range(RID p_voxel_gi) const { + return 0; +} + +void RasterizerStorageGLES3::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) { +} + +float RasterizerStorageGLES3::voxel_gi_get_propagation(RID p_voxel_gi) const { + return 0; +} + +void RasterizerStorageGLES3::voxel_gi_set_energy(RID p_voxel_gi, float p_range) { +} + +float RasterizerStorageGLES3::voxel_gi_get_energy(RID p_voxel_gi) const { + return 0.0; +} + +void RasterizerStorageGLES3::voxel_gi_set_bias(RID p_voxel_gi, float p_range) { +} + +float RasterizerStorageGLES3::voxel_gi_get_bias(RID p_voxel_gi) const { + return 0.0; +} + +void RasterizerStorageGLES3::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) { +} + +float RasterizerStorageGLES3::voxel_gi_get_normal_bias(RID p_voxel_gi) const { + return 0.0; +} + +void RasterizerStorageGLES3::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) { +} + +bool RasterizerStorageGLES3::voxel_gi_is_interior(RID p_voxel_gi) const { + return false; +} + +void RasterizerStorageGLES3::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) { +} + +bool RasterizerStorageGLES3::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const { + return false; +} + +void RasterizerStorageGLES3::voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) { +} + +float RasterizerStorageGLES3::voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const { + return 0; +} + +uint32_t RasterizerStorageGLES3::voxel_gi_get_version(RID p_voxel_gi) { + return 0; +} + +/* LIGHTMAP CAPTURE */ +RID RasterizerStorageGLES3::lightmap_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::lightmap_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) { +} + +void RasterizerStorageGLES3::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) { +} + +void RasterizerStorageGLES3::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) { +} + +void RasterizerStorageGLES3::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { +} + +PackedVector3Array RasterizerStorageGLES3::lightmap_get_probe_capture_points(RID p_lightmap) const { + return PackedVector3Array(); +} + +PackedColorArray RasterizerStorageGLES3::lightmap_get_probe_capture_sh(RID p_lightmap) const { + return PackedColorArray(); +} + +PackedInt32Array RasterizerStorageGLES3::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const { + return PackedInt32Array(); +} + +PackedInt32Array RasterizerStorageGLES3::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const { + return PackedInt32Array(); +} + +AABB RasterizerStorageGLES3::lightmap_get_aabb(RID p_lightmap) const { + return AABB(); +} + +void RasterizerStorageGLES3::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) { +} + +bool RasterizerStorageGLES3::lightmap_is_interior(RID p_lightmap) const { + return false; +} + +void RasterizerStorageGLES3::lightmap_set_probe_capture_update_speed(float p_speed) { +} + +float RasterizerStorageGLES3::lightmap_get_probe_capture_update_speed() const { + return 0; +} + +/* OCCLUDER */ + +void RasterizerStorageGLES3::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { +} + +/* PARTICLES */ + +RID RasterizerStorageGLES3::particles_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::particles_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) { +} + +void RasterizerStorageGLES3::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { +} + +void RasterizerStorageGLES3::particles_set_emitting(RID p_particles, bool p_emitting) { +} + +void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) { +} + +void RasterizerStorageGLES3::particles_set_lifetime(RID p_particles, double p_lifetime) { +} + +void RasterizerStorageGLES3::particles_set_one_shot(RID p_particles, bool p_one_shot) { +} + +void RasterizerStorageGLES3::particles_set_pre_process_time(RID p_particles, double p_time) { +} + +void RasterizerStorageGLES3::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) { +} + +void RasterizerStorageGLES3::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) { +} + +void RasterizerStorageGLES3::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { +} + +void RasterizerStorageGLES3::particles_set_speed_scale(RID p_particles, double p_scale) { +} + +void RasterizerStorageGLES3::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { +} + +void RasterizerStorageGLES3::particles_set_process_material(RID p_particles, RID p_material) { +} + +void RasterizerStorageGLES3::particles_set_fixed_fps(RID p_particles, int p_fps) { +} + +void RasterizerStorageGLES3::particles_set_interpolate(RID p_particles, bool p_enable) { +} + +void RasterizerStorageGLES3::particles_set_fractional_delta(RID p_particles, bool p_enable) { +} + +void RasterizerStorageGLES3::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { +} + +void RasterizerStorageGLES3::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) { +} + +void RasterizerStorageGLES3::particles_set_collision_base_size(RID p_particles, real_t p_size) { +} + +void RasterizerStorageGLES3::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) { +} + +void RasterizerStorageGLES3::particles_set_trails(RID p_particles, bool p_enable, double p_length) { +} + +void RasterizerStorageGLES3::particles_set_trail_bind_poses(RID p_particles, const Vector &p_bind_poses) { +} + +void RasterizerStorageGLES3::particles_restart(RID p_particles) { +} + +void RasterizerStorageGLES3::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { +} + +void RasterizerStorageGLES3::particles_set_draw_passes(RID p_particles, int p_count) { +} + +void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { +} + +void RasterizerStorageGLES3::particles_request_process(RID p_particles) { +} + +AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { + return AABB(); +} + +AABB RasterizerStorageGLES3::particles_get_aabb(RID p_particles) const { + return AABB(); +} + +void RasterizerStorageGLES3::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) { +} + +bool RasterizerStorageGLES3::particles_get_emitting(RID p_particles) { + return false; +} + +int RasterizerStorageGLES3::particles_get_draw_passes(RID p_particles) const { + return 0; +} + +RID RasterizerStorageGLES3::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { + return RID(); +} + +void RasterizerStorageGLES3::particles_add_collision(RID p_particles, RID p_instance) { +} + +void RasterizerStorageGLES3::particles_remove_collision(RID p_particles, RID p_instance) { +} + +void RasterizerStorageGLES3::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) { +} + +void RasterizerStorageGLES3::update_particles() { +} + +/* PARTICLES COLLISION */ + +RID RasterizerStorageGLES3::particles_collision_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::particles_collision_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { +} + +void RasterizerStorageGLES3::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { +} + +void RasterizerStorageGLES3::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) { +} + +void RasterizerStorageGLES3::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { +} + +void RasterizerStorageGLES3::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) { +} + +void RasterizerStorageGLES3::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) { +} + +void RasterizerStorageGLES3::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) { +} + +void RasterizerStorageGLES3::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { +} + +void RasterizerStorageGLES3::particles_collision_height_field_update(RID p_particles_collision) { +} + +void RasterizerStorageGLES3::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { +} + +AABB RasterizerStorageGLES3::particles_collision_get_aabb(RID p_particles_collision) const { + return AABB(); +} + +bool RasterizerStorageGLES3::particles_collision_is_heightfield(RID p_particles_collision) const { + return false; +} + +RID RasterizerStorageGLES3::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { + return RID(); +} + +RID RasterizerStorageGLES3::particles_collision_instance_create(RID p_collision) { + return RID(); +} + +void RasterizerStorageGLES3::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) { +} + +void RasterizerStorageGLES3::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) { +} + +RID RasterizerStorageGLES3::fog_volume_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::fog_volume_initialize(RID p_rid) { +} + +void RasterizerStorageGLES3::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) { +} + +void RasterizerStorageGLES3::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) { +} + +void RasterizerStorageGLES3::fog_volume_set_material(RID p_fog_volume, RID p_material) { +} + +AABB RasterizerStorageGLES3::fog_volume_get_aabb(RID p_fog_volume) const { + return AABB(); +} + +RS::FogVolumeShape RasterizerStorageGLES3::fog_volume_get_shape(RID p_fog_volume) const { + return RS::FOG_VOLUME_SHAPE_BOX; +} + +/* VISIBILITY NOTIFIER */ +RID RasterizerStorageGLES3::visibility_notifier_allocate() { + return RID(); +} + +void RasterizerStorageGLES3::visibility_notifier_initialize(RID p_notifier) { +} + +void RasterizerStorageGLES3::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) { +} + +void RasterizerStorageGLES3::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) { +} + +AABB RasterizerStorageGLES3::visibility_notifier_get_aabb(RID p_notifier) const { + return AABB(); +} + +void RasterizerStorageGLES3::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) { +} + +/* GLOBAL VARIABLES */ + +void RasterizerStorageGLES3::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) { +} + +void RasterizerStorageGLES3::global_variable_remove(const StringName &p_name) { +} + +Vector RasterizerStorageGLES3::global_variable_get_list() const { + return Vector(); +} + +void RasterizerStorageGLES3::global_variable_set(const StringName &p_name, const Variant &p_value) { +} + +void RasterizerStorageGLES3::global_variable_set_override(const StringName &p_name, const Variant &p_value) { +} + +Variant RasterizerStorageGLES3::global_variable_get(const StringName &p_name) const { + return Variant(); +} + +RS::GlobalVariableType RasterizerStorageGLES3::global_variable_get_type(const StringName &p_name) const { + return RS::GLOBAL_VAR_TYPE_MAX; +} + +void RasterizerStorageGLES3::global_variables_load_settings(bool p_load_textures) { +} + +void RasterizerStorageGLES3::global_variables_clear() { +} + +int32_t RasterizerStorageGLES3::global_variables_instance_allocate(RID p_instance) { + return 0; +} + +void RasterizerStorageGLES3::global_variables_instance_free(RID p_instance) { +} + +void RasterizerStorageGLES3::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) { +} + +bool RasterizerStorageGLES3::particles_is_inactive(RID p_particles) const { + return false; +} + +/* RENDER TARGET */ + +void RasterizerStorageGLES3::_set_current_render_target(RID p_render_target) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + + // FTODO + // if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) { + // // pending clear request. Do that first. + // glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); + // glClearColor(storage->frame.clear_request_color.r, + // storage->frame.clear_request_color.g, + // storage->frame.clear_request_color.b, + // storage->frame.clear_request_color.a); + // glClear(GL_COLOR_BUFFER_BIT); + // } + + if (rt) { + if (rt->allocate_is_dirty) { + rt->allocate_is_dirty = false; + _render_target_allocate(rt); + } + + // if (p_render_target.is_valid()) { + // RasterizerStorageGLES3::RenderTarget *rt = storage.render_target_owner.get_or_null(p_render_target); + frame.current_rt = rt; + ERR_FAIL_COND(!rt); + frame.clear_request = false; + + glViewport(0, 0, rt->width, rt->height); + + // print_line("_set_current_render_target w " + itos(rt->width) + " h " + itos(rt->height)); + + _dims.rt_width = rt->width; + _dims.rt_height = rt->height; + _dims.win_width = rt->width; + _dims.win_height = rt->height; + + } else { + frame.current_rt = NULL; + frame.clear_request = false; + // FTODO + // glViewport(0, 0, OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height); + bind_framebuffer_system(); + } +} + +void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + // do not allocate a render target with no size + if (rt->width <= 0 || rt->height <= 0) + return; + + // do not allocate a render target that is attached to the screen + if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { + rt->fbo = RasterizerStorageGLES3::system_fbo; + return; + } + + GLuint color_internal_format; + GLuint color_format; + GLuint color_type = GL_UNSIGNED_BYTE; + Image::Format image_format; + + if (rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { +#ifdef GLES_OVER_GL + color_internal_format = GL_RGBA8; +#else + color_internal_format = GL_RGBA; +#endif + color_format = GL_RGBA; + image_format = Image::FORMAT_RGBA8; + } else { +#ifdef GLES_OVER_GL + color_internal_format = GL_RGB8; +#else + color_internal_format = GL_RGB; +#endif + color_format = GL_RGB; + image_format = Image::FORMAT_RGB8; + } + + rt->used_dof_blur_near = false; + rt->mip_maps_allocated = false; + + { + /* Front FBO */ + + Texture *texture = texture_owner.get_or_null(rt->texture); + ERR_FAIL_COND(!texture); + + // framebuffer + glGenFramebuffers(1, &rt->fbo); + bind_framebuffer(rt->fbo); + + // color + glGenTextures(1, &rt->color); + glBindTexture(GL_TEXTURE_2D, rt->color); + + glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); + + if (texture->flags & TEXTURE_FLAG_FILTER) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + + // depth + + if (config.support_depth_texture) { + glGenTextures(1, &rt->depth); + glBindTexture(GL_TEXTURE_2D, rt->depth); + glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + } else { + glGenRenderbuffers(1, &rt->depth); + glBindRenderbuffer(GL_RENDERBUFFER, rt->depth); + + glRenderbufferStorage(GL_RENDERBUFFER, config.depth_buffer_internalformat, rt->width, rt->height); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + glDeleteFramebuffers(1, &rt->fbo); + if (config.support_depth_texture) { + glDeleteTextures(1, &rt->depth); + } else { + glDeleteRenderbuffers(1, &rt->depth); + } + + glDeleteTextures(1, &rt->color); + rt->fbo = 0; + rt->width = 0; + rt->height = 0; + rt->color = 0; + rt->depth = 0; + texture->tex_id = 0; + texture->active = false; + WARN_PRINT("Could not create framebuffer!!"); + return; + } + + texture->format = image_format; + texture->gl_format_cache = color_format; + texture->gl_type_cache = GL_UNSIGNED_BYTE; + texture->gl_internal_format_cache = color_internal_format; + texture->tex_id = rt->color; + texture->width = rt->width; + texture->alloc_width = rt->width; + texture->height = rt->height; + texture->alloc_height = rt->height; + texture->active = true; + + texture_set_flags(rt->texture, texture->flags); + } + + /* BACK FBO */ + /* For MSAA */ + +#ifndef JAVASCRIPT_ENABLED + if (rt->msaa >= RS::VIEWPORT_MSAA_2X && rt->msaa <= RS::VIEWPORT_MSAA_8X) { + rt->multisample_active = true; + + static const int msaa_value[] = { 0, 2, 4, 8, 16 }; + int msaa = msaa_value[rt->msaa]; + + int max_samples = 0; + glGetIntegerv(GL_MAX_SAMPLES, &max_samples); + if (msaa > max_samples) { + WARN_PRINT("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); + msaa = max_samples; + } + + //regular fbo + glGenFramebuffers(1, &rt->multisample_fbo); + bind_framebuffer(rt->multisample_fbo); + + glGenRenderbuffers(1, &rt->multisample_depth); + glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_depth); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_buffer_internalformat, rt->width, rt->height); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->multisample_depth); + + glGenRenderbuffers(1, &rt->multisample_color); + glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_color); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + // Delete allocated resources and default to no MSAA + WARN_PRINT_ONCE("Cannot allocate back framebuffer for MSAA"); + printf("err status: %x\n", status); + rt->multisample_active = false; + + glDeleteFramebuffers(1, &rt->multisample_fbo); + rt->multisample_fbo = 0; + + glDeleteRenderbuffers(1, &rt->multisample_depth); + rt->multisample_depth = 0; + + glDeleteRenderbuffers(1, &rt->multisample_color); + rt->multisample_color = 0; + } + + glBindRenderbuffer(GL_RENDERBUFFER, 0); + bind_framebuffer(0); + + } else +#endif // JAVASCRIPT_ENABLED + { + rt->multisample_active = false; + } + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // copy texscreen buffers + // if (!(rt->flags[RendererStorage::RENDER_TARGET_NO_SAMPLING])) { + if (true) { + glGenTextures(1, &rt->copy_screen_effect.color); + glBindTexture(GL_TEXTURE_2D, rt->copy_screen_effect.color); + + if (rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->width, rt->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glGenFramebuffers(1, &rt->copy_screen_effect.fbo); + bind_framebuffer(rt->copy_screen_effect.fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->copy_screen_effect.color, 0); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + _render_target_clear(rt); + ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); + } + } + + // Allocate mipmap chains for post_process effects + // if (!rt->flags[RendererStorage::RENDER_TARGET_NO_3D] && rt->width >= 2 && rt->height >= 2) { + if (rt->width >= 2 && rt->height >= 2) { + for (int i = 0; i < 2; i++) { + ERR_FAIL_COND(rt->mip_maps[i].sizes.size()); + int w = rt->width; + int h = rt->height; + + if (i > 0) { + w >>= 1; + h >>= 1; + } + + int level = 0; + int fb_w = w; + int fb_h = h; + + while (true) { + RenderTarget::MipMaps::Size mm; + mm.width = w; + mm.height = h; + rt->mip_maps[i].sizes.push_back(mm); + + w >>= 1; + h >>= 1; + + if (w < 2 || h < 2) + break; + + level++; + } + + GLsizei width = fb_w; + GLsizei height = fb_h; + + if (config.render_to_mipmap_supported) { + glGenTextures(1, &rt->mip_maps[i].color); + glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].color); + + for (int l = 0; l < level + 1; l++) { + glTexImage2D(GL_TEXTURE_2D, l, color_internal_format, width, height, 0, color_format, color_type, NULL); + width = MAX(1, (width / 2)); + height = MAX(1, (height / 2)); + } +#ifdef GLES_OVER_GL + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); +#endif + } else { + // Can't render to specific levels of a mipmap in ES 2.0 or Webgl so create a texture for each level + for (int l = 0; l < level + 1; l++) { + glGenTextures(1, &rt->mip_maps[i].sizes.write[l].color); + glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[l].color); + glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, width, height, 0, color_format, color_type, NULL); + width = MAX(1, (width / 2)); + height = MAX(1, (height / 2)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + } + + glDisable(GL_SCISSOR_TEST); + glColorMask(1, 1, 1, 1); + glDepthMask(GL_TRUE); + + for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { + RenderTarget::MipMaps::Size &mm = rt->mip_maps[i].sizes.write[j]; + + glGenFramebuffers(1, &mm.fbo); + bind_framebuffer(mm.fbo); + + if (config.render_to_mipmap_supported) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].color, j); + } else { + glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[j].color); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].sizes[j].color, 0); + } + + bool used_depth = false; + if (j == 0 && i == 0) { //use always + if (config.support_depth_texture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + } else { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + } + used_depth = true; + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + WARN_PRINT_ONCE("Cannot allocate mipmaps for 3D post processing effects"); + bind_framebuffer_system(); + return; + } + + glClearColor(1.0, 0.0, 1.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + if (used_depth) { + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + } + } + + rt->mip_maps[i].levels = level; + + if (config.render_to_mipmap_supported) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + } + rt->mip_maps_allocated = true; + } + + bind_framebuffer_system(); +} + +void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + // there is nothing to clear when DIRECT_TO_SCREEN is used + if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) + return; + + if (rt->fbo) { + glDeleteFramebuffers(1, &rt->fbo); + glDeleteTextures(1, &rt->color); + rt->fbo = 0; + } + + if (rt->external.fbo != 0) { + // free this + glDeleteFramebuffers(1, &rt->external.fbo); + + // clean up our texture + Texture *t = texture_owner.get_or_null(rt->external.texture); + t->alloc_height = 0; + t->alloc_width = 0; + t->width = 0; + t->height = 0; + t->active = false; + texture_owner.free(rt->external.texture); + memdelete(t); + + rt->external.fbo = 0; + } + + if (rt->depth) { + if (config.support_depth_texture) { + glDeleteTextures(1, &rt->depth); + } else { + glDeleteRenderbuffers(1, &rt->depth); + } + + rt->depth = 0; + } + + Texture *tex = texture_owner.get_or_null(rt->texture); + tex->alloc_height = 0; + tex->alloc_width = 0; + tex->width = 0; + tex->height = 0; + tex->active = false; + + if (rt->copy_screen_effect.color) { + glDeleteFramebuffers(1, &rt->copy_screen_effect.fbo); + rt->copy_screen_effect.fbo = 0; + + glDeleteTextures(1, &rt->copy_screen_effect.color); + rt->copy_screen_effect.color = 0; + } + + for (int i = 0; i < 2; i++) { + if (rt->mip_maps[i].sizes.size()) { + for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { + glDeleteFramebuffers(1, &rt->mip_maps[i].sizes[j].fbo); + glDeleteTextures(1, &rt->mip_maps[i].sizes[j].color); + } + + glDeleteTextures(1, &rt->mip_maps[i].color); + rt->mip_maps[i].sizes.clear(); + rt->mip_maps[i].levels = 0; + rt->mip_maps[i].color = 0; + } + } + + if (rt->multisample_active) { + glDeleteFramebuffers(1, &rt->multisample_fbo); + rt->multisample_fbo = 0; + + glDeleteRenderbuffers(1, &rt->multisample_depth); + rt->multisample_depth = 0; + + glDeleteRenderbuffers(1, &rt->multisample_color); + + rt->multisample_color = 0; + } +} + +RID RasterizerStorageGLES3::render_target_create() { +#ifdef OPENGL_DISABLE_RENDER_TARGETS +// return RID(); +#endif + + RenderTarget *rt = memnew(RenderTarget); + Texture *t = memnew(Texture); + + t->type = RenderingDevice::TEXTURE_TYPE_2D; + t->flags = 0; + t->width = 0; + t->height = 0; + t->alloc_height = 0; + t->alloc_width = 0; + t->format = Image::FORMAT_R8; + t->target = GL_TEXTURE_2D; + t->gl_format_cache = 0; + t->gl_internal_format_cache = 0; + t->gl_type_cache = 0; + t->data_size = 0; + t->total_data_size = 0; + t->ignore_mipmaps = false; + t->compressed = false; + t->mipmaps = 1; + t->active = true; + t->tex_id = 0; + t->render_target = rt; + + rt->texture = texture_owner.make_rid(t); + return render_target_owner.make_rid(rt); +} + +void RasterizerStorageGLES3::render_target_set_position(RID p_render_target, int p_x, int p_y) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + rt->x = p_x; + rt->y = p_y; +} + +void RasterizerStorageGLES3::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + if (p_width == rt->width && p_height == rt->height) + return; + + _render_target_clear(rt); + + rt->width = p_width; + rt->height = p_height; + + // print_line("render_target_set_size " + itos(p_render_target.get_id()) + ", w " + itos(p_width) + " h " + itos(p_height)); + + rt->allocate_is_dirty = true; + //_render_target_allocate(rt); +} + +RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return RID(); +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, RID()); + + if (rt->external.fbo == 0) { + return rt->texture; + } else { + return rt->external.texture; + } +} + +void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + if (p_texture_id == 0) { + if (rt->external.fbo != 0) { + // free this + glDeleteFramebuffers(1, &rt->external.fbo); + + // and this + if (rt->external.depth != 0) { + glDeleteRenderbuffers(1, &rt->external.depth); + } + + // clean up our texture + Texture *t = texture_owner.get_or_null(rt->external.texture); + t->alloc_height = 0; + t->alloc_width = 0; + t->width = 0; + t->height = 0; + t->active = false; + texture_owner.free(rt->external.texture); + memdelete(t); + + rt->external.fbo = 0; + rt->external.color = 0; + rt->external.depth = 0; + } + } else { + Texture *t; + + if (rt->external.fbo == 0) { + // create our fbo + glGenFramebuffers(1, &rt->external.fbo); + bind_framebuffer(rt->external.fbo); + + // allocate a texture + t = memnew(Texture); + + t->type = RenderingDevice::TEXTURE_TYPE_2D; + t->flags = 0; + t->width = 0; + t->height = 0; + t->alloc_height = 0; + t->alloc_width = 0; + t->format = Image::FORMAT_RGBA8; + t->target = GL_TEXTURE_2D; + t->gl_format_cache = 0; + t->gl_internal_format_cache = 0; + t->gl_type_cache = 0; + t->data_size = 0; + t->compressed = false; + t->srgb = false; + t->total_data_size = 0; + t->ignore_mipmaps = false; + t->mipmaps = 1; + t->active = true; + t->tex_id = 0; + t->render_target = rt; + + rt->external.texture = texture_owner.make_rid(t); + + } else { + // bind our frame buffer + bind_framebuffer(rt->external.fbo); + + // find our texture + t = texture_owner.get_or_null(rt->external.texture); + } + + // set our texture + t->tex_id = p_texture_id; + rt->external.color = p_texture_id; + + // size shouldn't be different + t->width = rt->width; + t->height = rt->height; + t->alloc_height = rt->width; + t->alloc_width = rt->height; + + // Switch our texture on our frame buffer + { + // set our texture as the destination for our framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0); + + // seeing we're rendering into this directly, better also use our depth buffer, just use our existing one :) + if (config.support_depth_texture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + } else { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + } + } + + // check status and unbind + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + bind_framebuffer_system(); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + printf("framebuffer fail, status: %x\n", status); + } + + ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); + } +} + +void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + // When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as + // those functions change how they operate depending on the value of DIRECT_TO_SCREEN + if (p_flag == RENDER_TARGET_DIRECT_TO_SCREEN && p_value != rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { + _render_target_clear(rt); + rt->flags[p_flag] = p_value; + _render_target_allocate(rt); + } + + rt->flags[p_flag] = p_value; + + switch (p_flag) { + case RENDER_TARGET_TRANSPARENT: + /* + case RENDER_TARGET_HDR: + case RENDER_TARGET_NO_3D: + case RENDER_TARGET_NO_SAMPLING: + case RENDER_TARGET_NO_3D_EFFECTS: */ + { + //must reset for these formats + _render_target_clear(rt); + _render_target_allocate(rt); + } + break; + default: { + } + } +} + +bool RasterizerStorageGLES3::render_target_was_used(RID p_render_target) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return false; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, false); + + return rt->used_in_frame; +} + +void RasterizerStorageGLES3::render_target_clear_used(RID p_render_target) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + rt->used_in_frame = false; +} + +void RasterizerStorageGLES3::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + if (rt->msaa == p_msaa) + return; + + _render_target_clear(rt); + rt->msaa = p_msaa; + _render_target_allocate(rt); +} + +//RasterizerStorageGLES3::RenderTarget * RasterizerStorageGLES3::render_target_get(RID p_render_target) +//{ +// return render_target_owner.get_or_null(p_render_target); +//} + +void RasterizerStorageGLES3::render_target_set_use_fxaa(RID p_render_target, bool p_fxaa) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + rt->use_fxaa = p_fxaa; +} + +void RasterizerStorageGLES3::render_target_set_use_debanding(RID p_render_target, bool p_debanding) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + + if (p_debanding) { + WARN_PRINT_ONCE("Debanding is not supported in the OpenGL backend. Switch to the Vulkan backend and make sure HDR is enabled."); + } + + rt->use_debanding = p_debanding; +} + +void RasterizerStorageGLES3::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + rt->clear_requested = true; + rt->clear_color = p_clear_color; + + // ERR_FAIL_COND(!frame.current_rt); + // frame.clear_request = true; + // frame.clear_request_color = p_color; +} + +bool RasterizerStorageGLES3::render_target_is_clear_requested(RID p_render_target) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return false; +#endif + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, false); + return rt->clear_requested; +} +Color RasterizerStorageGLES3::render_target_get_clear_request_color(RID p_render_target) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return Color(); +#endif + + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND_V(!rt, Color()); + return rt->clear_color; +} + +void RasterizerStorageGLES3::render_target_disable_clear_request(RID p_render_target) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + rt->clear_requested = false; +} + +void RasterizerStorageGLES3::render_target_do_clear_request(RID p_render_target) { +#ifdef OPENGL_DISABLE_RENDER_TARGETS + return; +#endif + + // NEW for GLES... + // This is being called at the wrong time. Instead it will be performed + // at canvas begin + return; + + /* + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); + ERR_FAIL_COND(!rt); + if (!rt->clear_requested) { + return; + } + + const Color &c = rt->clear_color; + + glClearColor(c.r, c.g, c.b, c.a); + // more bits? + glClear(GL_COLOR_BUFFER_BIT); + */ +} + +void RasterizerStorageGLES3::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { +} + +Rect2i RasterizerStorageGLES3::render_target_get_sdf_rect(RID p_render_target) const { + return Rect2i(); +} + +void RasterizerStorageGLES3::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) { +} + +/* CANVAS SHADOW */ + +RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) { + CanvasLightShadow *cls = memnew(CanvasLightShadow); + + if (p_width > config.max_texture_size) + p_width = config.max_texture_size; + + cls->size = p_width; + cls->height = 16; + + glActiveTexture(GL_TEXTURE0); + + glGenFramebuffers(1, &cls->fbo); + bind_framebuffer(cls->fbo); + + glGenRenderbuffers(1, &cls->depth); + glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); + glRenderbufferStorage(GL_RENDERBUFFER, config.depth_buffer_internalformat, cls->size, cls->height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); + + glGenTextures(1, &cls->distance); + glBindTexture(GL_TEXTURE_2D, cls->distance); + if (config.use_rgba_2d_shadows) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } else { +#ifdef GLES_OVER_GL + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, NULL); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_FLOAT, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, NULL); +#endif + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + 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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + //printf("errnum: %x\n",status); + bind_framebuffer_system(); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + memdelete(cls); + ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); + } + + return canvas_light_shadow_owner.make_rid(cls); +} + +/* LIGHT SHADOW MAPPING */ +/* + +RID RasterizerStorageGLES3::canvas_light_occluder_create() { + CanvasOccluder *co = memnew(CanvasOccluder); + co->index_id = 0; + co->vertex_id = 0; + co->len = 0; + + return canvas_occluder_owner.make_rid(co); +} + +void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector &p_lines) { + CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!co); + + co->lines = p_lines; + + if (p_lines.size() != co->len) { + if (co->index_id) + glDeleteBuffers(1, &co->index_id); + if (co->vertex_id) + glDeleteBuffers(1, &co->vertex_id); + + co->index_id = 0; + co->vertex_id = 0; + co->len = 0; + } + + if (p_lines.size()) { + PoolVector geometry; + PoolVector indices; + int lc = p_lines.size(); + + geometry.resize(lc * 6); + indices.resize(lc * 3); + + PoolVector::Write vw = geometry.write(); + PoolVector::Write iw = indices.write(); + + PoolVector::Read lr = p_lines.read(); + + const int POLY_HEIGHT = 16384; + + for (int i = 0; i < lc / 2; i++) { + vw[i * 12 + 0] = lr[i * 2 + 0].x; + vw[i * 12 + 1] = lr[i * 2 + 0].y; + vw[i * 12 + 2] = POLY_HEIGHT; + + vw[i * 12 + 3] = lr[i * 2 + 1].x; + vw[i * 12 + 4] = lr[i * 2 + 1].y; + vw[i * 12 + 5] = POLY_HEIGHT; + + vw[i * 12 + 6] = lr[i * 2 + 1].x; + vw[i * 12 + 7] = lr[i * 2 + 1].y; + vw[i * 12 + 8] = -POLY_HEIGHT; + + vw[i * 12 + 9] = lr[i * 2 + 0].x; + vw[i * 12 + 10] = lr[i * 2 + 0].y; + vw[i * 12 + 11] = -POLY_HEIGHT; + + iw[i * 6 + 0] = i * 4 + 0; + iw[i * 6 + 1] = i * 4 + 1; + iw[i * 6 + 2] = i * 4 + 2; + + iw[i * 6 + 3] = i * 4 + 2; + iw[i * 6 + 4] = i * 4 + 3; + iw[i * 6 + 5] = i * 4 + 0; + } + + //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush + + if (!co->vertex_id) { + glGenBuffers(1, &co->vertex_id); + glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); + glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); + } else { + glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); + glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr()); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + + if (!co->index_id) { + glGenBuffers(1, &co->index_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW); + } else { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr()); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind + + co->len = lc; + } +} +*/ + +RS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const { + return RS::INSTANCE_NONE; + + /* + if (mesh_owner.owns(p_rid)) { + return RS::INSTANCE_MESH; + } else if (light_owner.owns(p_rid)) { + return RS::INSTANCE_LIGHT; + } else if (multimesh_owner.owns(p_rid)) { + return RS::INSTANCE_MULTIMESH; + } else if (immediate_owner.owns(p_rid)) { + return RS::INSTANCE_IMMEDIATE; + } else if (reflection_probe_owner.owns(p_rid)) { + return RS::INSTANCE_REFLECTION_PROBE; + } else if (lightmap_capture_data_owner.owns(p_rid)) { + return RS::INSTANCE_LIGHTMAP_CAPTURE; + } else { + return RS::INSTANCE_NONE; + } +*/ +} + +bool RasterizerStorageGLES3::free(RID p_rid) { + if (render_target_owner.owns(p_rid)) { + RenderTarget *rt = render_target_owner.get_or_null(p_rid); + _render_target_clear(rt); + + Texture *t = texture_owner.get_or_null(rt->texture); + if (t) { + 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_or_null(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_or_null(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_or_null(p_rid); + + if (shader->shader && shader->custom_code_id) { + 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_or_null(p_rid); + + if (m->shader) { + m->shader->materials.remove(&m->list); + } + + /* + for (Map::Element *E = m->geometry_owners.front(); E; E = E->next()) { + Geometry *g = E->key(); + g->material = RID(); + } + + for (Map::Element *E = m->instance_owners.front(); E; E = E->next()) { + InstanceBaseDependency *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 { + return false; + } + /* + } else if (skeleton_owner.owns(p_rid)) { + Skeleton *s = skeleton_owner.get_or_null(p_rid); + + if (s->update_list.in_list()) { + skeleton_update_list.remove(&s->update_list); + } + + for (Set::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_or_null(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_or_null(p_rid); + multimesh->instance_remove_deps(); + + if (multimesh->mesh.is_valid()) { + Mesh *mesh = mesh_owner.get_or_null(multimesh->mesh); + if (mesh) { + mesh->multimeshes.remove(&multimesh->mesh_list); + } + } + + multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_3D, RS::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_or_null(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_or_null(p_rid); + light->instance_remove_deps(); + + light_owner.free(p_rid); + memdelete(light); + + return true; + } else if (reflection_probe_owner.owns(p_rid)) { + // delete the texture + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid); + reflection_probe->instance_remove_deps(); + + reflection_probe_owner.free(p_rid); + memdelete(reflection_probe); + + return true; + } else if (lightmap_capture_data_owner.owns(p_rid)) { + // delete the texture + LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get_or_null(p_rid); + lightmap_capture->instance_remove_deps(); + + lightmap_capture_data_owner.free(p_rid); + memdelete(lightmap_capture); + return true; + + } else if (canvas_occluder_owner.owns(p_rid)) { + CanvasOccluder *co = canvas_occluder_owner.get_or_null(p_rid); + if (co->index_id) + glDeleteBuffers(1, &co->index_id); + if (co->vertex_id) + glDeleteBuffers(1, &co->vertex_id); + + canvas_occluder_owner.free(p_rid); + memdelete(co); + + return true; + + } else if (canvas_light_shadow_owner.owns(p_rid)) { + CanvasLightShadow *cls = canvas_light_shadow_owner.get_or_null(p_rid); + glDeleteFramebuffers(1, &cls->fbo); + glDeleteRenderbuffers(1, &cls->depth); + glDeleteTextures(1, &cls->distance); + canvas_light_shadow_owner.free(p_rid); + memdelete(cls); + + return true; + */ +} + +bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const { + if (p_feature == "pvrtc") + return config.pvrtc_supported; + + if (p_feature == "s3tc") + return config.s3tc_supported; + + if (p_feature == "etc") + return config.etc_supported; + + if (p_feature == "skinning_fallback") + return config.use_skeleton_software; + + return false; +} + +//////////////////////////////////////////// + +void RasterizerStorageGLES3::set_debug_generate_wireframes(bool p_generate) { +} + +//void RasterizerStorageGLES3::render_info_begin_capture() { +// info.snap = info.render; +//} + +//void RasterizerStorageGLES3::render_info_end_capture() { +// info.snap.object_count = info.render.object_count - info.snap.object_count; +// info.snap.draw_call_count = info.render.draw_call_count - info.snap.draw_call_count; +// info.snap.material_switch_count = info.render.material_switch_count - info.snap.material_switch_count; +// info.snap.surface_switch_count = info.render.surface_switch_count - info.snap.surface_switch_count; +// info.snap.shader_rebind_count = info.render.shader_rebind_count - info.snap.shader_rebind_count; +// info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count; +// info.snap._2d_item_count = info.render._2d_item_count - info.snap._2d_item_count; +// info.snap._2d_draw_call_count = info.render._2d_draw_call_count - info.snap._2d_draw_call_count; +//} + +//int RasterizerStorageGLES3::get_captured_render_info(RS::RenderInfo p_info) { +// switch (p_info) { +// case RS::INFO_OBJECTS_IN_FRAME: { +// return info.snap.object_count; +// } break; +// case RS::INFO_VERTICES_IN_FRAME: { +// return info.snap.vertices_count; +// } break; +// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: { +// return info.snap.material_switch_count; +// } break; +// case RS::INFO_SHADER_CHANGES_IN_FRAME: { +// return info.snap.shader_rebind_count; +// } break; +// case RS::INFO_SURFACE_CHANGES_IN_FRAME: { +// return info.snap.surface_switch_count; +// } break; +// case RS::INFO_DRAW_CALLS_IN_FRAME: { +// return info.snap.draw_call_count; +// } break; +// /* +// case RS::INFO_2D_ITEMS_IN_FRAME: { +// return info.snap._2d_item_count; +// } break; +// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: { +// return info.snap._2d_draw_call_count; +// } break; +// */ +// default: { +// return get_render_info(p_info); +// } +// } +//} + +//int RasterizerStorageGLES3::get_render_info(RS::RenderInfo p_info) { +// switch (p_info) { +// case RS::INFO_OBJECTS_IN_FRAME: +// return info.render_final.object_count; +// case RS::INFO_VERTICES_IN_FRAME: +// return info.render_final.vertices_count; +// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: +// return info.render_final.material_switch_count; +// case RS::INFO_SHADER_CHANGES_IN_FRAME: +// return info.render_final.shader_rebind_count; +// case RS::INFO_SURFACE_CHANGES_IN_FRAME: +// return info.render_final.surface_switch_count; +// case RS::INFO_DRAW_CALLS_IN_FRAME: +// return info.render_final.draw_call_count; +// /* +// case RS::INFO_2D_ITEMS_IN_FRAME: +// return info.render_final._2d_item_count; +// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: +// return info.render_final._2d_draw_call_count; +//*/ +// case RS::INFO_USAGE_VIDEO_MEM_TOTAL: +// return 0; //no idea +// case RS::INFO_VIDEO_MEM_USED: +// return info.vertex_mem + info.texture_mem; +// case RS::INFO_TEXTURE_MEM_USED: +// return info.texture_mem; +// case RS::INFO_VERTEX_MEM_USED: +// return info.vertex_mem; +// default: +// return 0; //no idea either +// } +//} + +String RasterizerStorageGLES3::get_video_adapter_name() const { + return (const char *)glGetString(GL_RENDERER); +} + +String RasterizerStorageGLES3::get_video_adapter_vendor() const { + return (const char *)glGetString(GL_VENDOR); +} + +void RasterizerStorageGLES3::initialize() { + RasterizerStorageGLES3::system_fbo = 0; + + { + const GLubyte *extension_string = glGetString(GL_EXTENSIONS); + + Vector extensions = String((const char *)extension_string).split(" "); + + for (int i = 0; i < extensions.size(); i++) { + config.extensions.insert(extensions[i]); + } + } + + // FTODO + config.keep_original_textures = true; // false + config.shrink_textures_x2 = false; + config.depth_internalformat = GL_DEPTH_COMPONENT; + config.depth_type = GL_UNSIGNED_INT; + +#ifdef GLES_OVER_GL + config.float_texture_supported = true; + config.s3tc_supported = true; + config.pvrtc_supported = false; + config.etc_supported = false; + config.support_npot_repeat_mipmap = true; + config.depth_buffer_internalformat = GL_DEPTH_COMPONENT24; +#else + config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); + config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); + config.etc_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1"); + config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc") || config.extensions.has("WEBGL_compressed_texture_pvrtc"); + config.support_npot_repeat_mipmap = config.extensions.has("GL_OES_texture_npot"); + +#ifdef JAVASCRIPT_ENABLED + // RenderBuffer internal format must be 16 bits in WebGL, + // but depth_texture should default to 32 always + // if the implementation doesn't support 32, it should just quietly use 16 instead + // https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/ + config.depth_buffer_internalformat = GL_DEPTH_COMPONENT16; + config.depth_type = GL_UNSIGNED_INT; +#else + // on mobile check for 24 bit depth support for RenderBufferStorage + if (config.extensions.has("GL_OES_depth24")) { + config.depth_buffer_internalformat = _DEPTH_COMPONENT24_OES; + config.depth_type = GL_UNSIGNED_INT; + } else { + config.depth_buffer_internalformat = GL_DEPTH_COMPONENT16; + config.depth_type = GL_UNSIGNED_SHORT; + } +#endif +#endif + +#ifdef GLES_OVER_GL + //TODO: causes huge problems with desktop video drivers. Making false for now, needs to be true to render SCREEN_TEXTURE mipmaps + config.render_to_mipmap_supported = false; +#else + //check if mipmaps can be used for SCREEN_TEXTURE and Glow on Mobile and web platforms + config.render_to_mipmap_supported = config.extensions.has("GL_OES_fbo_render_mipmap") && config.extensions.has("GL_EXT_texture_lod"); +#endif + +#ifdef GLES_OVER_GL + config.use_rgba_2d_shadows = false; + config.support_depth_texture = true; + config.use_rgba_3d_shadows = false; + config.support_depth_cubemaps = true; +#else + config.use_rgba_2d_shadows = !(config.float_texture_supported && config.extensions.has("GL_EXT_texture_rg")); + config.support_depth_texture = config.extensions.has("GL_OES_depth_texture") || config.extensions.has("WEBGL_depth_texture"); + config.use_rgba_3d_shadows = !config.support_depth_texture; + config.support_depth_cubemaps = config.extensions.has("GL_OES_depth_texture_cube_map"); +#endif + +#ifdef GLES_OVER_GL + config.support_32_bits_indices = true; +#else + config.support_32_bits_indices = config.extensions.has("GL_OES_element_index_uint"); +#endif + +#ifdef GLES_OVER_GL + config.support_write_depth = true; +#elif defined(JAVASCRIPT_ENABLED) + config.support_write_depth = false; +#else + config.support_write_depth = config.extensions.has("GL_EXT_frag_depth"); +#endif + + config.support_half_float_vertices = true; +//every platform should support this except web, iOS has issues with their support, so add option to disable +#ifdef JAVASCRIPT_ENABLED + config.support_half_float_vertices = false; +#endif + bool disable_half_float = false; //GLOBAL_GET("rendering/opengl/compatibility/disable_half_float"); + if (disable_half_float) { + config.support_half_float_vertices = false; + } + + config.etc_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); + config.latc_supported = config.extensions.has("GL_EXT_texture_compression_latc"); + config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc"); + config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc"); + config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc") || config.extensions.has("EXT_texture_compression_rgtc"); + config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc") || config.extensions.has("EXT_texture_compression_bptc"); + config.srgb_decode_supported = config.extensions.has("GL_EXT_texture_sRGB_decode"); + //determine formats for depth textures (or renderbuffers) + if (config.support_depth_texture) { + // Will use texture for depth + // have to manually see if we can create a valid framebuffer texture using UNSIGNED_INT, + // as there is no extension to test for this. + GLuint fbo; + glGenFramebuffers(1, &fbo); + bind_framebuffer(fbo); + GLuint depth; + glGenTextures(1, &depth); + glBindTexture(GL_TEXTURE_2D, depth); + glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + bind_framebuffer_system(); + glDeleteFramebuffers(1, &fbo); + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &depth); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + // If it fails, test to see if it supports a framebuffer texture using UNSIGNED_SHORT + // This is needed because many OSX devices don't support either UNSIGNED_INT or UNSIGNED_SHORT +#ifdef GLES_OVER_GL + config.depth_internalformat = GL_DEPTH_COMPONENT16; +#else + // OES_depth_texture extension only specifies GL_DEPTH_COMPONENT. + config.depth_internalformat = GL_DEPTH_COMPONENT; +#endif + config.depth_type = GL_UNSIGNED_SHORT; + + glGenFramebuffers(1, &fbo); + bind_framebuffer(fbo); + + glGenTextures(1, &depth); + glBindTexture(GL_TEXTURE_2D, depth); + glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); + + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + //if it fails again depth textures aren't supported, use rgba shadows and renderbuffer for depth + config.support_depth_texture = false; + config.use_rgba_3d_shadows = true; + } + + bind_framebuffer_system(); + glDeleteFramebuffers(1, &fbo); + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &depth); + } + } + + //picky requirements for these + config.support_shadow_cubemaps = config.support_depth_texture && config.support_write_depth && config.support_depth_cubemaps; + + frame.count = 0; + frame.delta = 0; + frame.current_rt = NULL; + frame.clear_request = false; + + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &config.max_vertex_texture_image_units); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); + + // the use skeleton software path should be used if either float texture is not supported, + // OR max_vertex_texture_image_units is zero + config.use_skeleton_software = (config.float_texture_supported == false) || (config.max_vertex_texture_image_units == 0); + + shaders.copy.init(); + shaders.cubemap_filter.init(); + bool ggx_hq = false; //GLOBAL_GET("rendering/quality/reflections/high_quality_ggx"); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY, !ggx_hq); + + { + // 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 + + glGenTextures(1, &resources.white_tex); + unsigned char whitetexdata[8 * 8 * 3]; + for (int i = 0; i < 8 * 8 * 3; i++) { + whitetexdata[i] = 255; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, resources.white_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenTextures(1, &resources.black_tex); + unsigned char blacktexdata[8 * 8 * 3]; + for (int i = 0; i < 8 * 8 * 3; i++) { + blacktexdata[i] = 0; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, resources.black_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, blacktexdata); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenTextures(1, &resources.normal_tex); + unsigned char normaltexdata[8 * 8 * 3]; + for (int i = 0; i < 8 * 8 * 3; i += 3) { + normaltexdata[i + 0] = 128; + normaltexdata[i + 1] = 128; + normaltexdata[i + 2] = 255; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, resources.normal_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, normaltexdata); + glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + + glGenTextures(1, &resources.aniso_tex); + unsigned char anisotexdata[8 * 8 * 3]; + for (int i = 0; i < 8 * 8 * 3; i += 3) { + anisotexdata[i + 0] = 255; + anisotexdata[i + 1] = 128; + anisotexdata[i + 2] = 0; + } + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, resources.aniso_tex); + 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); + } + + // skeleton buffer + { + resources.skeleton_transform_buffer_size = 0; + glGenBuffers(1, &resources.skeleton_transform_buffer); + } + + // radical inverse vdc cache texture + // used for cubemap filtering + if (true /*||config.float_texture_supported*/) { //uint8 is similar and works everywhere + glGenTextures(1, &resources.radical_inverse_vdc_cache_tex); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, resources.radical_inverse_vdc_cache_tex); + + uint8_t 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] = uint8_t(CLAMP(value * 255.0, 0, 255)); + } + + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, radical_inverse); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //need this for proper sampling + + glBindTexture(GL_TEXTURE_2D, 0); + } + + { + glGenFramebuffers(1, &resources.mipmap_blur_fbo); + glGenTextures(1, &resources.mipmap_blur_color); + } + +#ifdef GLES_OVER_GL + //this needs to be enabled manually in OpenGL 2.1 + + if (config.extensions.has("GL_ARB_seamless_cube_map")) { + glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); + } + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); +#endif + + config.force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); + config.use_fast_texture_filter = false; //GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter"); + //config.should_orphan = GLOBAL_GET("rendering/options/api_usage_legacy/orphan_buffers"); +} + +void RasterizerStorageGLES3::finalize() { +} + +void RasterizerStorageGLES3::_copy_screen() { + bind_quad_array(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); +} + +void RasterizerStorageGLES3::update_memory_info() { +} + +uint64_t RasterizerStorageGLES3::get_rendering_info(RS::RenderingInfo p_info) { + return 0; +} + +void RasterizerStorageGLES3::update_dirty_resources() { + update_dirty_shaders(); + update_dirty_materials(); + // update_dirty_skeletons(); + // update_dirty_multimeshes(); +} + +RasterizerStorageGLES3::RasterizerStorageGLES3() { + RasterizerStorageGLES3::system_fbo = 0; + config.should_orphan = true; +} + +#endif // GLES3_BACKEND_ENABLED diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h new file mode 100644 index 0000000000..eb5614f70f --- /dev/null +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -0,0 +1,1453 @@ +/*************************************************************************/ +/* rasterizer_storage_gles3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef RASTERIZER_STORAGE_OPENGL_H +#define RASTERIZER_STORAGE_OPENGL_H + +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/templates/local_vector.h" +#include "core/templates/rid_owner.h" +#include "core/templates/self_list.h" +#include "drivers/gles3/rasterizer_asserts.h" +#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_storage.h" +#include "servers/rendering/shader_language.h" +#include "shader_compiler_gles3.h" +#include "shader_gles3.h" + +#include "shaders/copy.glsl.gen.h" +#include "shaders/cubemap_filter.glsl.gen.h" + +class RasterizerCanvasGLES3; +class RasterizerSceneGLES3; + +class RasterizerStorageGLES3 : public RendererStorage { + friend class RasterizerGLES3; + + Thread::ID _main_thread_id = 0; + bool _is_main_thread(); + +public: + RasterizerCanvasGLES3 *canvas; + RasterizerSceneGLES3 *scene; + + static GLuint system_fbo; + + struct Config { + bool shrink_textures_x2; + bool use_fast_texture_filter; + bool use_skeleton_software; + + int max_vertex_texture_image_units; + int max_texture_image_units; + int max_texture_size; + + // TODO implement wireframe in OpenGL + // bool generate_wireframes; + + Set extensions; + + bool float_texture_supported; + bool s3tc_supported; + bool latc_supported; + bool rgtc_supported; + bool bptc_supported; + bool etc_supported; + bool etc2_supported; + bool pvrtc_supported; + bool srgb_decode_supported; + + bool keep_original_textures; + + bool force_vertex_shading; + + bool use_rgba_2d_shadows; + bool use_rgba_3d_shadows; + + bool support_32_bits_indices; + bool support_write_depth; + bool support_half_float_vertices; + bool support_npot_repeat_mipmap; + bool support_depth_texture; + bool support_depth_cubemaps; + + bool support_shadow_cubemaps; + + bool render_to_mipmap_supported; + + GLuint depth_internalformat; + GLuint depth_type; + GLuint depth_buffer_internalformat; + + // in some cases the legacy render didn't orphan. We will mark these + // so the user can switch orphaning off for them. + bool should_orphan; + } config; + + struct Resources { + GLuint white_tex; + GLuint black_tex; + GLuint normal_tex; + GLuint aniso_tex; + + GLuint mipmap_blur_fbo; + GLuint mipmap_blur_color; + + GLuint radical_inverse_vdc_cache_tex; + bool use_rgba_2d_shadows; + + GLuint quadie; + + size_t skeleton_transform_buffer_size; + GLuint skeleton_transform_buffer; + LocalVector skeleton_transform_cpu_buffer; + + } resources; + + mutable struct Shaders { + ShaderCompilerGLES3 compiler; + + CopyShaderGLES3 copy; + CubemapFilterShaderGLES3 cubemap_filter; + + ShaderCompilerGLES3::IdentifierActions actions_canvas; + ShaderCompilerGLES3::IdentifierActions actions_scene; + ShaderCompilerGLES3::IdentifierActions actions_particles; + + } shaders; + + struct Info { + uint64_t texture_mem; + uint64_t vertex_mem; + + struct Render { + uint32_t object_count; + uint32_t draw_call_count; + uint32_t material_switch_count; + uint32_t surface_switch_count; + uint32_t shader_rebind_count; + uint32_t vertices_count; + uint32_t _2d_item_count; + uint32_t _2d_draw_call_count; + + void reset() { + object_count = 0; + draw_call_count = 0; + material_switch_count = 0; + surface_switch_count = 0; + shader_rebind_count = 0; + vertices_count = 0; + _2d_item_count = 0; + _2d_draw_call_count = 0; + } + } render, render_final, snap; + + Info() : + texture_mem(0), + vertex_mem(0) { + render.reset(); + render_final.reset(); + } + + } info; + + void bind_quad_array() const; + + ///////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////DATA/////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////// + + /* + struct Instantiable { + RID self; + + SelfList::List instance_list; + + _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { + SelfList *instances = instance_list.first(); + while (instances) { + instances->self()->base_changed(p_aabb, p_materials); + instances = instances->next(); + } + } + + _FORCE_INLINE_ void instance_remove_deps() { + SelfList *instances = instance_list.first(); + + while (instances) { + instances->self()->base_removed(); + instances = instances->next(); + } + } + + Instantiable() {} + + ~Instantiable() {} + }; + + struct GeometryOwner : public Instantiable { + }; + + struct Geometry : public Instantiable { + enum Type { + GEOMETRY_INVALID, + GEOMETRY_SURFACE, + GEOMETRY_IMMEDIATE, + GEOMETRY_MULTISURFACE + }; + + Type type; + RID material; + uint64_t last_pass; + uint32_t index; + + void material_changed_notify() {} + + Geometry() { + last_pass = 0; + index = 0; + } + }; +*/ + ///////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////API//////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////// + + bool can_create_resources_async() const override; + + // TEXTURE API + + enum OpenGLTextureFlags { + TEXTURE_FLAG_MIPMAPS = 1, /// Enable automatic mipmap generation - when available + TEXTURE_FLAG_REPEAT = 2, /// Repeat texture (Tiling), otherwise Clamping + TEXTURE_FLAG_FILTER = 4, /// Create texture with linear (or available) filter + TEXTURE_FLAG_ANISOTROPIC_FILTER = 8, + TEXTURE_FLAG_CONVERT_TO_LINEAR = 16, + TEXTURE_FLAG_MIRRORED_REPEAT = 32, /// Repeat texture, with alternate sections mirrored + TEXTURE_FLAG_USED_FOR_STREAMING = 2048, + TEXTURE_FLAGS_DEFAULT = TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS | TEXTURE_FLAG_FILTER + }; + + struct RenderTarget; + + struct Texture { + RID self; + + Texture *proxy; + Set proxy_owners; + + String path; + uint32_t flags; + int width, height, depth; + int alloc_width, alloc_height; + Image::Format format; + RenderingDevice::TextureType type; + + GLenum target; + GLenum gl_format_cache; + GLenum gl_internal_format_cache; + GLenum gl_type_cache; + + int data_size; + int total_data_size; + bool ignore_mipmaps; + + bool compressed; + + bool srgb; + + int mipmaps; + + bool resize_to_po2; + + bool active; + GLenum tex_id; + + uint16_t stored_cube_sides; + + RenderTarget *render_target; + + Vector> images; + + bool redraw_if_visible; + + RS::TextureDetectCallback detect_3d; + void *detect_3d_ud; + + RS::TextureDetectCallback detect_srgb; + void *detect_srgb_ud; + + RS::TextureDetectCallback detect_normal; + void *detect_normal_ud; + + // some silly opengl shenanigans where + // texture coords start from bottom left, means we need to draw render target textures upside down + // to be compatible with vulkan etc. + bool is_upside_down() const { + if (proxy) + return proxy->is_upside_down(); + + return render_target != nullptr; + } + + Texture() { + create(); + } + + _ALWAYS_INLINE_ Texture *get_ptr() { + if (proxy) { + return proxy; //->get_ptr(); only one level of indirection, else not inlining possible. + } else { + return this; + } + } + + ~Texture() { + destroy(); + + if (tex_id != 0) { + glDeleteTextures(1, &tex_id); + } + } + + void copy_from(const Texture &o) { + proxy = o.proxy; + flags = o.flags; + width = o.width; + height = o.height; + alloc_width = o.alloc_width; + alloc_height = o.alloc_height; + format = o.format; + type = o.type; + target = o.target; + data_size = o.data_size; + total_data_size = o.total_data_size; + ignore_mipmaps = o.ignore_mipmaps; + compressed = o.compressed; + mipmaps = o.mipmaps; + resize_to_po2 = o.resize_to_po2; + active = o.active; + tex_id = o.tex_id; + stored_cube_sides = o.stored_cube_sides; + render_target = o.render_target; + redraw_if_visible = o.redraw_if_visible; + detect_3d = o.detect_3d; + detect_3d_ud = o.detect_3d_ud; + detect_srgb = o.detect_srgb; + detect_srgb_ud = o.detect_srgb_ud; + detect_normal = o.detect_normal; + detect_normal_ud = o.detect_normal_ud; + + images.clear(); + } + + void create() { + proxy = nullptr; + flags = 0; + width = 0; + height = 0; + alloc_width = 0; + alloc_height = 0; + format = Image::FORMAT_L8; + type = RenderingDevice::TEXTURE_TYPE_2D; + target = 0; + data_size = 0; + total_data_size = 0; + ignore_mipmaps = false; + compressed = false; + mipmaps = 0; + resize_to_po2 = false; + active = false; + tex_id = 0; + stored_cube_sides = 0; + render_target = nullptr; + redraw_if_visible = false; + detect_3d = nullptr; + detect_3d_ud = nullptr; + detect_srgb = nullptr; + detect_srgb_ud = nullptr; + detect_normal = nullptr; + detect_normal_ud = nullptr; + } + void destroy() { + images.clear(); + + for (Set::Element *E = proxy_owners.front(); E; E = E->next()) { + E->get()->proxy = NULL; + } + + if (proxy) { + proxy->proxy_owners.erase(this); + } + } + + // texture state + void GLSetFilter(GLenum p_target, RS::CanvasItemTextureFilter p_filter) { + if (p_filter == state_filter) + return; + state_filter = p_filter; + GLint pmin = GL_LINEAR; // param min + GLint pmag = GL_LINEAR; // param mag + switch (state_filter) { + default: { + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: { + pmin = GL_LINEAR_MIPMAP_LINEAR; + pmag = GL_LINEAR; + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: { + pmin = GL_NEAREST; + pmag = GL_NEAREST; + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: { + pmin = GL_NEAREST_MIPMAP_NEAREST; + pmag = GL_NEAREST; + } break; + } + glTexParameteri(p_target, GL_TEXTURE_MIN_FILTER, pmin); + glTexParameteri(p_target, GL_TEXTURE_MAG_FILTER, pmag); + } + void GLSetRepeat(RS::CanvasItemTextureRepeat p_repeat) { + if (p_repeat == state_repeat) + return; + state_repeat = p_repeat; + GLint prep = GL_CLAMP_TO_EDGE; // parameter repeat + switch (state_repeat) { + default: { + } break; + case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: { + prep = GL_REPEAT; + } break; + case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: { + prep = GL_MIRRORED_REPEAT; + } break; + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, prep); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, prep); + } + + private: + RS::CanvasItemTextureFilter state_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; + RS::CanvasItemTextureRepeat state_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; + }; + + mutable RID_PtrOwner texture_owner; + + Ref _get_gl_image_and_format(const Ref &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const; + + void _texture_set_state_from_flags(Texture *p_tex); + + // new + RID texture_allocate() override; + void texture_2d_initialize(RID p_texture, const Ref &p_image) override; + void texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) override; + void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector> &p_data) override; + void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent + + void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) override; + void texture_3d_update(RID p_texture, const Vector> &p_data) override {} + void texture_proxy_update(RID p_proxy, RID p_base) override {} + + void texture_2d_placeholder_initialize(RID p_texture) override; + void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override; + void texture_3d_placeholder_initialize(RID p_texture) override; + + Ref texture_2d_get(RID p_texture) const override; + Ref texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref(); } + Vector> texture_3d_get(RID p_texture) const override { return Vector>(); } + + void texture_replace(RID p_texture, RID p_by_texture) override; + //void texture_set_size_override(RID p_texture, int p_width, int p_height) override {} + + void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} + void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} + + // old + uint32_t texture_get_width(RID p_texture) const; + uint32_t texture_get_height(RID p_texture) const; + +private: + RID texture_create(); + + //void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT); + void _texture_allocate_internal(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT); + + void texture_set_data(RID p_texture, const Ref &p_image, int p_layer = 0); + void texture_set_data_partial(RID p_texture, const Ref &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); + //Ref texture_get_data(RID p_texture, int p_layer = 0) const; + void texture_set_flags(RID p_texture, uint32_t p_flags); + uint32_t texture_get_flags(RID p_texture) const; + Image::Format texture_get_format(RID p_texture) const; + RenderingDevice::TextureType texture_get_type(RID p_texture) const; + uint32_t texture_get_texid(RID p_texture) const; + uint32_t texture_get_depth(RID p_texture) const; + void texture_set_size_override(RID p_texture, int p_width, int p_height) override; + + void texture_bind(RID p_texture, uint32_t p_texture_no); + + void texture_set_path(RID p_texture, const String &p_path) override; + String texture_get_path(RID p_texture) const override; + + void texture_set_shrink_all_x2_on_set_data(bool p_enable); + + void texture_debug_usage(List *r_info) override; + + RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const; + + void textures_keep_original(bool p_enable); + + void texture_set_proxy(RID p_texture, RID p_proxy); + Size2 texture_size_with_proxy(RID p_texture) override; + + void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override; + void texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata); + void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override; + void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override {} + + void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override; + +public: + RID canvas_texture_allocate() override; + void canvas_texture_initialize(RID p_rid) override; + + void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override; + void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override; + + void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override; + void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override; + + /* SKY API */ + // not sure if used in godot 4? + struct Sky { + RID self; + RID panorama; + GLuint radiance; + int radiance_size; + }; + + mutable RID_PtrOwner sky_owner; + + RID sky_create(); + void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size); + + // SHADER API + + struct Material; + + struct Shader { + RID self; + + RS::ShaderMode mode; + ShaderGLES3 *shader; + String code; + SelfList::List materials; + + Map uniforms; + + uint32_t texture_count; + + uint32_t custom_code_id; + uint32_t version; + + SelfList dirty_list; + + Map default_textures; + + Vector texture_hints; + + bool valid; + + String path; + + uint32_t index; + uint64_t last_pass; + + struct CanvasItem { + enum BlendMode { + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + BLEND_MODE_PMALPHA, + }; + + int blend_mode; + + enum LightMode { + LIGHT_MODE_NORMAL, + LIGHT_MODE_UNSHADED, + LIGHT_MODE_LIGHT_ONLY + }; + + int light_mode; + + // these flags are specifically for batching + // some of the logic is thus in rasterizer_storage.cpp + // we could alternatively set bitflags for each 'uses' and test on the fly + // defined in RasterizerStorageCommon::BatchFlags + unsigned int batch_flags; + + bool uses_screen_texture; + bool uses_screen_uv; + bool uses_time; + bool uses_modulate; + bool uses_color; + bool uses_vertex; + + // all these should disable item joining if used in a custom shader + bool uses_world_matrix; + bool uses_extra_matrix; + bool uses_projection_matrix; + bool uses_instance_custom; + + } canvas_item; + + struct Spatial { + enum BlendMode { + BLEND_MODE_MIX, + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL, + }; + + int blend_mode; + + enum DepthDrawMode { + DEPTH_DRAW_OPAQUE, + DEPTH_DRAW_ALWAYS, + DEPTH_DRAW_NEVER, + DEPTH_DRAW_ALPHA_PREPASS, + }; + + int depth_draw_mode; + + enum CullMode { + CULL_MODE_FRONT, + CULL_MODE_BACK, + CULL_MODE_DISABLED, + }; + + int cull_mode; + + bool uses_alpha; + bool uses_alpha_scissor; + bool unshaded; + bool no_depth_test; + bool uses_vertex; + bool uses_discard; + bool uses_sss; + bool uses_screen_texture; + bool uses_depth_texture; + bool uses_time; + bool uses_tangent; + bool uses_ensure_correct_normals; + bool writes_modelview_or_projection; + bool uses_vertex_lighting; + bool uses_world_coordinates; + + } spatial; + + struct Particles { + } particles; + + bool uses_vertex_time; + bool uses_fragment_time; + + Shader() : + dirty_list(this) { + shader = NULL; + valid = false; + custom_code_id = 0; + version = 1; + last_pass = 0; + } + }; + + mutable RID_PtrOwner shader_owner; + mutable SelfList::List _shader_dirty_list; + + void _shader_make_dirty(Shader *p_shader); + + RID shader_allocate() override; + void shader_initialize(RID p_rid) override; + + //RID shader_create() override; + + void shader_set_code(RID p_shader, const String &p_code) override; + String shader_get_code(RID p_shader) const override; + void shader_get_param_list(RID p_shader, List *p_param_list) const override; + + void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) override; + RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const override; + + RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); }; + + void shader_add_custom_define(RID p_shader, const String &p_define); + void shader_get_custom_defines(RID p_shader, Vector *p_defines) const; + void shader_remove_custom_define(RID p_shader, const String &p_define); + + void _update_shader(Shader *p_shader) const; + void update_dirty_shaders(); + + // new + Variant shader_get_param_default(RID p_material, const StringName &p_param) const override { return Variant(); } + + // COMMON MATERIAL API + + struct Material { + RID self; + Shader *shader; + Map params; + SelfList list; + SelfList dirty_list; + Vector> textures; + float line_width; + int render_priority; + + RID next_pass; + + uint32_t index; + uint64_t last_pass; + + // Map geometry_owners; + // Map instance_owners; + + bool can_cast_shadow_cache; + bool is_animated_cache; + + Material() : + list(this), + dirty_list(this) { + can_cast_shadow_cache = false; + is_animated_cache = false; + shader = NULL; + line_width = 1.0; + last_pass = 0; + render_priority = 0; + } + }; + + mutable SelfList::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_PtrOwner material_owner; + + // new + void material_get_instance_shader_parameters(RID p_material, List *r_parameters) override {} + void material_update_dependency(RID p_material, DependencyTracker *p_instance) override {} + + // old + RID material_allocate() override; + void material_initialize(RID p_rid) override; + + //RID material_create() override; + + void material_set_shader(RID p_material, RID p_shader) override; + RID material_get_shader(RID p_material) const; + + void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) override; + Variant material_get_param(RID p_material, const StringName &p_param) const override; + Variant material_get_param_default(RID p_material, const StringName &p_param) const; + + void material_set_line_width(RID p_material, float p_width); + void material_set_next_pass(RID p_material, RID p_next_material) override; + + bool material_is_animated(RID p_material) override; + bool material_casts_shadows(RID p_material) override; + bool material_uses_tangents(RID p_material); + bool material_uses_ensure_correct_normals(RID p_material); + + void material_add_instance_owner(RID p_material, DependencyTracker *p_instance); + void material_remove_instance_owner(RID p_material, DependencyTracker *p_instance); + + void material_set_render_priority(RID p_material, int priority) override; + + void update_dirty_materials(); + + /* MESH API */ + + RID mesh_allocate() override; + void mesh_initialize(RID p_rid) override; + void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override; + bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override; + RID mesh_instance_create(RID p_base) override; + void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override; + void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override; + void mesh_instance_check_for_update(RID p_mesh_instance) override; + void update_mesh_instances() override; + void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) override; + float reflection_probe_get_lod_threshold(RID p_probe) const override; + + void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override; + + int mesh_get_blend_shape_count(RID p_mesh) const override; + + void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override; + RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override; + + void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) override; + void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) override; + void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) override; + + void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override; + RID mesh_surface_get_material(RID p_mesh, int p_surface) const override; + + RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override; + int mesh_get_surface_count(RID p_mesh) const override; + + void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override; + AABB mesh_get_custom_aabb(RID p_mesh) const override; + + AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override; + void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override; + void mesh_clear(RID p_mesh) override; + + /* MULTIMESH API */ + + RID multimesh_allocate() override; + void multimesh_initialize(RID p_rid) override; + void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override; + int multimesh_get_instance_count(RID p_multimesh) const override; + + void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override; + void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override; + void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override; + void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override; + void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override; + + RID multimesh_get_mesh(RID p_multimesh) const override; + AABB multimesh_get_aabb(RID p_multimesh) const override; + + Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override; + Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override; + Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override; + Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override; + void multimesh_set_buffer(RID p_multimesh, const Vector &p_buffer) override; + Vector multimesh_get_buffer(RID p_multimesh) const override; + + void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override; + int multimesh_get_visible_instances(RID p_multimesh) const override; + + /* SKELETON API */ + + RID skeleton_allocate() override; + void skeleton_initialize(RID p_rid) override; + void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override; + void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override; + int skeleton_get_bone_count(RID p_skeleton) const override; + void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override; + Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override; + void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override; + Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override; + + /* Light API */ + + RID directional_light_allocate() override; + void directional_light_initialize(RID p_rid) override; + RID omni_light_allocate() override; + void omni_light_initialize(RID p_rid) override; + RID spot_light_allocate() override; + void spot_light_initialize(RID p_rid) override; + RID reflection_probe_allocate() override; + void reflection_probe_initialize(RID p_rid) override; + + void light_set_color(RID p_light, const Color &p_color) override; + void light_set_param(RID p_light, RS::LightParam p_param, float p_value) override; + void light_set_shadow(RID p_light, bool p_enabled) override; + void light_set_shadow_color(RID p_light, const Color &p_color) override; + void light_set_projector(RID p_light, RID p_texture) override; + void light_set_negative(RID p_light, bool p_enable) override; + void light_set_cull_mask(RID p_light, uint32_t p_mask) override; + void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override; + void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override; + void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override; + + void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) override; + + void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) override; + void light_directional_set_blend_splits(RID p_light, bool p_enable) override; + bool light_directional_get_blend_splits(RID p_light) const override; + void light_directional_set_sky_only(RID p_light, bool p_sky_only) override; + bool light_directional_is_sky_only(RID p_light) const override; + + RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override; + RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override; + + bool light_has_shadow(RID p_light) const override; + bool light_has_projector(RID p_light) const override; + + RS::LightType light_get_type(RID p_light) const override; + AABB light_get_aabb(RID p_light) const override; + float light_get_param(RID p_light, RS::LightParam p_param) override; + Color light_get_color(RID p_light) override; + RS::LightBakeMode light_get_bake_mode(RID p_light) override; + uint32_t light_get_max_sdfgi_cascade(RID p_light) override; + uint64_t light_get_version(RID p_light) const override; + + /* PROBE API */ + + void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) override; + void reflection_probe_set_intensity(RID p_probe, float p_intensity) override; + void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) override; + void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) override; + void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) override; + void reflection_probe_set_max_distance(RID p_probe, float p_distance) override; + void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) override; + void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) override; + void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override; + void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override; + void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override; + void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override; + void reflection_probe_set_resolution(RID p_probe, int p_resolution) override; + + AABB reflection_probe_get_aabb(RID p_probe) const override; + RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override; + uint32_t reflection_probe_get_cull_mask(RID p_probe) const override; + Vector3 reflection_probe_get_extents(RID p_probe) const override; + Vector3 reflection_probe_get_origin_offset(RID p_probe) const override; + float reflection_probe_get_origin_max_distance(RID p_probe) const override; + bool reflection_probe_renders_shadows(RID p_probe) const override; + + void base_update_dependency(RID p_base, DependencyTracker *p_instance) override; + void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override; + + /* DECAL API */ + + RID decal_allocate() override; + void decal_initialize(RID p_rid) override; + void decal_set_extents(RID p_decal, const Vector3 &p_extents) override; + void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override; + void decal_set_emission_energy(RID p_decal, float p_energy) override; + void decal_set_albedo_mix(RID p_decal, float p_mix) override; + void decal_set_modulate(RID p_decal, const Color &p_modulate) override; + void decal_set_cull_mask(RID p_decal, uint32_t p_layers) override; + void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) override; + void decal_set_fade(RID p_decal, float p_above, float p_below) override; + void decal_set_normal_fade(RID p_decal, float p_fade) override; + + AABB decal_get_aabb(RID p_decal) const override; + + /* VOXEL GI API */ + + RID voxel_gi_allocate() override; + void voxel_gi_initialize(RID p_rid) override; + void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector &p_octree_cells, const Vector &p_data_cells, const Vector &p_distance_field, const Vector &p_level_counts) override; + + AABB voxel_gi_get_bounds(RID p_voxel_gi) const override; + Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override; + Vector voxel_gi_get_octree_cells(RID p_voxel_gi) const override; + Vector voxel_gi_get_data_cells(RID p_voxel_gi) const override; + Vector voxel_gi_get_distance_field(RID p_voxel_gi) const override; + + Vector voxel_gi_get_level_counts(RID p_voxel_gi) const override; + Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override; + + void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override; + float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override; + + void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override; + float voxel_gi_get_propagation(RID p_voxel_gi) const override; + + void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override; + float voxel_gi_get_energy(RID p_voxel_gi) const override; + + void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override; + float voxel_gi_get_bias(RID p_voxel_gi) const override; + + void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override; + float voxel_gi_get_normal_bias(RID p_voxel_gi) const override; + + void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override; + bool voxel_gi_is_interior(RID p_voxel_gi) const override; + + void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override; + bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override; + + void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) override; + float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const override; + + uint32_t voxel_gi_get_version(RID p_voxel_gi) override; + + /* LIGHTMAP CAPTURE */ + RID lightmap_allocate() override; + void lightmap_initialize(RID p_rid) override; + void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override; + void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override; + void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override; + void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) override; + PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override; + PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override; + PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override; + PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const override; + AABB lightmap_get_aabb(RID p_lightmap) const override; + void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) override; + bool lightmap_is_interior(RID p_lightmap) const override; + void lightmap_set_probe_capture_update_speed(float p_speed) override; + float lightmap_get_probe_capture_update_speed() const override; + + /* OCCLUDER */ + + void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices); + + /* PARTICLES */ + + RID particles_allocate() override; + void particles_initialize(RID p_rid) override; + void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override; + void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override; + void particles_set_emitting(RID p_particles, bool p_emitting) override; + void particles_set_amount(RID p_particles, int p_amount) override; + void particles_set_lifetime(RID p_particles, double p_lifetime) override; + void particles_set_one_shot(RID p_particles, bool p_one_shot) override; + void particles_set_pre_process_time(RID p_particles, double p_time) override; + void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) override; + void particles_set_randomness_ratio(RID p_particles, real_t p_ratio) override; + void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override; + void particles_set_speed_scale(RID p_particles, double p_scale) override; + void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override; + void particles_set_process_material(RID p_particles, RID p_material) override; + void particles_set_fixed_fps(RID p_particles, int p_fps) override; + void particles_set_interpolate(RID p_particles, bool p_enable) override; + void particles_set_fractional_delta(RID p_particles, bool p_enable) override; + void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override; + void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) override; + void particles_set_collision_base_size(RID p_particles, real_t p_size) override; + + void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override; + + void particles_set_trails(RID p_particles, bool p_enable, double p_length) override; + void particles_set_trail_bind_poses(RID p_particles, const Vector &p_bind_poses) override; + + void particles_restart(RID p_particles) override; + + void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override; + + void particles_set_draw_passes(RID p_particles, int p_count) override; + void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) override; + + void particles_request_process(RID p_particles) override; + AABB particles_get_current_aabb(RID p_particles) override; + AABB particles_get_aabb(RID p_particles) const override; + + void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override; + + bool particles_get_emitting(RID p_particles) override; + int particles_get_draw_passes(RID p_particles) const override; + RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override; + + void particles_add_collision(RID p_particles, RID p_instance) override; + void particles_remove_collision(RID p_particles, RID p_instance) override; + + void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override; + + void update_particles() override; + + /* PARTICLES COLLISION */ + + RID particles_collision_allocate() override; + void particles_collision_initialize(RID p_rid) override; + void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) override; + void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) override; + void particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) override; + void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) override; + void particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) override; + void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) override; + void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) override; + void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) override; + void particles_collision_height_field_update(RID p_particles_collision) override; + void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override; + AABB particles_collision_get_aabb(RID p_particles_collision) const override; + bool particles_collision_is_heightfield(RID p_particles_collision) const override; + RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override; + + RID particles_collision_instance_create(RID p_collision) override; + void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override; + void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override; + + /* FOG VOLUMES */ + + RID fog_volume_allocate() override; + void fog_volume_initialize(RID p_rid) override; + + void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override; + void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override; + void fog_volume_set_material(RID p_fog_volume, RID p_material) override; + AABB fog_volume_get_aabb(RID p_fog_volume) const override; + RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override; + + /* VISIBILITY NOTIFIER */ + RID visibility_notifier_allocate() override; + void visibility_notifier_initialize(RID p_notifier) override; + void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override; + void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override; + + AABB visibility_notifier_get_aabb(RID p_notifier) const override; + void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override; + + /* GLOBAL VARIABLES */ + + void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) override; + void global_variable_remove(const StringName &p_name) override; + Vector global_variable_get_list() const override; + + void global_variable_set(const StringName &p_name, const Variant &p_value) override; + void global_variable_set_override(const StringName &p_name, const Variant &p_value) override; + Variant global_variable_get(const StringName &p_name) const override; + RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const override; + + void global_variables_load_settings(bool p_load_textures = true) override; + void global_variables_clear() override; + + int32_t global_variables_instance_allocate(RID p_instance) override; + void global_variables_instance_free(RID p_instance) override; + void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) override; + + bool particles_is_inactive(RID p_particles) const override; + + // RENDER TARGET + + struct RenderTarget { + RID self; + GLuint fbo; + GLuint color; + GLuint depth; + + GLuint multisample_fbo; + GLuint multisample_color; + GLuint multisample_depth; + bool multisample_active; + + struct Effect { + GLuint fbo; + int width; + int height; + + GLuint color; + + Effect() : + fbo(0), + width(0), + height(0), + color(0) { + } + }; + + Effect copy_screen_effect; + + struct MipMaps { + struct Size { + GLuint fbo; + GLuint color; + int width; + int height; + }; + + Vector sizes; + GLuint color; + int levels; + + MipMaps() : + color(0), + levels(0) { + } + }; + + MipMaps mip_maps[2]; + + struct External { + GLuint fbo; + GLuint color; + GLuint depth; + RID texture; + + External() : + fbo(0), + color(0), + depth(0) { + } + } external; + + int x, y, width, height; + + bool flags[RENDER_TARGET_FLAG_MAX]; + + // instead of allocating sized render targets immediately, + // defer this for faster startup + bool allocate_is_dirty = false; + bool used_in_frame; + RS::ViewportMSAA msaa; + + bool use_fxaa; + bool use_debanding; + + RID texture; + + bool used_dof_blur_near; + bool mip_maps_allocated; + + Color clear_color; + bool clear_requested; + + RenderTarget() : + fbo(0), + color(0), + depth(0), + multisample_fbo(0), + multisample_color(0), + multisample_depth(0), + multisample_active(false), + x(0), + y(0), + width(0), + height(0), + used_in_frame(false), + msaa(RS::VIEWPORT_MSAA_DISABLED), + use_fxaa(false), + use_debanding(false), + used_dof_blur_near(false), + mip_maps_allocated(false), + clear_color(Color(1, 1, 1, 1)), + clear_requested(false) { + for (int i = 0; i < RENDER_TARGET_FLAG_MAX; ++i) { + flags[i] = false; + } + external.fbo = 0; + } + }; + + mutable RID_PtrOwner render_target_owner; + + void _render_target_clear(RenderTarget *rt); + void _render_target_allocate(RenderTarget *rt); + void _set_current_render_target(RID p_render_target); + + RID render_target_create() override; + void render_target_set_position(RID p_render_target, int p_x, int p_y) override; + void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override; + RID render_target_get_texture(RID p_render_target) override; + void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override; + + void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override; + bool render_target_was_used(RID p_render_target) override; + void render_target_clear_used(RID p_render_target); + void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa); + void render_target_set_use_fxaa(RID p_render_target, bool p_fxaa); + void render_target_set_use_debanding(RID p_render_target, bool p_debanding); + + // new + void render_target_set_as_unused(RID p_render_target) override { + render_target_clear_used(p_render_target); + } + + void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override; + bool render_target_is_clear_requested(RID p_render_target) override; + Color render_target_get_clear_request_color(RID p_render_target) override; + void render_target_disable_clear_request(RID p_render_target) override; + void render_target_do_clear_request(RID p_render_target) override; + + void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override; + Rect2i render_target_get_sdf_rect(RID p_render_target) const override; + void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override; + + // access from canvas + // RenderTarget * render_target_get(RID p_render_target); + + /* CANVAS SHADOW */ + + struct CanvasLightShadow { + RID self; + int size; + int height; + GLuint fbo; + GLuint depth; + GLuint distance; //for older devices + }; + + RID_PtrOwner canvas_light_shadow_owner; + + RID canvas_light_shadow_buffer_create(int p_width); + + /* LIGHT SHADOW MAPPING */ + /* + struct CanvasOccluder { + RID self; + + GLuint vertex_id; // 0 means, unconfigured + GLuint index_id; // 0 means, unconfigured + LocalVector lines; + int len; + }; + + RID_Owner canvas_occluder_owner; + + RID canvas_light_occluder_create(); + void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector &p_lines); +*/ + + RS::InstanceType get_base_type(RID p_rid) const override; + + bool free(RID p_rid) override; + + struct Frame { + RenderTarget *current_rt; + + // these 2 may have been superceded by the equivalents in the render target. + // these may be able to be removed. + bool clear_request; + Color clear_request_color; + + float time[4]; + float delta; + uint64_t count; + + Frame() { + // current_rt = nullptr; + // clear_request = false; + } + } frame; + + void initialize(); + void finalize(); + + void _copy_screen(); + + void update_memory_info() override; + uint64_t get_rendering_info(RS::RenderingInfo p_info) override; + + bool has_os_feature(const String &p_feature) const override; + + void update_dirty_resources() override; + + void set_debug_generate_wireframes(bool p_generate) override; + + // void render_info_begin_capture() override; + // void render_info_end_capture() override; + // int get_captured_render_info(RS::RenderInfo p_info) override; + + // int get_render_info(RS::RenderInfo p_info) override; + String get_video_adapter_name() const override; + String get_video_adapter_vendor() const override; + + void capture_timestamps_begin() override {} + void capture_timestamp(const String &p_name) override {} + uint32_t get_captured_timestamps_count() const override { + return 0; + } + uint64_t get_captured_timestamps_frame() const override { + return 0; + } + uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override { + return 0; + } + uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override { + return 0; + } + String get_captured_timestamp_name(uint32_t p_index) const override { + return String(); + } + + // make access easier to these + struct Dimensions { + // render target + int rt_width; + int rt_height; + + // window + int win_width; + int win_height; + Dimensions() { + rt_width = 0; + rt_height = 0; + win_width = 0; + win_height = 0; + } + } _dims; + + void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false) const; + bool safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const; + + void bind_framebuffer(GLuint framebuffer) { + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); + } + + void bind_framebuffer_system() { + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); + } + + RasterizerStorageGLES3(); +}; + +inline bool RasterizerStorageGLES3::safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const { + r_offset_after = p_offset + p_data_size; +#ifdef DEBUG_ENABLED + // we are trying to write across the edge of the buffer + if (r_offset_after > p_total_buffer_size) + return false; +#endif + glBufferSubData(p_target, p_offset, p_data_size, p_data); + return true; +} + +// standardize the orphan / upload in one place so it can be changed per platform as necessary, and avoid future +// bugs causing pipeline stalls +inline void RasterizerStorageGLES3::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) const { + // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData + // Was previously #ifndef GLES_OVER_GL however this causes stalls on desktop mac also (and possibly other) + if (!p_optional_orphan || (config.should_orphan)) { + glBufferData(p_target, p_buffer_size, NULL, p_usage); +#ifdef RASTERIZER_EXTRA_CHECKS + // fill with garbage off the end of the array + if (p_buffer_size) { + unsigned int start = p_offset + p_data_size; + unsigned int end = start + 1024; + if (end < p_buffer_size) { + uint8_t *garbage = (uint8_t *)alloca(1024); + for (int n = 0; n < 1024; n++) { + garbage[n] = Math::random(0, 255); + } + glBufferSubData(p_target, start, 1024, garbage); + } + } +#endif + } + RAST_DEV_DEBUG_ASSERT((p_offset + p_data_size) <= p_buffer_size); + glBufferSubData(p_target, p_offset, p_data_size, p_data); +} + +#endif // GLES3_BACKEND_ENABLED + +#endif // RASTERIZER_STORAGE_OPENGL_H diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp new file mode 100644 index 0000000000..fa607472d3 --- /dev/null +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -0,0 +1,1120 @@ +/*************************************************************************/ +/* shader_compiler_gles3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "shader_compiler_gles3.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/config/project_settings.h" +#include "core/os/os.h" +#include "core/string/string_buffer.h" +#include "core/string/string_builder.h" + +#define SL ShaderLanguage + +static String _mktab(int p_level) { + String tb; + for (int i = 0; i < p_level; i++) { + tb += "\t"; + } + + return tb; +} + +static String _typestr(SL::DataType p_type) { + return ShaderLanguage::get_datatype_name(p_type); +} + +static String _prestr(SL::DataPrecision p_pres) { + switch (p_pres) { + case SL::PRECISION_LOWP: + return "lowp "; + case SL::PRECISION_MEDIUMP: + return "mediump "; + case SL::PRECISION_HIGHP: + return "highp "; + case SL::PRECISION_DEFAULT: + return ""; + } + return ""; +} + +static String _qualstr(SL::ArgumentQualifier p_qual) { + switch (p_qual) { + case SL::ARGUMENT_QUALIFIER_IN: + return "in "; + case SL::ARGUMENT_QUALIFIER_OUT: + return "out "; + case SL::ARGUMENT_QUALIFIER_INOUT: + return "inout "; + } + return ""; +} + +static String _opstr(SL::Operator p_op) { + return SL::get_operator_text(p_op); +} + +static String _mkid(const String &p_id) { + String id = "m_" + p_id.replace("__", "_dus_"); + return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl +} + +static String f2sp0(float p_float) { + String num = rtoss(p_float); + if (num.find(".") == -1 && num.find("e") == -1) { + num += ".0"; + } + return num; +} + +static String get_constant_text(SL::DataType p_type, const Vector &p_values) { + switch (p_type) { + case SL::TYPE_BOOL: + return p_values[0].boolean ? "true" : "false"; + case SL::TYPE_BVEC2: + case SL::TYPE_BVEC3: + case SL::TYPE_BVEC4: { + StringBuffer<> text; + + text += "bvec"; + text += itos(p_type - SL::TYPE_BOOL + 1); + text += "("; + + for (int i = 0; i < p_values.size(); i++) { + if (i > 0) + text += ","; + + text += p_values[i].boolean ? "true" : "false"; + } + text += ")"; + return text.as_string(); + } + + // GLSL ES 2 doesn't support uints, so we just use signed ints instead... + case SL::TYPE_UINT: + return itos(p_values[0].uint); + case SL::TYPE_UVEC2: + case SL::TYPE_UVEC3: + case SL::TYPE_UVEC4: { + StringBuffer<> text; + + text += "ivec"; + text += itos(p_type - SL::TYPE_UINT + 1); + text += "("; + + for (int i = 0; i < p_values.size(); i++) { + if (i > 0) + text += ","; + + text += itos(p_values[i].uint); + } + text += ")"; + return text.as_string(); + + } break; + + case SL::TYPE_INT: + return itos(p_values[0].sint); + case SL::TYPE_IVEC2: + case SL::TYPE_IVEC3: + case SL::TYPE_IVEC4: { + StringBuffer<> text; + + text += "ivec"; + text += itos(p_type - SL::TYPE_INT + 1); + text += "("; + + for (int i = 0; i < p_values.size(); i++) { + if (i > 0) + text += ","; + + text += itos(p_values[i].sint); + } + text += ")"; + return text.as_string(); + + } break; + case SL::TYPE_FLOAT: + return f2sp0(p_values[0].real); + case SL::TYPE_VEC2: + case SL::TYPE_VEC3: + case SL::TYPE_VEC4: { + StringBuffer<> text; + + text += "vec"; + text += itos(p_type - SL::TYPE_FLOAT + 1); + text += "("; + + for (int i = 0; i < p_values.size(); i++) { + if (i > 0) + text += ","; + + text += f2sp0(p_values[i].real); + } + text += ")"; + return text.as_string(); + + } break; + case SL::TYPE_MAT2: + case SL::TYPE_MAT3: + case SL::TYPE_MAT4: { + StringBuffer<> text; + + text += "mat"; + text += itos(p_type - SL::TYPE_MAT2 + 2); + text += "("; + + for (int i = 0; i < p_values.size(); i++) { + if (i > 0) + text += ","; + + text += f2sp0(p_values[i].real); + } + text += ")"; + return text.as_string(); + + } break; + default: + ERR_FAIL_V(String()); + } +} + +void ShaderCompilerGLES3::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, StringBuilder &r_to_add, Set &r_added) { + int fidx = -1; + + for (int i = 0; i < p_node->functions.size(); i++) { + if (p_node->functions[i].name == p_for_func) { + fidx = i; + break; + } + } + + ERR_FAIL_COND(fidx == -1); + + for (Set::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) { + if (r_added.has(E->get())) { + continue; + } + + _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, r_added); + + SL::FunctionNode *fnode = NULL; + + for (int i = 0; i < p_node->functions.size(); i++) { + if (p_node->functions[i].name == E->get()) { + fnode = p_node->functions[i].function; + break; + } + } + + ERR_FAIL_COND(!fnode); + + r_to_add += "\n"; + + StringBuffer<128> header; + + header += _typestr(fnode->return_type); + header += " "; + header += _mkid(fnode->name); + header += "("; + + for (int i = 0; i < fnode->arguments.size(); i++) { + if (i > 0) + header += ", "; + + header += _qualstr(fnode->arguments[i].qualifier); + header += _prestr(fnode->arguments[i].precision); + header += _typestr(fnode->arguments[i].type); + header += " "; + header += _mkid(fnode->arguments[i].name); + } + + header += ")\n"; + r_to_add += header.as_string(); + r_to_add += p_func_code[E->get()]; + + r_added.insert(E->get()); + } +} + +String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) { + StringBuilder code; + + switch (p_node->type) { + default: { + } break; + case SL::Node::TYPE_SHADER: { + SL::ShaderNode *snode = (SL::ShaderNode *)p_node; + + for (int i = 0; i < snode->render_modes.size(); i++) { + if (p_default_actions.render_mode_defines.has(snode->render_modes[i]) && !used_rmode_defines.has(snode->render_modes[i])) { + r_gen_code.custom_defines.push_back(p_default_actions.render_mode_defines[snode->render_modes[i]].utf8()); + used_rmode_defines.insert(snode->render_modes[i]); + } + + if (p_actions.render_mode_flags.has(snode->render_modes[i])) { + *p_actions.render_mode_flags[snode->render_modes[i]] = true; + } + + if (p_actions.render_mode_values.has(snode->render_modes[i])) { + Pair &p = p_actions.render_mode_values[snode->render_modes[i]]; + *p.first = p.second; + } + } + + int max_texture_uniforms = 0; + int max_uniforms = 0; + + for (Map::Element *E = snode->uniforms.front(); E; E = E->next()) { + if (SL::is_sampler_type(E->get().type)) + max_texture_uniforms++; + else + max_uniforms++; + } + + r_gen_code.texture_uniforms.resize(max_texture_uniforms); + r_gen_code.texture_hints.resize(max_texture_uniforms); + + r_gen_code.uniforms.resize(max_uniforms + max_texture_uniforms); + + StringBuilder vertex_global; + StringBuilder fragment_global; + + // uniforms + + for (Map::Element *E = snode->uniforms.front(); E; E = E->next()) { + StringBuffer<> uniform_code; + + // use highp if no precision is specified to prevent different default values in fragment and vertex shader + SL::DataPrecision precision = E->get().precision; + if (precision == SL::PRECISION_DEFAULT && E->get().type != SL::TYPE_BOOL) { + precision = SL::PRECISION_HIGHP; + } + + uniform_code += "uniform "; + uniform_code += _prestr(precision); + uniform_code += _typestr(E->get().type); + uniform_code += " "; + uniform_code += _mkid(E->key()); + uniform_code += ";\n"; + + if (SL::is_sampler_type(E->get().type)) { + 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.write[E->get().order] = E->key(); + } + + vertex_global += uniform_code.as_string(); + fragment_global += uniform_code.as_string(); + + p_actions.uniforms->insert(E->key(), E->get()); + } + + // varyings + + for (Map::Element *E = snode->varyings.front(); E; E = E->next()) { + StringBuffer<> varying_code; + + varying_code += "varying "; + varying_code += _prestr(E->get().precision); + varying_code += _typestr(E->get().type); + varying_code += " "; + varying_code += _mkid(E->key()); + if (E->get().array_size > 0) { + varying_code += "["; + varying_code += itos(E->get().array_size); + varying_code += "]"; + } + varying_code += ";\n"; + + String final_code = varying_code.as_string(); + + vertex_global += final_code; + fragment_global += final_code; + } + + // constants + + for (int i = 0; i < snode->vconstants.size(); i++) { + String gcode; + gcode += "const "; + gcode += _prestr(snode->vconstants[i].precision); + gcode += _typestr(snode->vconstants[i].type); + gcode += " " + _mkid(String(snode->vconstants[i].name)); + gcode += "="; + gcode += _dump_node_code(snode->vconstants[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + gcode += ";\n"; + vertex_global += gcode; + fragment_global += gcode; + } + + // functions + + Map function_code; + + for (int i = 0; i < snode->functions.size(); i++) { + SL::FunctionNode *fnode = snode->functions[i].function; + current_func_name = fnode->name; + function_code[fnode->name] = _dump_node_code(fnode->body, 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } + + Set added_vertex; + Set added_fragment; + + for (int i = 0; i < snode->functions.size(); i++) { + SL::FunctionNode *fnode = snode->functions[i].function; + + current_func_name = fnode->name; + + if (fnode->name == vertex_name) { + _dump_function_deps(snode, fnode->name, function_code, vertex_global, added_vertex); + r_gen_code.vertex = function_code[vertex_name]; + + } else if (fnode->name == fragment_name) { + _dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment); + r_gen_code.fragment = function_code[fragment_name]; + + } else if (fnode->name == light_name) { + _dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment); + r_gen_code.light = function_code[light_name]; + } + } + + r_gen_code.vertex_global = vertex_global.as_string(); + r_gen_code.fragment_global = fragment_global.as_string(); + + } break; + + case SL::Node::TYPE_FUNCTION: { + } break; + + case SL::Node::TYPE_BLOCK: { + SL::BlockNode *bnode = (SL::BlockNode *)p_node; + + if (!bnode->single_statement) { + code += _mktab(p_level - 1); + code += "{\n"; + } + + for (int i = 0; i < bnode->statements.size(); i++) { + String statement_code = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + + if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) { + code += statement_code; + } else { + code += _mktab(p_level); + code += statement_code; + code += ";\n"; + } + } + + if (!bnode->single_statement) { + code += _mktab(p_level - 1); + code += "}\n"; + } + } break; + + case SL::Node::TYPE_VARIABLE_DECLARATION: { + SL::VariableDeclarationNode *var_dec_node = (SL::VariableDeclarationNode *)p_node; + + StringBuffer<> declaration; + if (var_dec_node->is_const) { + declaration += "const "; + } + declaration += _prestr(var_dec_node->precision); + declaration += _typestr(var_dec_node->datatype); + + for (int i = 0; i < var_dec_node->declarations.size(); i++) { + if (i > 0) { + declaration += ","; + } + + declaration += " "; + + declaration += _mkid(var_dec_node->declarations[i].name); + + if (var_dec_node->declarations[i].initializer) { + declaration += " = "; + declaration += _dump_node_code(var_dec_node->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } + } + + code += declaration.as_string(); + } break; + + case SL::Node::TYPE_VARIABLE: { + SL::VariableNode *var_node = (SL::VariableNode *)p_node; + + if (p_assigning && p_actions.write_flag_pointers.has(var_node->name)) { + *p_actions.write_flag_pointers[var_node->name] = true; + } + + if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { + String define = p_default_actions.usage_defines[var_node->name]; + String node_name = define.substr(1, define.length()); + + if (define.begins_with("@")) { + define = p_default_actions.usage_defines[node_name]; + } + + if (!used_name_defines.has(node_name)) { + r_gen_code.custom_defines.push_back(define.utf8()); + } + used_name_defines.insert(var_node->name); + } + + if (p_actions.usage_flag_pointers.has(var_node->name) && !used_flag_pointers.has(var_node->name)) { + *p_actions.usage_flag_pointers[var_node->name] = true; + used_flag_pointers.insert(var_node->name); + } + + if (p_default_actions.renames.has(var_node->name)) { + code += p_default_actions.renames[var_node->name]; + } else { + code += _mkid(var_node->name); + } + + if (var_node->name == time_name) { + if (current_func_name == vertex_name) { + r_gen_code.uses_vertex_time = true; + } + if (current_func_name == fragment_name || current_func_name == light_name) { + r_gen_code.uses_fragment_time = true; + } + } + } break; + case SL::Node::TYPE_ARRAY_DECLARATION: { + SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node; + + StringBuffer<> declaration; + declaration += _prestr(arr_dec_node->precision); + declaration += _typestr(arr_dec_node->datatype); + + for (int i = 0; i < arr_dec_node->declarations.size(); i++) { + if (i > 0) { + declaration += ","; + } + + declaration += " "; + + declaration += _mkid(arr_dec_node->declarations[i].name); + declaration += "["; + declaration += itos(arr_dec_node->declarations[i].size); + declaration += "]"; + } + + code += declaration.as_string(); + } break; + case SL::Node::TYPE_ARRAY: { + SL::ArrayNode *arr_node = (SL::ArrayNode *)p_node; + + if (p_assigning && p_actions.write_flag_pointers.has(arr_node->name)) { + *p_actions.write_flag_pointers[arr_node->name] = true; + } + + if (p_default_actions.usage_defines.has(arr_node->name) && !used_name_defines.has(arr_node->name)) { + String define = p_default_actions.usage_defines[arr_node->name]; + String node_name = define.substr(1, define.length()); + + if (define.begins_with("@")) { + define = p_default_actions.usage_defines[node_name]; + } + + if (!used_name_defines.has(node_name)) { + r_gen_code.custom_defines.push_back(define.utf8()); + } + used_name_defines.insert(arr_node->name); + } + + if (p_actions.usage_flag_pointers.has(arr_node->name) && !used_flag_pointers.has(arr_node->name)) { + *p_actions.usage_flag_pointers[arr_node->name] = true; + used_flag_pointers.insert(arr_node->name); + } + + if (p_default_actions.renames.has(arr_node->name)) { + code += p_default_actions.renames[arr_node->name]; + } else { + code += _mkid(arr_node->name); + } + + if (arr_node->call_expression != NULL) { + code += "."; + code += _dump_node_code(arr_node->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning, false); + } + + if (arr_node->index_expression != NULL) { + code += "["; + code += _dump_node_code(arr_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += "]"; + } + + if (arr_node->name == time_name) { + if (current_func_name == vertex_name) { + r_gen_code.uses_vertex_time = true; + } + if (current_func_name == fragment_name || current_func_name == light_name) { + r_gen_code.uses_fragment_time = true; + } + } + + } break; + case SL::Node::TYPE_CONSTANT: { + SL::ConstantNode *const_node = (SL::ConstantNode *)p_node; + + return get_constant_text(const_node->datatype, const_node->values); + } break; + + case SL::Node::TYPE_OPERATOR: { + SL::OperatorNode *op_node = (SL::OperatorNode *)p_node; + + switch (op_node->op) { + case SL::OP_ASSIGN: + case SL::OP_ASSIGN_ADD: + case SL::OP_ASSIGN_SUB: + case SL::OP_ASSIGN_MUL: + case SL::OP_ASSIGN_DIV: + case SL::OP_ASSIGN_SHIFT_LEFT: + case SL::OP_ASSIGN_SHIFT_RIGHT: + case SL::OP_ASSIGN_BIT_AND: + case SL::OP_ASSIGN_BIT_OR: + case SL::OP_ASSIGN_BIT_XOR: { + code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true); + code += " "; + code += _opstr(op_node->op); + code += " "; + 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: { + String a = _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + String n = _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += a + " = " + n + " == 0 ? 0 : "; + code += a + " - " + n + " * (" + a + " / " + n + ")"; + } break; + + case SL::OP_BIT_INVERT: + case SL::OP_NEGATE: + case SL::OP_NOT: + case SL::OP_DECREMENT: + case SL::OP_INCREMENT: { + code += _opstr(op_node->op); + code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } break; + + case SL::OP_POST_DECREMENT: + case SL::OP_POST_INCREMENT: { + code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _opstr(op_node->op); + } break; + + case SL::OP_CALL: + case SL::OP_CONSTRUCT: { + ERR_FAIL_COND_V(op_node->arguments[0]->type != SL::Node::TYPE_VARIABLE, String()); + + SL::VariableNode *var_node = (SL::VariableNode *)op_node->arguments[0]; + + if (op_node->op == SL::OP_CONSTRUCT) { + code += var_node->name; + } else { + if (var_node->name == "texture") { + // emit texture call + + if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D) { // || + // op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLEREXT) { + code += "texture"; + } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) { + code += "textureCube"; + } + + } else if (var_node->name == "textureLod") { + // emit texture call + + if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D) { + code += "textureLod"; + } 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)) { + code += var_node->name; + } else { + code += _mkid(var_node->name); + } + } + + code += "("; + + for (int i = 1; i < op_node->arguments.size(); i++) { + if (i > 1) { + code += ", "; + } + + code += _dump_node_code(op_node->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } + + code += ")"; + + if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { + String define = p_default_actions.usage_defines[var_node->name]; + String node_name = define.substr(1, define.length()); + + if (define.begins_with("@")) { + define = p_default_actions.usage_defines[node_name]; + } + + if (!used_name_defines.has(node_name)) { + r_gen_code.custom_defines.push_back(define.utf8()); + } + used_name_defines.insert(var_node->name); + } + + } break; + + case SL::OP_INDEX: { + 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; + + case SL::OP_SELECT_IF: { + code += "("; + code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += " ? "; + code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += " : "; + code += _dump_node_code(op_node->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ")"; + } break; + + case SL::OP_MOD: { + String a = _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + String n = _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += "(" + n + " == 0 ? 0 : "; + code += a + " - " + n + " * (" + a + " / " + n + "))"; + } break; + + default: { + if (p_use_scope) { + code += "("; + } + code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += " "; + code += _opstr(op_node->op); + code += " "; + code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + if (p_use_scope) { + code += ")"; + } + } break; + } + } break; + + case SL::Node::TYPE_CONTROL_FLOW: { + SL::ControlFlowNode *cf_node = (SL::ControlFlowNode *)p_node; + + if (cf_node->flow_op == SL::FLOW_OP_IF) { + code += _mktab(p_level); + code += "if ("; + code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ")\n"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + + if (cf_node->blocks.size() == 2) { + code += _mktab(p_level); + code += "else\n"; + code += _dump_node_code(cf_node->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } + } else if (cf_node->flow_op == SL::FLOW_OP_DO) { + code += _mktab(p_level); + code += "do"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _mktab(p_level); + code += "while ("; + code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ");"; + } else if (cf_node->flow_op == SL::FLOW_OP_WHILE) { + code += _mktab(p_level); + code += "while ("; + code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ")\n"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cf_node->flow_op == SL::FLOW_OP_FOR) { + code += _mktab(p_level); + code += "for ("; + code += _dump_node_code(cf_node->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += "; "; + code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += "; "; + code += _dump_node_code(cf_node->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ")\n"; + + code += _dump_node_code(cf_node->blocks[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + + } else if (cf_node->flow_op == SL::FLOW_OP_RETURN) { + code += _mktab(p_level); + code += "return"; + + if (cf_node->expressions.size()) { + code += " "; + code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } + 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;"; + } else if (cf_node->flow_op == SL::FLOW_OP_BREAK) { + code += "break;"; + } + } break; + + case SL::Node::TYPE_MEMBER: { + SL::MemberNode *member_node = (SL::MemberNode *)p_node; + code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += "."; + code += member_node->name; + } break; + } + + return code.as_string(); +} + +ShaderLanguage::DataType ShaderCompilerGLES3::_get_variable_type(const StringName &p_type) { + // RS::GlobalVariableType gvt = ((RasterizerStorageRD *)(RendererStorage::base_singleton))->global_variable_get_type_internal(p_type); + RS::GlobalVariableType gvt = RS::GLOBAL_VAR_TYPE_MAX; + return RS::global_variable_type_get_shader_datatype(gvt); +} + +Error ShaderCompilerGLES3::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { + ShaderLanguage::VaryingFunctionNames var_names; + + Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), var_names, ShaderTypes::get_singleton()->get_types(), _get_variable_type); + + // Error ShaderLanguage::compile(const String &p_code, const Map &p_functions, const Vector &p_render_modes, const Set &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) { + if (err != OK) { + Vector shader = p_code.split("\n"); + for (int i = 0; i < shader.size(); i++) { + print_line(itos(i + 1) + " " + shader[i]); + } + + _err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), false, ERR_HANDLER_SHADER); + return err; + } + + r_gen_code.custom_defines.clear(); + r_gen_code.uniforms.clear(); + r_gen_code.texture_uniforms.clear(); + r_gen_code.texture_hints.clear(); + r_gen_code.vertex = String(); + r_gen_code.vertex_global = String(); + r_gen_code.fragment = String(); + r_gen_code.fragment_global = String(); + r_gen_code.light = String(); + r_gen_code.uses_fragment_time = false; + r_gen_code.uses_vertex_time = false; + + used_name_defines.clear(); + used_rmode_defines.clear(); + used_flag_pointers.clear(); + + _dump_node_code(parser.get_shader(), 1, r_gen_code, *p_actions, actions[p_mode], false); + + return OK; +} + +ShaderCompilerGLES3::ShaderCompilerGLES3() { + /** CANVAS ITEM SHADER **/ + + actions[RS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy"; + actions[RS::SHADER_CANVAS_ITEM].renames["UV"] = "uv"; + actions[RS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "point_size"; + + actions[RS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix"; + actions[RS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"] = "projection_matrix"; + actions[RS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] = "extra_matrix_instance"; + actions[RS::SHADER_CANVAS_ITEM].renames["TIME"] = "time"; + actions[RS::SHADER_CANVAS_ITEM].renames["PI"] = _MKSTR(Math_PI); + actions[RS::SHADER_CANVAS_ITEM].renames["TAU"] = _MKSTR(Math_TAU); + actions[RS::SHADER_CANVAS_ITEM].renames["E"] = _MKSTR(Math_E); + actions[RS::SHADER_CANVAS_ITEM].renames["AT_LIGHT_PASS"] = "at_light_pass"; + actions[RS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom"; + + actions[RS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; + actions[RS::SHADER_CANVAS_ITEM].renames["MODULATE"] = "final_modulate"; + actions[RS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; + actions[RS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map"; + actions[RS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth"; + actions[RS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture"; + actions[RS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size"; + actions[RS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture"; + actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"] = "screen_uv"; + actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"] = "screen_texture"; + actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size"; + actions[RS::SHADER_CANVAS_ITEM].renames["FRAGCOORD"] = "gl_FragCoord"; + actions[RS::SHADER_CANVAS_ITEM].renames["POINT_COORD"] = "gl_PointCoord"; + + actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_VEC"] = "light_vec"; + actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"] = "light_height"; + actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"] = "light_color"; + actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv"; + actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light"; + actions[RS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color"; + actions[RS::SHADER_CANVAS_ITEM].renames["SHADOW_VEC"] = "shadow_vec"; + + actions[RS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["MODULATE"] = "#define MODULATE_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + actions[RS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_VEC"] = "#define SHADOW_VEC_USED\n"; + + // Ported from GLES3 + + actions[RS::SHADER_CANVAS_ITEM].usage_defines["sinh"] = "#define SINH_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["cosh"] = "#define COSH_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["tanh"] = "#define TANH_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["asinh"] = "#define ASINH_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["acosh"] = "#define ACOSH_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["atanh"] = "#define ATANH_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["determinant"] = "#define DETERMINANT_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["transpose"] = "#define TRANSPOSE_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["round"] = "#define ROUND_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["inverse"] = "#define INVERSE_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["isinf"] = "#define IS_INF_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["isnan"] = "#define IS_NAN_USED\n"; + actions[RS::SHADER_CANVAS_ITEM].usage_defines["trunc"] = "#define TRUNC_USED\n"; + + /** SPATIAL SHADER **/ + + actions[RS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform"; + actions[RS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix"; + actions[RS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix"; + actions[RS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix"; + actions[RS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "projection_inverse_matrix"; + actions[RS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; + + actions[RS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz"; + actions[RS::SHADER_SPATIAL].renames["NORMAL"] = "normal"; + actions[RS::SHADER_SPATIAL].renames["TANGENT"] = "tangent"; + actions[RS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal"; + actions[RS::SHADER_SPATIAL].renames["POSITION"] = "position"; + actions[RS::SHADER_SPATIAL].renames["UV"] = "uv_interp"; + actions[RS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; + actions[RS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; + actions[RS::SHADER_SPATIAL].renames["POINT_SIZE"] = "point_size"; + // gl_InstanceID is not available in OpenGL ES 2.0 + actions[RS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0"; + + //builtins + + actions[RS::SHADER_SPATIAL].renames["TIME"] = "time"; + actions[RS::SHADER_SPATIAL].renames["PI"] = _MKSTR(Math_PI); + actions[RS::SHADER_SPATIAL].renames["TAU"] = _MKSTR(Math_TAU); + actions[RS::SHADER_SPATIAL].renames["E"] = _MKSTR(Math_E); + actions[RS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size"; + + actions[RS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord"; + actions[RS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing"; + actions[RS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap"; + actions[RS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth"; + actions[RS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo"; + actions[RS::SHADER_SPATIAL].renames["ALPHA"] = "alpha"; + actions[RS::SHADER_SPATIAL].renames["METALLIC"] = "metallic"; + actions[RS::SHADER_SPATIAL].renames["SPECULAR"] = "specular"; + actions[RS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness"; + actions[RS::SHADER_SPATIAL].renames["RIM"] = "rim"; + actions[RS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint"; + actions[RS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat"; + actions[RS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; + actions[RS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy"; + actions[RS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; + actions[RS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; + actions[RS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission"; + actions[RS::SHADER_SPATIAL].renames["AO"] = "ao"; + actions[RS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; + actions[RS::SHADER_SPATIAL].renames["EMISSION"] = "emission"; + actions[RS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; + actions[RS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; + actions[RS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; + actions[RS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; + actions[RS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_texture"; + // Defined in GLES3, but not available in GLES2 + //actions[RS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth"; + actions[RS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; + actions[RS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; + + //for light + actions[RS::SHADER_SPATIAL].renames["VIEW"] = "view"; + actions[RS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; + actions[RS::SHADER_SPATIAL].renames["LIGHT"] = "light"; + actions[RS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation"; + actions[RS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light"; + actions[RS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light"; + + actions[RS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n"; + actions[RS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT"; + actions[RS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n"; + actions[RS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM"; + actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n"; + actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; + actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n"; + actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; + actions[RS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n"; + actions[RS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n"; + actions[RS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n"; + actions[RS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n"; + actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n"; + actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; + actions[RS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; + actions[RS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; + actions[RS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; + + actions[RS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; + actions[RS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["DEPTH_TEXTURE"] = "#define DEPTH_TEXTURE_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; + + actions[RS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + actions[RS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + + // Ported from GLES3 + + actions[RS::SHADER_SPATIAL].usage_defines["sinh"] = "#define SINH_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["cosh"] = "#define COSH_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["tanh"] = "#define TANH_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["asinh"] = "#define ASINH_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["acosh"] = "#define ACOSH_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["atanh"] = "#define ATANH_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["determinant"] = "#define DETERMINANT_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["transpose"] = "#define TRANSPOSE_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["round"] = "#define ROUND_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["inverse"] = "#define INVERSE_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["isinf"] = "#define IS_INF_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["isnan"] = "#define IS_NAN_USED\n"; + actions[RS::SHADER_SPATIAL].usage_defines["trunc"] = "#define TRUNC_USED\n"; + + actions[RS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; + + // Defined in GLES3, could be implemented in GLES2 too if there's a need for it + //actions[RS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; + // Defined in GLES3, might not be possible in GLES2 as gl_FrontFacing is not available + //actions[RS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; + //actions[RS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; + + bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); + + if (!force_lambert) { + actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + + actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; + + bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); + + if (!force_blinn) { + actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + + actions[RS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; + actions[RS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; + + // No defines for particle shaders in OpenGL, there are no GPU particles + + vertex_name = "vertex"; + fragment_name = "fragment"; + light_name = "light"; + time_name = "TIME"; + + List func_list; + + ShaderLanguage::get_builtin_funcs(&func_list); + + for (List::Element *E = func_list.front(); E; E = E->next()) { + internal_functions.insert(E->get()); + } +} + +#endif // GLES3_BACKEND_ENABLED diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h new file mode 100644 index 0000000000..f3efbe9fc3 --- /dev/null +++ b/drivers/gles3/shader_compiler_gles3.h @@ -0,0 +1,106 @@ +/*************************************************************************/ +/* shader_compiler_gles3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SHADER_COMPILER_OPENGL_H +#define SHADER_COMPILER_OPENGL_H + +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/string/string_builder.h" +#include "core/templates/pair.h" +#include "servers/rendering/shader_language.h" +#include "servers/rendering/shader_types.h" +#include "servers/rendering_server.h" + +class ShaderCompilerGLES3 { +public: + struct IdentifierActions { + Map> render_mode_values; + Map render_mode_flags; + Map usage_flag_pointers; + Map write_flag_pointers; + + Map *uniforms; + }; + + struct GeneratedCode { + Vector custom_defines; + Vector uniforms; + Vector texture_uniforms; + Vector texture_hints; + + String vertex_global; + String vertex; + String fragment_global; + String fragment; + String light; + + bool uses_fragment_time; + bool uses_vertex_time; + }; + +private: + ShaderLanguage parser; + + struct DefaultIdentifierActions { + Map renames; + Map render_mode_defines; + Map usage_defines; + }; + + void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, StringBuilder &r_to_add, Set &r_added); + String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope = true); + + StringName current_func_name; + StringName vertex_name; + StringName fragment_name; + StringName light_name; + StringName time_name; + + Set used_name_defines; + Set used_flag_pointers; + Set used_rmode_defines; + Set internal_functions; + + DefaultIdentifierActions actions[RS::SHADER_MAX]; + + // compatibility with godot 4 + static ShaderLanguage::DataType _get_variable_type(const StringName &p_type); + +public: + Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code); + + ShaderCompilerGLES3(); +}; + +#endif // GLES3_BACKEND_ENABLED + +#endif // SHADER_COMPILER_OPENGL_H diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp new file mode 100644 index 0000000000..7d93d50ceb --- /dev/null +++ b/drivers/gles3/shader_gles3.cpp @@ -0,0 +1,1116 @@ +/*************************************************************************/ +/* shader_gles3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "shader_gles3.h" +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "rasterizer_gles3.h" +#include "rasterizer_storage_gles3.h" + +#include "core/config/project_settings.h" +#include "core/os/memory.h" +#include "core/string/print_string.h" +#include "core/string/string_builder.h" + +// #define DEBUG_OPENGL + +// #include "shaders/copy.glsl.gen.h" + +#ifdef DEBUG_OPENGL + +#define DEBUG_TEST_ERROR(m_section) \ + { \ + uint32_t err = glGetError(); \ + if (err) { \ + print_line("OpenGL Error #" + itos(err) + " at: " + m_section); \ + } \ + } +#else + +#define DEBUG_TEST_ERROR(m_section) + +#endif + +ShaderGLES3 *ShaderGLES3::active = NULL; + +//#define DEBUG_SHADER + +#ifdef DEBUG_SHADER + +#define DEBUG_PRINT(m_text) print_line(m_text); + +#else + +#define DEBUG_PRINT(m_text) + +#endif + +GLint ShaderGLES3::get_uniform_location(int p_index) const { + ERR_FAIL_COND_V(!version, -1); + + return version->uniform_location[p_index]; +} + +bool ShaderGLES3::bind() { + if (active != this || !version || new_conditional_version.key != conditional_version.key) { + conditional_version = new_conditional_version; + version = get_current_version(); + } else { + return false; + } + + ERR_FAIL_COND_V(!version, false); + + if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation). + glUseProgram(0); + return false; + } + + glUseProgram(version->id); + + DEBUG_TEST_ERROR("use program"); + + active = this; + uniforms_dirty = true; + + return true; +} + +void ShaderGLES3::unbind() { + version = NULL; + glUseProgram(0); + uniforms_dirty = true; + active = NULL; +} + +static void _display_error_with_code(const String &p_error, const Vector &p_code) { + int line = 1; + String total_code; + + for (int i = 0; i < p_code.size(); i++) { + total_code += String(p_code[i]); + } + + Vector lines = String(total_code).split("\n"); + + for (int j = 0; j < lines.size(); j++) { + print_line(itos(line) + ": " + lines[j]); + line++; + } + + ERR_PRINT(p_error); +} + +static String _mkid(const String &p_id) { + String id = "m_" + p_id; + return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl +} + +ShaderGLES3::Version *ShaderGLES3::get_current_version() { + if (!valid) + return nullptr; + + Version *_v = version_map.getptr(conditional_version); + + if (_v) { + if (conditional_version.code_version != 0) { + CustomCode *cc = custom_code_map.getptr(conditional_version.code_version); + ERR_FAIL_COND_V(!cc, _v); + if (cc->version == _v->code_version) + return _v; + } else { + return _v; + } + } + + if (!_v) + version_map[conditional_version] = Version(); + + Version &v = version_map[conditional_version]; + + if (!_v) { + v.uniform_location = memnew_arr(GLint, uniform_count); + } else { + if (v.ok) { + glDeleteShader(v.vert_id); + glDeleteShader(v.frag_id); + glDeleteProgram(v.id); + v.id = 0; + } + } + + v.ok = false; + + Vector strings; + +#ifdef GLES_OVER_GL + strings.push_back("#version 330\n"); + strings.push_back("#define USE_GLES_OVER_GL\n"); +#else + strings.push_back("#version 300 es\n"); +//angle does not like +#ifdef JAVASCRIPT_ENABLED + strings.push_back("#define USE_HIGHP_PRECISION\n"); +#endif + + //if (GLOBAL_GET("rendering/opengl/compatibility/enable_high_float.Android")) { + // enable USE_HIGHP_PRECISION but safeguarded by an availability check as highp support is optional in OpenGL + // see Section 4.5.4 of the GLSL_ES_Specification_1.00 + //strings.push_back("#ifdef GL_FRAGMENT_PRECISION_HIGH\n #define USE_HIGHP_PRECISION\n#endif\n"); + //} + +#endif + +#ifdef ANDROID_ENABLED + strings.push_back("#define ANDROID_ENABLED\n"); +#endif + + for (int i = 0; i < custom_defines.size(); i++) { + strings.push_back(custom_defines[i].get_data()); + strings.push_back("\n"); + } + + for (int j = 0; j < conditional_count; j++) { + bool enable = (conditional_version.version & (1 << j)) > 0; + + if (enable) { + strings.push_back(conditional_defines[j]); + DEBUG_PRINT(conditional_defines[j]); + } + } + + // keep them around during the function + CharString code_string; + CharString code_string2; + CharString code_globals; + + CustomCode *cc = NULL; + + if (conditional_version.code_version > 0) { + cc = custom_code_map.getptr(conditional_version.code_version); + + ERR_FAIL_COND_V(!cc, NULL); + v.code_version = cc->version; + } + + // program + + v.id = glCreateProgram(); + ERR_FAIL_COND_V(v.id == 0, NULL); + + if (cc) { + for (int i = 0; i < cc->custom_defines.size(); i++) { + strings.push_back(cc->custom_defines.write[i]); + DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data())); + } + } + + // vertex shader + + int string_base_size = strings.size(); + + strings.push_back(vertex_code0.get_data()); + + if (cc) { + code_globals = cc->vertex_globals.ascii(); + strings.push_back(code_globals.get_data()); + } + + strings.push_back(vertex_code1.get_data()); + + if (cc) { + code_string = cc->vertex.ascii(); + strings.push_back(code_string.get_data()); + } + + strings.push_back(vertex_code2.get_data()); + +#ifdef DEBUG_SHADER + + DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data())); + +#endif + + v.vert_id = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(v.vert_id, strings.size(), &strings[0], NULL); + glCompileShader(v.vert_id); + + GLint status; + + glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + GLsizei iloglen; + glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen); + + if (iloglen < 0) { + glDeleteShader(v.vert_id); + glDeleteProgram(v.id); + v.id = 0; + + ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?"); + } else { + if (iloglen == 0) { + iloglen = 4096; // buggy driver (Adreno 220+) + } + + char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); + ilogmem[iloglen] = '\0'; + glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem); + + String err_string = get_shader_name() + ": Vertex shader compilation failed:\n"; + + err_string += ilogmem; + + _display_error_with_code(err_string, strings); + + Memory::free_static(ilogmem); + glDeleteShader(v.vert_id); + glDeleteProgram(v.id); + v.id = 0; + } + + ERR_FAIL_V(NULL); + } + + strings.resize(string_base_size); + + // fragment shader + + strings.push_back(fragment_code0.get_data()); + + if (cc) { + code_globals = cc->fragment_globals.ascii(); + strings.push_back(code_globals.get_data()); + } + + strings.push_back(fragment_code1.get_data()); + + if (cc) { + code_string = cc->light.ascii(); + strings.push_back(code_string.get_data()); + } + + strings.push_back(fragment_code2.get_data()); + + if (cc) { + code_string2 = cc->fragment.ascii(); + strings.push_back(code_string2.get_data()); + } + + 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 + + v.frag_id = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(v.frag_id, strings.size(), &strings[0], NULL); + glCompileShader(v.frag_id); + + glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status); + if (status == GL_FALSE) { + GLsizei iloglen; + glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen); + + if (iloglen < 0) { + glDeleteShader(v.frag_id); + glDeleteShader(v.vert_id); + glDeleteProgram(v.id); + v.id = 0; + + ERR_PRINT("No OpenGL fragment shader compiler log. What the frick?"); + } else { + if (iloglen == 0) { + iloglen = 4096; // buggy driver (Adreno 220+) + } + + char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); + ilogmem[iloglen] = '\0'; + glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem); + + String err_string = get_shader_name() + ": Fragment shader compilation failed:\n"; + + err_string += ilogmem; + + _display_error_with_code(err_string, strings); + + Memory::free_static(ilogmem); + glDeleteShader(v.frag_id); + glDeleteShader(v.vert_id); + glDeleteProgram(v.id); + v.id = 0; + } + + ERR_FAIL_V(NULL); + } + + glAttachShader(v.id, v.frag_id); + glAttachShader(v.id, v.vert_id); + + // bind the attribute locations. This has to be done before linking so that the + // linker doesn't assign some random indices + + for (int i = 0; i < attribute_pair_count; i++) { + glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name); + } + + glLinkProgram(v.id); + + glGetProgramiv(v.id, GL_LINK_STATUS, &status); + if (status == GL_FALSE) { + GLsizei iloglen; + glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen); + + if (iloglen < 0) { + glDeleteShader(v.frag_id); + glDeleteShader(v.vert_id); + glDeleteProgram(v.id); + v.id = 0; + + ERR_PRINT("No OpenGL program link log. What the frick?"); + ERR_FAIL_V(NULL); + } + + if (iloglen == 0) { + iloglen = 4096; // buggy driver (Adreno 220+) + } + + char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); + ilogmem[iloglen] = '\0'; + glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem); + + String err_string = get_shader_name() + ": Program linking failed:\n"; + + err_string += ilogmem; + + _display_error_with_code(err_string, strings); + + Memory::free_static(ilogmem); + glDeleteShader(v.frag_id); + glDeleteShader(v.vert_id); + glDeleteProgram(v.id); + v.id = 0; + + ERR_FAIL_V(NULL); + } + + // get uniform locations + + glUseProgram(v.id); + + for (int i = 0; i < uniform_count; i++) { + v.uniform_location[i] = glGetUniformLocation(v.id, uniform_names[i]); + } + + for (int i = 0; i < texunit_pair_count; i++) { + GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name); + 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) { + // uniforms + for (int i = 0; i < cc->custom_uniforms.size(); i++) { + String native_uniform_name = _mkid(cc->custom_uniforms[i]); + GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); + v.custom_uniform_locations[cc->custom_uniforms[i]] = location; + } + + // textures + for (int i = 0; i < cc->texture_uniforms.size(); i++) { + String native_uniform_name = _mkid(cc->texture_uniforms[i]); + GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); + v.custom_uniform_locations[cc->texture_uniforms[i]] = location; + glUniform1i(location, i); + } + } + + glUseProgram(0); + v.ok = true; + + if (cc) { + cc->versions.insert(conditional_version.version); + } + + return &v; +} + +GLint ShaderGLES3::get_uniform_location(const String &p_name) const { + ERR_FAIL_COND_V(!version, -1); + return glGetUniformLocation(version->id, p_name.ascii().get_data()); +} + +void ShaderGLES3::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) { + ERR_FAIL_COND(version); + + conditional_version.key = 0; + new_conditional_version.key = 0; + uniform_count = p_uniform_count; + conditional_count = p_conditional_count; + conditional_defines = p_conditional_defines; + uniform_names = p_uniform_names; + vertex_code = p_vertex_code; + fragment_code = p_fragment_code; + texunit_pairs = p_texunit_pairs; + texunit_pair_count = p_texunit_pair_count; + vertex_code_start = p_vertex_code_start; + fragment_code_start = p_fragment_code_start; + attribute_pairs = p_attribute_pairs; + attribute_pair_count = p_attribute_count; + + { + String globals_tag = "\nVERTEX_SHADER_GLOBALS"; + String code_tag = "\nVERTEX_SHADER_CODE"; + String code = vertex_code; + int cpos = code.find(globals_tag); + if (cpos == -1) { + vertex_code0 = code.ascii(); + } else { + vertex_code0 = code.substr(0, cpos).ascii(); + code = code.substr(cpos + globals_tag.length(), code.length()); + + cpos = code.find(code_tag); + + if (cpos == -1) { + vertex_code1 = code.ascii(); + } else { + vertex_code1 = code.substr(0, cpos).ascii(); + vertex_code2 = code.substr(cpos + code_tag.length(), code.length()).ascii(); + } + } + } + + { + String globals_tag = "\nFRAGMENT_SHADER_GLOBALS"; + String code_tag = "\nFRAGMENT_SHADER_CODE"; + String light_code_tag = "\nLIGHT_SHADER_CODE"; + String code = fragment_code; + int cpos = code.find(globals_tag); + if (cpos == -1) { + fragment_code0 = code.ascii(); + } else { + fragment_code0 = code.substr(0, cpos).ascii(); + code = code.substr(cpos + globals_tag.length(), code.length()); + + cpos = code.find(light_code_tag); + + String code2; + + if (cpos != -1) { + fragment_code1 = code.substr(0, cpos).ascii(); + code2 = code.substr(cpos + light_code_tag.length(), code.length()); + } else { + code2 = code; + } + + cpos = code2.find(code_tag); + if (cpos == -1) { + fragment_code2 = code2.ascii(); + } else { + fragment_code2 = code2.substr(0, cpos).ascii(); + fragment_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); + } + } + } + + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units); + + valid = true; +} + +void ShaderGLES3::finish() { + const VersionKey *V = NULL; + + while ((V = version_map.next(V))) { + Version &v = version_map[*V]; + glDeleteShader(v.vert_id); + glDeleteShader(v.frag_id); + glDeleteProgram(v.id); + + if (v.uniform_location) + memdelete_arr(v.uniform_location); + } +} + +void ShaderGLES3::clear_caches() { + const VersionKey *V = NULL; + + while ((V = version_map.next(V))) { + Version &v = version_map[*V]; + glDeleteShader(v.vert_id); + glDeleteShader(v.frag_id); + glDeleteProgram(v.id); + memdelete_arr(v.uniform_location); + } + + version_map.clear(); + + custom_code_map.clear(); + version = NULL; + last_custom_code = 1; + uniforms_dirty = true; +} + +uint32_t ShaderGLES3::create_custom_shader() { + custom_code_map[last_custom_code] = CustomCode(); + custom_code_map[last_custom_code].version = 1; + return last_custom_code++; +} + +void ShaderGLES3::set_custom_shader_code(uint32_t p_code_id, + const String &p_vertex, + const String &p_vertex_globals, + const String &p_fragment, + const String &p_light, + const String &p_fragment_globals, + const Vector &p_uniforms, + const Vector &p_texture_uniforms, + const Vector &p_custom_defines) { + CustomCode *cc = custom_code_map.getptr(p_code_id); + ERR_FAIL_COND(!cc); + + cc->vertex = p_vertex; + cc->vertex_globals = p_vertex_globals; + cc->fragment = p_fragment; + cc->fragment_globals = p_fragment_globals; + cc->light = p_light; + cc->custom_uniforms = p_uniforms; + cc->custom_defines = p_custom_defines; + cc->texture_uniforms = p_texture_uniforms; + cc->version++; +} + +void ShaderGLES3::set_custom_shader(uint32_t p_code_id) { + new_conditional_version.code_version = p_code_id; +} + +void ShaderGLES3::free_custom_shader(uint32_t p_code_id) { + ERR_FAIL_COND(!custom_code_map.has(p_code_id)); + if (conditional_version.code_version == p_code_id) { + conditional_version.code_version = 0; //do not keep using a version that is going away + unbind(); + } + + VersionKey key; + key.code_version = p_code_id; + for (Set::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) { + key.version = E->get(); + ERR_CONTINUE(!version_map.has(key)); + Version &v = version_map[key]; + + glDeleteShader(v.vert_id); + glDeleteShader(v.frag_id); + glDeleteProgram(v.id); + memdelete_arr(v.uniform_location); + v.id = 0; + + version_map.erase(key); + } + + custom_code_map.erase(p_code_id); +} + +void ShaderGLES3::use_material(void *p_material) { + RasterizerStorageGLES3::Material *material = (RasterizerStorageGLES3::Material *)p_material; + + if (!material) { + return; + } + + if (!material->shader) { + return; + } + + Version *v = version_map.getptr(conditional_version); + + // bind uniforms + for (Map::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::Element *L = v->custom_uniform_locations.find(E->key()); + if (!L || L->get() < 0) + continue; //uniform not valid + + GLuint location = L->get(); + + Map::Element *V = material->params.find(E->key()); + + if (V) { + switch (E->get().type) { + case ShaderLanguage::TYPE_BOOL: { + bool boolean = V->get(); + glUniform1i(location, boolean ? 1 : 0); + } break; + + case ShaderLanguage::TYPE_BVEC2: { + int flags = V->get(); + glUniform2i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0); + } break; + + case ShaderLanguage::TYPE_BVEC3: { + int flags = V->get(); + glUniform3i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0); + + } break; + + case ShaderLanguage::TYPE_BVEC4: { + int flags = V->get(); + glUniform4i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0, (flags & 8) ? 1 : 0); + + } break; + + case ShaderLanguage::TYPE_INT: + case ShaderLanguage::TYPE_UINT: { + int value = V->get(); + glUniform1i(location, value); + } break; + + case ShaderLanguage::TYPE_IVEC2: + case ShaderLanguage::TYPE_UVEC2: { + Array r = V->get(); + const int count = 2; + if (r.size() == count) { + int values[count]; + for (int i = 0; i < count; i++) { + values[i] = r[i]; + } + glUniform2i(location, values[0], values[1]); + } + + } break; + + case ShaderLanguage::TYPE_IVEC3: + case ShaderLanguage::TYPE_UVEC3: { + Array r = V->get(); + const int count = 3; + if (r.size() == count) { + int values[count]; + for (int i = 0; i < count; i++) { + values[i] = r[i]; + } + glUniform3i(location, values[0], values[1], values[2]); + } + + } break; + + case ShaderLanguage::TYPE_IVEC4: + case ShaderLanguage::TYPE_UVEC4: { + Array r = V->get(); + const int count = 4; + if (r.size() == count) { + int values[count]; + for (int i = 0; i < count; i++) { + values[i] = r[i]; + } + glUniform4i(location, values[0], values[1], values[2], values[3]); + } + + } break; + + case ShaderLanguage::TYPE_FLOAT: { + float value = V->get(); + glUniform1f(location, value); + + } break; + + case ShaderLanguage::TYPE_VEC2: { + Vector2 value = V->get(); + glUniform2f(location, value.x, value.y); + } break; + + case ShaderLanguage::TYPE_VEC3: { + Vector3 value = V->get(); + glUniform3f(location, value.x, value.y, value.z); + } break; + + case ShaderLanguage::TYPE_VEC4: { + if (V->get().get_type() == Variant::COLOR) { + Color value = V->get(); + glUniform4f(location, value.r, value.g, value.b, value.a); + } else if (V->get().get_type() == Variant::QUATERNION) { + Quaternion value = V->get(); + glUniform4f(location, value.x, value.y, value.z, value.w); + } else { + Plane value = V->get(); + glUniform4f(location, value.normal.x, value.normal.y, value.normal.z, value.d); + } + + } break; + + case ShaderLanguage::TYPE_MAT2: { + Transform2D tr = V->get(); + GLfloat matrix[4] = { + /* build a 16x16 matrix */ + tr.elements[0][0], + tr.elements[0][1], + tr.elements[1][0], + tr.elements[1][1], + }; + glUniformMatrix2fv(location, 1, GL_FALSE, matrix); + + } break; + + case ShaderLanguage::TYPE_MAT3: { + Basis val = V->get(); + + GLfloat mat[9] = { + val.elements[0][0], + val.elements[1][0], + val.elements[2][0], + val.elements[0][1], + val.elements[1][1], + val.elements[2][1], + val.elements[0][2], + val.elements[1][2], + val.elements[2][2], + }; + + glUniformMatrix3fv(location, 1, GL_FALSE, mat); + + } break; + + case ShaderLanguage::TYPE_MAT4: { + Transform2D tr = V->get(); + GLfloat matrix[16] = { /* build a 16x16 matrix */ + tr.elements[0][0], + tr.elements[0][1], + 0, + 0, + tr.elements[1][0], + tr.elements[1][1], + 0, + 0, + 0, + 0, + 1, + 0, + tr.elements[2][0], + tr.elements[2][1], + 0, + 1 + }; + + glUniformMatrix4fv(location, 1, GL_FALSE, matrix); + + } break; + + default: { + ERR_PRINT("ShaderNode type missing, bug?"); + } break; + } + } else if (E->get().default_value.size()) { + const Vector &values = E->get().default_value; + switch (E->get().type) { + case ShaderLanguage::TYPE_BOOL: { + glUniform1i(location, values[0].boolean); + } break; + + case ShaderLanguage::TYPE_BVEC2: { + glUniform2i(location, values[0].boolean, values[1].boolean); + } break; + + case ShaderLanguage::TYPE_BVEC3: { + glUniform3i(location, values[0].boolean, values[1].boolean, values[2].boolean); + } break; + + case ShaderLanguage::TYPE_BVEC4: { + glUniform4i(location, values[0].boolean, values[1].boolean, values[2].boolean, values[3].boolean); + } break; + + case ShaderLanguage::TYPE_INT: { + glUniform1i(location, values[0].sint); + } break; + + case ShaderLanguage::TYPE_IVEC2: { + glUniform2i(location, values[0].sint, values[1].sint); + } break; + + case ShaderLanguage::TYPE_IVEC3: { + glUniform3i(location, values[0].sint, values[1].sint, values[2].sint); + } break; + + case ShaderLanguage::TYPE_IVEC4: { + glUniform4i(location, values[0].sint, values[1].sint, values[2].sint, values[3].sint); + } break; + + case ShaderLanguage::TYPE_UINT: { + glUniform1i(location, values[0].uint); + } break; + + case ShaderLanguage::TYPE_UVEC2: { + glUniform2i(location, values[0].uint, values[1].uint); + } break; + + case ShaderLanguage::TYPE_UVEC3: { + glUniform3i(location, values[0].uint, values[1].uint, values[2].uint); + } break; + + case ShaderLanguage::TYPE_UVEC4: { + glUniform4i(location, values[0].uint, values[1].uint, values[2].uint, values[3].uint); + } break; + + case ShaderLanguage::TYPE_FLOAT: { + glUniform1f(location, values[0].real); + } break; + + case ShaderLanguage::TYPE_VEC2: { + glUniform2f(location, values[0].real, values[1].real); + } break; + + case ShaderLanguage::TYPE_VEC3: { + glUniform3f(location, values[0].real, values[1].real, values[2].real); + } break; + + case ShaderLanguage::TYPE_VEC4: { + glUniform4f(location, 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(location, 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(location, 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(location, 1, GL_FALSE, mat); + + } break; + + case ShaderLanguage::TYPE_SAMPLER2D: { + } break; + + /* + case ShaderLanguage::TYPE_SAMPLEREXT: { + } break; +*/ + case ShaderLanguage::TYPE_ISAMPLER2D: { + } break; + + case ShaderLanguage::TYPE_USAMPLER2D: { + } break; + + case ShaderLanguage::TYPE_SAMPLERCUBE: { + } break; + + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in OpenGL + } break; + + case ShaderLanguage::TYPE_VOID: { + // Nothing to do? + } break; + default: { + ERR_PRINT("ShaderNode type missing, bug?"); + } break; + } + } else { //zero + + switch (E->get().type) { + case ShaderLanguage::TYPE_BOOL: { + glUniform1i(location, GL_FALSE); + } break; + + case ShaderLanguage::TYPE_BVEC2: { + glUniform2i(location, GL_FALSE, GL_FALSE); + } break; + + case ShaderLanguage::TYPE_BVEC3: { + glUniform3i(location, GL_FALSE, GL_FALSE, GL_FALSE); + } break; + + case ShaderLanguage::TYPE_BVEC4: { + glUniform4i(location, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } break; + + case ShaderLanguage::TYPE_INT: { + glUniform1i(location, 0); + } break; + + case ShaderLanguage::TYPE_IVEC2: { + glUniform2i(location, 0, 0); + } break; + + case ShaderLanguage::TYPE_IVEC3: { + glUniform3i(location, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_IVEC4: { + glUniform4i(location, 0, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_UINT: { + glUniform1i(location, 0); + } break; + + case ShaderLanguage::TYPE_UVEC2: { + glUniform2i(location, 0, 0); + } break; + + case ShaderLanguage::TYPE_UVEC3: { + glUniform3i(location, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_UVEC4: { + glUniform4i(location, 0, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_FLOAT: { + glUniform1f(location, 0); + } break; + + case ShaderLanguage::TYPE_VEC2: { + glUniform2f(location, 0, 0); + } break; + + case ShaderLanguage::TYPE_VEC3: { + glUniform3f(location, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_VEC4: { + glUniform4f(location, 0, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_MAT2: { + GLfloat mat[4] = { 0, 0, 0, 0 }; + + glUniformMatrix2fv(location, 1, GL_FALSE, mat); + } break; + + case ShaderLanguage::TYPE_MAT3: { + GLfloat mat[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + glUniformMatrix3fv(location, 1, GL_FALSE, mat); + + } break; + + case ShaderLanguage::TYPE_MAT4: { + GLfloat mat[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + glUniformMatrix4fv(location, 1, GL_FALSE, mat); + + } break; + + case ShaderLanguage::TYPE_SAMPLER2D: { + } break; + + /* + case ShaderLanguage::TYPE_SAMPLEREXT: { + } break; +*/ + + case ShaderLanguage::TYPE_ISAMPLER2D: { + } break; + + case ShaderLanguage::TYPE_USAMPLER2D: { + } break; + + case ShaderLanguage::TYPE_SAMPLERCUBE: { + } break; + + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in OpenGL + } break; + + case ShaderLanguage::TYPE_VOID: { + // Nothing to do? + } break; + default: { + ERR_PRINT("ShaderNode type missing, bug?"); + } break; + } + } + } +} + +ShaderGLES3::ShaderGLES3() { + version = NULL; + last_custom_code = 1; + uniforms_dirty = true; +} + +ShaderGLES3::~ShaderGLES3() { + finish(); +} + +#endif // GLES3_BACKEND_ENABLED diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h new file mode 100644 index 0000000000..1aca3a1cf6 --- /dev/null +++ b/drivers/gles3/shader_gles3.h @@ -0,0 +1,277 @@ +/*************************************************************************/ +/* shader_gles3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef SHADER_OPENGL_H +#define SHADER_OPENGL_H + +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +// This must come first to avoid windows.h mess +#include "platform_config.h" +#ifndef OPENGL_INCLUDE_H +#include +#else +#include OPENGL_INCLUDE_H +#endif + +#include "core/math/camera_matrix.h" +#include "core/templates/hash_map.h" +#include "core/templates/map.h" +#include "core/templates/pair.h" +#include "core/variant/variant.h" +#include "servers/rendering/shader_language.h" + +#include + +class RasterizerStorageGLES3; + +class ShaderGLES3 { +protected: + struct Enum { + uint64_t mask; + uint64_t shift; + const char *defines[16]; + }; + + struct EnumValue { + uint64_t set_mask; + uint64_t clear_mask; + }; + + struct AttributePair { + const char *name; + int index; + }; + + struct UniformPair { + const char *name; + Variant::Type type_hint; + }; + + struct TexUnitPair { + const char *name; + int index; + }; + + bool uniforms_dirty; + +private: + bool valid = false; + + //@TODO Optimize to a fixed set of shader pools and use a LRU + int uniform_count; + int texunit_pair_count; + int conditional_count; + int vertex_code_start; + int fragment_code_start; + int attribute_pair_count; + + struct CustomCode { + String vertex; + String vertex_globals; + String fragment; + String fragment_globals; + String light; + uint32_t version; + Vector texture_uniforms; + Vector custom_uniforms; + Vector custom_defines; + Set versions; + }; + + struct Version { + GLuint id; + GLuint vert_id; + GLuint frag_id; + GLint *uniform_location; + Vector texture_uniform_locations; + Map custom_uniform_locations; + uint32_t code_version; + bool ok; + Version() { + id = 0; + vert_id = 0; + frag_id = 0; + uniform_location = NULL; + code_version = 0; + ok = false; + } + }; + + Version *version; + + union VersionKey { + struct { + uint32_t version; + uint32_t code_version; + }; + uint64_t key; + bool operator==(const VersionKey &p_key) const { return key == p_key.key; } + bool operator<(const VersionKey &p_key) const { return key < p_key.key; } + }; + + struct VersionKeyHash { + static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return HashMapHasherDefault::hash(p_key.key); } + }; + + //this should use a way more cachefriendly version.. + HashMap version_map; + + HashMap custom_code_map; + uint32_t last_custom_code; + + VersionKey conditional_version; + VersionKey new_conditional_version; + + virtual String get_shader_name() const = 0; + + const char **conditional_defines; + const char **uniform_names; + const AttributePair *attribute_pairs; + const TexUnitPair *texunit_pairs; + const char *vertex_code; + const char *fragment_code; + CharString fragment_code0; + CharString fragment_code1; + CharString fragment_code2; + CharString fragment_code3; + + CharString vertex_code0; + CharString vertex_code1; + CharString vertex_code2; + + Vector custom_defines; + + Version *get_current_version(); + + static ShaderGLES3 *active; + + int max_image_units; + + Map>> 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); + + ShaderGLES3(); + +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_ ShaderGLES3 *get_active() { return active; } + bool bind(); + void unbind(); + + 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, + const String &p_vertex_globals, + const String &p_fragment, + const String &p_light, + const String &p_fragment_globals, + const Vector &p_uniforms, + const Vector &p_texture_uniforms, + const Vector &p_custom_defines); + + void set_custom_shader(uint32_t p_code_id); + void free_custom_shader(uint32_t p_code_id); + + uint32_t get_version_key() const { return conditional_version.version; } + + // this void* is actually a RasterizerStorageGLES3::Material, but C++ doesn't + // like forward declared nested classes. + void use_material(void *p_material); + + _FORCE_INLINE_ uint32_t get_version() const { return new_conditional_version.version; } + _FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; } + + virtual void init() = 0; + void finish(); + + void add_custom_define(const String &p_define) { + custom_defines.push_back(p_define.utf8()); + } + + void get_custom_defines(Vector *p_defines) { + for (int i = 0; i < custom_defines.size(); i++) { + p_defines->push_back(custom_defines[i].get_data()); + } + } + + void remove_custom_define(const String &p_define) { + custom_defines.erase(p_define.utf8()); + } + + virtual ~ShaderGLES3(); +}; + +// called a lot, made inline + +int ShaderGLES3::_get_uniform(int p_which) const { + ERR_FAIL_INDEX_V(p_which, uniform_count, -1); + ERR_FAIL_COND_V(!version, -1); + return version->uniform_location[p_which]; +} + +void ShaderGLES3::_set_conditional(int p_which, bool p_value) { + ERR_FAIL_INDEX(p_which, conditional_count); + if (p_value) + new_conditional_version.version |= (1 << p_which); + else + new_conditional_version.version &= ~(1 << p_which); +} + +#endif // GLES3_BACKEND_ENABLED + +#endif // SHADER_OPENGL_H diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub new file mode 100644 index 0000000000..47d56b9947 --- /dev/null +++ b/drivers/gles3/shaders/SCsub @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +Import("env") + +if "GLES3_GLSL" in env["BUILDERS"]: + env.GLES3_GLSL("copy.glsl") + env.GLES3_GLSL("canvas.glsl") + env.GLES3_GLSL("canvas_shadow.glsl") + env.GLES3_GLSL("scene.glsl") + env.GLES3_GLSL("cubemap_filter.glsl") + env.GLES3_GLSL("cube_to_dp.glsl") + env.GLES3_GLSL("effect_blur.glsl") + env.GLES3_GLSL("tonemap.glsl") + env.GLES3_GLSL("lens_distorted.glsl") diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl new file mode 100644 index 0000000000..f2b141252a --- /dev/null +++ b/drivers/gles3/shaders/canvas.glsl @@ -0,0 +1,665 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +uniform highp mat4 projection_matrix; +/* clang-format on */ + +uniform highp mat4 modelview_matrix; +uniform highp mat4 extra_matrix; +layout(location = 0) in highp vec2 vertex; + +#ifdef USE_ATTRIB_LIGHT_ANGLE +// shared with tangent, not used in canvas shader +layout(location = 2) in highp float light_angle; +#endif + +layout(location = 3) in vec4 color_attrib; +layout(location = 4) in vec2 uv_attrib; + +#ifdef USE_ATTRIB_MODULATE +layout(location = 5) in highp vec4 modulate_attrib; +#endif + +#ifdef USE_ATTRIB_LARGE_VERTEX +// shared with skeleton attributes, not used in batched shader +layout(location = 6) in highp vec2 translate_attrib; +layout(location = 7) in highp vec4 basis_attrib; +#endif + +#ifdef USE_SKELETON +layout(location = 6) in highp vec4 bone_indices; +layout(location = 7) in highp vec4 bone_weights; +#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 highp vec4 instance_color; + +#ifdef USE_INSTANCE_CUSTOM +layout(location = 12) in highp vec4 instance_custom_data; +#endif + +#endif + +#ifdef USE_SKELETON +uniform highp sampler2D skeleton_texture; // texunit:-3 +uniform highp ivec2 skeleton_texture_size; +uniform highp mat4 skeleton_transform; +uniform highp mat4 skeleton_transform_inverse; +#endif + +out vec2 uv_interp; +out vec4 color_interp; + +#ifdef USE_ATTRIB_MODULATE +// modulate doesn't need interpolating but we need to send it to the fragment shader +flat out vec4 modulate_interp; +#endif + +#ifdef MODULATE_USED +uniform vec4 final_modulate; +#endif + +uniform highp vec2 color_texpixel_size; + +#ifdef USE_TEXTURE_RECT + +uniform vec4 dst_rect; +uniform vec4 src_rect; + +#endif + +uniform highp float time; + +#ifdef USE_LIGHTING + +// light matrices +uniform highp mat4 light_matrix; +uniform highp mat4 light_matrix_inverse; +uniform highp mat4 light_local_matrix; +uniform highp mat4 shadow_matrix; +uniform highp vec4 light_color; +uniform highp vec4 light_shadow_color; +uniform highp vec2 light_pos; +uniform highp float shadowpixel_size; +uniform highp float shadow_gradient; +uniform highp float light_height; +uniform highp float light_outside_alpha; +uniform highp float shadow_distance_mult; + +out vec4 light_uv_interp; +out vec2 transformed_light_uv; +out vec4 local_rot; + +#ifdef USE_SHADOWS +out highp vec2 pos; +#endif + +const bool at_light_pass = true; +#else +const bool at_light_pass = false; +#endif + +/* clang-format off */ + +VERTEX_SHADER_GLOBALS + +/* clang-format on */ + +vec2 select(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; +} + +void main() { + vec4 color = color_attrib; + vec2 uv; + +#ifdef USE_INSTANCING + mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); + color *= instance_color; + +#ifdef USE_INSTANCE_CUSTOM + vec4 instance_custom = instance_custom_data; +#else + vec4 instance_custom = vec4(0.0); +#endif + +#else + mat4 extra_matrix_instance = extra_matrix; + vec4 instance_custom = vec4(0.0); +#endif + +#ifdef USE_TEXTURE_RECT + + if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z + uv = src_rect.xy + abs(src_rect.zw) * vertex.yx; + } else { + uv = src_rect.xy + abs(src_rect.zw) * vertex; + } + + vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); + + // This is what is done in the GLES 3 bindings and should + // take care of flipped rects. + // + // But it doesn't. + // I don't know why, will need to investigate further. + + outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))); + + // outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex; +#else + vec4 outvec = vec4(vertex.xy, 0.0, 1.0); + + uv = uv_attrib; +#endif + + float point_size = 1.0; + + { + vec2 src_vtx = outvec.xy; + /* clang-format off */ + +VERTEX_SHADER_CODE + + /* clang-format on */ + } + + gl_PointSize = point_size; + +#ifdef USE_ATTRIB_MODULATE + // modulate doesn't need interpolating but we need to send it to the fragment shader + modulate_interp = modulate_attrib; +#endif + +#ifdef USE_ATTRIB_LARGE_VERTEX + // transform is in attributes + vec2 temp; + + temp = outvec.xy; + temp.x = (outvec.x * basis_attrib.x) + (outvec.y * basis_attrib.z); + temp.y = (outvec.x * basis_attrib.y) + (outvec.y * basis_attrib.w); + + temp += translate_attrib; + outvec.xy = temp; + +#else + + // transform is in uniforms +#if !defined(SKIP_TRANSFORM_USED) + outvec = extra_matrix_instance * outvec; + outvec = modelview_matrix * outvec; +#endif + +#endif // not large integer + + color_interp = color; + +#ifdef USE_PIXEL_SNAP + outvec.xy = floor(outvec + 0.5).xy; + // precision issue on some hardware creates artifacts within texture + // offset uv by a small amount to avoid + uv += 1e-5; +#endif + +#ifdef USE_SKELETON + + // look up transform from the "pose texture" + if (bone_weights != vec4(0.0)) { + highp mat4 bone_transform = mat4(0.0); + + for (int i = 0; i < 4; i++) { + ivec2 tex_ofs = ivec2(int(bone_indices[i]) * 2, 0); + + highp mat4 b = mat4( + texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(0, 0)), + texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(1, 0)), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); + + bone_transform += b * bone_weights[i]; + } + + mat4 bone_matrix = skeleton_transform * transpose(bone_transform) * skeleton_transform_inverse; + + outvec = bone_matrix * outvec; + } + +#endif + + uv_interp = uv; + gl_Position = projection_matrix * outvec; + +#ifdef USE_LIGHTING + + light_uv_interp.xy = (light_matrix * outvec).xy; + light_uv_interp.zw = (light_local_matrix * outvec).xy; + + transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping + +#ifdef USE_SHADOWS + pos = outvec.xy; +#endif + +#ifdef USE_ATTRIB_LIGHT_ANGLE + // we add a fixed offset because we are using the sign later, + // and don't want floating point error around 0.0 + float la = abs(light_angle) - 1.0; + + // vector light angle + vec4 vla; + vla.xy = vec2(cos(la), sin(la)); + vla.zw = vec2(-vla.y, vla.x); + + // vertical flip encoded in the sign + vla.zw *= sign(light_angle); + + // apply the transform matrix. + // The rotate will be encoded in the transform matrix for single rects, + // and just the flips in the light angle. + // For batching we will encode the rotation and the flips + // in the light angle, and can use the same shader. + local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.xy, 0.0, 0.0))).xy); + local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.zw, 0.0, 0.0))).xy); +#else + local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy); + local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy); +#ifdef USE_TEXTURE_RECT + local_rot.xy *= sign(src_rect.z); + local_rot.zw *= sign(src_rect.w); +#endif +#endif // not using light angle + +#endif +} + +/* clang-format off */ +[fragment] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +uniform sampler2D color_texture; // texunit:-1 +/* clang-format on */ +uniform highp vec2 color_texpixel_size; +uniform mediump sampler2D normal_texture; // texunit:-2 + +in mediump vec2 uv_interp; +in mediump vec4 color_interp; + +#ifdef USE_ATTRIB_MODULATE +in mediump vec4 modulate_interp; +#endif + +uniform highp float time; + +uniform vec4 final_modulate; + +#ifdef SCREEN_TEXTURE_USED + +uniform sampler2D screen_texture; // texunit:-4 + +#endif + +#ifdef SCREEN_UV_USED + +uniform vec2 screen_pixel_size; + +#endif + +#ifdef USE_LIGHTING + +uniform highp mat4 light_matrix; +uniform highp mat4 light_local_matrix; +uniform highp mat4 shadow_matrix; +uniform highp vec4 light_color; +uniform highp vec4 light_shadow_color; +uniform highp vec2 light_pos; +uniform highp float shadowpixel_size; +uniform highp float shadow_gradient; +uniform highp float light_height; +uniform highp float light_outside_alpha; +uniform highp float shadow_distance_mult; + +uniform lowp sampler2D light_texture; // texunit:-6 +in vec4 light_uv_interp; +in vec2 transformed_light_uv; + +in vec4 local_rot; + +#ifdef USE_SHADOWS + +uniform highp sampler2D shadow_texture; // texunit:-5 +in highp vec2 pos; + +#endif + +const bool at_light_pass = true; +#else +const bool at_light_pass = false; +#endif + +uniform bool use_default_normal; + +layout(location = 0) out mediump vec4 frag_color; + +/* clang-format off */ + +FRAGMENT_SHADER_GLOBALS + +/* clang-format on */ + +void light_compute( + inout vec4 light, + inout vec2 light_vec, + inout float light_height, + inout vec4 light_color, + vec2 light_uv, + inout vec4 shadow_color, + inout vec2 shadow_vec, + vec3 normal, + vec2 uv, +#if defined(SCREEN_UV_USED) + vec2 screen_uv, +#endif + vec4 color) { + +#if defined(USE_LIGHT_SHADER_CODE) + + /* clang-format off */ + +LIGHT_SHADER_CODE + + /* clang-format on */ + +#endif +} + +void main() { + vec4 color = color_interp; + vec2 uv = uv_interp; +#ifdef USE_FORCE_REPEAT + //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it + uv = mod(uv, vec2(1.0, 1.0)); +#endif + +#if !defined(COLOR_USED) + //default behavior, texture by color + color *= texture(color_texture, uv); +#endif + +#ifdef SCREEN_UV_USED + vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#endif + + vec3 normal; + +#if defined(NORMAL_USED) + + bool normal_used = true; +#else + bool normal_used = false; +#endif + + if (use_default_normal) { + normal.xy = texture(normal_texture, uv).xy * 2.0 - 1.0; + normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); + normal_used = true; + } else { + normal = vec3(0.0, 0.0, 1.0); + } + + { + float normal_depth = 1.0; + +#if defined(NORMALMAP_USED) + vec3 normal_map = vec3(0.0, 0.0, 1.0); + normal_used = true; +#endif + + /* clang-format off */ + +FRAGMENT_SHADER_CODE + + /* clang-format on */ + +#if defined(NORMALMAP_USED) + normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); +#endif + } + +#ifdef USE_ATTRIB_MODULATE + color *= modulate_interp; +#else +#if !defined(MODULATE_USED) + color *= final_modulate; +#endif +#endif + +#ifdef USE_LIGHTING + + vec2 light_vec = transformed_light_uv; + vec2 shadow_vec = transformed_light_uv; + + if (normal_used) { + normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy; + } + + float att = 1.0; + + vec2 light_uv = light_uv_interp.xy; + vec4 light = 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 + + } else { + float real_light_height = light_height; + vec4 real_light_color = light_color; + vec4 real_light_shadow_color = light_shadow_color; + +#if defined(USE_LIGHT_SHADER_CODE) + //light is written by the light shader + light_compute( + light, + light_vec, + real_light_height, + real_light_color, + light_uv, + real_light_shadow_color, + shadow_vec, + normal, + uv, +#if defined(SCREEN_UV_USED) + screen_uv, +#endif + color); +#endif + + light *= real_light_color; + + if (normal_used) { + vec3 light_normal = normalize(vec3(light_vec, -real_light_height)); + light *= max(dot(-light_normal, normal), 0.0); + } + + color *= light; + +#ifdef USE_SHADOWS + +#ifdef SHADOW_VEC_USED + mat3 inverse_light_matrix = mat3(light_matrix); + inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); + inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); + inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); + shadow_vec = (inverse_light_matrix * vec3(shadow_vec, 0.0)).xy; +#else + shadow_vec = light_uv_interp.zw; +#endif + + float angle_to_light = -atan(shadow_vec.x, shadow_vec.y); + float PI = 3.14159265358979323846264; + /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays + float ang*/ + + float su, sz; + + float abs_angle = abs(angle_to_light); + vec2 point; + float sh; + if (abs_angle < 45.0 * PI / 180.0) { + point = shadow_vec; + sh = 0.0 + (1.0 / 8.0); + } else if (abs_angle > 135.0 * PI / 180.0) { + point = -shadow_vec; + sh = 0.5 + (1.0 / 8.0); + } else if (angle_to_light > 0.0) { + point = vec2(shadow_vec.y, -shadow_vec.x); + sh = 0.25 + (1.0 / 8.0); + } else { + point = vec2(-shadow_vec.y, shadow_vec.x); + sh = 0.75 + (1.0 / 8.0); + } + + highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0); + s.xyz /= s.w; + su = s.x * 0.5 + 0.5; + sz = s.z * 0.5 + 0.5; + //sz=lightlength(light_vec); + + highp float shadow_attenuation = 0.0; + +#ifdef USE_RGBA_SHADOWS +#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) + +#else + +#define SHADOW_DEPTH(m_tex, m_uv) (texture((m_tex), (m_uv)).r) + +#endif + +#ifdef SHADOW_USE_GRADIENT + + /* clang-format off */ + /* GLSL es 100 doesn't support line continuation characters(backslashes) */ +#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); } + +#else + +#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += step(sz, sd); } + /* clang-format on */ + +#endif + +#ifdef SHADOW_FILTER_NEAREST + + SHADOW_TEST(su); + +#endif + +#ifdef SHADOW_FILTER_PCF3 + + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + shadow_attenuation /= 3.0; + +#endif + +#ifdef SHADOW_FILTER_PCF5 + + SHADOW_TEST(su + shadowpixel_size * 2.0); + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + SHADOW_TEST(su - shadowpixel_size * 2.0); + shadow_attenuation /= 5.0; + +#endif + +#ifdef SHADOW_FILTER_PCF7 + + SHADOW_TEST(su + shadowpixel_size * 3.0); + SHADOW_TEST(su + shadowpixel_size * 2.0); + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + SHADOW_TEST(su - shadowpixel_size * 2.0); + SHADOW_TEST(su - shadowpixel_size * 3.0); + shadow_attenuation /= 7.0; + +#endif + +#ifdef SHADOW_FILTER_PCF9 + + SHADOW_TEST(su + shadowpixel_size * 4.0); + SHADOW_TEST(su + shadowpixel_size * 3.0); + SHADOW_TEST(su + shadowpixel_size * 2.0); + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + SHADOW_TEST(su - shadowpixel_size * 2.0); + SHADOW_TEST(su - shadowpixel_size * 3.0); + SHADOW_TEST(su - shadowpixel_size * 4.0); + shadow_attenuation /= 9.0; + +#endif + +#ifdef SHADOW_FILTER_PCF13 + + SHADOW_TEST(su + shadowpixel_size * 6.0); + SHADOW_TEST(su + shadowpixel_size * 5.0); + SHADOW_TEST(su + shadowpixel_size * 4.0); + SHADOW_TEST(su + shadowpixel_size * 3.0); + SHADOW_TEST(su + shadowpixel_size * 2.0); + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + SHADOW_TEST(su - shadowpixel_size * 2.0); + SHADOW_TEST(su - shadowpixel_size * 3.0); + SHADOW_TEST(su - shadowpixel_size * 4.0); + SHADOW_TEST(su - shadowpixel_size * 5.0); + SHADOW_TEST(su - shadowpixel_size * 6.0); + shadow_attenuation /= 13.0; + +#endif + + //color *= shadow_attenuation; + color = mix(real_light_shadow_color, color, shadow_attenuation); +//use shadows +#endif + } + +//use lighting +#endif + + frag_color = color; +} diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl new file mode 100644 index 0000000000..2b3be43f6e --- /dev/null +++ b/drivers/gles3/shaders/canvas_shadow.glsl @@ -0,0 +1,60 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +layout(location = 0) highp vec3 vertex; + +uniform highp mat4 projection_matrix; +/* clang-format on */ +uniform highp mat4 light_matrix; +uniform highp mat4 world_matrix; +uniform highp float distance_norm; + +out highp vec4 position_interp; + +void main() { + gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex, 1.0))); + position_interp = gl_Position; +} + +/* clang-format off */ +[fragment] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +in highp vec4 position_interp; +/* clang-format on */ + +void main() { + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias + +#ifdef USE_RGBA_SHADOWS + + highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); + comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); + frag_color = comp; +#else + + frag_color = vec4(depth); +#endif +} diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl new file mode 100644 index 0000000000..598c6fd614 --- /dev/null +++ b/drivers/gles3/shaders/copy.glsl @@ -0,0 +1,193 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +layout(location = 0) highp vec4 vertex_attrib; +/* clang-format on */ + +#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) +layout(location = 4) vec3 cube_in; +#else +layout(location = 4) vec2 uv_in; +#endif + +layout(location = 5) vec2 uv2_in; + +#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) +out vec3 cube_interp; +#else +out vec2 uv_interp; +#endif +out vec2 uv2_interp; + +// These definitions are here because the shader-wrapper builder does +// not understand `#elif defined()` +#ifdef USE_DISPLAY_TRANSFORM +#endif + +#ifdef USE_COPY_SECTION +uniform highp vec4 copy_section; +#elif defined(USE_DISPLAY_TRANSFORM) +uniform highp mat4 display_transform; +#endif + +void main() { +#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) + cube_interp = cube_in; +#elif defined(USE_ASYM_PANO) + uv_interp = vertex_attrib.xy; +#else + uv_interp = uv_in; +#endif + + uv2_interp = uv2_in; + gl_Position = vertex_attrib; + +#ifdef USE_COPY_SECTION + uv_interp = copy_section.xy + uv_interp * copy_section.zw; + gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; +#elif defined(USE_DISPLAY_TRANSFORM) + uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy; +#endif +} + +/* clang-format off */ +[fragment] + +#define M_PI 3.14159265359 + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) +in vec3 cube_interp; +#else +in vec2 uv_interp; +#endif +/* clang-format on */ + +#ifdef USE_ASYM_PANO +uniform highp mat4 pano_transform; +uniform highp vec4 asym_proj; +#endif + +#ifdef USE_CUBEMAP +uniform samplerCube source_cube; // texunit:0 +#else +uniform sampler2D source; // texunit:0 +#endif + +#ifdef SEP_CBCR_TEXTURE +uniform sampler2D CbCr; //texunit:1 +#endif + +in 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) +uniform highp mat4 sky_transform; + +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 texture(pano, st); +} + +#endif + +layout(location = 0) out vec4 frag_color; + +void main() { +#ifdef USE_PANORAMA + + vec3 cube_normal = normalize(cube_interp); + cube_normal.z = -cube_normal.z; + cube_normal = mat3(sky_transform) * cube_normal; + cube_normal.z = -cube_normal.z; + + vec4 color = texturePanorama(source, cube_normal); + +#elif defined(USE_ASYM_PANO) + + // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. + // Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted. + // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. + + vec3 cube_normal; + cube_normal.z = -1.0; + cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; + cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; + cube_normal = mat3(sky_transform) * mat3(pano_transform) * cube_normal; + cube_normal.z = -cube_normal.z; + + vec4 color = texturePanorama(source, normalize(cube_normal.xyz)); + +#elif defined(USE_CUBEMAP) + vec4 color = textureCube(source_cube, normalize(cube_interp)); +#elif defined(SEP_CBCR_TEXTURE) + vec4 color; + color.r = texture(source, uv_interp).r; + color.gb = texture(CbCr, uv_interp).rg - vec2(0.5, 0.5); + color.a = 1.0; +#else + vec4 color = texture(source, uv_interp); +#endif + +#ifdef YCBCR_TO_RGB + // YCbCr -> RGB conversion + + // Using BT.601, which is the standard for SDTV is provided as a reference + color.rgb = mat3( + vec3(1.00000, 1.00000, 1.00000), + vec3(0.00000, -0.34413, 1.77200), + vec3(1.40200, -0.71414, 0.00000)) * + color.rgb; +#endif + +#ifdef USE_NO_ALPHA + color.a = 1.0; +#endif + +#ifdef USE_CUSTOM_ALPHA + color.a = custom_alpha; +#endif + +#ifdef USE_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 new file mode 100644 index 0000000000..ea4df79d4e --- /dev/null +++ b/drivers/gles3/shaders/cube_to_dp.glsl @@ -0,0 +1,100 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision mediump float; +precision mediump int; +#endif + +layout(location = 0) highp vec4 vertex_attrib; +/* clang-format on */ +layout(location = 4) vec2 uv_in; + +out vec2 uv_interp; + +void main() { + uv_interp = uv_in; + gl_Position = vertex_attrib; +} + +/* clang-format off */ +[fragment] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +uniform highp samplerCube source_cube; //texunit:0 +/* clang-format on */ +in vec2 uv_interp; + +uniform bool z_flip; +uniform highp float z_far; +uniform highp float z_near; +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)); + } else { + 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 = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); + normal = normalize(normal); + /* + normal.z = 0.5; + normal = normalize(normal); + */ + + if (!z_flip) { + normal.z = -normal.z; + } + + //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 )); + 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); + } else { + // 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); + + 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; +} diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl new file mode 100644 index 0000000000..04bf3ebf02 --- /dev/null +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -0,0 +1,214 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +layout(location = 0) highp vec2 vertex; +/* clang-format on */ +layout(location = 4) highp vec2 uv; + +out highp vec2 uv_interp; + +void main() { + uv_interp = uv; + gl_Position = vec4(vertex, 0, 1); +} + +/* clang-format off */ +[fragment] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif + +#endif + +#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; + +uniform sampler2D radical_inverse_vdc_cache; // texunit:1 + +#define M_PI 3.14159265359 + +#ifdef LOW_QUALITY + +#define SAMPLE_COUNT 64 + +#else + +#define SAMPLE_COUNT 512 + +#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); + + return textureLod(pano, st, 0.0); +} + +#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; + for (int i = 0; i < 6; i++) { + if (i == faceID) { + result = (faceUvVectors[i][0] * uv.x) + (faceUvVectors[i][1] * uv.y) + faceUvVectors[i][2]; + break; + } + } + return normalize(result); +} + +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 SinTheta = sqrt(1.0 - CosTheta * CosTheta); + + // Convert to spherical direction + vec3 H; + H.x = SinTheta * cos(Phi); + H.y = SinTheta * sin(Phi); + H.z = CosTheta; + + vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); + vec3 TangentX = normalize(cross(UpVector, N)); + vec3 TangentY = cross(N, TangentX); + + // Tangent to world space + return TangentX * H.x + TangentY * H.y + N * H.z; +} + +float radical_inverse_VdC(int i) { + return texture(radical_inverse_vdc_cache, vec2(float(i) / 512.0, 0.0)).x; +} + +vec2 Hammersley(int i, int N) { + return vec2(float(i) / float(N), radical_inverse_VdC(i)); +} + +uniform bool z_flip; + +layout(location = 0) out vec4 frag_color; + +void main() { + vec3 color = vec3(0.0); + + vec2 uv = (uv_interp * 2.0) - 1.0; + vec3 N = texelCoordToVec(uv, face_id); + +#ifdef USE_DIRECT_WRITE + +#ifdef USE_SOURCE_PANORAMA + + frag_color = vec4(texturePanorama(source_panorama, N).rgb, 1.0); +#else + + frag_color = vec4(textureCube(source_cube, N).rgb, 1.0); +#endif //USE_SOURCE_PANORAMA + +#else + + vec4 sum = vec4(0.0); + + for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) { + vec2 xi = Hammersley(sample_num, SAMPLE_COUNT); + + 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); + + if (NdotL > 0.0) { + +#ifdef USE_SOURCE_PANORAMA + vec3 val = texturePanorama(source_panorama, L).rgb; +#else + vec3 val = textureCubeLod(source_cube, L, 0.0).rgb; +#endif + //mix using Linear, to approximate high end back-end + val = mix(pow((val + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), val * (1.0 / 12.92), vec3(lessThan(val, vec3(0.04045)))); + + sum.rgb += val * NdotL; + + sum.a += NdotL; + } + } + + sum /= sum.a; + + vec3 a = vec3(0.055); + sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308)))); + + frag_color = vec4(sum.rgb, 1.0); +#endif +} diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl new file mode 100644 index 0000000000..80063a7175 --- /dev/null +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -0,0 +1,291 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +layout(location = 0) vec2 vertex_attrib; +/* clang-format on */ +layout(location = 4) vec2 uv_in; + +out vec2 uv_interp; + +#ifdef USE_BLUR_SECTION + +uniform vec4 blur_section; + +#endif + +void main() { + uv_interp = uv_in; + gl_Position = vec4(vertex_attrib, 0.0, 1.0); +#ifdef USE_BLUR_SECTION + + uv_interp = blur_section.xy + uv_interp * blur_section.zw; + gl_Position.xy = (blur_section.xy + (gl_Position.xy * 0.5 + 0.5) * blur_section.zw) * 2.0 - 1.0; +#endif +} + +/* clang-format off */ +[fragment] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +in vec2 uv_interp; +/* clang-format on */ +uniform sampler2D source_color; //texunit:0 + +uniform float lod; +uniform vec2 pixel_size; + +#if defined(GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL) + +uniform float glow_strength; + +#endif + +#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR) + +#ifdef USE_GLES_OVER_GL +#ifdef DOF_QUALITY_LOW +const int dof_kernel_size = 5; +const int dof_kernel_from = 2; +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); + +#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); +#endif +#endif + +uniform sampler2D dof_source_depth; //texunit:1 +uniform float dof_begin; +uniform float dof_end; +uniform vec2 dof_dir; +uniform float dof_radius; + +#endif + +#ifdef GLOW_FIRST_PASS + +uniform highp float luminance_cap; + +uniform float glow_bloom; +uniform float glow_hdr_threshold; +uniform float glow_hdr_scale; + +#endif + +uniform float camera_z_far; +uniform float camera_z_near; + +layout(location = 0) out vec4 frag_color; + +void main() { +#ifdef GLOW_GAUSSIAN_HORIZONTAL + vec2 pix_size = pixel_size; + pix_size *= 0.5; //reading from larger buffer, so use more samples + vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.174938; + color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.165569; + color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.140367; + color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.106595; + color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.165569; + color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.140367; + color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.106595; + color *= glow_strength; + frag_color = color; +#endif + +#ifdef GLOW_GAUSSIAN_VERTICAL + vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.288713; + color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.233062; + color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.122581; + color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062; + color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581; + color *= glow_strength; + frag_color = color; +#endif + +#ifndef USE_GLES_OVER_GL +#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; + float dof_kernel[5]; + dof_kernel[0] = 0.153388; + dof_kernel[1] = 0.221461; + dof_kernel[2] = 0.250301; + dof_kernel[3] = 0.221461; + dof_kernel[4] = 0.153388; +#endif + +#ifdef DOF_QUALITY_MEDIUM + const int dof_kernel_size = 11; + const int dof_kernel_from = 5; + float dof_kernel[11]; + dof_kernel[0] = 0.055037; + dof_kernel[1] = 0.072806; + dof_kernel[2] = 0.090506; + dof_kernel[3] = 0.105726; + dof_kernel[4] = 0.116061; + dof_kernel[5] = 0.119726; + dof_kernel[6] = 0.116061; + dof_kernel[7] = 0.105726; + dof_kernel[8] = 0.090506; + dof_kernel[9] = 0.072806; + dof_kernel[10] = 0.055037; +#endif + +#ifdef DOF_QUALITY_HIGH + const int dof_kernel_size = 21; + const int dof_kernel_from = 10; + float dof_kernel[21]; + dof_kernel[0] = 0.028174; + dof_kernel[1] = 0.032676; + dof_kernel[2] = 0.037311; + dof_kernel[3] = 0.041944; + dof_kernel[4] = 0.046421; + dof_kernel[5] = 0.050582; + dof_kernel[6] = 0.054261; + dof_kernel[7] = 0.057307; + dof_kernel[8] = 0.059587; + dof_kernel[9] = 0.060998; + dof_kernel[10] = 0.061476; + dof_kernel[11] = 0.060998; + dof_kernel[12] = 0.059587; + dof_kernel[13] = 0.057307; + dof_kernel[14] = 0.054261; + dof_kernel[15] = 0.050582; + dof_kernel[16] = 0.046421; + dof_kernel[17] = 0.041944; + dof_kernel[18] = 0.037311; + dof_kernel[19] = 0.032676; + dof_kernel[20] = 0.028174; +#endif +#endif +#endif //!USE_GLES_OVER_GL + +#ifdef DOF_FAR_BLUR + + vec4 color_accum = vec4(0.0); + + float depth = textureLod(dof_source_depth, uv_interp, 0.0).r; + depth = depth * 2.0 - 1.0; +#ifdef USE_ORTHOGONAL_PROJECTION + depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; +#else + depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); +#endif + + float amount = smoothstep(dof_begin, dof_end, depth); + float k_accum = 0.0; + + for (int i = 0; i < dof_kernel_size; i++) { + int int_ofs = i - dof_kernel_from; + vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius; + + float tap_k = dof_kernel[i]; + + float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; + tap_depth = tap_depth * 2.0 - 1.0; +#ifdef USE_ORTHOGONAL_PROJECTION + tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; +#else + tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); +#endif + float tap_amount = int_ofs == 0 ? 1.0 : smoothstep(dof_begin, dof_end, tap_depth); + tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect + + vec4 tap_color = textureLod(source_color, tap_uv, 0.0) * tap_k; + + k_accum += tap_k * tap_amount; + color_accum += tap_color * tap_amount; + } + + if (k_accum > 0.0) { + color_accum /= k_accum; + } + + frag_color = color_accum; ///k_accum; + +#endif + +#ifdef DOF_NEAR_BLUR + + vec4 color_accum = vec4(0.0); + + float max_accum = 0.0; + + for (int i = 0; i < dof_kernel_size; i++) { + int int_ofs = i - dof_kernel_from; + vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius; + float ofs_influence = max(0.0, 1.0 - abs(float(int_ofs)) / float(dof_kernel_from)); + + float tap_k = dof_kernel[i]; + + vec4 tap_color = textureLod(source_color, tap_uv, 0.0); + + float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; + tap_depth = tap_depth * 2.0 - 1.0; +#ifdef USE_ORTHOGONAL_PROJECTION + tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; +#else + tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); +#endif + float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth); + tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect + +#ifdef DOF_NEAR_FIRST_TAP + + 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; + } + + color_accum.a = max(color_accum.a, sqrt(max_accum)); + + frag_color = color_accum; + +#endif + +#ifdef GLOW_FIRST_PASS + + 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 = min(frag_color * feedback, vec4(luminance_cap)); + +#endif +} diff --git a/drivers/gles3/shaders/lens_distorted.glsl b/drivers/gles3/shaders/lens_distorted.glsl new file mode 100644 index 0000000000..64c2d70cc8 --- /dev/null +++ b/drivers/gles3/shaders/lens_distorted.glsl @@ -0,0 +1,86 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +layout(location = 0) highp vec2 vertex; +/* clang-format on */ + +uniform vec2 offset; +uniform vec2 scale; + +out vec2 uv_interp; + +void main() { + uv_interp = vertex.xy * 2.0 - 1.0; + + vec2 v = vertex.xy * scale + offset; + gl_Position = vec4(v, 0.0, 1.0); +} + +/* clang-format off */ +[fragment] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +uniform sampler2D source; //texunit:0 +/* clang-format on */ + +uniform vec2 eye_center; +uniform float k1; +uniform float k2; +uniform float upscale; +uniform float aspect_ratio; + +in vec2 uv_interp; + +layout(location = 0) out vec4 frag_color; + +void main() { + vec2 coords = uv_interp; + vec2 offset = coords - eye_center; + + // take aspect ratio into account + offset.y /= aspect_ratio; + + // distort + vec2 offset_sq = offset * offset; + float radius_sq = offset_sq.x + offset_sq.y; + float radius_s4 = radius_sq * radius_sq; + float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); + offset *= distortion_scale; + + // reapply aspect ratio + offset.y *= aspect_ratio; + + // add our eye center back in + coords = offset + eye_center; + coords /= upscale; + + // and check our color + if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { + frag_color = vec4(0.0, 0.0, 0.0, 1.0); + } else { + coords = (coords + vec2(1.0)) / vec2(2.0); + frag_color = texture(source, coords); + } +} diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl new file mode 100644 index 0000000000..de2aa0fc48 --- /dev/null +++ b/drivers/gles3/shaders/scene.glsl @@ -0,0 +1,2153 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +#define SHADER_IS_SRGB true //TODO remove + +#define M_PI 3.14159265359 + +// +// attributes +// + +layout(location = 0) highp vec4 vertex_attrib; +/* clang-format on */ +layout(location = 1) vec3 normal_attrib; + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) +layout(location = 2) vec4 tangent_attrib; +#endif + +#if defined(ENABLE_COLOR_INTERP) +layout(location = 3) vec4 color_attrib; +#endif + +#if defined(ENABLE_UV_INTERP) +layout(location = 4) vec2 uv_attrib; +#endif + +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) +layout(location = 5) vec2 uv2_attrib; +#endif + +#ifdef USE_SKELETON + +#ifdef USE_SKELETON_SOFTWARE + +layout(location = 13) highp vec4 bone_transform_row_0; +layout(location = 14) highp vec4 bone_transform_row_1; +layout(location = 15) highp vec4 bone_transform_row_2; + +#else + +layout(location = 6) vec4 bone_ids; +layout(location = 7) highp vec4 bone_weights; + +uniform highp sampler2D bone_transforms; // texunit:-1 +uniform ivec2 skeleton_texture_size; + +#endif + +#endif + +#ifdef USE_INSTANCING + +layout(location = 8) highp vec4 instance_xform_row_0; +layout(location = 9) highp vec4 instance_xform_row_1; +layout(location = 10) highp vec4 instance_xform_row_2; + +layout(location = 11) highp vec4 instance_color; +layout(location = 12) highp vec4 instance_custom_data; + +#endif + +// +// uniforms +// + +uniform highp mat4 camera_matrix; +uniform highp mat4 camera_inverse_matrix; +uniform highp mat4 projection_matrix; +uniform highp mat4 projection_inverse_matrix; + +uniform highp mat4 world_transform; + +uniform highp float time; + +uniform highp vec2 viewport_size; + +#ifdef RENDER_DEPTH +uniform float light_bias; +uniform float light_normal_bias; +#endif + +// +// varyings +// + +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) +out highp vec4 position_interp; +#endif + +out highp vec3 vertex_interp; +out vec3 normal_interp; + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) +out vec3 tangent_interp; +out vec3 binormal_interp; +#endif + +#if defined(ENABLE_COLOR_INTERP) +out vec4 color_interp; +#endif + +#if defined(ENABLE_UV_INTERP) +out vec2 uv_interp; +#endif + +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) +out vec2 uv2_interp; +#endif + +/* clang-format off */ + +VERTEX_SHADER_GLOBALS + +/* clang-format on */ + +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + +out highp float dp_clip; +uniform highp float shadow_dual_paraboloid_render_zfar; +uniform highp float shadow_dual_paraboloid_render_side; + +#endif + +#if defined(USE_SHADOW) && defined(USE_LIGHTING) + +uniform highp mat4 light_shadow_matrix; +out highp vec4 shadow_coord; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) +uniform highp mat4 light_shadow_matrix2; +out highp vec4 shadow_coord2; +#endif + +#if defined(LIGHT_USE_PSSM4) + +uniform highp mat4 light_shadow_matrix3; +uniform highp mat4 light_shadow_matrix4; +out highp vec4 shadow_coord3; +out highp vec4 shadow_coord4; + +#endif + +#endif + +#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) + +out highp vec3 diffuse_interp; +out highp vec3 specular_interp; + +// general for all lights +uniform highp vec4 light_color; +uniform highp vec4 shadow_color; +uniform highp float light_specular; + +// directional +uniform highp vec3 light_direction; + +// omni +uniform highp vec3 light_position; + +uniform highp float light_range; +uniform highp float light_attenuation; + +// spot +uniform highp float light_spot_attenuation; +uniform highp float light_spot_range; +uniform highp float light_spot_angle; + +void light_compute( + vec3 N, + vec3 L, + vec3 V, + vec3 light_color, + vec3 attenuation, + float roughness) { +//this makes lights behave closer to linear, but then addition of lights looks bad +//better left disabled + +//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); +/* +#define SRGB_APPROX(m_var) {\ + float S1 = sqrt(m_var);\ + float S2 = sqrt(S1);\ + float S3 = sqrt(S2);\ + m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ + } +*/ +#define SRGB_APPROX(m_var) + + float NdotL = dot(N, L); + float cNdotL = max(NdotL, 0.0); // clamped NdotL + float NdotV = dot(N, V); + float cNdotV = max(NdotV, 0.0); + +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif + +#if defined(DIFFUSE_LAMBERT_WRAP) + // energy conserving lambert wrap shader + diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); + +#elif defined(DIFFUSE_OREN_NAYAR) + + { + // see http://mimosa-pudica.net/improved-oren-nayar.html + float LdotV = dot(L, V); + + float s = LdotV - NdotL * NdotV; + float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); + + float sigma2 = roughness * roughness; // TODO: this needs checking + vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); + float B = 0.45 * sigma2 / (sigma2 + 0.09); + + diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); + } +#else + // lambert by default for everything else + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + SRGB_APPROX(diffuse_brdf_NL) + + diffuse_interp += light_color * diffuse_brdf_NL * attenuation; + + if (roughness > 0.0) { + // D + float specular_brdf_NL = 0.0; + +#if !defined(SPECULAR_DISABLED) + //normalized blinn always unless disabled + vec3 H = normalize(V + L); + float cNdotH = max(dot(N, H), 0.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess) * cNdotL; + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + specular_brdf_NL = blinn; +#endif + + SRGB_APPROX(specular_brdf_NL) + specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI); + } +} + +#endif + +#ifdef USE_VERTEX_LIGHTING + +#ifdef USE_REFLECTION_PROBE1 + +uniform highp mat4 refprobe1_local_matrix; +out mediump vec4 refprobe1_reflection_normal_blend; +uniform highp vec3 refprobe1_box_extents; + +#ifndef USE_LIGHTMAP +out mediump vec3 refprobe1_ambient_normal; +#endif + +#endif //reflection probe1 + +#ifdef USE_REFLECTION_PROBE2 + +uniform highp mat4 refprobe2_local_matrix; +out mediump vec4 refprobe2_reflection_normal_blend; +uniform highp vec3 refprobe2_box_extents; + +#ifndef USE_LIGHTMAP +out mediump vec3 refprobe2_ambient_normal; +#endif + +#endif //reflection probe2 + +#endif //vertex lighting for refprobes + +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +out vec4 fog_interp; + +uniform mediump vec4 fog_color_base; +#ifdef LIGHT_MODE_DIRECTIONAL +uniform mediump vec4 fog_sun_color_amount; +#endif + +uniform bool fog_transmit_enabled; +uniform mediump float fog_transmit_curve; + +#ifdef FOG_DEPTH_ENABLED +uniform highp float fog_depth_begin; +uniform mediump float fog_depth_curve; +uniform mediump float fog_max_distance; +#endif + +#ifdef FOG_HEIGHT_ENABLED +uniform highp float fog_height_min; +uniform highp float fog_height_max; +uniform mediump float fog_height_curve; +#endif + +#endif //fog + +void main() { + highp vec4 vertex = vertex_attrib; + + mat4 world_matrix = world_transform; + +#ifdef USE_INSTANCING + { + 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; + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) + vec3 tangent = tangent_attrib.xyz; + float binormalf = tangent_attrib.a; + vec3 binormal = normalize(cross(normal, tangent) * binormalf); +#endif + +#if defined(ENABLE_COLOR_INTERP) + color_interp = color_attrib; +#ifdef USE_INSTANCING + color_interp *= instance_color; +#endif +#endif + +#if defined(ENABLE_UV_INTERP) + uv_interp = uv_attrib; +#endif + +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) + uv2_interp = uv2_attrib; +#endif + +#if defined(OVERRIDE_POSITION) + highp vec4 position; +#endif + +#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) + vertex = world_matrix * vertex; + normal = normalize((world_matrix * vec4(normal, 0.0)).xyz); +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) + + tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz); + binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz); +#endif +#endif + +#ifdef USE_SKELETON + + highp mat4 bone_transform = mat4(0.0); + +#ifdef USE_SKELETON_SOFTWARE + // passing the transform as attributes + + 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); + +#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); + + 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)); + + bone_transform += transpose(b) * bone_weights[i]; + } + } + +#endif + + world_matrix = world_matrix * bone_transform; + +#endif + +#ifdef USE_INSTANCING + vec4 instance_custom = instance_custom_data; +#else + vec4 instance_custom = vec4(0.0); + +#endif + + mat4 local_projection_matrix = projection_matrix; + + mat4 modelview = camera_inverse_matrix * world_matrix; + float roughness = 1.0; + +#define projection_matrix local_projection_matrix +#define world_transform world_matrix + + float point_size = 1.0; + + { + /* clang-format off */ + +VERTEX_SHADER_CODE + + /* clang-format on */ + } + + gl_PointSize = point_size; + vec4 outvec = vertex; + + // 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) + tangent = normalize((modelview * vec4(tangent, 0.0)).xyz); + binormal = normalize((modelview * vec4(binormal, 0.0)).xyz); +#endif +#endif + +#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) + 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) + 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; + + dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + highp vec3 vtx = vertex_interp + normalize(vertex_interp) * light_bias; + highp float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy /= 1.0 - vtx.z; + vtx.z = (distance / shadow_dual_paraboloid_render_zfar); + vtx.z = vtx.z * 2.0 - 1.0; + + vertex_interp = vtx; + +#else + float z_ofs = light_bias; + z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias; + + vertex_interp.z -= z_ofs; +#endif //dual parabolloid + +#endif //depth + +//vertex lighting +#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) + //vertex shaded version of lighting (more limited) + vec3 L; + vec3 light_att; + +#ifdef LIGHT_MODE_OMNI + vec3 light_vec = light_position - vertex_interp; + float light_length = length(light_vec); + + float normalized_distance = light_length / light_range; + + if (normalized_distance < 1.0) { + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); + + vec3 attenuation = vec3(omni_attenuation); + light_att = vec3(omni_attenuation); + } else { + light_att = vec3(0.0); + } + + L = normalize(light_vec); + +#endif + +#ifdef LIGHT_MODE_SPOT + + vec3 light_rel_vec = light_position - vertex_interp; + float light_length = length(light_rel_vec); + float normalized_distance = light_length / light_range; + + if (normalized_distance < 1.0) { + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); + vec3 spot_dir = light_direction; + + float spot_cutoff = light_spot_angle; + + float angle = dot(-normalize(light_rel_vec), spot_dir); + + if (angle > spot_cutoff) { + float scos = max(angle, spot_cutoff); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + + spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + + light_att = vec3(spot_attenuation); + } else { + light_att = vec3(0.0); + } + } else { + light_att = vec3(0.0); + } + + L = normalize(light_rel_vec); + +#endif + +#ifdef LIGHT_MODE_DIRECTIONAL + vec3 light_vec = -light_direction; + light_att = vec3(1.0); //no base attenuation + L = normalize(light_vec); +#endif + + diffuse_interp = vec3(0.0); + specular_interp = vec3(0.0); + light_compute(normal_interp, L, -normalize(vertex_interp), light_color.rgb, light_att, roughness); + +#endif + +//shadows (for both vertex and fragment) +#if defined(USE_SHADOW) && defined(USE_LIGHTING) + + vec4 vi4 = vec4(vertex_interp, 1.0); + shadow_coord = light_shadow_matrix * vi4; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) + shadow_coord2 = light_shadow_matrix2 * vi4; +#endif + +#if defined(LIGHT_USE_PSSM4) + shadow_coord3 = light_shadow_matrix3 * vi4; + shadow_coord4 = light_shadow_matrix4 * vi4; + +#endif + +#endif //use shadow and use lighting + +#ifdef USE_VERTEX_LIGHTING + +#ifdef USE_REFLECTION_PROBE1 + { + vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); + vec3 local_pos = (refprobe1_local_matrix * vec4(vertex_interp, 1.0)).xyz; + vec3 inner_pos = abs(local_pos / refprobe1_box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + + { + vec3 local_ref_vec = (refprobe1_local_matrix * vec4(ref_normal, 0.0)).xyz; + refprobe1_reflection_normal_blend.xyz = local_ref_vec; + refprobe1_reflection_normal_blend.a = blend; + } +#ifndef USE_LIGHTMAP + + refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz; +#endif + } + +#endif //USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + { + vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); + vec3 local_pos = (refprobe2_local_matrix * vec4(vertex_interp, 1.0)).xyz; + vec3 inner_pos = abs(local_pos / refprobe2_box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + + { + vec3 local_ref_vec = (refprobe2_local_matrix * vec4(ref_normal, 0.0)).xyz; + refprobe2_reflection_normal_blend.xyz = local_ref_vec; + refprobe2_reflection_normal_blend.a = blend; + } +#ifndef USE_LIGHTMAP + + refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz; +#endif + } + +#endif //USE_REFLECTION_PROBE2 + +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + + float fog_amount = 0.0; + +#ifdef LIGHT_MODE_DIRECTIONAL + + vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex_interp), light_direction), 0.0), 8.0)); +#else + vec3 fog_color = fog_color_base.rgb; +#endif + +#ifdef FOG_DEPTH_ENABLED + + { + float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); + + fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; + } +#endif + +#ifdef FOG_HEIGHT_ENABLED + { + float y = (camera_matrix * vec4(vertex_interp, 1.0)).y; + fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); + } +#endif + fog_interp = vec4(fog_color, fog_amount); + +#endif //fog + +#endif //use vertex lighting + +#if defined(OVERRIDE_POSITION) + gl_Position = position; +#else + gl_Position = projection_matrix * vec4(vertex_interp, 1.0); +#endif + +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) + position_interp = gl_Position; +#endif +} + +/* clang-format off */ +[fragment] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +#define M_PI 3.14159265359 +#define SHADER_IS_SRGB true + +// +// uniforms +// + +uniform highp mat4 camera_matrix; +/* clang-format on */ +uniform highp mat4 camera_inverse_matrix; +uniform highp mat4 projection_matrix; +uniform highp mat4 projection_inverse_matrix; + +uniform highp mat4 world_transform; + +uniform highp float time; + +uniform highp vec2 viewport_size; + +#if defined(SCREEN_UV_USED) +uniform vec2 screen_pixel_size; +#endif + +#if defined(SCREEN_TEXTURE_USED) +uniform highp sampler2D screen_texture; //texunit:-4 +#endif +#if defined(DEPTH_TEXTURE_USED) +uniform highp sampler2D depth_texture; //texunit:-4 +#endif + +#ifdef USE_REFLECTION_PROBE1 + +#ifdef USE_VERTEX_LIGHTING + +in mediump vec4 refprobe1_reflection_normal_blend; +#ifndef USE_LIGHTMAP +in mediump vec3 refprobe1_ambient_normal; +#endif + +#else + +uniform bool refprobe1_use_box_project; +uniform highp vec3 refprobe1_box_extents; +uniform vec3 refprobe1_box_offset; +uniform highp mat4 refprobe1_local_matrix; + +#endif //use vertex lighting + +uniform bool refprobe1_exterior; + +uniform highp samplerCube reflection_probe1; //texunit:-5 + +uniform float refprobe1_intensity; +uniform vec4 refprobe1_ambient; + +#endif //USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + +#ifdef USE_VERTEX_LIGHTING + +in mediump vec4 refprobe2_reflection_normal_blend; +#ifndef USE_LIGHTMAP +in mediump vec3 refprobe2_ambient_normal; +#endif + +#else + +uniform bool refprobe2_use_box_project; +uniform highp vec3 refprobe2_box_extents; +uniform vec3 refprobe2_box_offset; +uniform highp mat4 refprobe2_local_matrix; + +#endif //use vertex lighting + +uniform bool refprobe2_exterior; + +uniform highp samplerCube reflection_probe2; //texunit:-6 + +uniform float refprobe2_intensity; +uniform vec4 refprobe2_ambient; + +#endif //USE_REFLECTION_PROBE2 + +#define RADIANCE_MAX_LOD 6.0 + +#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + +void reflection_process(samplerCube reflection_map, +#ifdef USE_VERTEX_LIGHTING + vec3 ref_normal, +#ifndef USE_LIGHTMAP + vec3 amb_normal, +#endif + float ref_blend, + +#else //no vertex lighting + vec3 normal, vec3 vertex, + mat4 local_matrix, + bool use_box_project, vec3 box_extents, vec3 box_offset, +#endif //vertex lighting + bool exterior, float intensity, vec4 ref_ambient, float roughness, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { + vec4 reflection; + +#ifdef USE_VERTEX_LIGHTING + + reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; + + float blend = ref_blend; //crappier blend formula for vertex + blend *= blend; + blend = max(0.0, 1.0 - blend); + +#else //fragment lighting + + vec3 local_pos = (local_matrix * vec4(vertex, 1.0)).xyz; + + if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box + return; + } + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + blend = mix(length(inner_pos), blend, blend); + blend *= blend; + blend = max(0.0, 1.0 - blend); + + //reflect and make local + vec3 ref_normal = normalize(reflect(vertex, normal)); + ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz; + + if (use_box_project) { //box project + + vec3 nrdir = normalize(ref_normal); + vec3 rbmax = (box_extents - local_pos) / nrdir; + vec3 rbmin = (-box_extents - local_pos) / nrdir; + + vec3 rbminmax = mix(rbmin, rbmax, vec3(greaterThan(nrdir, vec3(0.0, 0.0, 0.0)))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + ref_normal = posonbox - box_offset.xyz; + } + + reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; +#endif + + if (exterior) { + reflection.rgb = mix(skybox, reflection.rgb, blend); + } + reflection.rgb *= intensity; + reflection.a = blend; + reflection.rgb *= blend; + + reflection_accum += reflection; + +#ifndef USE_LIGHTMAP + + vec4 ambient_out; +#ifndef USE_VERTEX_LIGHTING + + vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz; +#endif + + ambient_out.rgb = textureCubeLod(reflection_map, amb_normal, RADIANCE_MAX_LOD).rgb; + ambient_out.rgb = mix(ref_ambient.rgb, ambient_out.rgb, ref_ambient.a); + if (exterior) { + ambient_out.rgb = mix(ambient, ambient_out.rgb, blend); + } + + ambient_out.a = blend; + ambient_out.rgb *= blend; + ambient_accum += ambient_out; + +#endif +} + +#endif //use refprobe 1 or 2 + +#ifdef USE_LIGHTMAP +uniform mediump sampler2D lightmap; //texunit:-4 +uniform mediump float lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE +uniform mediump vec4[12] lightmap_captures; +uniform bool lightmap_capture_sky; + +#endif + +#ifdef USE_RADIANCE_MAP + +uniform samplerCube radiance_map; // texunit:-2 + +uniform mat4 radiance_inverse_xform; + +#endif + +uniform vec4 bg_color; +uniform float bg_energy; + +uniform float ambient_sky_contribution; +uniform vec4 ambient_color; +uniform float ambient_energy; + +#ifdef USE_LIGHTING + +uniform highp vec4 shadow_color; + +#ifdef USE_VERTEX_LIGHTING + +//get from vertex +in highp vec3 diffuse_interp; +in highp vec3 specular_interp; + +uniform highp vec3 light_direction; //may be used by fog, so leave here + +#else +//done in fragment +// general for all lights +uniform highp vec4 light_color; + +uniform highp float light_specular; + +// directional +uniform highp vec3 light_direction; +// omni +uniform highp vec3 light_position; + +uniform highp float light_attenuation; + +// spot +uniform highp float light_spot_attenuation; +uniform highp float light_spot_range; +uniform highp float light_spot_angle; +#endif + +//this is needed outside above if because dual paraboloid wants it +uniform highp float light_range; + +#ifdef USE_SHADOW + +uniform highp vec2 shadow_pixel_size; + +#if defined(LIGHT_MODE_OMNI) || defined(LIGHT_MODE_SPOT) +uniform highp sampler2D light_shadow_atlas; //texunit:-3 +#endif + +#ifdef LIGHT_MODE_DIRECTIONAL +uniform highp sampler2D light_directional_shadow; // texunit:-3 +uniform highp vec4 light_split_offsets; +#endif + +in highp vec4 shadow_coord; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) +in highp vec4 shadow_coord2; +#endif + +#if defined(LIGHT_USE_PSSM4) + +in highp vec4 shadow_coord3; +in highp vec4 shadow_coord4; + +#endif + +uniform vec4 light_clamp; + +#endif // light shadow + +// directional shadow + +#endif + +// +// varyings +// + +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) +in highp vec4 position_interp; +#endif + +in highp vec3 vertex_interp; +in vec3 normal_interp; + +#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) +in vec3 tangent_interp; +in vec3 binormal_interp; +#endif + +#if defined(ENABLE_COLOR_INTERP) +in vec4 color_interp; +#endif + +#if defined(ENABLE_UV_INTERP) +in vec2 uv_interp; +#endif + +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) +in vec2 uv2_interp; +#endif + +in vec3 view_interp; + +layout(location = 0) out vec4 frag_color; + +vec3 F0(float metallic, float specular, vec3 albedo) { + float dielectric = 0.16 * specular * specular; + // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; + // see https://google.github.io/filament/Filament.md.html + return mix(vec3(dielectric), albedo, vec3(metallic)); +} + +/* clang-format off */ + +FRAGMENT_SHADER_GLOBALS + +/* clang-format on */ + +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + +in highp float dp_clip; + +#endif + +#ifdef USE_LIGHTING + +// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. +// We're dividing this factor off because the overall term we'll end up looks like +// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): +// +// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) +// +// We're basically regouping this as +// +// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] +// +// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. +// +// The contents of the D and G (G1) functions (GGX) are taken from +// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). +// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). + +/* +float G_GGX_2cos(float cos_theta_m, float alpha) { + // Schlick's approximation + // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) + // Eq. (19), although see Heitz (2014) the about the problems with his derivation. + // It nevertheless approximates GGX well with k = alpha/2. + float k = 0.5 * alpha; + return 0.5 / (cos_theta_m * (1.0 - k) + k); + + // float cos2 = cos_theta_m * cos_theta_m; + // float sin2 = (1.0 - cos2); + // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); +} +*/ + +// This approximates G_GGX_2cos(cos_theta_l, alpha) * G_GGX_2cos(cos_theta_v, alpha) +// See Filament docs, Specular G section. +float V_GGX(float cos_theta_l, float cos_theta_v, float alpha) { + return 0.5 / mix(2.0 * cos_theta_l * cos_theta_v, cos_theta_l + cos_theta_v, alpha); +} + +float D_GGX(float cos_theta_m, float alpha) { + float alpha2 = alpha * alpha; + float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; + return alpha2 / (M_PI * d * d); +} + +/* +float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float s_x = alpha_x * cos_phi; + float s_y = alpha_y * sin_phi; + return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); +} +*/ + +// This approximates G_GGX_anisotropic_2cos(cos_theta_l, ...) * G_GGX_anisotropic_2cos(cos_theta_v, ...) +// See Filament docs, Anisotropic specular BRDF section. +float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { + float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); + float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); + return 0.5 / (Lambda_V + Lambda_L); +} + +float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) { + float alpha2 = alpha_x * alpha_y; + highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH); + highp float v2 = dot(v, v); + float w2 = alpha2 / v2; + float D = alpha2 * w2 * w2 * (1.0 / M_PI); + return D; + + /* float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float r_x = cos_phi / alpha_x; + float r_y = sin_phi / alpha_y; + float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); + return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); */ +} + +float SchlickFresnel(float u) { + float m = 1.0 - u; + float m2 = m * m; + return m2 * m2 * m; // pow(m,5) +} + +float GTR1(float NdotH, float a) { + if (a >= 1.0) + return 1.0 / M_PI; + float a2 = a * a; + float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; + return (a2 - 1.0) / (M_PI * log(a2) * t); +} + +void light_compute( + vec3 N, + vec3 L, + vec3 V, + vec3 B, + vec3 T, + vec3 light_color, + vec3 attenuation, + vec3 diffuse_color, + vec3 transmission, + float specular_blob_intensity, + float roughness, + float metallic, + float specular, + float rim, + float rim_tint, + float clearcoat, + float clearcoat_gloss, + float anisotropy, + inout vec3 diffuse_light, + inout vec3 specular_light, + inout float alpha) { +//this makes lights behave closer to linear, but then addition of lights looks bad +//better left disabled + +//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); +/* +#define SRGB_APPROX(m_var) {\ + float S1 = sqrt(m_var);\ + float S2 = sqrt(S1);\ + float S3 = sqrt(S2);\ + m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ + } +*/ +#define SRGB_APPROX(m_var) + +#if defined(USE_LIGHT_SHADER_CODE) + // light is written by the light shader + + vec3 normal = N; + vec3 albedo = diffuse_color; + vec3 light = L; + vec3 view = V; + + /* clang-format off */ + +LIGHT_SHADER_CODE + + /* clang-format on */ + +#else + float NdotL = dot(N, L); + float cNdotL = max(NdotL, 0.0); // clamped NdotL + float NdotV = dot(N, V); + float cNdotV = max(abs(NdotV), 1e-6); + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + vec3 H = normalize(V + L); +#endif + +#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cNdotH = max(dot(N, H), 0.0); +#endif + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cLdotH = max(dot(L, H), 0.0); +#endif + + if (metallic < 1.0) { +#if defined(DIFFUSE_OREN_NAYAR) + 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) + + { + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); + diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; + /* + float energyBias = mix(roughness, 0.0, 0.5); + float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); + float fd90 = energyBias + 2.0 * VoH * VoH * roughness; + float f0 = 1.0; + float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); + float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); + + diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; + */ + } +#else + // lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + SRGB_APPROX(diffuse_brdf_NL) + + diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; + +#if defined(TRANSMISSION_USED) + diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; +#endif + +#if defined(LIGHT_USE_RIM) + float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); + diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; +#endif + } + + if (roughness > 0.0) { + +#if defined(SPECULAR_SCHLICK_GGX) + vec3 specular_brdf_NL = vec3(0.0); +#else + float specular_brdf_NL = 0.0; +#endif + +#if defined(SPECULAR_BLINN) + + //normalized blinn + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess) * cNdotL; + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + specular_brdf_NL = blinn; + +#elif defined(SPECULAR_PHONG) + + vec3 R = normalize(-reflect(L, N)); + float cRdotV = max(0.0, dot(R, V)); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float phong = pow(cRdotV, shininess); + phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); + specular_brdf_NL = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + +#elif defined(SPECULAR_TOON) + + vec3 R = normalize(-reflect(L, N)); + float RdotV = dot(R, V); + float mid = 1.0 - roughness; + mid *= mid; + specular_brdf_NL = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + +#elif defined(SPECULAR_DISABLED) + // none.. +#elif defined(SPECULAR_SCHLICK_GGX) + // shlick+ggx as default + +#if defined(LIGHT_USE_ANISOTROPY) + float alpha_ggx = roughness * roughness; + float aspect = sqrt(1.0 - anisotropy * 0.9); + float ax = alpha_ggx / aspect; + float ay = alpha_ggx * aspect; + float XdotH = dot(T, H); + float YdotH = dot(B, H); + float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH, cNdotH); + //float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL); + +#else + float alpha_ggx = roughness * roughness; + float D = D_GGX(cNdotH, alpha_ggx); + //float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); + float G = V_GGX(cNdotL, cNdotV, alpha_ggx); +#endif + // F + vec3 f0 = F0(metallic, specular, diffuse_color); + float cLdotH5 = SchlickFresnel(cLdotH); + vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); + + specular_brdf_NL = cNdotL * D * F * G; + +#endif + + SRGB_APPROX(specular_brdf_NL) + specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; + +#if defined(LIGHT_USE_CLEARCOAT) + +#if !defined(SPECULAR_SCHLICK_GGX) + float cLdotH5 = SchlickFresnel(cLdotH); +#endif + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + //float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + float Gr = V_GGX(cNdotL, cNdotV, 0.25); + + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + + specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; +#endif + } + +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); +#endif + +#endif //defined(USE_LIGHT_SHADER_CODE) +} + +#endif +// shadows + +#ifdef USE_SHADOW + +#ifdef USE_RGBA_SHADOWS + +#define SHADOW_DEPTH(m_val) dot(m_val, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) + +#else + +#define SHADOW_DEPTH(m_val) (m_val).r + +#endif + +#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, SHADOW_DEPTH(texture(p_shadow, p_pos))) +#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, SHADOW_DEPTH(textureProj(p_shadow, p_pos))) + +float sample_shadow(highp sampler2D shadow, highp vec4 spos) { +#ifdef SHADOW_MODE_PCF_13 + + spos.xyz /= spos.w; + vec2 pos = spos.xy; + float depth = spos.z; + + float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth); + return avg * (1.0 / 13.0); +#endif + +#ifdef SHADOW_MODE_PCF_5 + + spos.xyz /= spos.w; + vec2 pos = spos.xy; + float depth = spos.z; + + float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); + return avg * (1.0 / 5.0); + +#endif + +#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) + + return SAMPLE_SHADOW_TEXEL_PROJ(shadow, spos); +#endif +} + +#endif + +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#if defined(USE_VERTEX_LIGHTING) + +in vec4 fog_interp; + +#else +uniform mediump vec4 fog_color_base; +#ifdef LIGHT_MODE_DIRECTIONAL +uniform mediump vec4 fog_sun_color_amount; +#endif + +uniform bool fog_transmit_enabled; +uniform mediump float fog_transmit_curve; + +#ifdef FOG_DEPTH_ENABLED +uniform highp float fog_depth_begin; +uniform mediump float fog_depth_curve; +uniform mediump float fog_max_distance; +#endif + +#ifdef FOG_HEIGHT_ENABLED +uniform highp float fog_height_min; +uniform highp float fog_height_max; +uniform mediump float fog_height_curve; +#endif + +#endif //vertex lit +#endif //fog + +void main() { +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + + if (dp_clip > 0.0) + discard; +#endif + highp vec3 vertex = vertex_interp; + vec3 view = -normalize(vertex_interp); + vec3 albedo = vec3(1.0); + vec3 transmission = vec3(0.0); + float metallic = 0.0; + float specular = 0.5; + 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 = 0.0; + vec2 anisotropy_flow = vec2(1.0, 0.0); + float sss_strength = 0.0; //unused + // gl_FragDepth is not available in GLES2, so writing to DEPTH is not converted to gl_FragDepth by Godot compiler resulting in a + // compile error because DEPTH is not a variable. + float m_DEPTH = 0.0; + + float alpha = 1.0; + float side = 1.0; + + float specular_blob_intensity = 1.0; +#if defined(SPECULAR_TOON) + specular_blob_intensity *= specular * 2.0; +#endif + +#if defined(ENABLE_AO) + float ao = 1.0; + float ao_light_affect = 0.0; +#endif + +#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_NORMALMAP) + vec3 normalmap = vec3(0.5); +#endif + float normaldepth = 1.0; + +#if defined(ALPHA_SCISSOR_USED) + float alpha_scissor = 0.5; +#endif + +#if defined(SCREEN_UV_USED) + vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; +#endif + + { + /* clang-format off */ + +FRAGMENT_SHADER_CODE + + /* clang-format on */ + } + +#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))); + + normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; + //normal = normalmap; +#endif + + normal = normalize(normal); + + vec3 N = normal; + + vec3 specular_light = vec3(0.0, 0.0, 0.0); + vec3 diffuse_light = vec3(0.0, 0.0, 0.0); + vec3 ambient_light = vec3(0.0, 0.0, 0.0); + + vec3 eye_position = view; + +#if !defined(USE_SHADOW_TO_OPACITY) + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_DEPTH_PREPASS + if (alpha < 0.1) { + discard; + } +#endif // USE_DEPTH_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY + +#ifdef BASE_PASS + + // IBL precalculations + float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); + vec3 f0 = F0(metallic, specular, albedo); + vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0); + +#ifdef AMBIENT_LIGHT_DISABLED + ambient_light = vec3(0.0, 0.0, 0.0); +#else + +#ifdef USE_RADIANCE_MAP + + vec3 ref_vec = reflect(-eye_position, N); + ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); + + ref_vec.z *= -1.0; + + specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; +#ifndef USE_LIGHTMAP + { + vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz); + vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy; + env_ambient *= 1.0 - F; + + ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); + } +#endif + +#else + + ambient_light = ambient_color.rgb; + specular_light = bg_color.rgb * bg_energy; + +#endif +#endif // AMBIENT_LIGHT_DISABLED + ambient_light *= ambient_energy; + +#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + + vec4 ambient_accum = vec4(0.0); + vec4 reflection_accum = vec4(0.0); + +#ifdef USE_REFLECTION_PROBE1 + + reflection_process(reflection_probe1, +#ifdef USE_VERTEX_LIGHTING + refprobe1_reflection_normal_blend.rgb, +#ifndef USE_LIGHTMAP + refprobe1_ambient_normal, +#endif + refprobe1_reflection_normal_blend.a, +#else + normal_interp, vertex_interp, refprobe1_local_matrix, + refprobe1_use_box_project, refprobe1_box_extents, refprobe1_box_offset, +#endif + refprobe1_exterior, refprobe1_intensity, refprobe1_ambient, roughness, + ambient_light, specular_light, reflection_accum, ambient_accum); + +#endif // USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + + reflection_process(reflection_probe2, +#ifdef USE_VERTEX_LIGHTING + refprobe2_reflection_normal_blend.rgb, +#ifndef USE_LIGHTMAP + refprobe2_ambient_normal, +#endif + refprobe2_reflection_normal_blend.a, +#else + normal_interp, vertex_interp, refprobe2_local_matrix, + refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset, +#endif + refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness, + ambient_light, specular_light, reflection_accum, ambient_accum); + +#endif // USE_REFLECTION_PROBE2 + + if (reflection_accum.a > 0.0) { + specular_light = reflection_accum.rgb / reflection_accum.a; + } + +#ifndef USE_LIGHTMAP + if (ambient_accum.a > 0.0) { + ambient_light = ambient_accum.rgb / ambient_accum.a; + } +#endif + +#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + + // environment BRDF approximation + { +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + + // scales the specular reflections, needs to be be computed before lighting happens, + // but after environment and reflection probes are added + //TODO: this curve is not really designed for gammaspace, should be adjusted + const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); + const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); + vec4 r = roughness * c0 + c1; + float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; + specular_light *= env.x * F + env.y; + +#endif + } + +#ifdef USE_LIGHTMAP + //ambient light will come entirely from lightmap is lightmap is used + ambient_light = texture(lightmap, uv2_interp).rgb * lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE + { + vec3 cone_dirs[12]; + cone_dirs[0] = vec3(0.0, 0.0, 1.0); + cone_dirs[1] = vec3(0.866025, 0.0, 0.5); + cone_dirs[2] = vec3(0.267617, 0.823639, 0.5); + cone_dirs[3] = vec3(-0.700629, 0.509037, 0.5); + cone_dirs[4] = vec3(-0.700629, -0.509037, 0.5); + cone_dirs[5] = vec3(0.267617, -0.823639, 0.5); + cone_dirs[6] = vec3(0.0, 0.0, -1.0); + cone_dirs[7] = vec3(0.866025, 0.0, -0.5); + cone_dirs[8] = vec3(0.267617, 0.823639, -0.5); + cone_dirs[9] = vec3(-0.700629, 0.509037, -0.5); + cone_dirs[10] = vec3(-0.700629, -0.509037, -0.5); + cone_dirs[11] = vec3(0.267617, -0.823639, -0.5); + + vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz; + vec4 captured = vec4(0.0); + float sum = 0.0; + for (int i = 0; i < 12; i++) { + float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect + captured += lightmap_captures[i] * amount; + sum += amount; + } + + captured /= sum; + + if (lightmap_capture_sky) { + ambient_light = mix(ambient_light, captured.rgb, captured.a); + } else { + ambient_light = captured.rgb; + } + } +#endif + +#endif //BASE PASS + +// +// Lighting +// +#ifdef USE_LIGHTING + +#ifndef USE_VERTEX_LIGHTING + vec3 L; +#endif + vec3 light_att = vec3(1.0); + +#ifdef LIGHT_MODE_OMNI + +#ifndef USE_VERTEX_LIGHTING + vec3 light_vec = light_position - vertex; + float light_length = length(light_vec); + + float normalized_distance = light_length / light_range; + if (normalized_distance < 1.0) { + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); + + light_att = vec3(omni_attenuation); + } else { + light_att = vec3(0.0); + } + L = normalize(light_vec); + +#endif + +#if !defined(SHADOWS_DISABLED) + +#ifdef USE_SHADOW + { + highp vec4 splane = shadow_coord; + float shadow_len = length(splane.xyz); + + splane.xyz = normalize(splane.xyz); + + vec4 clamp_rect = light_clamp; + + if (splane.z >= 0.0) { + splane.z += 1.0; + + clamp_rect.y += clamp_rect.w; + } else { + splane.z = 1.0 - splane.z; + } + + 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; + splane.w = 1.0; + + float shadow = sample_shadow(light_shadow_atlas, splane); + + light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); + } +#endif + +#endif //SHADOWS_DISABLED + +#endif //type omni + +#ifdef LIGHT_MODE_DIRECTIONAL + +#ifndef USE_VERTEX_LIGHTING + vec3 light_vec = -light_direction; + L = normalize(light_vec); +#endif + float depth_z = -vertex.z; + +#if !defined(SHADOWS_DISABLED) + +#ifdef USE_SHADOW + +#ifdef USE_VERTEX_LIGHTING + //compute shadows in a mobile friendly way + +#ifdef LIGHT_USE_PSSM4 + //take advantage of prefetch + float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); + float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); + float shadow3 = sample_shadow(light_directional_shadow, shadow_coord3); + float shadow4 = sample_shadow(light_directional_shadow, shadow_coord4); + + if (depth_z < light_split_offsets.w) { + float pssm_fade = 0.0; + float shadow_att = 1.0; +#ifdef LIGHT_USE_PSSM_BLEND + float shadow_att2 = 1.0; + float pssm_blend = 0.0; + bool use_blend = true; +#endif + if (depth_z < light_split_offsets.y) { + if (depth_z < light_split_offsets.x) { + shadow_att = shadow1; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow2; + + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); +#endif + } else { + shadow_att = shadow2; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow3; + + pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#endif + } + } else { + if (depth_z < light_split_offsets.z) { + shadow_att = shadow3; + +#if defined(LIGHT_USE_PSSM_BLEND) + shadow_att2 = shadow4; + pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); +#endif + + } else { + shadow_att = shadow4; + pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); + +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend = false; +#endif + } + } +#if defined(LIGHT_USE_PSSM_BLEND) + if (use_blend) { + shadow_att = mix(shadow_att, shadow_att2, pssm_blend); + } +#endif + light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att); + } + +#endif //LIGHT_USE_PSSM4 + +#ifdef LIGHT_USE_PSSM2 + + //take advantage of prefetch + float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); + float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); + + if (depth_z < light_split_offsets.y) { + float shadow_att = 1.0; + float pssm_fade = 0.0; + +#ifdef LIGHT_USE_PSSM_BLEND + float shadow_att2 = 1.0; + float pssm_blend = 0.0; + bool use_blend = true; +#endif + if (depth_z < light_split_offsets.x) { + float pssm_fade = 0.0; + shadow_att = shadow1; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow2; + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); +#endif + } else { + shadow_att = shadow2; + pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#ifdef LIGHT_USE_PSSM_BLEND + use_blend = false; +#endif + } +#ifdef LIGHT_USE_PSSM_BLEND + if (use_blend) { + shadow_att = mix(shadow_att, shadow_att2, pssm_blend); + } +#endif + light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att); + } + +#endif //LIGHT_USE_PSSM2 + +#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) + + light_att *= mix(shadow_color.rgb, vec3(1.0), sample_shadow(light_directional_shadow, shadow_coord)); +#endif //orthogonal + +#else //fragment version of pssm + + { +#ifdef LIGHT_USE_PSSM4 + if (depth_z < light_split_offsets.w) { +#elif defined(LIGHT_USE_PSSM2) + if (depth_z < light_split_offsets.y) { +#else + if (depth_z < light_split_offsets.x) { +#endif //pssm2 + + highp vec4 pssm_coord; + float pssm_fade = 0.0; + +#ifdef LIGHT_USE_PSSM_BLEND + float pssm_blend; + highp vec4 pssm_coord2; + bool use_blend = true; +#endif + +#ifdef LIGHT_USE_PSSM4 + + if (depth_z < light_split_offsets.y) { + if (depth_z < light_split_offsets.x) { + pssm_coord = shadow_coord; + +#ifdef LIGHT_USE_PSSM_BLEND + pssm_coord2 = shadow_coord2; + + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); +#endif + } else { + pssm_coord = shadow_coord2; + +#ifdef LIGHT_USE_PSSM_BLEND + pssm_coord2 = shadow_coord3; + + pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#endif + } + } else { + if (depth_z < light_split_offsets.z) { + pssm_coord = shadow_coord3; + +#if defined(LIGHT_USE_PSSM_BLEND) + pssm_coord2 = shadow_coord4; + pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); +#endif + + } else { + pssm_coord = shadow_coord4; + pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); + +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend = false; +#endif + } + } + +#endif // LIGHT_USE_PSSM4 + +#ifdef LIGHT_USE_PSSM2 + if (depth_z < light_split_offsets.x) { + pssm_coord = shadow_coord; + +#ifdef LIGHT_USE_PSSM_BLEND + pssm_coord2 = shadow_coord2; + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); +#endif + } else { + pssm_coord = shadow_coord2; + pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#ifdef LIGHT_USE_PSSM_BLEND + use_blend = false; +#endif + } + +#endif // LIGHT_USE_PSSM2 + +#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) + { + pssm_coord = shadow_coord; + } +#endif + + float shadow = sample_shadow(light_directional_shadow, pssm_coord); + +#ifdef LIGHT_USE_PSSM_BLEND + if (use_blend) { + shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2), pssm_blend); + } +#endif + + light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); + } + } +#endif //use vertex lighting + +#endif //use shadow + +#endif // SHADOWS_DISABLED + +#endif + +#ifdef LIGHT_MODE_SPOT + + light_att = vec3(1.0); + +#ifndef USE_VERTEX_LIGHTING + + vec3 light_rel_vec = light_position - vertex; + float light_length = length(light_rel_vec); + float normalized_distance = light_length / light_range; + + if (normalized_distance < 1.0) { + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); + vec3 spot_dir = light_direction; + + float spot_cutoff = light_spot_angle; + float angle = dot(-normalize(light_rel_vec), spot_dir); + + if (angle > spot_cutoff) { + float scos = max(angle, spot_cutoff); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + + light_att = vec3(spot_attenuation); + } else { + light_att = vec3(0.0); + } + } else { + light_att = vec3(0.0); + } + + L = normalize(light_rel_vec); + +#endif + +#if !defined(SHADOWS_DISABLED) + +#ifdef USE_SHADOW + { + highp vec4 splane = shadow_coord; + + float shadow = sample_shadow(light_shadow_atlas, splane); + light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); + } +#endif + +#endif // SHADOWS_DISABLED + +#endif // LIGHT_MODE_SPOT + +#ifdef USE_VERTEX_LIGHTING + //vertex lighting + + specular_light += specular_interp * specular_blob_intensity * light_att; + diffuse_light += diffuse_interp * albedo * light_att; + +#else + //fragment lighting + light_compute( + normal, + L, + eye_position, + binormal, + tangent, + light_color.xyz, + light_att, + albedo, + transmission, + specular_blob_intensity * light_specular, + roughness, + metallic, + specular, + rim, + rim_tint, + clearcoat, + clearcoat_gloss, + anisotropy, + diffuse_light, + specular_light, + alpha); + +#endif //vertex lighting + +#endif //USE_LIGHTING + //compute and merge + +#ifdef USE_SHADOW_TO_OPACITY + + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_DEPTH_PREPASS + if (alpha < 0.1) { + discard; + } +#endif // USE_DEPTH_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY + +#ifndef RENDER_DEPTH + +#ifdef SHADELESS + + frag_color = vec4(albedo, alpha); +#else + + 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; +#endif + + diffuse_light *= 1.0 - metallic; + ambient_light *= 1.0 - metallic; + + frag_color = vec4(ambient_light + diffuse_light + specular_light, alpha); + + //add emission if in base pass +#ifdef BASE_PASS + frag_color.rgb += emission; +#endif + // frag_color = vec4(normal, 1.0); + +//apply fog +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#if defined(USE_VERTEX_LIGHTING) + +#if defined(BASE_PASS) + frag_color.rgb = mix(frag_color.rgb, fog_interp.rgb, fog_interp.a); +#else + frag_color.rgb *= (1.0 - fog_interp.a); +#endif // BASE_PASS + +#else //pixel based fog + float fog_amount = 0.0; + +#ifdef LIGHT_MODE_DIRECTIONAL + + vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(eye_position, light_direction), 0.0), 8.0)); +#else + vec3 fog_color = fog_color_base.rgb; +#endif + +#ifdef FOG_DEPTH_ENABLED + + { + float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); + + fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; + + if (fog_transmit_enabled) { + vec3 total_light = frag_color.rgb; + float transmit = pow(fog_z, fog_transmit_curve); + fog_color = mix(max(total_light, fog_color), fog_color, transmit); + } + } +#endif + +#ifdef FOG_HEIGHT_ENABLED + { + float y = (camera_matrix * vec4(vertex, 1.0)).y; + fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); + } +#endif + +#if defined(BASE_PASS) + frag_color.rgb = mix(frag_color.rgb, fog_color, fog_amount); +#else + frag_color.rgb *= (1.0 - fog_amount); +#endif // BASE_PASS + +#endif //use vertex lit + +#endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#endif //unshaded + +#else // not RENDER_DEPTH +//depth render +#ifdef USE_RGBA_SHADOWS + + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias + highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); + comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); + frag_color = comp; + +#endif +#endif +} diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl new file mode 100644 index 0000000000..8b3aa4d309 --- /dev/null +++ b/drivers/gles3/shaders/tonemap.glsl @@ -0,0 +1,313 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +layout(location = 0) vec2 vertex_attrib; +/* clang-format on */ +layout(location = 4) vec2 uv_in; + +out vec2 uv_interp; + +void main() { + gl_Position = vec4(vertex_attrib, 0.0, 1.0); + + uv_interp = uv_in; +} + +/* clang-format off */ +[fragment] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +in vec2 uv_interp; +/* clang-format on */ + +layout(location = 0) out vec4 frag_color; + +uniform highp sampler2D source; //texunit:0 + +#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) +#define USING_GLOW // only use glow when at least one glow level is selected + +#ifdef USE_MULTI_TEXTURE_GLOW +uniform highp sampler2D source_glow1; //texunit:2 +uniform highp sampler2D source_glow2; //texunit:3 +uniform highp sampler2D source_glow3; //texunit:4 +uniform highp sampler2D source_glow4; //texunit:5 +uniform highp sampler2D source_glow5; //texunit:6 +uniform highp sampler2D source_glow6; //texunit:7 +#ifdef USE_GLOW_LEVEL7 +uniform highp sampler2D source_glow7; //texunit:8 +#endif +#else +uniform highp sampler2D source_glow; //texunit:2 +#endif +uniform highp float glow_intensity; +#endif + +#ifdef USE_BCS +uniform vec3 bcs; +#endif + +#ifdef USE_FXAA +uniform vec2 pixel_size; +#endif + +#ifdef USE_COLOR_CORRECTION +uniform sampler2D color_correction; //texunit:1 +#endif + +#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 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 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 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 h1(float a) { + return 1.0 + w3(a) / (w2(a) + w3(a)); +} + +uniform ivec2 glow_texture_size; + +vec4 texture_bicubic(sampler2D tex, vec2 uv, int p_lod) { + float lod = float(p_lod); + vec2 tex_size = vec2(glow_texture_size >> p_lod); + vec2 texel_size = vec2(1.0) / tex_size; + + uv = uv * tex_size + vec2(0.5); + + vec2 iuv = floor(uv); + vec2 fuv = fract(uv); + + float g0x = g0(fuv.x); + float g1x = g1(fuv.x); + float h0x = h0(fuv.x); + float h1x = h1(fuv.x); + float h0y = h0(fuv.y); + float h1y = h1(fuv.y); + + vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * texel_size; + vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * texel_size; + vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * texel_size; + vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * texel_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))); +} + +#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture_bicubic(m_tex, m_uv, m_lod) +#else //!USE_GLOW_FILTER_BICUBIC +#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod)) +#endif //USE_GLOW_FILTER_BICUBIC + +vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode +#ifdef USE_GLOW_REPLACE + color = glow; +#endif + +#ifdef USE_GLOW_SCREEN + color = max((color + glow) - (color * glow), vec3(0.0)); +#endif + +#ifdef USE_GLOW_SOFTLIGHT + glow = glow * vec3(0.5) + vec3(0.5); + + color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); + color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); + color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); +#endif + +#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) // no other selected -> additive + color += glow; +#endif + + return color; +} + +vec3 apply_bcs(vec3 color, vec3 bcs) { + color = mix(vec3(0.0), color, bcs.x); + color = mix(vec3(0.5), color, bcs.y); + color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z); + + return color; +} + +vec3 apply_color_correction(vec3 color, sampler2D correction_tex) { + color.r = texture(correction_tex, vec2(color.r, 0.0)).r; + color.g = texture(correction_tex, vec2(color.g, 0.0)).g; + color.b = texture(correction_tex, vec2(color.b, 0.0)).b; + + return color; +} + +vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) { + const float FXAA_REDUCE_MIN = (1.0 / 128.0); + const float FXAA_REDUCE_MUL = (1.0 / 8.0); + const float FXAA_SPAN_MAX = 8.0; + + vec3 rgbNW = textureLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz; + vec3 rgbNE = textureLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz; + vec3 rgbSW = textureLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz; + vec3 rgbSE = textureLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz; + vec3 rgbM = color; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), + FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * + pixel_size; + + vec3 rgbA = 0.5 * (textureLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + textureLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * (textureLod(source, uv_interp + dir * -0.5, 0.0).xyz + textureLod(source, uv_interp + dir * 0.5, 0.0).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) { + return rgbA; + } else { + return rgbB; + } +} + +void main() { + vec3 color = textureLod(source, uv_interp, 0.0).rgb; + +#ifdef USE_FXAA + color = apply_fxaa(color, uv_interp, pixel_size); +#endif + + // Glow + +#ifdef USING_GLOW + vec3 glow = vec3(0.0); +#ifdef USE_MULTI_TEXTURE_GLOW +#ifdef USE_GLOW_LEVEL1 + glow += GLOW_TEXTURE_SAMPLE(source_glow1, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL2 + glow += GLOW_TEXTURE_SAMPLE(source_glow2, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL3 + glow += GLOW_TEXTURE_SAMPLE(source_glow3, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL4 + glow += GLOW_TEXTURE_SAMPLE(source_glow4, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL5 + glow += GLOW_TEXTURE_SAMPLE(source_glow5, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL6 + glow += GLOW_TEXTURE_SAMPLE(source_glow6, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL7 + glow += GLOW_TEXTURE_SAMPLE(source_glow7, uv_interp, 0).rgb; +#endif +#endif +#endif +#endif +#endif +#endif +#endif + +#else + +#ifdef USE_GLOW_LEVEL1 + 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; +#endif + +#ifdef USE_GLOW_LEVEL3 + 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; +#endif + +#ifdef USE_GLOW_LEVEL5 + 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; +#endif + +#ifdef USE_GLOW_LEVEL7 + glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 7).rgb; +#endif +#endif //USE_MULTI_TEXTURE_GLOW + + glow *= glow_intensity; + color = apply_glow(color, glow); +#endif + + // Additional effects + +#ifdef USE_BCS + color = apply_bcs(color, bcs); +#endif + +#ifdef USE_COLOR_CORRECTION + color = apply_color_correction(color, color_correction); +#endif + + frag_color = vec4(color, 1.0); +} diff --git a/drivers/gles3/texture_loader_gles3.cpp b/drivers/gles3/texture_loader_gles3.cpp new file mode 100644 index 0000000000..1954eff923 --- /dev/null +++ b/drivers/gles3/texture_loader_gles3.cpp @@ -0,0 +1,112 @@ +/*************************************************************************/ +/* texture_loader_gles3.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "texture_loader_gles3.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/io/file_access.h" +#include "core/string/print_string.h" + +#include + +RES ResourceFormatGLES2Texture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { + unsigned int width = 8; + unsigned int height = 8; + + //We just use some format + Image::Format fmt = Image::FORMAT_RGB8; + int rowsize = 3 * width; + + Vector dstbuff; + + dstbuff.resize(rowsize * height); + + uint8_t **row_p = memnew_arr(uint8_t *, height); + + for (unsigned int i = 0; i < height; i++) { + row_p[i] = 0; //No colors any more, I want them to turn black + } + + memdelete_arr(row_p); + + Ref img = memnew(Image(width, height, 0, fmt, dstbuff)); + + Ref texture = memnew(ImageTexture); + texture->create_from_image(img); + + if (r_error) + *r_error = OK; + + return texture; +} + +void ResourceFormatGLES2Texture::get_recognized_extensions(List *p_extensions) const { + p_extensions->push_back("bmp"); + p_extensions->push_back("dds"); + p_extensions->push_back("exr"); + p_extensions->push_back("jpeg"); + p_extensions->push_back("jpg"); + p_extensions->push_back("hdr"); + p_extensions->push_back("pkm"); + p_extensions->push_back("png"); + p_extensions->push_back("pvr"); + p_extensions->push_back("svg"); + p_extensions->push_back("svgz"); + p_extensions->push_back("tga"); + p_extensions->push_back("webp"); +} + +bool ResourceFormatGLES2Texture::handles_type(const String &p_type) const { + return ClassDB::is_parent_class(p_type, "Texture2D"); +} + +String ResourceFormatGLES2Texture::get_resource_type(const String &p_path) const { + String extension = p_path.get_extension().to_lower(); + if ( + extension == "bmp" || + extension == "dds" || + extension == "exr" || + extension == "jpeg" || + extension == "jpg" || + extension == "hdr" || + extension == "pkm" || + extension == "png" || + extension == "pvr" || + extension == "svg" || + extension == "svgz" || + extension == "tga" || + extension == "webp") { + return "ImageTexture"; + } + + return ""; +} + +#endif diff --git a/drivers/gles3/texture_loader_gles3.h b/drivers/gles3/texture_loader_gles3.h new file mode 100644 index 0000000000..64a635fb06 --- /dev/null +++ b/drivers/gles3/texture_loader_gles3.h @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* texture_loader_gles3.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEXTURE_LOADER_OPENGL_H +#define TEXTURE_LOADER_OPENGL_H + +#include "drivers/gles3/rasterizer_platforms.h" +#ifdef GLES3_BACKEND_ENABLED + +#include "core/io/resource_loader.h" +#include "scene/resources/texture.h" + +class ResourceFormatGLES2Texture : public ResourceFormatLoader { +public: + virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); + virtual void get_recognized_extensions(List *p_extensions) const; + virtual bool handles_type(const String &p_type) const; + virtual String get_resource_type(const String &p_path) const; + + virtual ~ResourceFormatGLES2Texture() {} +}; + +#endif // GLES3_BACKEND_ENABLED + +#endif // TEXTURE_LOADER_OPENGL_H diff --git a/drivers/opengl/SCsub b/drivers/opengl/SCsub deleted file mode 100644 index 987ddcd16e..0000000000 --- a/drivers/opengl/SCsub +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -env.add_source_files(env.drivers_sources, "*.cpp") - -SConscript("shaders/SCsub") diff --git a/drivers/opengl/rasterizer_array.h b/drivers/opengl/rasterizer_array.h deleted file mode 100644 index aeadee56bf..0000000000 --- a/drivers/opengl/rasterizer_array.h +++ /dev/null @@ -1,421 +0,0 @@ -/*************************************************************************/ -/* rasterizer_array.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_ARRAY_H -#define RASTERIZER_ARRAY_H - -/** - * Fast single-threaded growable array for POD types. - * For use in render drivers, not for general use. - * TO BE REPLACED by local_vector. -*/ - -#include "core/os/memory.h" -#include - -#include "core/templates/local_vector.h" -#include "core/templates/vector.h" - -// very simple non-growable array, that keeps track of the size of a 'unit' -// which can be cast to whatever vertex format FVF required, and is initially -// created with enough memory to hold the biggest FVF. -// This allows multiple FVFs to use the same array. -class RasterizerUnitArrayOpenGL { -public: - RasterizerUnitArrayOpenGL() { - _list = nullptr; - free(); - } - ~RasterizerUnitArrayOpenGL() { free(); } - - uint8_t *get_unit(unsigned int ui) { return &_list[ui * _unit_size_bytes]; } - const uint8_t *get_unit(unsigned int ui) const { return &_list[ui * _unit_size_bytes]; } - - int size() const { return _size; } - int max_size() const { return _max_size; } - - void free() { - if (_list) { - memdelete_arr(_list); - _list = 0; - } - _size = 0; - _max_size = 0; - _max_size_bytes = 0; - _unit_size_bytes = 0; - } - - void create(int p_max_size_units, int p_max_unit_size_bytes) { - free(); - - _max_unit_size_bytes = p_max_unit_size_bytes; - _max_size = p_max_size_units; - _max_size_bytes = p_max_size_units * p_max_unit_size_bytes; - - if (_max_size_bytes) { - _list = memnew_arr(uint8_t, _max_size_bytes); - } - } - - void prepare(int p_unit_size_bytes) { - _unit_size_bytes = p_unit_size_bytes; - _size = 0; - } - - // several items at a time - uint8_t *request(int p_num_items = 1) { - int old_size = _size; - _size += p_num_items; - - if (_size <= _max_size) { - return get_unit(old_size); - } - - // revert - _size = old_size; - return nullptr; - } - -private: - uint8_t *_list; - int _size; // in units - int _max_size; // in units - int _max_size_bytes; - int _unit_size_bytes; - int _max_unit_size_bytes; -}; - -template -class RasterizerArray { -public: - RasterizerArray() { - _list = 0; - _size = 0; - _max_size = 0; - } - ~RasterizerArray() { free(); } - - T &operator[](unsigned int ui) { return _list[ui]; } - const T &operator[](unsigned int ui) const { return _list[ui]; } - - void free() { - if (_list) { - memdelete_arr(_list); - _list = 0; - } - _size = 0; - _max_size = 0; - } - - void create(int p_size) { - free(); - if (p_size) { - _list = memnew_arr(T, p_size); - } - _size = 0; - _max_size = p_size; - } - - void reset() { _size = 0; } - - T *request_with_grow() { - T *p = request(); - if (!p) { - grow(); - return request_with_grow(); - } - return p; - } - - // none of that inefficient pass by value stuff here, thanks - T *request() { - if (_size < _max_size) { - return &_list[_size++]; - } - return 0; - } - - // several items at a time - T *request(int p_num_items) { - int old_size = _size; - _size += p_num_items; - - if (_size <= _max_size) { - return &_list[old_size]; - } - - // revert - _size = old_size; - return 0; - } - - int size() const { return _size; } - int max_size() const { return _max_size; } - const T *get_data() const { return _list; } - - bool copy_from(const RasterizerArray &o) { - // no resizing done here, it should be done manually - if (o.size() > _max_size) - return false; - - // pod types only please! - memcpy(_list, o.get_data(), o.size() * sizeof(T)); - _size = o.size(); - return true; - } - - // if you want this to be cheap, call reset before grow, - // to ensure there is no data to copy - void grow() { - unsigned int new_max_size = _max_size * 2; - if (!new_max_size) - new_max_size = 1; - - T *new_list = memnew_arr(T, new_max_size); - - // copy .. pod types only - if (_list) { - memcpy(new_list, _list, _size * sizeof(T)); - } - - unsigned int new_size = size(); - free(); - _list = new_list; - _size = new_size; - _max_size = new_max_size; - } - -private: - T *_list; - int _size; - int _max_size; -}; - -template -class RasterizerArray_non_pod { -public: - RasterizerArray_non_pod() { - _size = 0; - } - - const T &operator[](unsigned int ui) const { return _list[ui]; } - - void create(int p_size) { - _list.resize(p_size); - _size = 0; - } - void reset() { _size = 0; } - - void push_back(const T &val) { - while (true) { - if (_size < max_size()) { - _list.set(_size, val); - _size++; - return; - } - - grow(); - } - } - - int size() const { return _size; } - int max_size() const { return _list.size(); } - -private: - void grow() { - unsigned int new_max_size = _list.size() * 2; - if (!new_max_size) - new_max_size = 1; - _list.resize(new_max_size); - } - - Vector _list; - int _size; -}; - -// very simple non-growable array, that keeps track of the size of a 'unit' -// which can be cast to whatever vertex format FVF required, and is initially -// created with enough memory to hold the biggest FVF. -// This allows multiple FVFs to use the same array. -class RasterizerUnitArray { -public: - RasterizerUnitArray() { - _list = nullptr; - free(); - } - ~RasterizerUnitArray() { free(); } - - uint8_t *get_unit(unsigned int ui) { return &_list[ui * _unit_size_bytes]; } - const uint8_t *get_unit(unsigned int ui) const { return &_list[ui * _unit_size_bytes]; } - - int size() const { return _size; } - int max_size() const { return _max_size; } - int get_unit_size_bytes() const { return _unit_size_bytes; } - - void free() { - if (_list) { - memdelete_arr(_list); - _list = 0; - } - _size = 0; - _max_size = 0; - _max_size_bytes = 0; - _unit_size_bytes = 0; - } - - void create(int p_max_size_units, int p_max_unit_size_bytes) { - free(); - - _max_unit_size_bytes = p_max_unit_size_bytes; - _max_size = p_max_size_units; - _max_size_bytes = p_max_size_units * p_max_unit_size_bytes; - - if (_max_size_bytes) { - _list = memnew_arr(uint8_t, _max_size_bytes); - } - } - - void prepare(int p_unit_size_bytes) { - _unit_size_bytes = p_unit_size_bytes; - _size = 0; - } - - // several items at a time - uint8_t *request(int p_num_items = 1) { - int old_size = _size; - _size += p_num_items; - - if (_size <= _max_size) { - return get_unit(old_size); - } - - // revert - _size = old_size; - return nullptr; - } - -private: - uint8_t *_list; - int _size; // in units - int _max_size; // in units - int _max_size_bytes; - int _unit_size_bytes; - int _max_unit_size_bytes; -}; - -template -class RasterizerPooledList { - LocalVector list; - LocalVector freelist; - - // not all list members are necessarily used - int _used_size; - -public: - RasterizerPooledList() { - _used_size = 0; - } - - int estimate_memory_use() const { - return (list.size() * sizeof(T)) + (freelist.size() * sizeof(uint32_t)); - } - - const T &operator[](uint32_t p_index) const { - return list[p_index]; - } - T &operator[](uint32_t p_index) { - return list[p_index]; - } - - int size() const { return _used_size; } - - // returns the list id of the allocated item - uint32_t alloc() { - uint32_t id = 0; - _used_size++; - - if (freelist.size()) { - // pop from freelist - int new_size = freelist.size() - 1; - id = freelist[new_size]; - freelist.resize(new_size); - return id; - // return &list[r_id]; - } - - id = list.size(); - list.resize(id + 1); - return id; - // return &list[r_id]; - } - void free(const uint32_t &p_id) { - // should not be on free list already - CRASH_COND(p_id >= list.size()); - freelist.push_back(p_id); - _used_size--; - } -}; - -template -class RasterizerPooledIndirectList { -public: - const T &operator[](uint32_t p_index) const { - return *_list[p_index]; - } - T &operator[](uint32_t p_index) { - return *_list[p_index]; - } - - uint32_t alloc() { - uint32_t id = _list.alloc(); - _list[id] = memnew(T); - return id; - } - void free(const uint32_t &p_id) { - CRASH_COND(!_list[p_id]); - memdelete_notnull(_list[p_id]); - _list[p_id] = nullptr; - _list.free(p_id); - } - - ~RasterizerPooledIndirectList() { - // autodelete - for (int n = 0; n < _list.size(); n++) { - if (_list[n]) { - memdelete_notnull(_list[n]); - } - } - } - -private: - RasterizerPooledList _list; -}; - -#endif // RASTERIZER_ARRAY_H diff --git a/drivers/opengl/rasterizer_asserts.h b/drivers/opengl/rasterizer_asserts.h deleted file mode 100644 index dbc45035b2..0000000000 --- a/drivers/opengl/rasterizer_asserts.h +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************/ -/* rasterizer_asserts.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_ASSERTS_H -#define RASTERIZER_ASSERTS_H - -// For flow control checking, we want an easy way to apply asserts that occur in debug development builds only. -// This is enforced by outputting a warning which will fail CI checks if the define is set in a PR. -#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) -// only uncomment this define for error checking in development, not in the main repository -// as these checks will slow things down in debug builds. -//#define RASTERIZER_EXTRA_CHECKS -#endif - -#ifdef RASTERIZER_EXTRA_CHECKS -#ifndef _MSC_VER -#warning do not define RASTERIZER_EXTRA_CHECKS in main repository builds -#endif -#define RAST_DEV_DEBUG_ASSERT(a) CRASH_COND(!(a)) -#else -#define RAST_DEV_DEBUG_ASSERT(a) -#endif - -// Also very useful, an assert check that only occurs in debug tools builds -#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) -#define RAST_DEBUG_ASSERT(a) CRASH_COND(!(a)) -#else -#define RAST_DEBUG_ASSERT(a) -#endif - -// Thin wrapper around ERR_FAIL_COND to allow us to make it debug only -#ifdef DEBUG_ENABLED -#define RAST_FAIL_COND(m_cond) ERR_FAIL_COND(m_cond) -#else -#define RAST_FAIL_COND(m_cond) \ - if (m_cond) { \ - } -#endif - -#endif // RASTERIZER_ASSERTS_H diff --git a/drivers/opengl/rasterizer_canvas_base_opengl.cpp b/drivers/opengl/rasterizer_canvas_base_opengl.cpp deleted file mode 100644 index 9b586f296d..0000000000 --- a/drivers/opengl/rasterizer_canvas_base_opengl.cpp +++ /dev/null @@ -1,1252 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_base_opengl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rasterizer_canvas_base_opengl.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/os/os.h" -#include "drivers/opengl/rasterizer_asserts.h" -#include "rasterizer_scene_opengl.h" - -#include "core/config/project_settings.h" -#include "servers/rendering/rendering_server_default.h" - -#ifndef GLES_OVER_GL -#define glClearDepth glClearDepthf -#endif - -RID RasterizerCanvasBaseOpenGL::light_internal_create() { - return RID(); -} - -void RasterizerCanvasBaseOpenGL::light_internal_update(RID p_rid, Light *p_light) { -} - -void RasterizerCanvasBaseOpenGL::light_internal_free(RID p_rid) { -} - -RID RasterizerCanvasBaseOpenGL::light_create() { - return RID(); -} - -void RasterizerCanvasBaseOpenGL::light_set_texture(RID p_rid, RID p_texture) { -} - -void RasterizerCanvasBaseOpenGL::light_set_use_shadow(RID p_rid, bool p_enable) { -} - -void RasterizerCanvasBaseOpenGL::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { -} - -void RasterizerCanvasBaseOpenGL::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { -} - -void RasterizerCanvasBaseOpenGL::render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) { -} - -RID RasterizerCanvasBaseOpenGL::occluder_polygon_create() { - return RID(); -} - -void RasterizerCanvasBaseOpenGL::occluder_polygon_set_shape(RID p_occluder, const Vector &p_points, bool p_closed) { -} - -void RasterizerCanvasBaseOpenGL::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { -} - -void RasterizerCanvasBaseOpenGL::set_shadow_texture_size(int p_size) { -} - -bool RasterizerCanvasBaseOpenGL::free(RID p_rid) { - return true; -} - -void RasterizerCanvasBaseOpenGL::update() { -} - -void RasterizerCanvasBaseOpenGL::canvas_begin() { - state.using_transparent_rt = false; - - // always start with light_angle unset - state.using_light_angle = false; - state.using_large_vertex = false; - state.using_modulate = false; - - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_ATTRIB_LIGHT_ANGLE, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_ATTRIB_MODULATE, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_ATTRIB_LARGE_VERTEX, false); - state.canvas_shader.bind(); - - int viewport_x, viewport_y, viewport_width, viewport_height; - - if (storage->frame.current_rt) { - storage->bind_framebuffer(storage->frame.current_rt->fbo); - state.using_transparent_rt = storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]; - - if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - // set Viewport and Scissor when rendering directly to screen - viewport_width = storage->_dims.rt_width; - viewport_height = storage->_dims.rt_height; - viewport_x = storage->frame.current_rt->x; - // FTODO - // viewport_y = OS::get_singleton()->get_window_size().height - viewport_height - storage->frame.current_rt->y; - viewport_y = storage->frame.current_rt->y; - - // viewport_x = 0; - // viewport_y = 0; - - glScissor(viewport_x, viewport_y, viewport_width, viewport_height); - glViewport(viewport_x, viewport_y, viewport_width, viewport_height); - glEnable(GL_SCISSOR_TEST); - } - } - - // FTODO .. this was commented out to try and get the clear color correct - //#ifdef GODOT3 - // OLD METHOD .. now done by render target rather than frame -#if 0 - if (storage->frame.clear_request) { - glClearColor(storage->frame.clear_request_color.r, - storage->frame.clear_request_color.g, - storage->frame.clear_request_color.b, - state.using_transparent_rt ? storage->frame.clear_request_color.a : 1.0); - glClear(GL_COLOR_BUFFER_BIT); - storage->frame.clear_request = false; - } -#endif - - // NEW METHOD - if (storage->frame.current_rt && storage->frame.current_rt->clear_requested) { - const Color &col = storage->frame.current_rt->clear_color; - glClearColor(col.r, col.g, col.b, col.a); - - // clear EVERYTHING. - // not clearing everything can be devastating on tiled renderers especially, - // because if anything is preserved, often the whole frame buffer needs to be preserved. - // Not sure if GL_ACCUM_BUFFER_BIT is needed or supported in GLES. - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - storage->frame.current_rt->clear_requested = false; - } - - //#endif - - /* - if (storage->frame.current_rt) { - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - glColorMask(1, 1, 1, 1); - } - */ - - reset_canvas(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - glDisableVertexAttribArray(RS::ARRAY_COLOR); - - // set up default uniforms - - Transform3D canvas_transform; - - if (storage->frame.current_rt) { - float csy = 1.0; - // FTODO - // if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_VFLIP]) { - // csy = -1.0; - // } - canvas_transform.translate(-(storage->frame.current_rt->width / 2.0f), -(storage->frame.current_rt->height / 2.0f), 0.0f); - canvas_transform.scale(Vector3(2.0f / storage->frame.current_rt->width, csy * -2.0f / storage->frame.current_rt->height, 1.0f)); - } else { - // FTODO - // Vector2 ssize = OS::get_singleton()->get_window_size(); - Vector2 ssize; - ssize.x = storage->_dims.win_width; - ssize.y = storage->_dims.win_height; - - canvas_transform.translate(-(ssize.width / 2.0f), -(ssize.height / 2.0f), 0.0f); - canvas_transform.scale(Vector3(2.0f / ssize.width, -2.0f / ssize.height, 1.0f)); - } - - state.uniforms.projection_matrix = canvas_transform; - - state.uniforms.final_modulate = Color(1, 1, 1, 1); - - state.uniforms.modelview_matrix = Transform2D(); - state.uniforms.extra_matrix = Transform2D(); - - _set_uniforms(); - _bind_quad_buffer(); -} - -void RasterizerCanvasBaseOpenGL::canvas_end() { - glBindBuffer(GL_ARRAY_BUFFER, 0); - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - glDisableVertexAttribArray(i); - } - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - //reset viewport to full window size - // int viewport_width = OS::get_singleton()->get_window_size().width; - // int viewport_height = OS::get_singleton()->get_window_size().height; - int viewport_width = storage->_dims.win_width; - int viewport_height = storage->_dims.win_height; - glViewport(0, 0, viewport_width, viewport_height); - glScissor(0, 0, viewport_width, viewport_height); - } - - state.using_texture_rect = false; - state.using_skeleton = false; - state.using_ninepatch = false; - state.using_transparent_rt = false; -} - -void RasterizerCanvasBaseOpenGL::draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src) { - state.canvas_shader.set_uniform(CanvasShaderOpenGL::DST_RECT, Color(p_rect.position.x, p_rect.position.y, p_rect.size.x, p_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SRC_RECT, Color(p_src.position.x, p_src.position.y, p_src.size.x, p_src.size.y)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -} - -void RasterizerCanvasBaseOpenGL::_set_texture_rect_mode(bool p_texture_rect, bool p_light_angle, bool p_modulate, bool p_large_vertex) { - // always set this directly (this could be state checked) - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_TEXTURE_RECT, p_texture_rect); - - if (state.using_light_angle != p_light_angle) { - state.using_light_angle = p_light_angle; - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_ATTRIB_LIGHT_ANGLE, p_light_angle); - } - - if (state.using_modulate != p_modulate) { - state.using_modulate = p_modulate; - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_ATTRIB_MODULATE, p_modulate); - } - - if (state.using_large_vertex != p_large_vertex) { - state.using_large_vertex = p_large_vertex; - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_ATTRIB_LARGE_VERTEX, p_large_vertex); - } -} - -RasterizerStorageOpenGL::Texture *RasterizerCanvasBaseOpenGL::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map) { - RasterizerStorageOpenGL::Texture *tex_return = NULL; - - if (p_texture.is_valid()) { - RasterizerStorageOpenGL::Texture *texture = storage->texture_owner.get_or_null(p_texture); - - if (!texture) { - state.current_tex = RID(); - state.current_tex_ptr = NULL; - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - } else { - if (texture->redraw_if_visible) { - RenderingServerDefault::redraw_request(); - } - - texture = texture->get_ptr(); - - if (texture->render_target) { - texture->render_target->used_in_frame = true; - } - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - - state.current_tex = p_texture; - state.current_tex_ptr = texture; - - // new for Godot 4. Set the texture min mag filter and repeat per item - // we use a wrapper to avoid noop GL state changes - texture->GLSetFilter(GL_TEXTURE_2D, state.current_filter); - - tex_return = texture; - } - } else { - state.current_tex = RID(); - state.current_tex_ptr = NULL; - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } - - if (p_normal_map == state.current_normal) { - //do none - state.canvas_shader.set_uniform(CanvasShaderOpenGL::USE_DEFAULT_NORMAL, state.current_normal.is_valid()); - - } else if (p_normal_map.is_valid()) { - RasterizerStorageOpenGL::Texture *normal_map = storage->texture_owner.get_or_null(p_normal_map); - - if (!normal_map) { - state.current_normal = RID(); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::USE_DEFAULT_NORMAL, false); - - } else { - if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies - RenderingServerDefault::redraw_request(); - } - - normal_map = normal_map->get_ptr(); - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); - state.current_normal = p_normal_map; - state.canvas_shader.set_uniform(CanvasShaderOpenGL::USE_DEFAULT_NORMAL, true); - } - - } else { - state.current_normal = RID(); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::USE_DEFAULT_NORMAL, false); - } - - return tex_return; -} - -/* -void RasterizerCanvasBaseOpenGL::draw_window_margins(int *black_margin, RID *black_image) { - return; - - // FTODO - int window_w = storage->_dims.rt_width; - int window_h = storage->_dims.rt_height; - //Vector2 window_size = Vector2(window_w, window_h); - - // int window_h = window_size.height; - // int window_w = window_size.width; - - // glBindFramebuffer(GL_FRAMEBUFFER, storage->system_fbo); - // glViewport(0, 0, window_size.width, window_size.height); - - canvas_begin(); - - if (black_image[SIDE_LEFT].is_valid()) { - _bind_canvas_texture(black_image[SIDE_LEFT], RID()); - Size2 sz(storage->texture_get_width(black_image[SIDE_LEFT]), storage->texture_get_height(black_image[SIDE_LEFT])); - draw_generic_textured_rect(Rect2(0, 0, black_margin[SIDE_LEFT], window_h), - Rect2(0, 0, (float)black_margin[SIDE_LEFT] / sz.x, (float)(window_h) / sz.y)); - } else if (black_margin[SIDE_LEFT]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, 0, black_margin[SIDE_LEFT], window_h), Rect2(0, 0, 1, 1)); - } - - if (black_image[SIDE_RIGHT].is_valid()) { - _bind_canvas_texture(black_image[SIDE_RIGHT], RID()); - Size2 sz(storage->texture_get_width(black_image[SIDE_RIGHT]), storage->texture_get_height(black_image[SIDE_RIGHT])); - draw_generic_textured_rect(Rect2(window_w - black_margin[SIDE_RIGHT], 0, black_margin[SIDE_RIGHT], window_h), - Rect2(0, 0, (float)black_margin[SIDE_RIGHT] / sz.x, (float)window_h / sz.y)); - } else if (black_margin[SIDE_RIGHT]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(window_w - black_margin[SIDE_RIGHT], 0, black_margin[SIDE_RIGHT], window_h), Rect2(0, 0, 1, 1)); - } - - if (black_image[SIDE_TOP].is_valid()) { - _bind_canvas_texture(black_image[SIDE_TOP], RID()); - - Size2 sz(storage->texture_get_width(black_image[SIDE_TOP]), storage->texture_get_height(black_image[SIDE_TOP])); - draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[SIDE_TOP]), - Rect2(0, 0, (float)window_w / sz.x, (float)black_margin[SIDE_TOP] / sz.y)); - - } else if (black_margin[SIDE_TOP]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[SIDE_TOP]), Rect2(0, 0, 1, 1)); - } - - if (black_image[SIDE_BOTTOM].is_valid()) { - _bind_canvas_texture(black_image[SIDE_BOTTOM], RID()); - - Size2 sz(storage->texture_get_width(black_image[SIDE_BOTTOM]), storage->texture_get_height(black_image[SIDE_BOTTOM])); - draw_generic_textured_rect(Rect2(0, window_h - black_margin[SIDE_BOTTOM], window_w, black_margin[SIDE_BOTTOM]), - Rect2(0, 0, (float)window_w / sz.x, (float)black_margin[SIDE_BOTTOM] / sz.y)); - - } else if (black_margin[SIDE_BOTTOM]) { - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); - - draw_generic_textured_rect(Rect2(0, window_h - black_margin[SIDE_BOTTOM], window_w, black_margin[SIDE_BOTTOM]), Rect2(0, 0, 1, 1)); - } - - canvas_end(); -} -*/ - -void RasterizerCanvasBaseOpenGL::_bind_quad_buffer() { - glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, NULL); -} - -void RasterizerCanvasBaseOpenGL::_set_uniforms() { - state.canvas_shader.set_uniform(CanvasShaderOpenGL::PROJECTION_MATRIX, state.uniforms.projection_matrix); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::EXTRA_MATRIX, state.uniforms.extra_matrix); - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::FINAL_MODULATE, state.uniforms.final_modulate); - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::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(CanvasShaderOpenGL::SCREEN_PIXEL_SIZE, screen_pixel_size); - } - - if (state.using_skeleton) { - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SKELETON_TRANSFORM, state.skeleton_transform); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SKELETON_TEXTURE_SIZE, state.skeleton_texture_size); - } - - if (state.using_light) { - Light *light = state.using_light; - state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_MATRIX, light->light_shader_xform); - Transform2D basis_inverse = light->light_shader_xform.affine_inverse().orthonormalized(); - basis_inverse.elements[2] = Vector2(); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_MATRIX_INVERSE, basis_inverse); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_LOCAL_MATRIX, light->xform_cache.affine_inverse()); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_COLOR, light->color * light->energy); - // state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_POS, light->light_shader_pos); - // FTODO - state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_POS, light->light_shader_xform.elements[2]); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_HEIGHT, light->height); - - // FTODO - //state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_OUTSIDE_ALPHA, light->mode == RS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_OUTSIDE_ALPHA, 0.0f); - - if (state.using_shadow) { - // FTODO -#if 0 - RasterizerStorageOpenGL::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(light->shadow_buffer); - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); - glBindTexture(GL_TEXTURE_2D, cls->distance); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SHADOW_MATRIX, light->shadow_matrix_cache); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::LIGHT_SHADOW_COLOR, light->shadow_color); - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SHADOWPIXEL_SIZE, (1.0 / light->shadow_buffer_size) * (1.0 + light->shadow_smooth)); - if (light->radius_cache == 0) { - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SHADOW_GRADIENT, 0.0); - } else { - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SHADOW_GRADIENT, light->shadow_gradient_length / (light->radius_cache * 1.1)); - } - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SHADOW_DISTANCE_MULT, light->radius_cache * 1.1); -#endif - } - } -} - -void RasterizerCanvasBaseOpenGL::reset_canvas() { - glDisable(GL_CULL_FACE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DITHER); - glEnable(GL_BLEND); - - if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::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); - } - - // bind the back buffer to a texture so shaders can use it. - // It should probably use texture unit -3 (as OpenGL does as well) but currently that's buggy. - // keeping this for now as there's nothing else that uses texture unit 2 - // TODO ^ - if (storage->frame.current_rt) { - // glActiveTexture(GL_TEXTURE0 + 2); - // glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasBaseOpenGL::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) { -} - -void RasterizerCanvasBaseOpenGL::_copy_texscreen(const Rect2 &p_rect) { - state.canvas_texscreen_used = true; - - _copy_screen(p_rect); - - // back to canvas, force rebind - state.using_texture_rect = false; - state.canvas_shader.bind(); - _bind_canvas_texture(state.current_tex, state.current_normal); - _set_uniforms(); -} - -void RasterizerCanvasBaseOpenGL::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights, const int *p_bones) { - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - - uint32_t buffer_ofs = 0; - uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count); -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size); -#endif - - storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true); - - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); - buffer_ofs = buffer_ofs_after; - - if (p_singlecolor) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after)); - glEnableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs = buffer_ofs_after; - } - - if (p_uvs) { - RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after)); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs = buffer_ofs_after; - } else { - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - } - - if (p_weights && p_bones) { - RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights, buffer_ofs_after)); - glEnableVertexAttribArray(RS::ARRAY_WEIGHTS); - glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs = buffer_ofs_after; - - RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones, buffer_ofs_after)); - glEnableVertexAttribArray(RS::ARRAY_BONES); - glVertexAttribPointer(RS::ARRAY_BONES, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs = buffer_ofs_after; - - } else { - glDisableVertexAttribArray(RS::ARRAY_WEIGHTS); - glDisableVertexAttribArray(RS::ARRAY_BONES); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); - - if (storage->config.support_32_bits_indices) { //should check for -#ifdef DEBUG_ENABLED - ERR_FAIL_COND((sizeof(int) * p_index_count) > data.polygon_index_buffer_size); -#endif - storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(int) * p_index_count, p_indices, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true); - - glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); - storage->info.render._2d_draw_call_count++; - } else { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND((sizeof(uint16_t) * p_index_count) > data.polygon_index_buffer_size); -#endif - uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count); - for (int i = 0; i < p_index_count; i++) { - index16[i] = uint16_t(p_indices[i]); - } - storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(uint16_t) * p_index_count, index16, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true); - glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_SHORT, 0); - storage->info.render._2d_draw_call_count++; - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasBaseOpenGL::_draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - - uint32_t buffer_ofs = 0; - uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count); -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size); -#endif - storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true); - - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); - buffer_ofs = buffer_ofs_after; - - if (p_singlecolor) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after)); - glEnableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs = buffer_ofs_after; - } - - if (p_uvs) { - RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after)); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs = buffer_ofs_after; - } else { - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - } - - glDrawArrays(p_primitive, 0, p_vertex_count); - storage->info.render._2d_draw_call_count++; - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasBaseOpenGL::_draw_generic_indices(GLuint p_primitive, 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) { - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - - uint32_t buffer_ofs = 0; - uint32_t buffer_ofs_after = buffer_ofs + (sizeof(Vector2) * p_vertex_count); -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs_after > data.polygon_buffer_size); -#endif - storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, sizeof(Vector2) * p_vertex_count, p_vertices, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true); - - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); - buffer_ofs = buffer_ofs_after; - - if (p_singlecolor) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - Color m = *p_colors; - glVertexAttrib4f(RS::ARRAY_COLOR, m.r, m.g, m.b, m.a); - } else if (!p_colors) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - } else { - RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors, buffer_ofs_after)); - glEnableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs = buffer_ofs_after; - } - - if (p_uvs) { - RAST_FAIL_COND(!storage->safe_buffer_sub_data(data.polygon_buffer_size, GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs, buffer_ofs_after)); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); - buffer_ofs = buffer_ofs_after; - } else { - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - } - -#ifdef RASTERIZER_EXTRA_CHECKS - // very slow, do not enable in normal use - for (int n = 0; n < p_index_count; n++) { - RAST_DEV_DEBUG_ASSERT(p_indices[n] < p_vertex_count); - } -#endif - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); - - if (storage->config.support_32_bits_indices) { //should check for -#ifdef DEBUG_ENABLED - ERR_FAIL_COND((sizeof(int) * p_index_count) > data.polygon_index_buffer_size); -#endif - storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(int) * p_index_count, p_indices, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true); - glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_INT, 0); - storage->info.render._2d_draw_call_count++; - } else { -#ifdef DEBUG_ENABLED - ERR_FAIL_COND((sizeof(uint16_t) * p_index_count) > data.polygon_index_buffer_size); -#endif - uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count); - for (int i = 0; i < p_index_count; i++) { - index16[i] = uint16_t(p_indices[i]); - } - storage->buffer_orphan_and_upload(data.polygon_index_buffer_size, 0, sizeof(uint16_t) * p_index_count, index16, GL_ELEMENT_ARRAY_BUFFER, _buffer_upload_usage_flag, true); - glDrawElements(p_primitive, p_index_count, GL_UNSIGNED_SHORT, 0); - storage->info.render._2d_draw_call_count++; - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasBaseOpenGL::_legacy_draw_poly_triangles(Item::CommandPolygon *p_poly, RasterizerStorageOpenGL::Material *p_material) { - // return; - - const PolyData &pd = _polydata[p_poly->polygon.polygon_id]; - - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - // FTODO - //RasterizerStorageOpenGL::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map); - RasterizerStorageOpenGL::Texture *texture = _bind_canvas_texture(p_poly->texture, RID()); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - _draw_polygon(pd.indices.ptr(), pd.indices.size(), pd.points.size(), pd.points.ptr(), pd.uvs.ptr(), pd.colors.ptr(), pd.colors.size() == 1, nullptr, nullptr); - -// _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->weights.ptr(), polygon->bones.ptr()); -#ifdef GLES_OVER_GL -#if 0 - if (polygon->antialiased) { - glEnable(GL_LINE_SMOOTH); - if (polygon->antialiasing_use_indices) { - _draw_generic_indices(GL_LINE_STRIP, polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - } else { - _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); - } - glDisable(GL_LINE_SMOOTH); - } -#endif -#endif -} - -void RasterizerCanvasBaseOpenGL::_legacy_draw_primitive(Item::CommandPrimitive *p_pr, RasterizerStorageOpenGL::Material *p_material) { - // return; - - if (p_pr->point_count != 4) - return; // not sure if supported - - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - _bind_canvas_texture(RID(), RID()); - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, p_pr->colors[0].components); - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - - _draw_gui_primitive(p_pr->point_count, p_pr->points, NULL, NULL); -} - -void RasterizerCanvasBaseOpenGL::_legacy_draw_line(Item::CommandPrimitive *p_pr, RasterizerStorageOpenGL::Material *p_material) { - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - _bind_canvas_texture(RID(), RID()); - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, p_pr->colors[0].components); - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - -#ifdef GLES_OVER_GL -// if (line->antialiased) -// glEnable(GL_LINE_SMOOTH); -#endif - _draw_gui_primitive(2, p_pr->points, NULL, NULL); - -#ifdef GLES_OVER_GL -// if (line->antialiased) -// glDisable(GL_LINE_SMOOTH); -#endif -} - -void RasterizerCanvasBaseOpenGL::_draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs, const float *p_light_angles) { - static const GLenum prim[5] = { GL_POINTS, GL_POINTS, GL_LINES, GL_TRIANGLES, GL_TRIANGLE_FAN }; - - int color_offset = 0; - int uv_offset = 0; - int light_angle_offset = 0; - int stride = 2; - - if (p_colors) { - color_offset = stride; - stride += 4; - } - - if (p_uvs) { - uv_offset = stride; - stride += 2; - } - - if (p_light_angles) { //light_angles - light_angle_offset = stride; - stride += 1; - } - - RAST_DEV_DEBUG_ASSERT(p_points <= 4); - float buffer_data[(2 + 2 + 4 + 1) * 4]; - - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + 0] = p_vertices[i].x; - buffer_data[stride * i + 1] = p_vertices[i].y; - } - - if (p_colors) { - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + color_offset + 0] = p_colors[i].r; - buffer_data[stride * i + color_offset + 1] = p_colors[i].g; - buffer_data[stride * i + color_offset + 2] = p_colors[i].b; - buffer_data[stride * i + color_offset + 3] = p_colors[i].a; - } - } - - if (p_uvs) { - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + uv_offset + 0] = p_uvs[i].x; - buffer_data[stride * i + uv_offset + 1] = p_uvs[i].y; - } - } - - if (p_light_angles) { - for (int i = 0; i < p_points; i++) { - buffer_data[stride * i + light_angle_offset + 0] = p_light_angles[i]; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - storage->buffer_orphan_and_upload(data.polygon_buffer_size, 0, p_points * stride * 4 * sizeof(float), buffer_data, GL_ARRAY_BUFFER, _buffer_upload_usage_flag, true); - - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), NULL); - - if (p_colors) { - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_offset * sizeof(float))); - glEnableVertexAttribArray(RS::ARRAY_COLOR); - } - - if (p_uvs) { - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(uv_offset * sizeof(float))); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - } - - if (p_light_angles) { - glVertexAttribPointer(RS::ARRAY_TANGENT, 1, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(light_angle_offset * sizeof(float))); - glEnableVertexAttribArray(RS::ARRAY_TANGENT); - } - - glDrawArrays(prim[p_points], 0, p_points); - storage->info.render._2d_draw_call_count++; - - if (p_light_angles) { - // may not be needed - glDisableVertexAttribArray(RS::ARRAY_TANGENT); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasBaseOpenGL::_copy_screen(const Rect2 &p_rect) { - if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { - ERR_PRINT_ONCE("Cannot use screen texture copying in render target set to render direct to screen."); - return; - } - - ERR_FAIL_COND_MSG(storage->frame.current_rt->copy_screen_effect.color == 0, "Can't use screen texture copying in a render target configured without copy buffers."); - - glDisable(GL_BLEND); - - Vector2 wh(storage->frame.current_rt->width, storage->frame.current_rt->height); - - Color copy_section(p_rect.position.x / wh.x, p_rect.position.y / wh.y, p_rect.size.x / wh.x, p_rect.size.y / wh.y); - - if (p_rect != Rect2()) { - storage->shaders.copy.set_conditional(CopyShaderOpenGL::USE_COPY_SECTION, true); - } - - storage->shaders.copy.set_conditional(CopyShaderOpenGL::USE_NO_ALPHA, !state.using_transparent_rt); - - storage->bind_framebuffer(storage->frame.current_rt->copy_screen_effect.fbo); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); - - storage->shaders.copy.bind(); - storage->shaders.copy.set_uniform(CopyShaderOpenGL::COPY_SECTION, copy_section); - - const Vector2 vertpos[4] = { - Vector2(-1, -1), - Vector2(-1, 1), - Vector2(1, 1), - Vector2(1, -1), - }; - - const Vector2 uvpos[4] = { - Vector2(0, 0), - Vector2(0, 1), - Vector2(1, 1), - Vector2(1, 0) - }; - - const int indexpos[6] = { - 0, 1, 2, - 2, 3, 0 - }; - - _draw_polygon(indexpos, 6, 4, vertpos, uvpos, NULL, false); - - storage->shaders.copy.set_conditional(CopyShaderOpenGL::USE_COPY_SECTION, false); - storage->shaders.copy.set_conditional(CopyShaderOpenGL::USE_NO_ALPHA, false); - - storage->bind_framebuffer(storage->frame.current_rt->fbo); - glEnable(GL_BLEND); -} - -void RasterizerCanvasBaseOpenGL::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) { -#if 0 - RasterizerStorageOpenGL::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(p_buffer); - ERR_FAIL_COND(!cls); - - glDisable(GL_BLEND); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_DITHER); - glDisable(GL_CULL_FACE); - glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); - - glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); - - state.canvas_shadow_shader.set_conditional(CanvasShadowShaderOpenGL::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); - state.canvas_shadow_shader.bind(); - - glViewport(0, 0, cls->size, cls->height); - glClearDepth(1.0f); - glClearColor(1, 1, 1, 1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - RS::CanvasOccluderPolygonCullMode cull = RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; - - for (int i = 0; i < 4; i++) { - //make sure it remains orthogonal, makes easy to read angle later - - Transform3D light; - light.origin[0] = p_light_xform[2][0]; - light.origin[1] = p_light_xform[2][1]; - light.basis[0][0] = p_light_xform[0][0]; - light.basis[0][1] = p_light_xform[1][0]; - light.basis[1][0] = p_light_xform[0][1]; - light.basis[1][1] = p_light_xform[1][1]; - - //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); - - //p_near=1; - CameraMatrix projection; - { - real_t fov = 90; - real_t nearp = p_near; - real_t farp = p_far; - real_t aspect = 1.0; - - real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5)); - real_t ymin = -ymax; - real_t xmin = ymin * aspect; - real_t xmax = ymax * aspect; - - projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); - } - - Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * (i / 4.0))).xform(Vector3(0, 1, 0)); - projection = projection * CameraMatrix(Transform3D().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); - - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderOpenGL::PROJECTION_MATRIX, projection); - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderOpenGL::LIGHT_MATRIX, light); - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderOpenGL::DISTANCE_NORM, 1.0 / p_far); - - if (i == 0) - *p_xform_cache = projection; - - glViewport(0, (cls->height / 4) * i, cls->size, cls->height / 4); - - LightOccluderInstance *instance = p_occluders; - - while (instance) { - RasterizerStorageOpenGL::CanvasOccluder *cc = storage->canvas_occluder_owner.get_or_null(instance->polygon_buffer); - if (!cc || cc->len == 0 || !(p_light_mask & instance->light_mask)) { - instance = instance->next; - continue; - } - - state.canvas_shadow_shader.set_uniform(CanvasShadowShaderOpenGL::WORLD_MATRIX, instance->xform_cache); - - RS::CanvasOccluderPolygonCullMode transformed_cull_cache = instance->cull_cache; - - if (transformed_cull_cache != RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED && - (p_light_xform.basis_determinant() * instance->xform_cache.basis_determinant()) < 0) { - transformed_cull_cache = - transformed_cull_cache == RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE ? - RS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE : - RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE; - } - - if (cull != transformed_cull_cache) { - cull = transformed_cull_cache; - switch (cull) { - case RS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: { - glDisable(GL_CULL_FACE); - - } break; - case RS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: { - glEnable(GL_CULL_FACE); - glCullFace(GL_FRONT); - } break; - case RS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: { - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - } break; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, cc->vertex_id); - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glVertexAttribPointer(RS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cc->index_id); - - glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0); - - instance = instance->next; - } - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -#endif -} - -void RasterizerCanvasBaseOpenGL::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { - Vector2 half_size; - if (storage->frame.current_rt) { - half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height); - } else { - // half_size = OS::get_singleton()->get_window_size(); - half_size = Vector2(storage->_dims.win_width, storage->_dims.win_height); - } - half_size *= 0.5; - Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y); - Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y); - - float aspect_ratio = p_rect.size.x / p_rect.size.y; - - // setup our lens shader - state.lens_shader.bind(); - state.lens_shader.set_uniform(LensDistortedShaderOpenGL::OFFSET, offset); - state.lens_shader.set_uniform(LensDistortedShaderOpenGL::SCALE, scale); - state.lens_shader.set_uniform(LensDistortedShaderOpenGL::K1, p_k1); - state.lens_shader.set_uniform(LensDistortedShaderOpenGL::K2, p_k2); - state.lens_shader.set_uniform(LensDistortedShaderOpenGL::EYE_CENTER, p_eye_center); - state.lens_shader.set_uniform(LensDistortedShaderOpenGL::UPSCALE, p_oversample); - state.lens_shader.set_uniform(LensDistortedShaderOpenGL::ASPECT_RATIO, aspect_ratio); - - // bind our quad buffer - _bind_quad_buffer(); - - // and draw - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - // and cleanup - glBindBuffer(GL_ARRAY_BUFFER, 0); - - for (int i = 0; i < RS::ARRAY_MAX; i++) { - glDisableVertexAttribArray(i); - } -} - -void RasterizerCanvasBaseOpenGL::initialize() { - bool flag_stream = false; - //flag_stream = GLOBAL_GET("rendering/options/api_usage_legacy/flag_stream"); - if (flag_stream) - _buffer_upload_usage_flag = GL_STREAM_DRAW; - else - _buffer_upload_usage_flag = GL_DYNAMIC_DRAW; - - // quad buffer - { - glGenBuffers(1, &data.canvas_quad_vertices); - glBindBuffer(GL_ARRAY_BUFFER, data.canvas_quad_vertices); - - const float qv[8] = { - 0, 0, - 0, 1, - 1, 1, - 1, 0 - }; - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, qv, GL_STATIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - // polygon buffer - { - uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); - poly_size = MAX(poly_size, 128); // minimum 2k, may still see anomalies in editor - poly_size *= 1024; - glGenBuffers(1, &data.polygon_buffer); - glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); - glBufferData(GL_ARRAY_BUFFER, poly_size, NULL, GL_DYNAMIC_DRAW); - - data.polygon_buffer_size = poly_size; - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); - index_size = MAX(index_size, 128); - index_size *= 1024; // kb - glGenBuffers(1, &data.polygon_index_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_size, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - data.polygon_index_buffer_size = index_size; - } - - // ninepatch buffers - { - // array buffer - glGenBuffers(1, &data.ninepatch_vertices); - glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices); - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, NULL, GL_DYNAMIC_DRAW); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // element buffer - glGenBuffers(1, &data.ninepatch_elements); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); - -#define _EIDX(y, x) (y * 4 + x) - uint8_t elems[3 * 2 * 9] = { - // first row - - _EIDX(0, 0), _EIDX(0, 1), _EIDX(1, 1), - _EIDX(1, 1), _EIDX(1, 0), _EIDX(0, 0), - - _EIDX(0, 1), _EIDX(0, 2), _EIDX(1, 2), - _EIDX(1, 2), _EIDX(1, 1), _EIDX(0, 1), - - _EIDX(0, 2), _EIDX(0, 3), _EIDX(1, 3), - _EIDX(1, 3), _EIDX(1, 2), _EIDX(0, 2), - - // second row - - _EIDX(1, 0), _EIDX(1, 1), _EIDX(2, 1), - _EIDX(2, 1), _EIDX(2, 0), _EIDX(1, 0), - - // the center one would be here, but we'll put it at the end - // so it's easier to disable the center and be able to use - // one draw call for both - - _EIDX(1, 2), _EIDX(1, 3), _EIDX(2, 3), - _EIDX(2, 3), _EIDX(2, 2), _EIDX(1, 2), - - // third row - - _EIDX(2, 0), _EIDX(2, 1), _EIDX(3, 1), - _EIDX(3, 1), _EIDX(3, 0), _EIDX(2, 0), - - _EIDX(2, 1), _EIDX(2, 2), _EIDX(3, 2), - _EIDX(3, 2), _EIDX(3, 1), _EIDX(2, 1), - - _EIDX(2, 2), _EIDX(2, 3), _EIDX(3, 3), - _EIDX(3, 3), _EIDX(3, 2), _EIDX(2, 2), - - // center field - - _EIDX(1, 1), _EIDX(1, 2), _EIDX(2, 2), - _EIDX(2, 2), _EIDX(2, 1), _EIDX(1, 1) - }; -#undef _EIDX - - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - state.canvas_shadow_shader.init(); - - state.canvas_shader.init(); - - _set_texture_rect_mode(true); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); - - state.canvas_shader.bind(); - - state.lens_shader.init(); - - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false)); - - state.using_light = NULL; - state.using_transparent_rt = false; - state.using_skeleton = false; -} - -RendererCanvasRender::PolygonID RasterizerCanvasBaseOpenGL::request_polygon(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs, const Vector &p_bones, const Vector &p_weights) { - uint32_t id = _polydata.alloc(); - PolyData &pd = _polydata[id]; - pd.indices = p_indices; - pd.points = p_points; - pd.colors = p_colors; - pd.uvs = p_uvs; - return id; -} -void RasterizerCanvasBaseOpenGL::free_polygon(PolygonID p_polygon) { - _polydata.free(p_polygon); -} - -void RasterizerCanvasBaseOpenGL::finalize() { -} - -RasterizerCanvasBaseOpenGL::RasterizerCanvasBaseOpenGL() { -} - -#endif // OPENGL_BACKEND_ENABLED diff --git a/drivers/opengl/rasterizer_canvas_base_opengl.h b/drivers/opengl/rasterizer_canvas_base_opengl.h deleted file mode 100644 index ac2020e5d7..0000000000 --- a/drivers/opengl/rasterizer_canvas_base_opengl.h +++ /dev/null @@ -1,196 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_base_opengl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_CANVAS_BASE_OPENGL_H -#define RASTERIZER_CANVAS_BASE_OPENGL_H - -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "drivers/opengl/rasterizer_array.h" -#include "drivers/opengl/rasterizer_storage_common.h" -#include "rasterizer_scene_opengl.h" -#include "rasterizer_storage_opengl.h" -#include "servers/rendering/renderer_canvas_render.h" -#include "servers/rendering/renderer_compositor.h" - -#include "shaders/canvas.glsl.gen.h" -#include "shaders/canvas_shadow.glsl.gen.h" -#include "shaders/lens_distorted.glsl.gen.h" - -class RasterizerCanvasBaseOpenGL : public RendererCanvasRender { -public: - enum { - INSTANCE_ATTRIB_BASE = 8, - }; - - struct Uniforms { - Transform3D projection_matrix; - - Transform2D modelview_matrix; - Transform2D extra_matrix; - - Color final_modulate; - - float time; - }; - - struct Data { - GLuint canvas_quad_vertices; - GLuint polygon_buffer; - GLuint polygon_index_buffer; - - uint32_t polygon_buffer_size; - uint32_t polygon_index_buffer_size; - - GLuint ninepatch_vertices; - GLuint ninepatch_elements; - } data; - - struct State { - Uniforms uniforms; - bool canvas_texscreen_used; - CanvasShaderOpenGL canvas_shader; - CanvasShadowShaderOpenGL canvas_shadow_shader; - LensDistortedShaderOpenGL lens_shader; - - bool using_texture_rect; - - bool using_light_angle; - bool using_modulate; - bool using_large_vertex; - - bool using_ninepatch; - bool using_skeleton; - - Transform2D skeleton_transform; - Transform2D skeleton_transform_inverse; - Size2i skeleton_texture_size; - - RID current_tex; - RID current_normal; - RasterizerStorageOpenGL::Texture *current_tex_ptr; - - Transform3D vp; - Light *using_light; - bool using_shadow; - bool using_transparent_rt; - - // new for Godot 4.0 - // min mag filter is per item, and repeat - RS::CanvasItemTextureFilter current_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; - RS::CanvasItemTextureRepeat current_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; - } state; - - typedef void Texture; - - RasterizerSceneOpenGL *scene_render; - - RasterizerStorageOpenGL *storage; - - // allow user to choose api usage - GLenum _buffer_upload_usage_flag; - - void _set_uniforms(); - - virtual RID light_internal_create(); - virtual void light_internal_update(RID p_rid, Light *p_light); - virtual void light_internal_free(RID p_rid); - - virtual void canvas_begin(); - virtual void canvas_end(); - -protected: - void _legacy_draw_primitive(Item::CommandPrimitive *p_pr, RasterizerStorageOpenGL::Material *p_material); - void _legacy_draw_line(Item::CommandPrimitive *p_pr, RasterizerStorageOpenGL::Material *p_material); - void _legacy_draw_poly_triangles(Item::CommandPolygon *p_poly, RasterizerStorageOpenGL::Material *p_material); - -public: - void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs, const float *p_light_angles = nullptr); - void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights = NULL, const int *p_bones = NULL); - 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); - void _draw_generic_indices(GLuint p_primitive, const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); - - void _bind_quad_buffer(); - void _copy_texscreen(const Rect2 &p_rect); - void _copy_screen(const Rect2 &p_rect); - - //virtual void draw_window_margins(int *black_margin, RID *black_image) override; - void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); - void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); - - virtual void reset_canvas(); - virtual void canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache); - - // Copied from RasterizerCanvasDummy: - virtual void canvas_debug_viewport_shadows(Light *p_lights_with_shadow) override; - - RID light_create() override; - void light_set_texture(RID p_rid, RID p_texture) override; - void light_set_use_shadow(RID p_rid, bool p_enable) override; - void light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) override; - void light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) override; - - void render_sdf(RID p_render_target, LightOccluderInstance *p_occluders) override; - RID occluder_polygon_create() override; - void occluder_polygon_set_shape(RID p_occluder, const Vector &p_points, bool p_closed) override; - void occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) override; - void set_shadow_texture_size(int p_size) override; - - bool free(RID p_rid) override; - void update() override; - // End copied from RasterizerCanvasDummy. - - RasterizerStorageOpenGL::Texture *_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map); - void _set_texture_rect_mode(bool p_texture_rect, bool p_light_angle = false, bool p_modulate = false, bool p_large_vertex = false); - - // NEW API - struct PolyData { - LocalVector indices; - LocalVector points; - LocalVector colors; - LocalVector uvs; - }; - - RendererCanvasRender::PolygonID request_polygon(const Vector &p_indices, const Vector &p_points, const Vector &p_colors, const Vector &p_uvs = Vector(), const Vector &p_bones = Vector(), const Vector &p_weights = Vector()) override; - void free_polygon(PolygonID p_polygon) override; - - RasterizerPooledIndirectList _polydata; - - ////////////////////// - void initialize(); - void finalize(); - - RasterizerCanvasBaseOpenGL(); -}; - -#endif // OPENGL_BACKEND_ENABLED - -#endif // RASTERIZER_CANVAS_BASE_OPENGL_H diff --git a/drivers/opengl/rasterizer_canvas_batcher.h b/drivers/opengl/rasterizer_canvas_batcher.h deleted file mode 100644 index c7345824ab..0000000000 --- a/drivers/opengl/rasterizer_canvas_batcher.h +++ /dev/null @@ -1,1560 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_batcher.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_CANVAS_BATCHER_H -#define RASTERIZER_CANVAS_BATCHER_H - -#include "core/os/os.h" -#include "core/templates/local_vector.h" -#include "rasterizer_array.h" -#include "rasterizer_asserts.h" -#include "rasterizer_storage_common.h" - -#include "core/config/project_settings.h" -#include "servers/rendering/renderer_compositor.h" - -// We are using the curiously recurring template pattern -// https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern -// For static polymorphism. - -// This makes it super easy to access -// data / call funcs in the derived rasterizers from the base without writing and -// maintaining a boatload of virtual functions. -// In addition it assures that vtable will not be used and the function calls can be optimized, -// because it gives compile time static polymorphism. - -// These macros makes it simpler and less verbose to define (and redefine) the inline functions -// template preamble -#define T_PREAMBLE template -// class preamble -#define C_PREAMBLE RasterizerCanvasBatcher -// generic preamble -#define PREAMBLE(RET_T) \ - T_PREAMBLE \ - RET_T C_PREAMBLE - -template -class RasterizerCanvasBatcher { -public: - // used to determine whether we use hardware transform (none) - // software transform all verts, or software transform just a translate - // (no rotate or scale) - enum TransformMode { - TM_NONE, - TM_ALL, - TM_TRANSLATE, - }; - - // pod versions of vector and color and RID, need to be 32 bit for vertex format - struct BatchVector2 { - float x, y; - void set(float xx, float yy) { - x = xx; - y = yy; - } - void set(const Vector2 &p_o) { - x = p_o.x; - y = p_o.y; - } - void to(Vector2 &r_o) const { - r_o.x = x; - r_o.y = y; - } - }; - - struct BatchColor { - float r, g, b, a; - void set_white() { - r = 1.0f; - g = 1.0f; - b = 1.0f; - a = 1.0f; - } - void set(const Color &p_c) { - r = p_c.r; - g = p_c.g; - b = p_c.b; - a = p_c.a; - } - void set(float rr, float gg, float bb, float aa) { - r = rr; - g = gg; - b = bb; - a = aa; - } - bool operator==(const BatchColor &p_c) const { - return (r == p_c.r) && (g == p_c.g) && (b == p_c.b) && (a == p_c.a); - } - bool operator!=(const BatchColor &p_c) const { return (*this == p_c) == false; } - bool equals(const Color &p_c) const { - return (r == p_c.r) && (g == p_c.g) && (b == p_c.b) && (a == p_c.a); - } - const float *get_data() const { return &r; } - String to_string() const { - String sz = "{"; - const float *data = get_data(); - for (int c = 0; c < 4; c++) { - float f = data[c]; - int val = ((f * 255.0f) + 0.5f); - sz += String(Variant(val)) + " "; - } - sz += "}"; - return sz; - } - }; - - // simplest FVF - local or baked position - struct BatchVertex { - // must be 32 bit pod - BatchVector2 pos; - BatchVector2 uv; - }; - - // simple FVF but also incorporating baked color - struct BatchVertexColored : public BatchVertex { - // must be 32 bit pod - BatchColor col; - }; - - // if we are using normal mapping, we need light angles to be sent - struct BatchVertexLightAngled : public BatchVertexColored { - // must be pod - float light_angle; - }; - - // CUSTOM SHADER vertex formats. These are larger but will probably - // be needed with custom shaders in order to have the data accessible in the shader. - - // if we are using COLOR in vertex shader but not position (VERTEX) - struct BatchVertexModulated : public BatchVertexLightAngled { - BatchColor modulate; - }; - - struct BatchTransform { - BatchVector2 translate; - BatchVector2 basis[2]; - }; - - // last resort, specially for custom shader, we put everything possible into a huge FVF - // not very efficient, but better than no batching at all. - struct BatchVertexLarge : public BatchVertexModulated { - // must be pod - BatchTransform transform; - }; - - // Batch should be as small as possible, and ideally nicely aligned (is 32 bytes at the moment) - struct Batch { - RasterizerStorageCommon::BatchType type; // should be 16 bit - uint16_t batch_texture_id; - - // also item reference number - uint32_t first_command; - - // in the case of DEFAULT, this is num commands. - // with rects, is number of command and rects. - // with lines, is number of lines - uint32_t num_commands; - - // first vertex of this batch in the vertex lists - uint32_t first_vert; - - BatchColor color; - }; - - struct BatchTex { - enum TileMode : uint32_t { - TILE_OFF, - TILE_NORMAL, - TILE_FORCE_REPEAT, - }; - RID RID_texture; - RID RID_normal; - TileMode tile_mode; - BatchVector2 tex_pixel_size; - uint32_t flags; - }; - - // items in a list to be sorted prior to joining - struct BSortItem { - // have a function to keep as pod, rather than operator - void assign(const BSortItem &o) { - item = o.item; - z_index = o.z_index; - } - RendererCanvasRender::Item *item; - int z_index; - }; - - // batch item may represent 1 or more items - struct BItemJoined { - uint32_t first_item_ref; - uint32_t num_item_refs; - - Rect2 bounding_rect; - - // note the z_index may only be correct for the first of the joined item references - // this has implications for light culling with z ranged lights. - int16_t z_index; - - // these are defined in RasterizerStorageCommon::BatchFlags - uint16_t flags; - - // we are always splitting items with lots of commands, - // and items with unhandled primitives (default) - bool use_hardware_transform() const { return num_item_refs == 1; } - }; - - struct BItemRef { - RendererCanvasRender::Item *item; - Color final_modulate; - }; - - struct BLightRegion { - void reset() { - light_bitfield = 0; - shadow_bitfield = 0; - too_many_lights = false; - } - uint64_t light_bitfield; - uint64_t shadow_bitfield; - bool too_many_lights; // we can only do light region optimization if there are 64 or less lights - }; - - struct BatchData { - BatchData() { - reset_flush(); - reset_joined_item(); - - gl_vertex_buffer = 0; - gl_index_buffer = 0; - max_quads = 0; - vertex_buffer_size_units = 0; - vertex_buffer_size_bytes = 0; - index_buffer_size_units = 0; - index_buffer_size_bytes = 0; - - use_colored_vertices = false; - - settings_use_batching = false; - settings_max_join_item_commands = 0; - settings_colored_vertex_format_threshold = 0.0f; - settings_batch_buffer_num_verts = 0; - scissor_threshold_area = 0.0f; - joined_item_batch_flags = 0; - diagnose_frame = false; - next_diagnose_tick = 10000; - diagnose_frame_number = 9999999999; // some high number - join_across_z_indices = true; - settings_item_reordering_lookahead = 0; - - settings_use_batching_original_choice = false; - settings_flash_batching = false; - settings_diagnose_frame = false; - settings_scissor_lights = false; - settings_scissor_threshold = -1.0f; - settings_use_single_rect_fallback = false; - settings_use_software_skinning = true; - settings_ninepatch_mode = 0; // default - settings_light_max_join_items = 16; - - settings_uv_contract = false; - settings_uv_contract_amount = 0.0f; - - buffer_mode_batch_upload_send_null = true; - buffer_mode_batch_upload_flag_stream = false; - - stats_items_sorted = 0; - stats_light_items_joined = 0; - } - - // called for each joined item - void reset_joined_item() { - // noop but left in as a stub - } - - // called after each flush - void reset_flush() { - batches.reset(); - batch_textures.reset(); - - vertices.reset(); - light_angles.reset(); - vertex_colors.reset(); - vertex_modulates.reset(); - vertex_transforms.reset(); - - total_quads = 0; - total_verts = 0; - total_color_changes = 0; - - use_light_angles = false; - use_modulate = false; - use_large_verts = false; - fvf = RasterizerStorageCommon::FVF_REGULAR; - } - - unsigned int gl_vertex_buffer; - unsigned int gl_index_buffer; - - uint32_t max_quads; - uint32_t vertex_buffer_size_units; - uint32_t vertex_buffer_size_bytes; - uint32_t index_buffer_size_units; - uint32_t index_buffer_size_bytes; - - // small vertex FVF type - pos and UV. - // This will always be written to initially, but can be translated - // to larger FVFs if necessary. - RasterizerArray vertices; - - // extra data which can be stored during prefilling, for later translation to larger FVFs - RasterizerArray light_angles; - RasterizerArray vertex_colors; // these aren't usually used, but are for polys - RasterizerArray vertex_modulates; - RasterizerArray vertex_transforms; - - // instead of having a different buffer for each vertex FVF type - // we have a special array big enough for the biggest FVF - // which can have a changeable unit size, and reuse it. - RasterizerUnitArray unit_vertices; - - RasterizerArray batches; - RasterizerArray batches_temp; // used for translating to colored vertex batches - RasterizerArray_non_pod batch_textures; // the only reason this is non-POD is because of RIDs - - // SHOULD THESE BE IN FILLSTATE? - // flexible vertex format. - // all verts have pos and UV. - // some have color, some light angles etc. - RasterizerStorageCommon::FVF fvf; - bool use_colored_vertices; - bool use_light_angles; - bool use_modulate; - bool use_large_verts; - - // if the shader is using MODULATE, we prevent baking color so the final_modulate can - // be read in the shader. - // if the shader is reading VERTEX, we prevent baking vertex positions with extra matrices etc - // to prevent the read position being incorrect. - // These flags are defined in RasterizerStorageCommon::BatchFlags - uint32_t joined_item_batch_flags; - - RasterizerArray items_joined; - RasterizerArray item_refs; - - // items are sorted prior to joining - RasterizerArray sort_items; - - // new for Godot 4 .. the client outputs a linked list so we need to convert this - // to a linear array - LocalVector command_shortlist; - - // counts - int total_quads; - int total_verts; - - // we keep a record of how many color changes caused new batches - // if the colors are causing an excessive number of batches, we switch - // to alternate batching method and add color to the vertex format. - int total_color_changes; - - // measured in pixels, recalculated each frame - float scissor_threshold_area; - - // diagnose this frame, every nTh frame when settings_diagnose_frame is on - bool diagnose_frame; - String frame_string; - uint32_t next_diagnose_tick; - uint64_t diagnose_frame_number; - - // whether to join items across z_indices - this can interfere with z ranged lights, - // so has to be disabled in some circumstances - bool join_across_z_indices; - - // global settings - bool settings_use_batching; // the current use_batching (affected by flash) - bool settings_use_batching_original_choice; // the choice entered in project settings - bool settings_flash_batching; // for regression testing, flash between non-batched and batched renderer - bool settings_diagnose_frame; // print out batches to help optimize / regression test - int settings_max_join_item_commands; - float settings_colored_vertex_format_threshold; - int settings_batch_buffer_num_verts; - bool settings_scissor_lights; - float settings_scissor_threshold; // 0.0 to 1.0 - int settings_item_reordering_lookahead; - bool settings_use_single_rect_fallback; - bool settings_use_software_skinning; - int settings_light_max_join_items; - int settings_ninepatch_mode; - - // buffer orphaning modes - bool buffer_mode_batch_upload_send_null; - bool buffer_mode_batch_upload_flag_stream; - - // uv contraction - bool settings_uv_contract; - float settings_uv_contract_amount; - - // only done on diagnose frame - void reset_stats() { - stats_items_sorted = 0; - stats_light_items_joined = 0; - } - - // frame stats (just for monitoring and debugging) - int stats_items_sorted; - int stats_light_items_joined; - } bdata; - - struct FillState { - void reset_flush() { - // don't reset members that need to be preserved after flushing - // half way through a list of commands - curr_batch = 0; - batch_tex_id = -1; - texpixel_size = Vector2(1, 1); - contract_uvs = false; - - sequence_batch_type_flags = 0; - } - - void reset_joined_item(bool p_use_hardware_transform) { - reset_flush(); - use_hardware_transform = p_use_hardware_transform; - extra_matrix_sent = false; - } - - // for batching multiple types, we don't allow mixing RECTs / LINEs etc. - // using flags allows quicker rejection of sequences with different batch types - uint32_t sequence_batch_type_flags; - - Batch *curr_batch; - int batch_tex_id; - bool use_hardware_transform; - bool contract_uvs; - Vector2 texpixel_size; - Color final_modulate; - TransformMode transform_mode; - TransformMode orig_transform_mode; - - // support for extra matrices - bool extra_matrix_sent; // whether sent on this item (in which case sofware transform can't be used untl end of item) - int transform_extra_command_number_p1; // plus one to allow fast checking against zero - Transform2D transform_combined; // final * extra - }; - - // used during try_join - struct RenderItemState { - RenderItemState() { reset(); } - void reset() { - current_clip = nullptr; - shader_cache = nullptr; - rebind_shader = true; - prev_use_skeleton = false; - last_blend_mode = -1; - canvas_last_material = RID(); - item_group_z = 0; - item_group_light = nullptr; - final_modulate = Color(-1.0, -1.0, -1.0, -1.0); // just something unlikely - - joined_item_batch_type_flags_curr = 0; - joined_item_batch_type_flags_prev = 0; - - joined_item = nullptr; - } - - RendererCanvasRender::Item *current_clip; - typename T_STORAGE::Shader *shader_cache; - bool rebind_shader; - bool prev_use_skeleton; - bool prev_distance_field; - int last_blend_mode; - RID canvas_last_material; - Color final_modulate; - - // used for joining items only - BItemJoined *joined_item; - bool join_batch_break; - BLightRegion light_region; - - // we need some logic to prevent joining items that have vastly different batch types - // these are defined in RasterizerStorageCommon::BatchTypeFlags - uint32_t joined_item_batch_type_flags_curr; - uint32_t joined_item_batch_type_flags_prev; - - // 'item group' is data over a single call to canvas_render_items - int item_group_z; - Color item_group_modulate; - RendererCanvasRender::Light *item_group_light; - Transform2D item_group_base_transform; - } _render_item_state; - - bool use_nvidia_rect_workaround; - - ////////////////////////////////////////////////////////////////////////////// - // End of structs used by the batcher. Beginning of funcs. -private: - // curiously recurring template pattern - allows access to functions in the DERIVED class - // this is kind of like using virtual functions but more efficient as they are resolved at compile time - T_STORAGE *get_storage() { return static_cast(this)->storage; } - const T_STORAGE *get_storage() const { return static_cast(this)->storage; } - T *get_this() { return static_cast(this); } - const T *get_this() const { return static_cast(this); } - -protected: - // main functions called from the rasterizer canvas - void batch_constructor(); - void batch_initialize(); - - void batch_canvas_begin(); - void batch_canvas_end(); - void batch_canvas_render_items_begin(const Color &p_modulate, RendererCanvasRender::Light *p_light, const Transform2D &p_base_transform); - void batch_canvas_render_items_end(); - void batch_canvas_render_items(RendererCanvasRender::Item *p_item_list, int p_z, const Color &p_modulate, RendererCanvasRender::Light *p_light, const Transform2D &p_base_transform); - - // recording and sorting items from the initial pass - void record_items(RendererCanvasRender::Item *p_item_list, int p_z); - void join_sorted_items(); - void sort_items(); - bool _sort_items_match(const BSortItem &p_a, const BSortItem &p_b) const; - bool sort_items_from(int p_start); - - // joining logic - bool _disallow_item_join_if_batch_types_too_different(RenderItemState &r_ris, uint32_t btf_allowed); - bool _detect_item_batch_break(RenderItemState &r_ris, RendererCanvasRender::Item *p_ci, bool &r_batch_break); - - // drives the loop filling batches and flushing - void render_joined_item_commands(const BItemJoined &p_bij, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material, bool p_lit); - -private: - // flush once full or end of joined item - void flush_render_batches(RendererCanvasRender::Item *p_first_item, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material, uint32_t p_sequence_batch_type_flags); - - // a single joined item can contain multiple itemrefs, and thus create lots of batches - // command start given a separate name to make easier to tell apart godot 3 and 4 - bool prefill_joined_item(FillState &r_fill_state, RendererCanvasRender::Item::Command **r_first_command, RendererCanvasRender::Item *p_item, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material); - - // prefilling different types of batch - - // default batch is an 'unhandled' legacy type batch that will be drawn with the legacy path, - // all other batches are accelerated. - void _prefill_default_batch(FillState &r_fill_state, int p_command_num, const RendererCanvasRender::Item &p_item); - - // accelerated batches - bool _prefill_rect(RendererCanvasRender::Item::CommandRect *rect, FillState &r_fill_state, int &r_command_start, int command_num, int command_count, RendererCanvasRender::Item::Command *const *commands, RendererCanvasRender::Item *p_item, bool multiply_final_modulate); - - // dealing with textures - int _batch_find_or_create_tex(const RID &p_texture, const RID &p_normal, bool p_tile, int p_previous_match); - -protected: - // legacy support for non batched mode - void _legacy_canvas_item_render_commands(RendererCanvasRender::Item *p_item, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material); - - // light scissoring - bool _light_scissor_begin(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect) const; - bool _light_find_intersection(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect, Rect2 &r_cliprect) const; - void _calculate_scissor_threshold_area(); - -private: - // translating vertex formats prior to rendering - void _translate_batches_to_vertex_colored_FVF(); - template - void _translate_batches_to_larger_FVF(uint32_t p_sequence_batch_type_flags); - -protected: - // accessory funcs - void _software_transform_vertex(BatchVector2 &r_v, const Transform2D &p_tr) const; - void _software_transform_vertex(Vector2 &r_v, const Transform2D &p_tr) const; - TransformMode _find_transform_mode(const Transform2D &p_tr) const { - // decided whether to do translate only for software transform - if ((p_tr.elements[0].x == 1.0f) && - (p_tr.elements[0].y == 0.0f) && - (p_tr.elements[1].x == 0.0f) && - (p_tr.elements[1].y == 1.0f)) { - return TM_TRANSLATE; - } - - return TM_ALL; - } - - typename T_STORAGE::Texture *_get_canvas_texture(const RID &p_texture) const { - if (p_texture.is_valid()) { - typename T_STORAGE::Texture *texture = get_storage()->texture_owner.get_or_null(p_texture); - - if (texture) { - return texture->get_ptr(); - } - } - - return 0; - } - -public: - Batch *_batch_request_new(bool p_blank = true) { - Batch *batch = bdata.batches.request(); - if (!batch) { - // grow the batches - bdata.batches.grow(); - - // and the temporary batches (used for color verts) - bdata.batches_temp.reset(); - bdata.batches_temp.grow(); - - // this should always succeed after growing - batch = bdata.batches.request(); - RAST_DEBUG_ASSERT(batch); - } - - if (p_blank) - memset(batch, 0, sizeof(Batch)); - - return batch; - } - - BatchVertex *_batch_vertex_request_new() { - return bdata.vertices.request(); - } - -protected: - int godot4_commands_count(RendererCanvasRender::Item::Command *p_comm) const { - int count = 0; - while (p_comm) { - count++; - p_comm = p_comm->next; - } - return count; - } - - unsigned int godot4_commands_to_vector(RendererCanvasRender::Item::Command *p_comm, LocalVector &p_list) { - p_list.clear(); - while (p_comm) { - p_list.push_back(p_comm); - p_comm = p_comm->next; - } - return p_list.size(); - } -}; - -PREAMBLE(void)::batch_canvas_begin() { - // diagnose_frame? - bdata.frame_string = ""; // just in case, always set this as we don't want a string leak in release... -#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) - if (bdata.settings_diagnose_frame) { - bdata.diagnose_frame = false; - - uint32_t tick = OS::get_singleton()->get_ticks_msec(); - uint64_t frame = Engine::get_singleton()->get_frames_drawn(); - - if (tick >= bdata.next_diagnose_tick) { - bdata.next_diagnose_tick = tick + 10000; - - // the plus one is prevent starting diagnosis half way through frame - bdata.diagnose_frame_number = frame + 1; - } - - if (frame == bdata.diagnose_frame_number) { - bdata.diagnose_frame = true; - bdata.reset_stats(); - } - - if (bdata.diagnose_frame) { - bdata.frame_string = "canvas_begin FRAME " + itos(frame) + "\n"; - } - } -#endif -} - -PREAMBLE(void)::batch_canvas_end() { -#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) - if (bdata.diagnose_frame) { - bdata.frame_string += "canvas_end\n"; - if (bdata.stats_items_sorted) { - bdata.frame_string += "\titems reordered: " + itos(bdata.stats_items_sorted) + "\n"; - } - if (bdata.stats_light_items_joined) { - bdata.frame_string += "\tlight items joined: " + itos(bdata.stats_light_items_joined) + "\n"; - } - - print_line(bdata.frame_string); - } -#endif -} - -PREAMBLE(void)::batch_canvas_render_items_begin(const Color &p_modulate, RendererCanvasRender::Light *p_light, const Transform2D &p_base_transform) { - // if we are debugging, flash each frame between batching renderer and old version to compare for regressions - if (bdata.settings_flash_batching) { - if ((Engine::get_singleton()->get_frames_drawn() % 2) == 0) - bdata.settings_use_batching = true; - else - bdata.settings_use_batching = false; - } - - if (!bdata.settings_use_batching) { - return; - } - - // this only needs to be done when screen size changes, but this should be - // infrequent enough - _calculate_scissor_threshold_area(); - - // set up render item state for all the z_indexes (this is common to all z_indexes) - _render_item_state.reset(); - _render_item_state.item_group_modulate = p_modulate; - _render_item_state.item_group_light = p_light; - _render_item_state.item_group_base_transform = p_base_transform; - _render_item_state.light_region.reset(); - - // batch break must be preserved over the different z indices, - // to prevent joining to an item on a previous index if not allowed - _render_item_state.join_batch_break = false; - - // whether to join across z indices depends on whether there are z ranged lights. - // joined z_index items can be wrongly classified with z ranged lights. - bdata.join_across_z_indices = true; - - int light_count = 0; - while (p_light) { - light_count++; - - if ((p_light->z_min != RS::CANVAS_ITEM_Z_MIN) || (p_light->z_max != RS::CANVAS_ITEM_Z_MAX)) { - // prevent joining across z indices. This would have caused visual regressions - bdata.join_across_z_indices = false; - } - - p_light = p_light->next_ptr; - } - - // can't use the light region bitfield if there are too many lights - // hopefully most games won't blow this limit.. - // if they do they will work but it won't batch join items just in case - if (light_count > 64) { - _render_item_state.light_region.too_many_lights = true; - } -} - -PREAMBLE(void)::batch_canvas_render_items_end() { - if (!bdata.settings_use_batching) { - return; - } - - join_sorted_items(); - -#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) - if (bdata.diagnose_frame) { - bdata.frame_string += "items\n"; - } -#endif - - // batching render is deferred until after going through all the z_indices, joining all the items - get_this()->canvas_render_items_implementation(0, 0, _render_item_state.item_group_modulate, - _render_item_state.item_group_light, - _render_item_state.item_group_base_transform); - - bdata.items_joined.reset(); - bdata.item_refs.reset(); - bdata.sort_items.reset(); -} - -PREAMBLE(void)::batch_canvas_render_items(RendererCanvasRender::Item *p_item_list, int p_z, const Color &p_modulate, RendererCanvasRender::Light *p_light, const Transform2D &p_base_transform) { - // stage 1 : join similar items, so that their state changes are not repeated, - // and commands from joined items can be batched together - if (bdata.settings_use_batching) { - record_items(p_item_list, p_z); - return; - } - - // only legacy renders at this stage, batched renderer doesn't render until canvas_render_items_end() - get_this()->canvas_render_items_implementation(p_item_list, p_z, p_modulate, p_light, p_base_transform); -} - -// Default batches will not occur in software transform only items -// EXCEPT IN THE CASE OF SINGLE RECTS (and this may well not occur, check the logic in prefill_join_item TYPE_RECT) -// but can occur where transform commands have been sent during hardware batch -PREAMBLE(void)::_prefill_default_batch(FillState &r_fill_state, int p_command_num, const RendererCanvasRender::Item &p_item) { - if (r_fill_state.curr_batch->type == RasterizerStorageCommon::BT_DEFAULT) { - // don't need to flush an extra transform command? - if (!r_fill_state.transform_extra_command_number_p1) { - // another default command, just add to the existing batch - r_fill_state.curr_batch->num_commands++; - } else { -#if defined(TOOLS_ENABLED) && defined(DEBUG_ENABLED) - if (r_fill_state.transform_extra_command_number_p1 != p_command_num) { - WARN_PRINT_ONCE("_prefill_default_batch : transform_extra_command_number_p1 != p_command_num"); - } -#endif - // if the first member of the batch is a transform we have to be careful - if (!r_fill_state.curr_batch->num_commands) { - // there can be leading useless extra transforms (sometimes happens with debug collision polys) - // we need to rejig the first_command for the first useful transform - r_fill_state.curr_batch->first_command += r_fill_state.transform_extra_command_number_p1 - 1; - } - - // we do have a pending extra transform command to flush - // either the extra transform is in the prior command, or not, in which case we need 2 batches - r_fill_state.curr_batch->num_commands += 2; - - r_fill_state.transform_extra_command_number_p1 = 0; // mark as sent - r_fill_state.extra_matrix_sent = true; - - // the original mode should always be hardware transform .. - // test this assumption - //CRASH_COND(r_fill_state.orig_transform_mode != TM_NONE); - r_fill_state.transform_mode = r_fill_state.orig_transform_mode; - - // do we need to restore anything else? - } - } else { - // end of previous different type batch, so start new default batch - - // first consider whether there is a dirty extra matrix to send - if (r_fill_state.transform_extra_command_number_p1) { - // get which command the extra is in, and blank all the records as it no longer is stored CPU side - int extra_command = r_fill_state.transform_extra_command_number_p1 - 1; // plus 1 based - r_fill_state.transform_extra_command_number_p1 = 0; - r_fill_state.extra_matrix_sent = true; - - // send the extra to the GPU in a batch - r_fill_state.curr_batch = _batch_request_new(); - r_fill_state.curr_batch->type = RasterizerStorageCommon::BT_DEFAULT; - r_fill_state.curr_batch->first_command = extra_command; - r_fill_state.curr_batch->num_commands = 1; - - // revert to the original transform mode - // e.g. go back to NONE if we were in hardware transform mode - r_fill_state.transform_mode = r_fill_state.orig_transform_mode; - - // reset the original transform if we are going back to software mode, - // because the extra is now done on the GPU... - // (any subsequent extras are sent directly to the GPU, no deferring) - if (r_fill_state.orig_transform_mode != TM_NONE) { - r_fill_state.transform_combined = p_item.final_transform; - } - - // can possibly combine batch with the next one in some cases - // this is more efficient than having an extra batch especially for the extra - if ((extra_command + 1) == p_command_num) { - r_fill_state.curr_batch->num_commands = 2; - return; - } - } - - // start default batch - r_fill_state.curr_batch = _batch_request_new(); - r_fill_state.curr_batch->type = RasterizerStorageCommon::BT_DEFAULT; - r_fill_state.curr_batch->first_command = p_command_num; - r_fill_state.curr_batch->num_commands = 1; - } -} - -PREAMBLE(int)::_batch_find_or_create_tex(const RID &p_texture, const RID &p_normal, bool p_tile, int p_previous_match) { - // optimization .. in 99% cases the last matched value will be the same, so no need to traverse the list - if (p_previous_match > 0) // if it is zero, it will get hit first in the linear search anyway - { - const BatchTex &batch_texture = bdata.batch_textures[p_previous_match]; - - // note for future reference, if RID implementation changes, this could become more expensive - if ((batch_texture.RID_texture == p_texture) && (batch_texture.RID_normal == p_normal)) { - // tiling mode must also match - bool tiles = batch_texture.tile_mode != BatchTex::TILE_OFF; - - if (tiles == p_tile) - // match! - return p_previous_match; - } - } - - // not the previous match .. we will do a linear search ... slower, but should happen - // not very often except with non-batchable runs, which are going to be slow anyway - // n.b. could possibly be replaced later by a fast hash table - for (int n = 0; n < bdata.batch_textures.size(); n++) { - const BatchTex &batch_texture = bdata.batch_textures[n]; - if ((batch_texture.RID_texture == p_texture) && (batch_texture.RID_normal == p_normal)) { - // tiling mode must also match - bool tiles = batch_texture.tile_mode != BatchTex::TILE_OFF; - - if (tiles == p_tile) - // match! - return n; - } - } - - // pushing back from local variable .. not ideal but has to use a Vector because non pod - // due to RIDs - BatchTex new_batch_tex; - new_batch_tex.RID_texture = p_texture; - new_batch_tex.RID_normal = p_normal; - - // get the texture - typename T_STORAGE::Texture *texture = _get_canvas_texture(p_texture); - - if (texture) { - // special case, there can be textures with no width or height - int w = texture->width; - int h = texture->height; - - if (!w || !h) { - w = 1; - h = 1; - } - - new_batch_tex.tex_pixel_size.x = 1.0 / w; - new_batch_tex.tex_pixel_size.y = 1.0 / h; - new_batch_tex.flags = texture->flags; - } else { - // maybe doesn't need doing... - new_batch_tex.tex_pixel_size.x = 1.0f; - new_batch_tex.tex_pixel_size.y = 1.0f; - new_batch_tex.flags = 0; - } - - if (p_tile) { - if (texture) { - // default - new_batch_tex.tile_mode = BatchTex::TILE_NORMAL; - - // no hardware support for non power of 2 tiling - if (!get_storage()->config.support_npot_repeat_mipmap) { - if (next_power_of_2(texture->alloc_width) != (unsigned int)texture->alloc_width && next_power_of_2(texture->alloc_height) != (unsigned int)texture->alloc_height) { - new_batch_tex.tile_mode = BatchTex::TILE_FORCE_REPEAT; - } - } - } else { - // this should not happen? - new_batch_tex.tile_mode = BatchTex::TILE_OFF; - } - } else { - new_batch_tex.tile_mode = BatchTex::TILE_OFF; - } - - // push back - bdata.batch_textures.push_back(new_batch_tex); - - return bdata.batch_textures.size() - 1; -} - -PREAMBLE(void)::batch_constructor() { - bdata.settings_use_batching = false; - -#ifdef GLES_OVER_GL - use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/use_nvidia_rect_flicker_workaround"); -#else - // Not needed (a priori) on GLES devices - use_nvidia_rect_workaround = false; -#endif -} - -PREAMBLE(void)::batch_initialize() { -#define BATCHING_LOAD_PROJECT_SETTINGS - -#ifdef BATCHING_LOAD_PROJECT_SETTINGS - bdata.settings_use_batching = GLOBAL_GET("rendering/batching/options/use_batching"); - bdata.settings_max_join_item_commands = GLOBAL_GET("rendering/batching/parameters/max_join_item_commands"); - bdata.settings_colored_vertex_format_threshold = GLOBAL_GET("rendering/batching/parameters/colored_vertex_format_threshold"); - bdata.settings_item_reordering_lookahead = GLOBAL_GET("rendering/batching/parameters/item_reordering_lookahead"); - bdata.settings_light_max_join_items = GLOBAL_GET("rendering/batching/lights/max_join_items"); - bdata.settings_use_single_rect_fallback = GLOBAL_GET("rendering/batching/options/single_rect_fallback"); - bdata.settings_use_software_skinning = GLOBAL_GET("rendering/quality/2d/use_software_skinning"); - bdata.settings_ninepatch_mode = GLOBAL_GET("rendering/quality/2d/ninepatch_mode"); - - // alternatively only enable uv contract if pixel snap in use, - // but with this enable bool, it should not be necessary - bdata.settings_uv_contract = GLOBAL_GET("rendering/batching/precision/uv_contract"); - bdata.settings_uv_contract_amount = (float)GLOBAL_GET("rendering/batching/precision/uv_contract_amount") / 1000000.0f; - - // we can use the threshold to determine whether to turn scissoring off or on - bdata.settings_scissor_threshold = GLOBAL_GET("rendering/batching/lights/scissor_area_threshold"); -#endif - - if (bdata.settings_scissor_threshold > 0.999f) { - bdata.settings_scissor_lights = false; - } else { - bdata.settings_scissor_lights = true; - - // apply power of 4 relationship for the area, as most of the important changes - // will be happening at low values of scissor threshold - bdata.settings_scissor_threshold *= bdata.settings_scissor_threshold; - bdata.settings_scissor_threshold *= bdata.settings_scissor_threshold; - } - - // The sweet spot on my desktop for cache is actually smaller than the max, and this - // is the default. This saves memory too so we will use it for now, needs testing to see whether this varies according - // to device / platform. -#ifdef BATCHING_LOAD_PROJECT_SETTINGS - bdata.settings_batch_buffer_num_verts = GLOBAL_GET("rendering/batching/parameters/batch_buffer_size"); - - // override the use_batching setting in the editor - // (note that if the editor can't start, you can't change the use_batching project setting!) - if (Engine::get_singleton()->is_editor_hint()) { - bool use_in_editor = GLOBAL_GET("rendering/batching/options/use_batching_in_editor"); - bdata.settings_use_batching = use_in_editor; - - // fix some settings in the editor, as the performance not worth the risk - bdata.settings_use_single_rect_fallback = false; - } -#endif - - // if we are using batching, we will purposefully disable the nvidia workaround. - // This is because the only reason to use the single rect fallback is the approx 2x speed - // of the uniform drawing technique. If we used nvidia workaround, speed would be - // approx equal to the batcher drawing technique (indexed primitive + VB). - if (bdata.settings_use_batching) { - use_nvidia_rect_workaround = false; - } - - // For debugging, if flash is set in project settings, it will flash on alternate frames - // between the non-batched renderer and the batched renderer, - // in order to find regressions. - // This should not be used except during development. - // make a note of the original choice in case we are flashing on and off the batching - bdata.settings_use_batching_original_choice = bdata.settings_use_batching; - -#ifdef BATCHING_LOAD_PROJECT_SETTINGS - bdata.settings_flash_batching = GLOBAL_GET("rendering/batching/debug/flash_batching"); -#endif - if (!bdata.settings_use_batching) { - // no flash when batching turned off - bdata.settings_flash_batching = false; - } - - // frame diagnosis. print out the batches every nth frame - bdata.settings_diagnose_frame = false; - if (!Engine::get_singleton()->is_editor_hint() && bdata.settings_use_batching) { -#ifdef BATCHING_LOAD_PROJECT_SETTINGS - bdata.settings_diagnose_frame = GLOBAL_GET("rendering/batching/debug/diagnose_frame"); -#endif - } - - // the maximum num quads in a batch is limited by GLES2. We can have only 16 bit indices, - // which means we can address a vertex buffer of max size 65535. 4 vertices are needed per quad. - - // Note this determines the memory use by the vertex buffer vector. max quads (65536/4)-1 - // but can be reduced to save memory if really required (will result in more batches though) - const int max_possible_quads = (65536 / 4) - 1; - const int min_possible_quads = 8; // some reasonable small value - - // value from project settings - int max_quads = bdata.settings_batch_buffer_num_verts / 4; - - // sanity checks - max_quads = CLAMP(max_quads, min_possible_quads, max_possible_quads); - bdata.settings_max_join_item_commands = CLAMP(bdata.settings_max_join_item_commands, 0, 65535); - bdata.settings_colored_vertex_format_threshold = CLAMP(bdata.settings_colored_vertex_format_threshold, 0.0f, 1.0f); - bdata.settings_scissor_threshold = CLAMP(bdata.settings_scissor_threshold, 0.0f, 1.0f); - bdata.settings_light_max_join_items = CLAMP(bdata.settings_light_max_join_items, 0, 65535); - bdata.settings_item_reordering_lookahead = CLAMP(bdata.settings_item_reordering_lookahead, 0, 65535); - - // allow user to override the api usage techniques using project settings - // bdata.buffer_mode_batch_upload_send_null = GLOBAL_GET("rendering/options/api_usage_batching/send_null"); - // bdata.buffer_mode_batch_upload_flag_stream = GLOBAL_GET("rendering/options/api_usage_batching/flag_stream"); - - // for debug purposes, output a string with the batching options - String batching_options_string = "OpenGL ES Batching: "; - if (bdata.settings_use_batching) { - batching_options_string += "ON"; - - if (OS::get_singleton()->is_stdout_verbose()) { - batching_options_string += "\n\tOPTIONS\n"; - batching_options_string += "\tmax_join_item_commands " + itos(bdata.settings_max_join_item_commands) + "\n"; - batching_options_string += "\tcolored_vertex_format_threshold " + String(Variant(bdata.settings_colored_vertex_format_threshold)) + "\n"; - batching_options_string += "\tbatch_buffer_size " + itos(bdata.settings_batch_buffer_num_verts) + "\n"; - batching_options_string += "\tlight_scissor_area_threshold " + String(Variant(bdata.settings_scissor_threshold)) + "\n"; - - batching_options_string += "\titem_reordering_lookahead " + itos(bdata.settings_item_reordering_lookahead) + "\n"; - batching_options_string += "\tlight_max_join_items " + itos(bdata.settings_light_max_join_items) + "\n"; - batching_options_string += "\tsingle_rect_fallback " + String(Variant(bdata.settings_use_single_rect_fallback)) + "\n"; - - batching_options_string += "\tdebug_flash " + String(Variant(bdata.settings_flash_batching)) + "\n"; - batching_options_string += "\tdiagnose_frame " + String(Variant(bdata.settings_diagnose_frame)); - } - - print_line(batching_options_string); - } - - // special case, for colored vertex format threshold. - // as the comparison is >=, we want to be able to totally turn on or off - // conversion to colored vertex format at the extremes, so we will force - // 1.0 to be just above 1.0 - if (bdata.settings_colored_vertex_format_threshold > 0.995f) { - bdata.settings_colored_vertex_format_threshold = 1.01f; - } - - // save memory when batching off - if (!bdata.settings_use_batching) { - max_quads = 0; - } - - uint32_t sizeof_batch_vert = sizeof(BatchVertex); - - bdata.max_quads = max_quads; - - // 4 verts per quad - bdata.vertex_buffer_size_units = max_quads * 4; - - // the index buffer can be longer than 65535, only the indices need to be within this range - bdata.index_buffer_size_units = max_quads * 6; - - const int max_verts = bdata.vertex_buffer_size_units; - - // this comes out at approx 64K for non-colored vertex buffer, and 128K for colored vertex buffer - bdata.vertex_buffer_size_bytes = max_verts * sizeof_batch_vert; - bdata.index_buffer_size_bytes = bdata.index_buffer_size_units * 2; // 16 bit inds - - // create equal number of normal and (max) unit sized verts (as the normal may need to be translated to a larger FVF) - bdata.vertices.create(max_verts); // 512k - bdata.unit_vertices.create(max_verts, sizeof(BatchVertexLarge)); - - // extra data per vert needed for larger FVFs - bdata.light_angles.create(max_verts); - bdata.vertex_colors.create(max_verts); - bdata.vertex_modulates.create(max_verts); - bdata.vertex_transforms.create(max_verts); - - // num batches will be auto increased dynamically if required - bdata.batches.create(1024); - bdata.batches_temp.create(bdata.batches.max_size()); - - // batch textures can also be increased dynamically - bdata.batch_textures.create(32); -} - -PREAMBLE(bool)::_light_scissor_begin(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect) const { - float area_item = p_item_rect.size.x * p_item_rect.size.y; // double check these are always positive - - // quick reject .. the area of pixels saved can never be more than the area of the item - if (area_item < bdata.scissor_threshold_area) { - return false; - } - - Rect2 cliprect; - if (!_light_find_intersection(p_item_rect, p_light_xform, p_light_rect, cliprect)) { - // should not really occur .. but just in case - cliprect = Rect2(0, 0, 0, 0); - } else { - // some conditions not to scissor - // determine the area (fill rate) that will be saved - float area_cliprect = cliprect.size.x * cliprect.size.y; - float area_saved = area_item - area_cliprect; - - // if area saved is too small, don't scissor - if (area_saved < bdata.scissor_threshold_area) { - return false; - } - } - - int rh = get_storage()->frame.current_rt->height; - - int y = rh - (cliprect.position.y + cliprect.size.y); - get_this()->gl_enable_scissor(cliprect.position.x, y, cliprect.size.width, cliprect.size.height); - - return true; -} - -PREAMBLE(bool)::_light_find_intersection(const Rect2 &p_item_rect, const Transform2D &p_light_xform, const Rect2 &p_light_rect, Rect2 &r_cliprect) const { - // transform light to world space (note this is done in the earlier intersection test, so could - // be made more efficient) - Vector2 pts[4] = { - p_light_xform.xform(p_light_rect.position), - p_light_xform.xform(Vector2(p_light_rect.position.x + p_light_rect.size.x, p_light_rect.position.y)), - p_light_xform.xform(Vector2(p_light_rect.position.x, p_light_rect.position.y + p_light_rect.size.y)), - p_light_xform.xform(Vector2(p_light_rect.position.x + p_light_rect.size.x, p_light_rect.position.y + p_light_rect.size.y)), - }; - - // calculate the light bound rect in world space - Rect2 lrect(pts[0].x, pts[0].y, 0, 0); - for (int n = 1; n < 4; n++) { - lrect.expand_to(pts[n]); - } - - // intersection between the 2 rects - // they should probably always intersect, because of earlier check, but just in case... - if (!p_item_rect.intersects(lrect)) - return false; - - // note this does almost the same as Rect2.clip but slightly more efficient for our use case - r_cliprect.position.x = MAX(p_item_rect.position.x, lrect.position.x); - r_cliprect.position.y = MAX(p_item_rect.position.y, lrect.position.y); - - Point2 item_rect_end = p_item_rect.position + p_item_rect.size; - Point2 lrect_end = lrect.position + lrect.size; - - r_cliprect.size.x = MIN(item_rect_end.x, lrect_end.x) - r_cliprect.position.x; - r_cliprect.size.y = MIN(item_rect_end.y, lrect_end.y) - r_cliprect.position.y; - - return true; -} - -PREAMBLE(void)::_calculate_scissor_threshold_area() { - if (!bdata.settings_scissor_lights) { - return; - } - - // scissor area threshold is 0.0 to 1.0 in the settings for ease of use. - // we need to translate to an absolute area to determine quickly whether - // to scissor. - if (bdata.settings_scissor_threshold < 0.0001f) { - bdata.scissor_threshold_area = -1.0f; // will always pass - } else { - // in pixels - int w = get_storage()->frame.current_rt->width; - int h = get_storage()->frame.current_rt->height; - - int screen_area = w * h; - - bdata.scissor_threshold_area = bdata.settings_scissor_threshold * screen_area; - } -} - -PREAMBLE(void)::render_joined_item_commands(const BItemJoined &p_bij, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material, bool p_lit) { - RendererCanvasRender::Item *item = 0; - RendererCanvasRender::Item *first_item = bdata.item_refs[p_bij.first_item_ref].item; - - // fill_state and bdata have once off setup per joined item, and a smaller reset on flush - FillState fill_state; - fill_state.reset_joined_item(p_bij.use_hardware_transform()); - - bdata.reset_joined_item(); - - // should this joined item be using large FVF? - if (p_bij.flags & RasterizerStorageCommon::USE_MODULATE_FVF) { - bdata.use_modulate = true; - bdata.fvf = RasterizerStorageCommon::FVF_MODULATED; - } - if (p_bij.flags & RasterizerStorageCommon::USE_LARGE_FVF) { - bdata.use_modulate = true; - bdata.use_large_verts = true; - bdata.fvf = RasterizerStorageCommon::FVF_LARGE; - } - - // in the special case of custom shaders that read from VERTEX (i.e. vertex position) - // we want to disable software transform of extra matrix - if (bdata.joined_item_batch_flags & RasterizerStorageCommon::PREVENT_VERTEX_BAKING) { - fill_state.extra_matrix_sent = true; - } - - for (unsigned int i = 0; i < p_bij.num_item_refs; i++) { - const BItemRef &ref = bdata.item_refs[p_bij.first_item_ref + i]; - item = ref.item; - - if (!p_lit) { - // if not lit we use the complex calculated final modulate - fill_state.final_modulate = ref.final_modulate; - } else { - // if lit we ignore canvas modulate and just use the item modulate - fill_state.final_modulate = item->final_modulate; - } - - // ONCE OFF fill state setup, that will be retained over multiple calls to - // prefill_joined_item() - fill_state.transform_combined = item->final_transform; - - // decide the initial transform mode, and make a backup - // in orig_transform_mode in case we need to switch back - if (!fill_state.use_hardware_transform) { - fill_state.transform_mode = _find_transform_mode(fill_state.transform_combined); - } else { - fill_state.transform_mode = TM_NONE; - } - fill_state.orig_transform_mode = fill_state.transform_mode; - - // keep track of when we added an extra matrix - // so we can defer sending until we see a default command - fill_state.transform_extra_command_number_p1 = 0; - - RendererCanvasRender::Item::Command *current_command = item->commands; - while (current_command) { - // fill as many batches as possible (until all done, or the vertex buffer is full) - bool bFull = get_this()->prefill_joined_item(fill_state, current_command, item, p_current_clip, r_reclip, p_material); - - if (bFull) { - // always pass first item (commands for default are always first item) - flush_render_batches(first_item, p_current_clip, r_reclip, p_material, fill_state.sequence_batch_type_flags); - - // zero all the batch data ready for a new run - bdata.reset_flush(); - - // don't zero all the fill state, some may need to be preserved - fill_state.reset_flush(); - } - } - } - - // flush if any left - flush_render_batches(first_item, p_current_clip, r_reclip, p_material, fill_state.sequence_batch_type_flags); - - // zero all the batch data ready for a new run - bdata.reset_flush(); -} - -PREAMBLE(void)::_legacy_canvas_item_render_commands(RendererCanvasRender::Item *p_item, RendererCanvasRender::Item *p_current_clip, bool &r_reclip, typename T_STORAGE::Material *p_material) { - // reuse the same list each time to prevent needless dynamic allocations - unsigned int command_count = godot4_commands_to_vector(p_item->commands, bdata.command_shortlist); - RendererCanvasRender::Item::Command *const *commands = nullptr; - if (command_count) { - commands = &bdata.command_shortlist[0]; - } - - // legacy .. just create one massive batch and render everything as before - bdata.batches.reset(); - Batch *batch = _batch_request_new(); - batch->type = RasterizerStorageCommon::BT_DEFAULT; - batch->num_commands = command_count; - - get_this()->render_batches(commands, p_current_clip, r_reclip, p_material); - bdata.reset_flush(); -} - -PREAMBLE(void)::record_items(RendererCanvasRender::Item *p_item_list, int p_z) { - while (p_item_list) { - BSortItem *s = bdata.sort_items.request_with_grow(); - - s->item = p_item_list; - s->z_index = p_z; - - p_item_list = p_item_list->next; - } -} - -PREAMBLE(void)::join_sorted_items() { -} - -PREAMBLE(void)::_software_transform_vertex(BatchVector2 &r_v, const Transform2D &p_tr) const { - Vector2 vc(r_v.x, r_v.y); - vc = p_tr.xform(vc); - r_v.set(vc); -} - -PREAMBLE(void)::_software_transform_vertex(Vector2 &r_v, const Transform2D &p_tr) const { - r_v = p_tr.xform(r_v); -} - -PREAMBLE(void)::_translate_batches_to_vertex_colored_FVF() { - // zeros the size and sets up how big each unit is - bdata.unit_vertices.prepare(sizeof(BatchVertexColored)); - - const BatchColor *source_vertex_colors = &bdata.vertex_colors[0]; - RAST_DEBUG_ASSERT(bdata.vertex_colors.size() == bdata.vertices.size()); - - int num_verts = bdata.vertices.size(); - - for (int n = 0; n < num_verts; n++) { - const BatchVertex &bv = bdata.vertices[n]; - - BatchVertexColored *cv = (BatchVertexColored *)bdata.unit_vertices.request(); - - cv->pos = bv.pos; - cv->uv = bv.uv; - cv->col = *source_vertex_colors++; - } -} - -// Translation always involved adding color to the FVF, which enables -// joining of batches that have different colors. -// There is a trade off. Non colored verts are smaller so work faster, but -// there comes a point where it is better to just use colored verts to avoid lots of -// batches. -// In addition this can optionally add light angles to the FVF, necessary for normal mapping. -T_PREAMBLE -template -void C_PREAMBLE::_translate_batches_to_larger_FVF(uint32_t p_sequence_batch_type_flags) { - bool include_poly_color = false; - - // we ONLY want to include the color verts in translation when using polys, - // as rects do not write vertex colors, only colors per batch. - if (p_sequence_batch_type_flags & RasterizerStorageCommon::BTF_POLY) { - include_poly_color = INCLUDE_LIGHT_ANGLES | INCLUDE_MODULATE | INCLUDE_LARGE; - } - - // zeros the size and sets up how big each unit is - bdata.unit_vertices.prepare(sizeof(BATCH_VERTEX_TYPE)); - bdata.batches_temp.reset(); - - // As the vertices_colored and batches_temp are 'mirrors' of the non-colored version, - // the sizes should be equal, and allocations should never fail. Hence the use of debug - // asserts to check program flow, these should not occur at runtime unless the allocation - // code has been altered. - RAST_DEBUG_ASSERT(bdata.unit_vertices.max_size() == bdata.vertices.max_size()); - RAST_DEBUG_ASSERT(bdata.batches_temp.max_size() == bdata.batches.max_size()); - - Color curr_col(-1.0f, -1.0f, -1.0f, -1.0f); - - Batch *dest_batch = nullptr; - - const BatchColor *source_vertex_colors = &bdata.vertex_colors[0]; - const float *source_light_angles = &bdata.light_angles[0]; - const BatchColor *source_vertex_modulates = &bdata.vertex_modulates[0]; - const BatchTransform *source_vertex_transforms = &bdata.vertex_transforms[0]; - - // translate the batches into vertex colored batches - for (int n = 0; n < bdata.batches.size(); n++) { - const Batch &source_batch = bdata.batches[n]; - - // does source batch use light angles? - const BatchTex &btex = bdata.batch_textures[source_batch.batch_texture_id]; - bool source_batch_uses_light_angles = btex.RID_normal != RID(); - - bool needs_new_batch = true; - - if (dest_batch) { - if (dest_batch->type == source_batch.type) { - if (source_batch.type == RasterizerStorageCommon::BT_RECT) { - if (dest_batch->batch_texture_id == source_batch.batch_texture_id) { - // add to previous batch - dest_batch->num_commands += source_batch.num_commands; - needs_new_batch = false; - - // create the colored verts (only if not default) - //int first_vert = source_batch.first_quad * 4; - //int end_vert = 4 * (source_batch.first_quad + source_batch.num_commands); - int first_vert = source_batch.first_vert; - int end_vert = first_vert + (4 * source_batch.num_commands); - - for (int v = first_vert; v < end_vert; v++) { - RAST_DEV_DEBUG_ASSERT(bdata.vertices.size()); - const BatchVertex &bv = bdata.vertices[v]; - BATCH_VERTEX_TYPE *cv = (BATCH_VERTEX_TYPE *)bdata.unit_vertices.request(); - RAST_DEBUG_ASSERT(cv); - cv->pos = bv.pos; - cv->uv = bv.uv; - cv->col = source_batch.color; - - if (INCLUDE_LIGHT_ANGLES) { - RAST_DEV_DEBUG_ASSERT(bdata.light_angles.size()); - // this is required to allow compilation with non light angle vertex. - // it should be compiled out. - BatchVertexLightAngled *lv = (BatchVertexLightAngled *)cv; - if (source_batch_uses_light_angles) - lv->light_angle = *source_light_angles++; - else - lv->light_angle = 0.0f; // dummy, unused in vertex shader (could possibly be left uninitialized, but probably bad idea) - } // if including light angles - - if (INCLUDE_MODULATE) { - RAST_DEV_DEBUG_ASSERT(bdata.vertex_modulates.size()); - BatchVertexModulated *mv = (BatchVertexModulated *)cv; - mv->modulate = *source_vertex_modulates++; - } // including modulate - - if (INCLUDE_LARGE) { - RAST_DEV_DEBUG_ASSERT(bdata.vertex_transforms.size()); - BatchVertexLarge *lv = (BatchVertexLarge *)cv; - lv->transform = *source_vertex_transforms++; - } // if including large - } - } // textures match - } else { - // default - // we can still join, but only under special circumstances - // does this ever happen? not sure at this stage, but left for future expansion - uint32_t source_last_command = source_batch.first_command + source_batch.num_commands; - if (source_last_command == dest_batch->first_command) { - dest_batch->num_commands += source_batch.num_commands; - needs_new_batch = false; - } // if the commands line up exactly - } - } // if both batches are the same type - - } // if dest batch is valid - - if (needs_new_batch) { - dest_batch = bdata.batches_temp.request(); - RAST_DEBUG_ASSERT(dest_batch); - - *dest_batch = source_batch; - - // create the colored verts (only if not default) - if (source_batch.type != RasterizerStorageCommon::BT_DEFAULT) { - // int first_vert = source_batch.first_quad * 4; - // int end_vert = 4 * (source_batch.first_quad + source_batch.num_commands); - int first_vert = source_batch.first_vert; - int end_vert = first_vert + (4 * source_batch.num_commands); - - for (int v = first_vert; v < end_vert; v++) { - RAST_DEV_DEBUG_ASSERT(bdata.vertices.size()); - const BatchVertex &bv = bdata.vertices[v]; - BATCH_VERTEX_TYPE *cv = (BATCH_VERTEX_TYPE *)bdata.unit_vertices.request(); - RAST_DEBUG_ASSERT(cv); - cv->pos = bv.pos; - cv->uv = bv.uv; - - // polys are special, they can have per vertex colors - if (!include_poly_color) { - cv->col = source_batch.color; - } else { - RAST_DEV_DEBUG_ASSERT(bdata.vertex_colors.size()); - cv->col = *source_vertex_colors++; - } - - if (INCLUDE_LIGHT_ANGLES) { - RAST_DEV_DEBUG_ASSERT(bdata.light_angles.size()); - // this is required to allow compilation with non light angle vertex. - // it should be compiled out. - BatchVertexLightAngled *lv = (BatchVertexLightAngled *)cv; - if (source_batch_uses_light_angles) - lv->light_angle = *source_light_angles++; - else - lv->light_angle = 0.0f; // dummy, unused in vertex shader (could possibly be left uninitialized, but probably bad idea) - } // if using light angles - - if (INCLUDE_MODULATE) { - RAST_DEV_DEBUG_ASSERT(bdata.vertex_modulates.size()); - BatchVertexModulated *mv = (BatchVertexModulated *)cv; - mv->modulate = *source_vertex_modulates++; - } // including modulate - - if (INCLUDE_LARGE) { - RAST_DEV_DEBUG_ASSERT(bdata.vertex_transforms.size()); - BatchVertexLarge *lv = (BatchVertexLarge *)cv; - lv->transform = *source_vertex_transforms++; - } // if including large - } - } - } - } - - // copy the temporary batches to the master batch list (this could be avoided but it makes the code cleaner) - bdata.batches.copy_from(bdata.batches_temp); -} - -PREAMBLE(bool)::_disallow_item_join_if_batch_types_too_different(RenderItemState &r_ris, uint32_t btf_allowed) { - r_ris.joined_item_batch_type_flags_curr |= btf_allowed; - - bool disallow = false; - - if (r_ris.joined_item_batch_type_flags_prev & (~btf_allowed)) - disallow = true; - - return disallow; -} - -#undef PREAMBLE -#undef T_PREAMBLE -#undef C_PREAMBLE - -#endif // RASTERIZER_CANVAS_BATCHER_H diff --git a/drivers/opengl/rasterizer_canvas_opengl.cpp b/drivers/opengl/rasterizer_canvas_opengl.cpp deleted file mode 100644 index 41d68e5bc9..0000000000 --- a/drivers/opengl/rasterizer_canvas_opengl.cpp +++ /dev/null @@ -1,1708 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_opengl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rasterizer_canvas_opengl.h" -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/os/os.h" -#include "drivers/opengl/rasterizer_asserts.h" -#include "rasterizer_scene_opengl.h" -#include "rasterizer_storage_opengl.h" - -#include "core/config/project_settings.h" -#include "servers/rendering/rendering_server_default.h" - -//static const GLenum gl_primitive[] = { -// GL_POINTS, -// GL_LINES, -// GL_LINE_STRIP, -// GL_LINE_LOOP, -// GL_TRIANGLES, -// GL_TRIANGLE_STRIP, -// GL_TRIANGLE_FAN -//}; - -#if 0 -void RasterizerCanvasOpenGL::_batch_upload_buffers() { - // noop? - if (!bdata.vertices.size()) - return; - - glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); - - // usage flag is a project setting - GLenum buffer_usage_flag = GL_DYNAMIC_DRAW; - if (bdata.buffer_mode_batch_upload_flag_stream) { - buffer_usage_flag = GL_STREAM_DRAW; - } - - // orphan the old (for now) - if (bdata.buffer_mode_batch_upload_send_null) { - glBufferData(GL_ARRAY_BUFFER, 0, 0, buffer_usage_flag); // GL_DYNAMIC_DRAW); - } - - switch (bdata.fvf) { - case RasterizerStorageCommon::FVF_UNBATCHED: // should not happen - break; - case RasterizerStorageCommon::FVF_REGULAR: // no change - glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertex) * bdata.vertices.size(), bdata.vertices.get_data(), buffer_usage_flag); - break; - case RasterizerStorageCommon::FVF_COLOR: - glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertexColored) * bdata.unit_vertices.size(), bdata.unit_vertices.get_unit(0), buffer_usage_flag); - break; - case RasterizerStorageCommon::FVF_LIGHT_ANGLE: - glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertexLightAngled) * bdata.unit_vertices.size(), bdata.unit_vertices.get_unit(0), buffer_usage_flag); - break; - case RasterizerStorageCommon::FVF_MODULATED: - glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertexModulated) * bdata.unit_vertices.size(), bdata.unit_vertices.get_unit(0), buffer_usage_flag); - break; - case RasterizerStorageCommon::FVF_LARGE: - glBufferData(GL_ARRAY_BUFFER, sizeof(BatchVertexLarge) * bdata.unit_vertices.size(), bdata.unit_vertices.get_unit(0), buffer_usage_flag); - break; - } - - // might not be necessary - glBindBuffer(GL_ARRAY_BUFFER, 0); -} - -void RasterizerCanvasOpenGL::_batch_render_lines(const Batch &p_batch, RasterizerStorageOpenGL::Material *p_material, bool p_anti_alias) { - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - _bind_canvas_texture(RID(), RID()); - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, (float *)&p_batch.color); - -#ifdef GLES_OVER_GL - if (p_anti_alias) - glEnable(GL_LINE_SMOOTH); -#endif - - int sizeof_vert = sizeof(BatchVertex); - - // bind the index and vertex buffer - glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bdata.gl_index_buffer); - - uint64_t pointer = 0; - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof_vert, (const void *)pointer); - - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - - int64_t offset = p_batch.first_vert; // 6 inds per quad at 2 bytes each - - int num_elements = p_batch.num_commands * 2; - glDrawArrays(GL_LINES, offset, num_elements); - - storage->info.render._2d_draw_call_count++; - - // may not be necessary .. state change optimization still TODO - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - -#ifdef GLES_OVER_GL - if (p_anti_alias) - glDisable(GL_LINE_SMOOTH); -#endif -} - -void RasterizerCanvasOpenGL::_batch_render_generic(const Batch &p_batch, RasterizerStorageOpenGL::Material *p_material) { - ERR_FAIL_COND(p_batch.num_commands <= 0); - - const bool &use_light_angles = bdata.use_light_angles; - const bool &use_modulate = bdata.use_modulate; - const bool &use_large_verts = bdata.use_large_verts; - const bool &colored_verts = bdata.use_colored_vertices | use_light_angles | use_modulate | use_large_verts; - - int sizeof_vert; - - switch (bdata.fvf) { - default: - sizeof_vert = 0; // prevent compiler warning - this should never happen - break; - case RasterizerStorageCommon::FVF_UNBATCHED: { - sizeof_vert = 0; // prevent compiler warning - this should never happen - return; - } break; - case RasterizerStorageCommon::FVF_REGULAR: // no change - sizeof_vert = sizeof(BatchVertex); - break; - case RasterizerStorageCommon::FVF_COLOR: - sizeof_vert = sizeof(BatchVertexColored); - break; - case RasterizerStorageCommon::FVF_LIGHT_ANGLE: - sizeof_vert = sizeof(BatchVertexLightAngled); - break; - case RasterizerStorageCommon::FVF_MODULATED: - sizeof_vert = sizeof(BatchVertexModulated); - break; - case RasterizerStorageCommon::FVF_LARGE: - sizeof_vert = sizeof(BatchVertexLarge); - break; - } - - // make sure to set all conditionals BEFORE binding the shader - _set_texture_rect_mode(false, use_light_angles, use_modulate, use_large_verts); - - // batch tex - const BatchTex &tex = bdata.batch_textures[p_batch.batch_texture_id]; - //VSG::rasterizer->gl_check_for_error(); - - // force repeat is set if non power of 2 texture, and repeat is needed if hardware doesn't support npot - if (tex.tile_mode == BatchTex::TILE_FORCE_REPEAT) { - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_FORCE_REPEAT, true); - } - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - _bind_canvas_texture(tex.RID_texture, tex.RID_normal); - - // bind the index and vertex buffer - glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bdata.gl_index_buffer); - - uint64_t pointer = 0; - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof_vert, (const void *)pointer); - - // always send UVs, even within a texture specified because a shader can still use UVs - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (2 * 4))); - - // color - if (!colored_verts) { - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, p_batch.color.get_data()); - } else { - glEnableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttribPointer(RS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (4 * 4))); - } - - if (use_light_angles) { - glEnableVertexAttribArray(RS::ARRAY_TANGENT); - glVertexAttribPointer(RS::ARRAY_TANGENT, 1, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (8 * 4))); - } - - if (use_modulate) { - glEnableVertexAttribArray(RS::ARRAY_TEX_UV2); - glVertexAttribPointer(RS::ARRAY_TEX_UV2, 4, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (9 * 4))); - } - - if (use_large_verts) { - glEnableVertexAttribArray(RS::ARRAY_BONES); - glVertexAttribPointer(RS::ARRAY_BONES, 2, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (13 * 4))); - glEnableVertexAttribArray(RS::ARRAY_WEIGHTS); - glVertexAttribPointer(RS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof_vert, CAST_INT_TO_UCHAR_PTR(pointer + (15 * 4))); - } - - // We only want to set the GL wrapping mode if the texture is not already tiled (i.e. set in Import). - // This is an optimization left over from the legacy renderer. - // If we DID set tiling in the API, and reverted to clamped, then the next draw using this texture - // may use clamped mode incorrectly. - bool tex_is_already_tiled = tex.flags & RasterizerStorageOpenGL::TEXTURE_FLAG_REPEAT; - - if (tex.tile_mode == BatchTex::TILE_NORMAL) { - // if the texture is imported as tiled, no need to set GL state, as it will already be bound with repeat - if (!tex_is_already_tiled) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - } - } - - // we need to convert explicitly from pod Vec2 to Vector2 ... - // could use a cast but this might be unsafe in future - Vector2 tps; - tex.tex_pixel_size.to(tps); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::COLOR_TEXPIXEL_SIZE, tps); - - switch (p_batch.type) { - default: { - // prevent compiler warning - } break; - case RasterizerStorageCommon::BT_RECT: { - int64_t offset = p_batch.first_vert * 3; - - int num_elements = p_batch.num_commands * 6; - glDrawElements(GL_TRIANGLES, num_elements, GL_UNSIGNED_SHORT, (void *)offset); - } break; - case RasterizerStorageCommon::BT_POLY: { - int64_t offset = p_batch.first_vert; - - int num_elements = p_batch.num_commands; - glDrawArrays(GL_TRIANGLES, offset, num_elements); - } break; - } - - storage->info.render._2d_draw_call_count++; - - switch (tex.tile_mode) { - case BatchTex::TILE_FORCE_REPEAT: { - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_FORCE_REPEAT, false); - } break; - case BatchTex::TILE_NORMAL: { - // if the texture is imported as tiled, no need to revert GL state - if (!tex_is_already_tiled) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } break; - default: { - } break; - } - - // could these have ifs? - glDisableVertexAttribArray(RS::ARRAY_TEX_UV); - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glDisableVertexAttribArray(RS::ARRAY_TANGENT); - glDisableVertexAttribArray(RS::ARRAY_TEX_UV2); - glDisableVertexAttribArray(RS::ARRAY_BONES); - glDisableVertexAttribArray(RS::ARRAY_WEIGHTS); - - // may not be necessary .. state change optimization still TODO - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -} -#endif -void RasterizerCanvasOpenGL::render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageOpenGL::Material *p_material) { - int num_batches = bdata.batches.size(); - - for (int batch_num = 0; batch_num < num_batches; batch_num++) { - const Batch &batch = bdata.batches[batch_num]; - - switch (batch.type) { - case RasterizerStorageCommon::BT_RECT: { - //_batch_render_generic(batch, p_material); - } break; - case RasterizerStorageCommon::BT_POLY: { - //_batch_render_generic(batch, p_material); - } break; - case RasterizerStorageCommon::BT_LINE: { - //_batch_render_lines(batch, p_material, false); - } break; - case RasterizerStorageCommon::BT_LINE_AA: { - //_batch_render_lines(batch, p_material, true); - } break; - default: { - int end_command = batch.first_command + batch.num_commands; - - for (int i = batch.first_command; i < end_command; i++) { - Item::Command *command = p_commands[i]; - - switch (command->type) { -#if 0 - case Item::Command::TYPE_LINE: { - Item::CommandLine *line = static_cast(command); - - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - _bind_canvas_texture(RID(), RID()); - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, line->color.components); - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - - if (line->width <= 1) { - Vector2 verts[2] = { - Vector2(line->from.x, line->from.y), - Vector2(line->to.x, line->to.y) - }; - -#ifdef GLES_OVER_GL - if (line->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - _draw_gui_primitive(2, verts, NULL, NULL); - -#ifdef GLES_OVER_GL - if (line->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } else { - Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; - - Vector2 verts[4] = { - line->from - t, - line->from + t, - line->to + t, - line->to - t - }; - - _draw_gui_primitive(4, verts, NULL, NULL); -#ifdef GLES_OVER_GL - if (line->antialiased) { - glEnable(GL_LINE_SMOOTH); - for (int j = 0; j < 4; j++) { - Vector2 vertsl[2] = { - verts[j], - verts[(j + 1) % 4], - }; - _draw_gui_primitive(2, vertsl, NULL, NULL); - } - glDisable(GL_LINE_SMOOTH); - } -#endif - } - } break; -#endif - case Item::Command::TYPE_PRIMITIVE: { - Item::CommandPrimitive *pr = static_cast(command); - - switch (pr->point_count) { - case 2: { - _legacy_draw_line(pr, p_material); - } break; - default: { - _legacy_draw_primitive(pr, p_material); - } break; - } - - } break; - - case Item::Command::TYPE_RECT: { - Item::CommandRect *r = static_cast(command); - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, r->modulate.components); - - bool can_tile = true; - - // we will take account of render target textures which need to be drawn upside down - // quirk of opengl - bool upside_down = r->flags & CANVAS_RECT_FLIP_V; - - // very inefficient, improve this - if (r->texture.is_valid()) { - RasterizerStorageOpenGL::Texture *texture = storage->texture_owner.get_or_null(r->texture); - - if (texture) { - if (texture->is_upside_down()) - upside_down = true; - } - } - - if (r->texture.is_valid() && r->flags & CANVAS_RECT_TILE && !storage->config.support_npot_repeat_mipmap) { - // workaround for when setting tiling does not work due to hardware limitation - - RasterizerStorageOpenGL::Texture *texture = storage->texture_owner.get_or_null(r->texture); - - if (texture) { - texture = texture->get_ptr(); - - if (next_power_of_2(texture->alloc_width) != (unsigned int)texture->alloc_width && next_power_of_2(texture->alloc_height) != (unsigned int)texture->alloc_height) { - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_FORCE_REPEAT, true); - can_tile = false; - } - } - } - - // On some widespread Nvidia cards, the normal draw method can produce some - // flickering in draw_rect and especially TileMap rendering (tiles randomly flicker). - // See GH-9913. - // To work it around, we use a simpler draw method which does not flicker, but gives - // a non negligible performance hit, so it's opt-in (GH-24466). - if (use_nvidia_rect_workaround) { - // are we using normal maps, if so we want to use light angle - bool send_light_angles = false; - - // only need to use light angles when normal mapping - // otherwise we can use the default shader - if (state.current_normal != RID()) { - send_light_angles = true; - } - - _set_texture_rect_mode(false, send_light_angles); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - Vector2 points[4] = { - r->rect.position, - r->rect.position + Vector2(r->rect.size.x, 0.0), - r->rect.position + r->rect.size, - r->rect.position + Vector2(0.0, r->rect.size.y), - }; - - if (r->rect.size.x < 0) { - SWAP(points[0], points[1]); - SWAP(points[2], points[3]); - } - if (r->rect.size.y < 0) { - SWAP(points[0], points[3]); - SWAP(points[1], points[2]); - } - - // FTODO - //RasterizerStorageOpenGL::Texture *texture = _bind_canvas_texture(r->texture, r->normal_map); - RasterizerStorageOpenGL::Texture *texture = _bind_canvas_texture(r->texture, RID()); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - - Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); - - Vector2 uvs[4] = { - src_rect.position, - src_rect.position + Vector2(src_rect.size.x, 0.0), - src_rect.position + src_rect.size, - src_rect.position + Vector2(0.0, src_rect.size.y), - }; - - // for encoding in light angle - bool flip_h = false; - bool flip_v = false; - - if (r->flags & CANVAS_RECT_TRANSPOSE) { - SWAP(uvs[1], uvs[3]); - } - - if (r->flags & CANVAS_RECT_FLIP_H) { - SWAP(uvs[0], uvs[1]); - SWAP(uvs[2], uvs[3]); - flip_h = true; - flip_v = !flip_v; - } - if (upside_down) { - SWAP(uvs[0], uvs[3]); - SWAP(uvs[1], uvs[2]); - flip_v = !flip_v; - } - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::COLOR_TEXPIXEL_SIZE, texpixel_size); - - bool untile = false; - - if (can_tile && r->flags & CANVAS_RECT_TILE && !(texture->flags & RasterizerStorageOpenGL::TEXTURE_FLAG_REPEAT)) { - texture->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - untile = true; - } - - if (send_light_angles) { - // for single rects, there is no need to fully utilize the light angle, - // we only need it to encode flips (horz and vert). But the shader can be reused with - // batching in which case the angle encodes the transform as well as - // the flips. - // Note transpose is NYI. I don't think it worked either with the non-nvidia method. - - // if horizontal flip, angle is 180 - float angle = 0.0f; - if (flip_h) - angle = Math_PI; - - // add 1 (to take care of zero floating point error with sign) - angle += 1.0f; - - // flip if necessary - if (flip_v) - angle *= -1.0f; - - // light angle must be sent for each vert, instead as a single uniform in the uniform draw method - // this has the benefit of enabling batching with light angles. - float light_angles[4] = { angle, angle, angle, angle }; - - _draw_gui_primitive(4, points, NULL, uvs, light_angles); - } else { - _draw_gui_primitive(4, points, NULL, uvs); - } - - if (untile) { - texture->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - } - } else { - static const Vector2 uvs[4] = { - Vector2(0.0, 0.0), - Vector2(0.0, 1.0), - Vector2(1.0, 1.0), - Vector2(1.0, 0.0), - }; - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::COLOR_TEXPIXEL_SIZE, Vector2()); - _draw_gui_primitive(4, points, NULL, uvs); - } - - } else { - // This branch is better for performance, but can produce flicker on Nvidia, see above comment. - _bind_quad_buffer(); - - _set_texture_rect_mode(true); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - // FTODO - //RasterizerStorageOpenGL::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map); - RasterizerStorageOpenGL::Texture *tex = _bind_canvas_texture(r->texture, RID()); - - if (!tex) { - Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); - - if (dst_rect.size.width < 0) { - dst_rect.position.x += dst_rect.size.width; - dst_rect.size.width *= -1; - } - if (dst_rect.size.height < 0) { - dst_rect.position.y += dst_rect.size.height; - dst_rect.size.height *= -1; - } - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SRC_RECT, Color(0, 0, 1, 1)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - storage->info.render._2d_draw_call_count++; - } else { - bool untile = false; - - if (can_tile && r->flags & CANVAS_RECT_TILE && !(tex->flags & RasterizerStorageOpenGL::TEXTURE_FLAG_REPEAT)) { - tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - untile = true; - } - - Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); - Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); - - Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); - - if (dst_rect.size.width < 0) { - dst_rect.position.x += dst_rect.size.width; - dst_rect.size.width *= -1; - } - if (dst_rect.size.height < 0) { - dst_rect.position.y += dst_rect.size.height; - dst_rect.size.height *= -1; - } - - if (r->flags & CANVAS_RECT_FLIP_H) { - src_rect.size.x *= -1; - } - - if (upside_down) { - src_rect.size.y *= -1; - } - - if (r->flags & CANVAS_RECT_TRANSPOSE) { - dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform - } - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::COLOR_TEXPIXEL_SIZE, texpixel_size); - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - storage->info.render._2d_draw_call_count++; - - if (untile) { - tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - } - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_FORCE_REPEAT, false); - - } break; - case Item::Command::TYPE_NINEPATCH: { - Item::CommandNinePatch *np = static_cast(command); - - _set_texture_rect_mode(false); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - glDisableVertexAttribArray(RS::ARRAY_COLOR); - glVertexAttrib4fv(RS::ARRAY_COLOR, np->color.components); - - // FTODO - //RasterizerStorageOpenGL::Texture *tex = _bind_canvas_texture(np->texture, np->normal_map); - RasterizerStorageOpenGL::Texture *tex = _bind_canvas_texture(np->texture, RID()); - - if (!tex) { - // FIXME: Handle textureless ninepatch gracefully - WARN_PRINT("NinePatch without texture not supported yet in OpenGL backend, skipping."); - continue; - } - if (tex->width == 0 || tex->height == 0) { - WARN_PRINT("Cannot set empty texture to NinePatch."); - continue; - } - - Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); - - // state.canvas_shader.set_uniform(CanvasShaderOpenGL::MODELVIEW_MATRIX, state.uniforms.modelview_matrix); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::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; - } - - float screen_scale = 1.0; - - if ((bdata.settings_ninepatch_mode == 1) && (source.size.x != 0) && (source.size.y != 0)) { - screen_scale = MIN(np->rect.size.x / source.size.x, np->rect.size.y / source.size.y); - screen_scale = MIN(1.0, screen_scale); - } - - // prepare vertex buffer - - // this buffer contains [ POS POS UV UV ] * - - float buffer[16 * 2 + 16 * 2]; - - { - // first row - - buffer[(0 * 4 * 4) + 0] = np->rect.position.x; - buffer[(0 * 4 * 4) + 1] = np->rect.position.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[SIDE_LEFT] * screen_scale; - buffer[(0 * 4 * 4) + 5] = np->rect.position.y; - - buffer[(0 * 4 * 4) + 6] = (source.position.x + np->margin[SIDE_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[SIDE_RIGHT] * screen_scale; - buffer[(0 * 4 * 4) + 9] = np->rect.position.y; - - buffer[(0 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[SIDE_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] = (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[SIDE_TOP] * screen_scale; - - buffer[(1 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(1 * 4 * 4) + 3] = (source.position.y + np->margin[SIDE_TOP]) * texpixel_size.y; - - buffer[(1 * 4 * 4) + 4] = np->rect.position.x + np->margin[SIDE_LEFT] * screen_scale; - buffer[(1 * 4 * 4) + 5] = np->rect.position.y + np->margin[SIDE_TOP] * screen_scale; - - buffer[(1 * 4 * 4) + 6] = (source.position.x + np->margin[SIDE_LEFT]) * texpixel_size.x; - buffer[(1 * 4 * 4) + 7] = (source.position.y + np->margin[SIDE_TOP]) * texpixel_size.y; - - buffer[(1 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[SIDE_RIGHT] * screen_scale; - buffer[(1 * 4 * 4) + 9] = np->rect.position.y + np->margin[SIDE_TOP] * screen_scale; - - buffer[(1 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[SIDE_RIGHT]) * texpixel_size.x; - buffer[(1 * 4 * 4) + 11] = (source.position.y + np->margin[SIDE_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[SIDE_TOP] * screen_scale; - - buffer[(1 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; - buffer[(1 * 4 * 4) + 15] = (source.position.y + np->margin[SIDE_TOP]) * texpixel_size.y; - - // third row - - buffer[(2 * 4 * 4) + 0] = np->rect.position.x; - buffer[(2 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y - np->margin[SIDE_BOTTOM] * screen_scale; - - buffer[(2 * 4 * 4) + 2] = source.position.x * texpixel_size.x; - buffer[(2 * 4 * 4) + 3] = (source.position.y + source.size.y - np->margin[SIDE_BOTTOM]) * texpixel_size.y; - - buffer[(2 * 4 * 4) + 4] = np->rect.position.x + np->margin[SIDE_LEFT] * screen_scale; - buffer[(2 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y - np->margin[SIDE_BOTTOM] * screen_scale; - - buffer[(2 * 4 * 4) + 6] = (source.position.x + np->margin[SIDE_LEFT]) * texpixel_size.x; - buffer[(2 * 4 * 4) + 7] = (source.position.y + source.size.y - np->margin[SIDE_BOTTOM]) * texpixel_size.y; - - buffer[(2 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[SIDE_RIGHT] * screen_scale; - buffer[(2 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y - np->margin[SIDE_BOTTOM] * screen_scale; - - buffer[(2 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[SIDE_RIGHT]) * texpixel_size.x; - buffer[(2 * 4 * 4) + 11] = (source.position.y + source.size.y - np->margin[SIDE_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[SIDE_BOTTOM] * screen_scale; - - 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[SIDE_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] = 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[SIDE_LEFT] * screen_scale; - buffer[(3 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y; - - buffer[(3 * 4 * 4) + 6] = (source.position.x + np->margin[SIDE_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[SIDE_RIGHT] * screen_scale; - buffer[(3 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y; - - buffer[(3 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[SIDE_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] = (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); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * (16 + 16) * 2, buffer, _buffer_upload_usage_flag); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.ninepatch_elements); - - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); - - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), CAST_INT_TO_UCHAR_PTR((sizeof(float) * 2))); - - glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_BYTE, NULL); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - storage->info.render._2d_draw_call_count++; - - } break; -#if 0 - case Item::Command::TYPE_CIRCLE: { - Item::CommandCircle *circle = static_cast(command); - - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - static const int num_points = 32; - - Vector2 points[num_points + 1]; - points[num_points] = circle->pos; - - int indices[num_points * 3]; - - for (int j = 0; j < num_points; j++) { - points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / num_points), Math::cos(j * Math_PI * 2.0 / num_points)) * circle->radius; - indices[j * 3 + 0] = j; - indices[j * 3 + 1] = (j + 1) % num_points; - indices[j * 3 + 2] = num_points; - } - - _bind_canvas_texture(RID(), RID()); - - _draw_polygon(indices, num_points * 3, num_points + 1, points, NULL, &circle->color, true); - } break; -#endif - case Item::Command::TYPE_POLYGON: { - Item::CommandPolygon *polygon = static_cast(command); - //const PolyData &pd = _polydata[polygon->polygon.polygon_id]; - - switch (polygon->primitive) { - case RS::PRIMITIVE_TRIANGLES: { - _legacy_draw_poly_triangles(polygon, p_material); - } break; - default: - break; - } - - } break; -#if 0 - case Item::Command::TYPE_MESH: { - Item::CommandMesh *mesh = static_cast(command); - - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - RasterizerStorageOpenGL::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - RasterizerStorageOpenGL::Mesh *mesh_data = storage->mesh_owner.get_or_null(mesh->mesh); - if (mesh_data) { - for (int j = 0; j < mesh_data->surfaces.size(); j++) { - RasterizerStorageOpenGL::Surface *s = mesh_data->surfaces[j]; - // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing - - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } - - for (int k = 0; k < RS::ARRAY_MAX - 1; k++) { - if (s->attribs[k].enabled) { - glEnableVertexAttribArray(k); - glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset)); - } else { - glDisableVertexAttribArray(k); - switch (k) { - case RS::ARRAY_NORMAL: { - glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); - } break; - case RS::ARRAY_COLOR: { - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - - } break; - default: { - } - } - } - } - - if (s->index_array_len > 0) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - } - } - - for (int j = 1; j < RS::ARRAY_MAX - 1; j++) { - glDisableVertexAttribArray(j); - } - } - - storage->info.render._2d_draw_call_count++; - } break; - case Item::Command::TYPE_MULTIMESH: { - Item::CommandMultiMesh *mmesh = static_cast(command); - - RasterizerStorageOpenGL::MultiMesh *multi_mesh = storage->multimesh_owner.get_or_null(mmesh->multimesh); - - if (!multi_mesh) - break; - - RasterizerStorageOpenGL::Mesh *mesh_data = storage->mesh_owner.get_or_null(multi_mesh->mesh); - - if (!mesh_data) - break; - - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != RS::MULTIMESH_CUSTOM_DATA_NONE); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_INSTANCING, true); - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - RasterizerStorageOpenGL::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - //reset shader and force rebind - - int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - - if (amount == -1) { - amount = multi_mesh->size; - } - - int stride = multi_mesh->color_floats + multi_mesh->custom_data_floats + multi_mesh->xform_floats; - - int color_ofs = multi_mesh->xform_floats; - int custom_data_ofs = color_ofs + multi_mesh->color_floats; - - // drawing - - const float *base_buffer = multi_mesh->data.ptr(); - - for (int j = 0; j < mesh_data->surfaces.size(); j++) { - RasterizerStorageOpenGL::Surface *s = mesh_data->surfaces[j]; - // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing - - //bind buffers for mesh surface - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } - - for (int k = 0; k < RS::ARRAY_MAX - 1; k++) { - if (s->attribs[k].enabled) { - glEnableVertexAttribArray(k); - glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset)); - } else { - glDisableVertexAttribArray(k); - switch (k) { - case RS::ARRAY_NORMAL: { - glVertexAttrib4f(RS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); - } break; - case RS::ARRAY_COLOR: { - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - - } break; - default: { - } - } - } - } - - for (int k = 0; k < amount; k++) { - const float *buffer = base_buffer + k * stride; - - { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]); - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]); - if (multi_mesh->transform_format == RS::MULTIMESH_TRANSFORM_3D) { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]); - } else { - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 2, 0.0, 0.0, 1.0, 0.0); - } - } - - if (multi_mesh->color_floats) { - if (multi_mesh->color_format == RS::MULTIMESH_COLOR_8BIT) { - uint8_t *color_data = (uint8_t *)(buffer + color_ofs); - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); - } else { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); - } - } else { - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, 1.0, 1.0, 1.0, 1.0); - } - - if (multi_mesh->custom_data_floats) { - if (multi_mesh->custom_data_format == RS::MULTIMESH_CUSTOM_DATA_8BIT) { - uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); - glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); - } else { - glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 4, buffer + custom_data_ofs); - } - } - - if (s->index_array_len > 0) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - } - } - } - - // LIGHT ANGLE PR replaced USE_INSTANCE_CUSTOM line with below .. think it was a typo, - // but just in case, made this note. - //_set_texture_rect_mode(false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_INSTANCING, false); - - storage->info.render._2d_draw_call_count++; - } break; - case Item::Command::TYPE_POLYLINE: { - Item::CommandPolyLine *pline = static_cast(command); - - _set_texture_rect_mode(false); - - 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); -#ifdef GLES_OVER_GL - glEnable(GL_LINE_SMOOTH); - if (pline->multiline) { - //needs to be different - } else { - _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - glDisable(GL_LINE_SMOOTH); -#endif - } else { -#ifdef GLES_OVER_GL - if (pline->antialiased) - glEnable(GL_LINE_SMOOTH); -#endif - - if (pline->multiline) { - int todo = pline->lines.size() / 2; - int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); - int offset = 0; - - while (todo) { - int to_draw = MIN(max_per_call, todo); - _draw_generic(GL_LINES, to_draw * 2, &pline->lines.ptr()[offset], NULL, pline->line_colors.size() == 1 ? pline->line_colors.ptr() : &pline->line_colors.ptr()[offset], pline->line_colors.size() == 1); - todo -= to_draw; - offset += to_draw * 2; - } - } else { - _draw_generic(GL_LINE_STRIP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); - } - -#ifdef GLES_OVER_GL - if (pline->antialiased) - glDisable(GL_LINE_SMOOTH); -#endif - } - } break; - - case Item::Command::TYPE_PRIMITIVE: { - Item::CommandPrimitive *primitive = static_cast(command); - _set_texture_rect_mode(false); - - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); - } - - ERR_CONTINUE(primitive->points.size() < 1); - - RasterizerStorageOpenGL::Texture *texture = _bind_canvas_texture(primitive->texture, primitive->normal_map); - - if (texture) { - Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::COLOR_TEXPIXEL_SIZE, texpixel_size); - } - - // we need a temporary because this must be nulled out - // if only a single color specified - const Color *colors = primitive->colors.ptr(); - if (primitive->colors.size() == 1 && primitive->points.size() > 1) { - Color c = primitive->colors[0]; - glVertexAttrib4f(RS::ARRAY_COLOR, c.r, c.g, c.b, c.a); - colors = nullptr; - } else if (primitive->colors.empty()) { - glVertexAttrib4f(RS::ARRAY_COLOR, 1, 1, 1, 1); - } -#ifdef RASTERIZER_EXTRA_CHECKS - else { - RAST_DEV_DEBUG_ASSERT(primitive->colors.size() == primitive->points.size()); - } - - if (primitive->uvs.ptr()) { - RAST_DEV_DEBUG_ASSERT(primitive->uvs.size() == primitive->points.size()); - } -#endif - - _draw_gui_primitive(primitive->points.size(), primitive->points.ptr(), colors, primitive->uvs.ptr()); - } break; -#endif - case Item::Command::TYPE_TRANSFORM: { - Item::CommandTransform *transform = static_cast(command); - state.uniforms.extra_matrix = transform->xform; - state.canvas_shader.set_uniform(CanvasShaderOpenGL::EXTRA_MATRIX, state.uniforms.extra_matrix); - } break; - - case Item::Command::TYPE_PARTICLES: { - } break; - case Item::Command::TYPE_CLIP_IGNORE: { - Item::CommandClipIgnore *ci = static_cast(command); - if (p_current_clip) { - if (ci->ignore != r_reclip) { - if (ci->ignore) { - glDisable(GL_SCISSOR_TEST); - r_reclip = true; - } else { - glEnable(GL_SCISSOR_TEST); - - int x = p_current_clip->final_clip_rect.position.x; - int y = storage->frame.current_rt->height - (p_current_clip->final_clip_rect.position.y + p_current_clip->final_clip_rect.size.y); - int w = p_current_clip->final_clip_rect.size.x; - int h = p_current_clip->final_clip_rect.size.y; - - // FTODO - // if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_VFLIP]) - // y = p_current_clip->final_clip_rect.position.y; - - glScissor(x, y, w, h); - - r_reclip = false; - } - } - } - - } break; - default: { - // FIXME: Proper error handling if relevant - //print_line("other"); - } break; - } - } - - } // default - break; - } - } -} - -void RasterizerCanvasOpenGL::canvas_end() { - batch_canvas_end(); - RasterizerCanvasBaseOpenGL::canvas_end(); -} - -void RasterizerCanvasOpenGL::canvas_begin() { - batch_canvas_begin(); - RasterizerCanvasBaseOpenGL::canvas_begin(); -} - -void RasterizerCanvasOpenGL::canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { - batch_canvas_render_items_begin(p_modulate, p_light, p_base_transform); -} - -void RasterizerCanvasOpenGL::canvas_render_items_end() { - batch_canvas_render_items_end(); -} - -void RasterizerCanvasOpenGL::canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) { - storage->frame.current_rt = nullptr; - - // first set the current render target - storage->_set_current_render_target(p_to_render_target); - - // binds the render target (framebuffer) - canvas_begin(); - - canvas_render_items_begin(p_modulate, p_light_list, p_canvas_transform); - canvas_render_items_internal(p_item_list, 0, p_modulate, p_light_list, p_canvas_transform); - canvas_render_items_end(); - - canvas_end(); - - // not sure why these are needed to get frame to render? - storage->_set_current_render_target(RID()); - // storage->frame.current_rt = nullptr; - // canvas_begin(); - // canvas_end(); -} - -void RasterizerCanvasOpenGL::canvas_render_items_internal(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { - batch_canvas_render_items(p_item_list, p_z, p_modulate, p_light, p_base_transform); - - //glClearColor(Math::randf(), 0, 1, 1); -} - -void RasterizerCanvasOpenGL::canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { - // parameters are easier to pass around in a structure - RenderItemState ris; - ris.item_group_z = p_z; - ris.item_group_modulate = p_modulate; - ris.item_group_light = p_light; - ris.item_group_base_transform = p_base_transform; - - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_SKELETON, false); - - state.current_tex = RID(); - state.current_tex_ptr = NULL; - state.current_normal = RID(); - state.canvas_texscreen_used = false; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - - while (p_item_list) { - Item *ci = p_item_list; - _legacy_canvas_render_item(ci, ris); - p_item_list = p_item_list->next; - } - - if (ris.current_clip) { - glDisable(GL_SCISSOR_TEST); - } - - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_SKELETON, false); -} - -// Legacy non-batched implementation for regression testing. -// Should be removed after testing phase to avoid duplicate codepaths. -void RasterizerCanvasOpenGL::_legacy_canvas_render_item(Item *p_ci, RenderItemState &r_ris) { - storage->info.render._2d_item_count++; - - // defaults - state.current_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; - state.current_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; - - if (p_ci->texture_filter != RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT) { - state.current_filter = p_ci->texture_filter; - } - - if (p_ci->texture_repeat != RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT) { - state.current_repeat = p_ci->texture_repeat; - } - - if (r_ris.current_clip != p_ci->final_clip_owner) { - r_ris.current_clip = p_ci->final_clip_owner; - - if (r_ris.current_clip) { - glEnable(GL_SCISSOR_TEST); - int y = storage->_dims.rt_height - (r_ris.current_clip->final_clip_rect.position.y + r_ris.current_clip->final_clip_rect.size.y); - // int y = storage->frame.current_rt->height - (r_ris.current_clip->final_clip_rect.position.y + r_ris.current_clip->final_clip_rect.size.y); - // FTODO - // if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_VFLIP]) - // y = r_ris.current_clip->final_clip_rect.position.y; - glScissor(r_ris.current_clip->final_clip_rect.position.x, y, r_ris.current_clip->final_clip_rect.size.width, r_ris.current_clip->final_clip_rect.size.height); - - // debug VFLIP - // if ((r_ris.current_clip->final_clip_rect.position.x == 223) - // && (y == 54) - // && (r_ris.current_clip->final_clip_rect.size.width == 1383)) - // { - // glScissor(r_ris.current_clip->final_clip_rect.position.x, y, r_ris.current_clip->final_clip_rect.size.width, r_ris.current_clip->final_clip_rect.size.height); - // } - - } else { - glDisable(GL_SCISSOR_TEST); - } - } - - // TODO: copy back buffer - - if (p_ci->copy_back_buffer) { - if (p_ci->copy_back_buffer->full) { - _copy_texscreen(Rect2()); - } else { - _copy_texscreen(p_ci->copy_back_buffer->rect); - } - } - -#if 0 - RasterizerStorageOpenGL::Skeleton *skeleton = NULL; - - { - //skeleton handling - if (p_ci->skeleton.is_valid() && storage->skeleton_owner.owns(p_ci->skeleton)) { - skeleton = storage->skeleton_owner.get(p_ci->skeleton); - if (!skeleton->use_2d) { - skeleton = NULL; - } else { - state.skeleton_transform = r_ris.item_group_base_transform * skeleton->base_transform_2d; - state.skeleton_transform_inverse = state.skeleton_transform.affine_inverse(); - state.skeleton_texture_size = Vector2(skeleton->size * 2, 0); - } - } - - bool use_skeleton = skeleton != NULL; - if (r_ris.prev_use_skeleton != use_skeleton) { - r_ris.rebind_shader = true; - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_SKELETON, use_skeleton); - r_ris.prev_use_skeleton = use_skeleton; - } - - if (skeleton) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); - glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); - state.using_skeleton = true; - } else { - state.using_skeleton = false; - } - } -#endif - - Item *material_owner = p_ci->material_owner ? p_ci->material_owner : p_ci; - - RID material = material_owner->material; - RasterizerStorageOpenGL::Material *material_ptr = storage->material_owner.get_or_null(material); - - if (material != r_ris.canvas_last_material || r_ris.rebind_shader) { - RasterizerStorageOpenGL::Shader *shader_ptr = NULL; - - if (material_ptr) { - shader_ptr = material_ptr->shader; - - if (shader_ptr && shader_ptr->mode != RS::SHADER_CANVAS_ITEM) { - shader_ptr = NULL; // not a canvas item shader, don't use. - } - } - - if (shader_ptr) { - if (shader_ptr->canvas_item.uses_screen_texture) { - if (!state.canvas_texscreen_used) { - //copy if not copied before - _copy_texscreen(Rect2()); - - // blend mode will have been enabled so make sure we disable it again later on - //last_blend_mode = last_blend_mode != RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_DISABLED ? last_blend_mode : -1; - } - - if (storage->frame.current_rt->copy_screen_effect.color) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); - } - } - - if (shader_ptr != r_ris.shader_cache) { - if (shader_ptr->canvas_item.uses_time) { - RenderingServerDefault::redraw_request(); - } - - state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); - state.canvas_shader.bind(); - } - - int tc = material_ptr->textures.size(); - Pair *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_TEXTURE0 + i); - - RasterizerStorageOpenGL::Texture *t = storage->texture_owner.get_or_null(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; - } - - if (t->redraw_if_visible) { - RenderingServerDefault::redraw_request(); - } - - t = t->get_ptr(); - -#ifdef TOOLS_ENABLED - if (t->detect_normal && texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL) { - t->detect_normal(t->detect_normal_ud); - } -#endif - if (t->render_target) - t->render_target->used_in_frame = true; - - glBindTexture(t->target, t->tex_id); - } - - } else { - state.canvas_shader.set_custom_shader(0); - state.canvas_shader.bind(); - } - state.canvas_shader.use_material((void *)material_ptr); - - r_ris.shader_cache = shader_ptr; - - r_ris.canvas_last_material = material; - - r_ris.rebind_shader = false; - } - - int blend_mode = r_ris.shader_cache ? r_ris.shader_cache->canvas_item.blend_mode : RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_MIX; - bool unshaded = r_ris.shader_cache && (r_ris.shader_cache->canvas_item.light_mode == RasterizerStorageOpenGL::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_PMALPHA)); - bool reclip = false; - - if (r_ris.last_blend_mode != blend_mode) { - switch (blend_mode) { - case RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_MIX: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } - - } break; - case RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_ADD: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - } - - } break; - case RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_SUB: { - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); - } else { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); - } - } break; - case RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); - } else { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); - } - } break; - case RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_PMALPHA: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); - } - } break; - } - } - - state.uniforms.final_modulate = unshaded ? p_ci->final_modulate : Color(p_ci->final_modulate.r * r_ris.item_group_modulate.r, p_ci->final_modulate.g * r_ris.item_group_modulate.g, p_ci->final_modulate.b * r_ris.item_group_modulate.b, p_ci->final_modulate.a * r_ris.item_group_modulate.a); - - state.uniforms.modelview_matrix = p_ci->final_transform; - state.uniforms.extra_matrix = Transform2D(); - - _set_uniforms(); - - if (unshaded || (state.uniforms.final_modulate.a > 0.001 && (!r_ris.shader_cache || r_ris.shader_cache->canvas_item.light_mode != RasterizerStorageOpenGL::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !p_ci->light_masked)) - _legacy_canvas_item_render_commands(p_ci, NULL, reclip, material_ptr); - - r_ris.rebind_shader = true; // hacked in for now. - - if ((blend_mode == RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_MIX || blend_mode == RasterizerStorageOpenGL::Shader::CanvasItem::BLEND_MODE_PMALPHA) && r_ris.item_group_light && !unshaded) { - Light *light = r_ris.item_group_light; - bool light_used = false; - RS::CanvasLightBlendMode bmode = RS::CANVAS_LIGHT_BLEND_MODE_ADD; - state.uniforms.final_modulate = p_ci->final_modulate; // remove the canvas modulate - - while (light) { - if (p_ci->light_mask & light->item_mask && r_ris.item_group_z >= light->z_min && r_ris.item_group_z <= light->z_max && p_ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) { - //intersects this light - - if (!light_used || bmode != light->blend_mode) { - bmode = light->blend_mode; - - switch (bmode) { - case RS::CANVAS_LIGHT_BLEND_MODE_ADD: { - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - - } break; - case RS::CANVAS_LIGHT_BLEND_MODE_SUB: { - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - } break; - case RS::CANVAS_LIGHT_BLEND_MODE_MIX: { - // case RS::CANVAS_LIGHT_MODE_MASK: { - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - } break; - } - } - - if (!light_used) { - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_LIGHTING, true); - light_used = true; - } - - // FTODO - //bool has_shadow = light->shadow_buffer.is_valid() && p_ci->light_mask & light->item_shadow_mask; - bool has_shadow = light->use_shadow && p_ci->light_mask & light->item_shadow_mask; - - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_SHADOWS, has_shadow); - if (has_shadow) { - // FTODO - //state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_USE_GRADIENT, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_NEAREST, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_NONE); - //state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF3, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF3); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF3, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF5, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF5); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF7, false); - //state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF7, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF7); - //state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF9, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF9); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF9, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF13, light->shadow_filter == RS::CANVAS_LIGHT_FILTER_PCF13); - } - - state.canvas_shader.bind(); - state.using_light = light; - state.using_shadow = has_shadow; - - //always re-set uniforms, since light parameters changed - _set_uniforms(); - state.canvas_shader.use_material((void *)material_ptr); - - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6); - RasterizerStorageOpenGL::Texture *t = storage->texture_owner.get_or_null(light->texture); - if (!t) { - glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); - } else { - t = t->get_ptr(); - - glBindTexture(t->target, t->tex_id); - } - - glActiveTexture(GL_TEXTURE0); - _legacy_canvas_item_render_commands(p_ci, NULL, reclip, material_ptr); //redraw using light - - state.using_light = NULL; - } - - light = light->next_ptr; - } - - if (light_used) { - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_LIGHTING, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::USE_SHADOWS, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_NEAREST, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF3, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF5, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF7, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF9, false); - state.canvas_shader.set_conditional(CanvasShaderOpenGL::SHADOW_FILTER_PCF13, false); - - state.canvas_shader.bind(); - - r_ris.last_blend_mode = -1; - -#if 0 - //this is set again, so it should not be needed anyway? - state.canvas_item_modulate = unshaded ? ci->final_modulate : Color(ci->final_modulate.r * p_modulate.r, ci->final_modulate.g * p_modulate.g, ci->final_modulate.b * p_modulate.b, ci->final_modulate.a * p_modulate.a); - - state.canvas_shader.set_uniform(CanvasShaderOpenGL::MODELVIEW_MATRIX, state.final_transform); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::EXTRA_MATRIX, Transform2D()); - state.canvas_shader.set_uniform(CanvasShaderOpenGL::FINAL_MODULATE, state.canvas_item_modulate); - - glBlendEquation(GL_FUNC_ADD); - - if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - //@TODO RESET canvas_blend_mode -#endif - } - } - - if (reclip) { - glEnable(GL_SCISSOR_TEST); - int y = storage->frame.current_rt->height - (r_ris.current_clip->final_clip_rect.position.y + r_ris.current_clip->final_clip_rect.size.y); - // FTODO - // if (storage->frame.current_rt->flags[RendererStorage::RENDER_TARGET_VFLIP]) - // y = r_ris.current_clip->final_clip_rect.position.y; - glScissor(r_ris.current_clip->final_clip_rect.position.x, y, r_ris.current_clip->final_clip_rect.size.width, r_ris.current_clip->final_clip_rect.size.height); - } -} - -void RasterizerCanvasOpenGL::gl_enable_scissor(int p_x, int p_y, int p_width, int p_height) const { - glEnable(GL_SCISSOR_TEST); - glScissor(p_x, p_y, p_width, p_height); -} - -void RasterizerCanvasOpenGL::gl_disable_scissor() const { - glDisable(GL_SCISSOR_TEST); -} - -void RasterizerCanvasOpenGL::initialize() { - RasterizerCanvasBaseOpenGL::initialize(); - - batch_initialize(); - - // just reserve some space (may not be needed as we are orphaning, but hey ho) - glGenBuffers(1, &bdata.gl_vertex_buffer); - - if (bdata.vertex_buffer_size_bytes) { - glBindBuffer(GL_ARRAY_BUFFER, bdata.gl_vertex_buffer); - glBufferData(GL_ARRAY_BUFFER, bdata.vertex_buffer_size_bytes, NULL, GL_DYNAMIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - // pre fill index buffer, the indices never need to change so can be static - glGenBuffers(1, &bdata.gl_index_buffer); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bdata.gl_index_buffer); - - Vector indices; - indices.resize(bdata.index_buffer_size_units); - - for (unsigned int q = 0; q < bdata.max_quads; q++) { - int i_pos = q * 6; // 6 inds per quad - int q_pos = q * 4; // 4 verts per quad - indices.set(i_pos, q_pos); - indices.set(i_pos + 1, q_pos + 1); - indices.set(i_pos + 2, q_pos + 2); - indices.set(i_pos + 3, q_pos); - indices.set(i_pos + 4, q_pos + 2); - indices.set(i_pos + 5, q_pos + 3); - - // we can only use 16 bit indices in OpenGL! -#ifdef DEBUG_ENABLED - CRASH_COND((q_pos + 3) > 65535); -#endif - } - - glBufferData(GL_ELEMENT_ARRAY_BUFFER, bdata.index_buffer_size_bytes, &indices[0], GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - } // only if there is a vertex buffer (batching is on) -} - -RasterizerCanvasOpenGL::RasterizerCanvasOpenGL() { - batch_constructor(); -} - -#endif // OPENGL_BACKEND_ENABLED diff --git a/drivers/opengl/rasterizer_canvas_opengl.h b/drivers/opengl/rasterizer_canvas_opengl.h deleted file mode 100644 index ff5295e739..0000000000 --- a/drivers/opengl/rasterizer_canvas_opengl.h +++ /dev/null @@ -1,71 +0,0 @@ -/*************************************************************************/ -/* rasterizer_canvas_opengl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_CANVAS_OPENGL_H -#define RASTERIZER_CANVAS_OPENGL_H - -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "drivers/opengl/rasterizer_canvas_batcher.h" -#include "rasterizer_canvas_base_opengl.h" - -class RasterizerSceneOpenGL; - -class RasterizerCanvasOpenGL : public RasterizerCanvasBaseOpenGL, public RasterizerCanvasBatcher { - friend class RasterizerCanvasBatcher; - -private: - // legacy codepath .. to remove after testing - void _legacy_canvas_render_item(Item *p_ci, RenderItemState &r_ris); - - // high level batch funcs - void canvas_render_items_implementation(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); - void render_batches(Item::Command *const *p_commands, Item *p_current_clip, bool &r_reclip, RasterizerStorageOpenGL::Material *p_material); - - // funcs used from rasterizer_canvas_batcher template - void gl_enable_scissor(int p_x, int p_y, int p_width, int p_height) const; - void gl_disable_scissor() const; - -public: - void canvas_render_items_begin(const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); - void canvas_render_items_end(); - void canvas_render_items_internal(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); - void canvas_begin() override; - void canvas_end() override; - - void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used) override; - - void initialize(); - RasterizerCanvasOpenGL(); -}; - -#endif // OPENGL_BACKEND_ENABLED -#endif // RASTERIZER_CANVAS_OPENGL_H diff --git a/drivers/opengl/rasterizer_opengl.cpp b/drivers/opengl/rasterizer_opengl.cpp deleted file mode 100644 index b7eef805c0..0000000000 --- a/drivers/opengl/rasterizer_opengl.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/*************************************************************************/ -/* rasterizer_opengl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rasterizer_opengl.h" - -#ifdef OPENGL_BACKEND_ENABLED -#include "shader_opengl.h" - -#include "core/config/project_settings.h" -#include "core/os/os.h" - -#define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 -#define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 -#define _EXT_DEBUG_CALLBACK_FUNCTION_ARB 0x8244 -#define _EXT_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245 -#define _EXT_DEBUG_SOURCE_API_ARB 0x8246 -#define _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247 -#define _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248 -#define _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249 -#define _EXT_DEBUG_SOURCE_APPLICATION_ARB 0x824A -#define _EXT_DEBUG_SOURCE_OTHER_ARB 0x824B -#define _EXT_DEBUG_TYPE_ERROR_ARB 0x824C -#define _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D -#define _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E -#define _EXT_DEBUG_TYPE_PORTABILITY_ARB 0x824F -#define _EXT_DEBUG_TYPE_PERFORMANCE_ARB 0x8250 -#define _EXT_DEBUG_TYPE_OTHER_ARB 0x8251 -#define _EXT_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143 -#define _EXT_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144 -#define _EXT_DEBUG_LOGGED_MESSAGES_ARB 0x9145 -#define _EXT_DEBUG_SEVERITY_HIGH_ARB 0x9146 -#define _EXT_DEBUG_SEVERITY_MEDIUM_ARB 0x9147 -#define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 -#define _EXT_DEBUG_OUTPUT 0x92E0 - -#ifndef GLAPIENTRY -#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED) -#define GLAPIENTRY APIENTRY -#else -#define GLAPIENTRY -#endif -#endif - -#ifndef IPHONE_ENABLED -// We include EGL below to get debug callback on GLES2 platforms, -// but EGL is not available on iOS. -#define CAN_DEBUG -#endif - -#if !defined(GLES_OVER_GL) && defined(CAN_DEBUG) -#include -#include -#include - -#include -#include -#endif - -#if defined(MINGW_ENABLED) || defined(_MSC_VER) -#define strcpy strcpy_s -#endif - -void RasterizerOpenGL::begin_frame(double frame_step) { - frame++; - delta = frame_step; - - // from 3.2 - time_total += frame_step * time_scale; - - if (frame_step == 0) { - //to avoid hiccups - frame_step = 0.001; - } - - double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs"); - time_total = Math::fmod(time_total, time_roll_over); - - storage.frame.time[0] = time_total; - storage.frame.time[1] = Math::fmod(time_total, 3600); - storage.frame.time[2] = Math::fmod(time_total, 900); - storage.frame.time[3] = Math::fmod(time_total, 60); - storage.frame.count++; - storage.frame.delta = frame_step; - - storage.update_dirty_resources(); - - storage.info.render_final = storage.info.render; - storage.info.render.reset(); - - //scene->iteration(); -} - -void RasterizerOpenGL::end_frame(bool p_swap_buffers) { - // if (OS::get_singleton()->is_layered_allowed()) { - // if (!OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { - //clear alpha - // glColorMask(false, false, false, true); - // glClearColor(0.5, 0, 0, 1); - // glClear(GL_COLOR_BUFFER_BIT); - // glColorMask(true, true, true, true); - // } - // } - - // glClearColor(1, 0, 0, 1); - // glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - if (p_swap_buffers) - DisplayServer::get_singleton()->swap_buffers(); - else - glFinish(); -} - -#ifdef CAN_DEBUG -static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) { - if (type == _EXT_DEBUG_TYPE_OTHER_ARB) - return; - - if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB) - return; //these are ultimately annoying, so removing for now - - char debSource[256], debType[256], debSev[256]; - - if (source == _EXT_DEBUG_SOURCE_API_ARB) - strcpy(debSource, "OpenGL"); - else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB) - strcpy(debSource, "Windows"); - else if (source == _EXT_DEBUG_SOURCE_SHADER_COMPILER_ARB) - strcpy(debSource, "Shader Compiler"); - else if (source == _EXT_DEBUG_SOURCE_THIRD_PARTY_ARB) - strcpy(debSource, "Third Party"); - else if (source == _EXT_DEBUG_SOURCE_APPLICATION_ARB) - strcpy(debSource, "Application"); - else if (source == _EXT_DEBUG_SOURCE_OTHER_ARB) - strcpy(debSource, "Other"); - - if (type == _EXT_DEBUG_TYPE_ERROR_ARB) - strcpy(debType, "Error"); - else if (type == _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB) - strcpy(debType, "Deprecated behavior"); - else if (type == _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB) - strcpy(debType, "Undefined behavior"); - else if (type == _EXT_DEBUG_TYPE_PORTABILITY_ARB) - strcpy(debType, "Portability"); - else if (type == _EXT_DEBUG_TYPE_PERFORMANCE_ARB) - strcpy(debType, "Performance"); - else if (type == _EXT_DEBUG_TYPE_OTHER_ARB) - strcpy(debType, "Other"); - - if (severity == _EXT_DEBUG_SEVERITY_HIGH_ARB) - strcpy(debSev, "High"); - else if (severity == _EXT_DEBUG_SEVERITY_MEDIUM_ARB) - strcpy(debSev, "Medium"); - else if (severity == _EXT_DEBUG_SEVERITY_LOW_ARB) - strcpy(debSev, "Low"); - - String output = String() + "GL ERROR: Source: " + debSource + "\tType: " + debType + "\tID: " + itos(id) + "\tSeverity: " + debSev + "\tMessage: " + message; - - ERR_PRINT(output); -} -#endif // CAN_DEBUG - -typedef void (*DEBUGPROCARB)(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const char *message, - const void *userParam); - -typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam); - -void RasterizerOpenGL::initialize() { - print_verbose("Using OpenGL video driver"); - - storage._main_thread_id = Thread::get_caller_id(); - -#ifdef GLAD_ENABLED - if (!gladLoadGL()) { - ERR_PRINT("Error initializing GLAD"); - return; - } -#endif - -#ifdef GLAD_ENABLED - if (OS::get_singleton()->is_stdout_verbose()) { - if (GLAD_GL_ARB_debug_output) { - glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - glDebugMessageCallbackARB(_gl_debug_print, NULL); - glEnable(_EXT_DEBUG_OUTPUT); - } else { - print_line("OpenGL debugging not supported!"); - } - } -#endif // GLAD_ENABLED - - // For debugging -#ifdef CAN_DEBUG -#ifdef GLES_OVER_GL - if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) { - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PORTABILITY_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PERFORMANCE_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); - glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_OTHER_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); - // glDebugMessageInsertARB( - // GL_DEBUG_SOURCE_API_ARB, - // GL_DEBUG_TYPE_OTHER_ARB, 1, - // GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello"); - } -#else - if (OS::get_singleton()->is_stdout_verbose()) { - DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback"); - if (!callback) { - callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR"); - } - - if (callback) { - print_line("godot: ENABLING GL DEBUG"); - glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); - callback(_gl_debug_print, NULL); - glEnable(_EXT_DEBUG_OUTPUT); - } - } -#endif // GLES_OVER_GL -#endif // CAN_DEBUG - - print_line("OpenGL Renderer: " + RS::get_singleton()->get_video_adapter_name()); - storage.initialize(); - canvas.initialize(); - // scene.initialize(); - - // make sure the OS knows to only access the renderer from the main thread - OS::get_singleton()->set_render_main_thread_mode(OS::RENDER_MAIN_THREAD_ONLY); -} - -RasterizerOpenGL::RasterizerOpenGL() { - canvas.storage = &storage; - canvas.scene_render = &scene; - storage.canvas = &canvas; - //scene.storage = &storage; - storage.scene = &scene; -} - -void RasterizerOpenGL::prepare_for_blitting_render_targets() { -} - -void RasterizerOpenGL::_blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect) { - ERR_FAIL_COND(storage.frame.current_rt); - - // print_line("_blit_render_target_to_screen " + itos (p_screen) + ", rect " + String(Variant(p_screen_rect))); - - RasterizerStorageOpenGL::RenderTarget *rt = storage.render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - canvas._set_texture_rect_mode(true); - canvas.state.canvas_shader.set_custom_shader(0); - canvas.state.canvas_shader.bind(); - - canvas.canvas_begin(); - - glDisable(GL_BLEND); - glActiveTexture(GL_TEXTURE0 + storage.config.max_texture_image_units - 1); - if (rt->external.fbo != 0) { - glBindTexture(GL_TEXTURE_2D, rt->external.color); - } else { - glBindTexture(GL_TEXTURE_2D, rt->color); - } - canvas.draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1)); - glBindTexture(GL_TEXTURE_2D, 0); - - canvas.canvas_end(); -} - -// is this p_screen useless in a multi window environment? -void RasterizerOpenGL::blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount) { - // do this once off for all blits - storage.bind_framebuffer_system(); - - storage.frame.current_rt = nullptr; - - for (int i = 0; i < p_amount; i++) { - const BlitToScreen &blit = p_render_targets[i]; - - RID rid_rt = blit.render_target; - - Rect2 dst_rect = blit.dst_rect; - _blit_render_target_to_screen(rid_rt, dst_rect); - } -} - -void RasterizerOpenGL::set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { - if (p_image.is_null() || p_image->is_empty()) - return; - - int window_w = 640; //OS::get_singleton()->get_video_mode(0).width; - int window_h = 480; //OS::get_singleton()->get_video_mode(0).height; - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glViewport(0, 0, window_w, window_h); - glDisable(GL_BLEND); - glDepthMask(GL_FALSE); - if (false) { - // if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { - glClearColor(0.0, 0.0, 0.0, 0.0); - } else { - glClearColor(p_color.r, p_color.g, p_color.b, 1.0); - } - glClear(GL_COLOR_BUFFER_BIT); - - canvas.canvas_begin(); - - RID texture = storage.texture_create(); - //storage.texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0); - storage._texture_allocate_internal(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D); - 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(); - } - - RasterizerStorageOpenGL::Texture *t = storage.texture_owner.get_or_null(texture); - 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); - canvas.canvas_end(); - - storage.free(texture); - - end_frame(true); -} - -#endif // OPENGL_BACKEND_ENABLED diff --git a/drivers/opengl/rasterizer_opengl.h b/drivers/opengl/rasterizer_opengl.h deleted file mode 100644 index e72c23faf9..0000000000 --- a/drivers/opengl/rasterizer_opengl.h +++ /dev/null @@ -1,92 +0,0 @@ -/*************************************************************************/ -/* rasterizer_opengl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_OPENGL_H -#define RASTERIZER_OPENGL_H - -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "rasterizer_canvas_opengl.h" -#include "rasterizer_scene_opengl.h" -#include "rasterizer_storage_opengl.h" -#include "servers/rendering/renderer_compositor.h" - -class RasterizerOpenGL : public RendererCompositor { -private: - uint64_t frame = 1; - float delta = 0; - - double time_total = 0.0; - double time_scale = 1.0; - -protected: - RasterizerCanvasOpenGL canvas; - RasterizerStorageOpenGL storage; - RasterizerSceneOpenGL scene; - - void _blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect); - -public: - RendererStorage *get_storage() { return &storage; } - RendererCanvasRender *get_canvas() { return &canvas; } - RendererSceneRender *get_scene() { return &scene; } - - void set_boot_image(const Ref &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); - - void initialize(); - void begin_frame(double frame_step); - - void prepare_for_blitting_render_targets(); - void blit_render_targets_to_screen(DisplayServer::WindowID p_screen, const BlitToScreen *p_render_targets, int p_amount); - - void end_frame(bool p_swap_buffers); - - void finalize() {} - - static RendererCompositor *_create_current() { - return memnew(RasterizerOpenGL); - } - - static void make_current() { - _create_func = _create_current; - } - - virtual bool is_low_end() const { return true; } - uint64_t get_frame_number() const { return frame; } - double get_frame_delta_time() const { return delta; } - - RasterizerOpenGL(); - ~RasterizerOpenGL() {} -}; - -#endif // OPENGL_BACKEND_ENABLED - -#endif diff --git a/drivers/opengl/rasterizer_platforms.h b/drivers/opengl/rasterizer_platforms.h deleted file mode 100644 index effae51819..0000000000 --- a/drivers/opengl/rasterizer_platforms.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* rasterizer_platforms.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_PLATFORMS_H -#define RASTERIZER_PLATFORMS_H - -///////////////////////////////////////////////////// -// override for intellisense .. ONLY FOR DEVELOPMENT -//#ifndef X11_ENABLED -//#define X11_ENABLED -//#endif -//#define OPENGL_BACKEND_ENABLED -///////////////////////////////////////////////////// - -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) - -#define OPENGL_BACKEND_ENABLED - -#endif // defined(OPENGL_ENABLED) || defined(GLES_ENABLED) - -#endif // RASTERIZER_PLATFORMS_H diff --git a/drivers/opengl/rasterizer_scene_opengl.cpp b/drivers/opengl/rasterizer_scene_opengl.cpp deleted file mode 100644 index 5895147f94..0000000000 --- a/drivers/opengl/rasterizer_scene_opengl.cpp +++ /dev/null @@ -1,439 +0,0 @@ -/*************************************************************************/ -/* rasterizer_scene_opengl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "rasterizer_scene_opengl.h" -#ifdef OPENGL_BACKEND_ENABLED - -// TODO: 3D support not implemented yet. - -RasterizerSceneOpenGL::GeometryInstance *RasterizerSceneOpenGL::geometry_instance_create(RID p_base) { - return nullptr; -} - -void RasterizerSceneOpenGL::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_material) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) { -} - -uint32_t RasterizerSceneOpenGL::geometry_instance_get_pair_mask() { - return 0; -} - -void RasterizerSceneOpenGL::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) { -} - -void RasterizerSceneOpenGL::geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) { -} - -void RasterizerSceneOpenGL::geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) { -} - -void RasterizerSceneOpenGL::geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) { -} - -void RasterizerSceneOpenGL::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) { -} - -void RasterizerSceneOpenGL::geometry_instance_free(GeometryInstance *p_geometry_instance) { -} - -/* SHADOW ATLAS API */ - -RID RasterizerSceneOpenGL::shadow_atlas_create() { - return RID(); -} - -void RasterizerSceneOpenGL::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) { -} - -void RasterizerSceneOpenGL::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { -} - -bool RasterizerSceneOpenGL::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { - return false; -} - -void RasterizerSceneOpenGL::directional_shadow_atlas_set_size(int p_size, bool p_16_bits) { -} - -int RasterizerSceneOpenGL::get_directional_light_shadow_size(RID p_light_intance) { - return 0; -} - -void RasterizerSceneOpenGL::set_directional_shadow_count(int p_count) { -} - -/* SDFGI UPDATE */ - -void RasterizerSceneOpenGL::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) { -} - -int RasterizerSceneOpenGL::sdfgi_get_pending_region_count(RID p_render_buffers) const { - return 0; -} - -AABB RasterizerSceneOpenGL::sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const { - return AABB(); -} - -uint32_t RasterizerSceneOpenGL::sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const { - return 0; -} - -/* SKY API */ - -RID RasterizerSceneOpenGL::sky_allocate() { - return RID(); -} - -void RasterizerSceneOpenGL::sky_initialize(RID p_rid) { -} - -void RasterizerSceneOpenGL::sky_set_radiance_size(RID p_sky, int p_radiance_size) { -} - -void RasterizerSceneOpenGL::sky_set_mode(RID p_sky, RS::SkyMode p_samples) { -} - -void RasterizerSceneOpenGL::sky_set_material(RID p_sky, RID p_material) { -} - -Ref RasterizerSceneOpenGL::sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) { - return Ref(); -} - -/* ENVIRONMENT API */ - -RID RasterizerSceneOpenGL::environment_allocate() { - return RID(); -} - -void RasterizerSceneOpenGL::environment_initialize(RID p_rid) { -} - -void RasterizerSceneOpenGL::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { -} - -void RasterizerSceneOpenGL::environment_set_sky(RID p_env, RID p_sky) { -} - -void RasterizerSceneOpenGL::environment_set_sky_custom_fov(RID p_env, float p_scale) { -} - -void RasterizerSceneOpenGL::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { -} - -void RasterizerSceneOpenGL::environment_set_bg_color(RID p_env, const Color &p_color) { -} - -void RasterizerSceneOpenGL::environment_set_bg_energy(RID p_env, float p_energy) { -} - -void RasterizerSceneOpenGL::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { -} - -void RasterizerSceneOpenGL::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source) { -} - -void RasterizerSceneOpenGL::environment_set_glow(RID p_env, bool p_enable, Vector p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { -} - -void RasterizerSceneOpenGL::environment_glow_set_use_bicubic_upscale(bool p_enable) { -} - -void RasterizerSceneOpenGL::environment_glow_set_use_high_quality(bool p_enable) { -} - -void RasterizerSceneOpenGL::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) { -} - -void RasterizerSceneOpenGL::environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) { -} - -void RasterizerSceneOpenGL::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { -} - -void RasterizerSceneOpenGL::environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) { -} - -void RasterizerSceneOpenGL::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { -} - -void RasterizerSceneOpenGL::environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) { -} - -void RasterizerSceneOpenGL::environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) { -} - -void RasterizerSceneOpenGL::environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) { -} - -void RasterizerSceneOpenGL::environment_set_tonemap(RID p_env, RS::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) { -} - -void RasterizerSceneOpenGL::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) { -} - -void RasterizerSceneOpenGL::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) { -} - -void RasterizerSceneOpenGL::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) { -} - -void RasterizerSceneOpenGL::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { -} - -void RasterizerSceneOpenGL::environment_set_volumetric_fog_filter_active(bool p_enable) { -} - -Ref RasterizerSceneOpenGL::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { - return Ref(); -} - -bool RasterizerSceneOpenGL::is_environment(RID p_env) const { - return false; -} - -RS::EnvironmentBG RasterizerSceneOpenGL::environment_get_background(RID p_env) const { - return RS::ENV_BG_KEEP; -} - -int RasterizerSceneOpenGL::environment_get_canvas_max_layer(RID p_env) const { - return 0; -} - -RID RasterizerSceneOpenGL::camera_effects_allocate() { - return RID(); -} - -void RasterizerSceneOpenGL::camera_effects_initialize(RID p_rid) { -} - -void RasterizerSceneOpenGL::camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) { -} - -void RasterizerSceneOpenGL::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) { -} - -void RasterizerSceneOpenGL::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) { -} - -void RasterizerSceneOpenGL::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) { -} - -void RasterizerSceneOpenGL::shadows_quality_set(RS::ShadowQuality p_quality) { -} - -void RasterizerSceneOpenGL::directional_shadow_quality_set(RS::ShadowQuality p_quality) { -} - -RID RasterizerSceneOpenGL::light_instance_create(RID p_light) { - return RID(); -} - -void RasterizerSceneOpenGL::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) { -} - -void RasterizerSceneOpenGL::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { -} - -void RasterizerSceneOpenGL::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { -} - -void RasterizerSceneOpenGL::light_instance_mark_visible(RID p_light_instance) { -} - -RID RasterizerSceneOpenGL::reflection_atlas_create() { - return RID(); -} - -int RasterizerSceneOpenGL::reflection_atlas_get_size(RID p_ref_atlas) const { - return 0; -} - -void RasterizerSceneOpenGL::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { -} - -RID RasterizerSceneOpenGL::reflection_probe_instance_create(RID p_probe) { - return RID(); -} - -void RasterizerSceneOpenGL::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) { -} - -void RasterizerSceneOpenGL::reflection_probe_release_atlas_index(RID p_instance) { -} - -bool RasterizerSceneOpenGL::reflection_probe_instance_needs_redraw(RID p_instance) { - return false; -} - -bool RasterizerSceneOpenGL::reflection_probe_instance_has_reflection(RID p_instance) { - return false; -} - -bool RasterizerSceneOpenGL::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { - return false; -} - -bool RasterizerSceneOpenGL::reflection_probe_instance_postprocess_step(RID p_instance) { - return true; -} - -RID RasterizerSceneOpenGL::decal_instance_create(RID p_decal) { - return RID(); -} - -void RasterizerSceneOpenGL::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) { -} - -RID RasterizerSceneOpenGL::lightmap_instance_create(RID p_lightmap) { - return RID(); -} - -void RasterizerSceneOpenGL::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) { -} - -RID RasterizerSceneOpenGL::voxel_gi_instance_create(RID p_voxel_gi) { - return RID(); -} - -void RasterizerSceneOpenGL::voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) { -} - -bool RasterizerSceneOpenGL::voxel_gi_needs_update(RID p_probe) const { - return false; -} - -void RasterizerSceneOpenGL::voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector &p_light_instances, const PagedArray &p_dynamic_objects) { -} - -void RasterizerSceneOpenGL::voxel_gi_set_quality(RS::VoxelGIQuality) { -} - -void RasterizerSceneOpenGL::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_info) { -} - -void RasterizerSceneOpenGL::render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) { -} - -void RasterizerSceneOpenGL::render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray &p_instances) { -} - -void RasterizerSceneOpenGL::set_scene_pass(uint64_t p_pass) { -} - -void RasterizerSceneOpenGL::set_time(double p_time, double p_step) { -} - -void RasterizerSceneOpenGL::set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) { -} - -RID RasterizerSceneOpenGL::render_buffers_create() { - return RID(); -} - -void RasterizerSceneOpenGL::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { -} - -void RasterizerSceneOpenGL::gi_set_use_half_resolution(bool p_enable) { -} - -void RasterizerSceneOpenGL::screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) { -} - -bool RasterizerSceneOpenGL::screen_space_roughness_limiter_is_active() const { - return false; -} - -void RasterizerSceneOpenGL::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { -} - -void RasterizerSceneOpenGL::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { -} - -TypedArray RasterizerSceneOpenGL::bake_render_uv2(RID p_base, const Vector &p_material_overrides, const Size2i &p_image_size) { - return TypedArray(); -} - -bool RasterizerSceneOpenGL::free(RID p_rid) { - return false; -} - -void RasterizerSceneOpenGL::update() { -} - -void RasterizerSceneOpenGL::sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) { -} - -void RasterizerSceneOpenGL::decals_set_filter(RS::DecalFilter p_filter) { -} - -void RasterizerSceneOpenGL::light_projectors_set_filter(RS::LightProjectorFilter p_filter) { -} - -RasterizerSceneOpenGL::RasterizerSceneOpenGL() { -} - -#endif // OPENGL_BACKEND_ENABLED diff --git a/drivers/opengl/rasterizer_scene_opengl.h b/drivers/opengl/rasterizer_scene_opengl.h deleted file mode 100644 index 2ae7633ba3..0000000000 --- a/drivers/opengl/rasterizer_scene_opengl.h +++ /dev/null @@ -1,220 +0,0 @@ -/*************************************************************************/ -/* rasterizer_scene_opengl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_SCENE_OPENGL_H -#define RASTERIZER_SCENE_OPENGL_H - -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/math/camera_matrix.h" -#include "core/templates/rid_owner.h" -#include "core/templates/self_list.h" -#include "scene/resources/mesh.h" -#include "servers/rendering/renderer_compositor.h" -#include "servers/rendering/renderer_scene_render.h" -#include "servers/rendering_server.h" -#include "shaders/scene.glsl.gen.h" - -class RasterizerSceneOpenGL : public RendererSceneRender { -public: - struct State { - SceneShaderOpenGL scene_shader; - } state; - - GeometryInstance *geometry_instance_create(RID p_base) override; - void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; - void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; - void geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector &p_material) override; - void geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) override; - void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) override; - void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override; - void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override; - void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override; - void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override; - void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; - void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override; - void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override; - void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override; - - uint32_t geometry_instance_get_pair_mask() override; - void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override; - void geometry_instance_pair_reflection_probe_instances(GeometryInstance *p_geometry_instance, const RID *p_reflection_probe_instances, uint32_t p_reflection_probe_instance_count) override; - void geometry_instance_pair_decal_instances(GeometryInstance *p_geometry_instance, const RID *p_decal_instances, uint32_t p_decal_instance_count) override; - void geometry_instance_pair_voxel_gi_instances(GeometryInstance *p_geometry_instance, const RID *p_voxel_gi_instances, uint32_t p_voxel_gi_instance_count) override; - void geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) override; - - void geometry_instance_free(GeometryInstance *p_geometry_instance) override; - - /* SHADOW ATLAS API */ - - RID shadow_atlas_create() override; - void shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits = false) override; - void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; - bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override; - - void directional_shadow_atlas_set_size(int p_size, bool p_16_bits = false) override; - int get_directional_light_shadow_size(RID p_light_intance) override; - void set_directional_shadow_count(int p_count) override; - - /* SDFGI UPDATE */ - - void sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) override; - int sdfgi_get_pending_region_count(RID p_render_buffers) const override; - AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override; - uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override; - - /* SKY API */ - - RID sky_allocate() override; - void sky_initialize(RID p_rid) override; - void sky_set_radiance_size(RID p_sky, int p_radiance_size) override; - void sky_set_mode(RID p_sky, RS::SkyMode p_samples) override; - void sky_set_material(RID p_sky, RID p_material) override; - Ref sky_bake_panorama(RID p_sky, float p_energy, bool p_bake_irradiance, const Size2i &p_size) override; - - /* ENVIRONMENT API */ - - RID environment_allocate() override; - void environment_initialize(RID p_rid) override; - void environment_set_background(RID p_env, RS::EnvironmentBG p_bg) override; - void environment_set_sky(RID p_env, RID p_sky) override; - void environment_set_sky_custom_fov(RID p_env, float p_scale) override; - void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) override; - void environment_set_bg_color(RID p_env, const Color &p_color) override; - void environment_set_bg_energy(RID p_env, float p_energy) override; - void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override; - void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) override; - - void environment_set_glow(RID p_env, bool p_enable, Vector p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override; - void environment_glow_set_use_bicubic_upscale(bool p_enable) override; - void environment_glow_set_use_high_quality(bool p_enable) override; - - 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) override; - void environment_set_ssr_roughness_quality(RS::EnvironmentSSRRoughnessQuality p_quality) override; - void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) override; - void environment_set_ssao_quality(RS::EnvironmentSSAOQuality p_quality, bool p_half_size, float p_adaptive_target, int p_blur_passes, float p_fadeout_from, float p_fadeout_to) override; - - void environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) override; - - void environment_set_sdfgi_ray_count(RS::EnvironmentSDFGIRayCount p_ray_count) override; - void environment_set_sdfgi_frames_to_converge(RS::EnvironmentSDFGIFramesToConverge p_frames) override; - void environment_set_sdfgi_frames_to_update_light(RS::EnvironmentSDFGIFramesToUpdateLight p_update) override; - - void environment_set_tonemap(RID p_env, RS::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) override; - - void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) override; - - void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) override; - void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) override; - void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override; - void environment_set_volumetric_fog_filter_active(bool p_enable) override; - - Ref environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override; - - bool is_environment(RID p_env) const override; - RS::EnvironmentBG environment_get_background(RID p_env) const override; - int environment_get_canvas_max_layer(RID p_env) const override; - - RID camera_effects_allocate() override; - void camera_effects_initialize(RID p_rid) override; - void camera_effects_set_dof_blur_quality(RS::DOFBlurQuality p_quality, bool p_use_jitter) override; - void camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokehShape p_shape) override; - - void camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) override; - void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override; - - void shadows_quality_set(RS::ShadowQuality p_quality) override; - void directional_shadow_quality_set(RS::ShadowQuality p_quality) override; - - RID light_instance_create(RID p_light) override; - void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; - void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; - void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; - void light_instance_mark_visible(RID p_light_instance) override; - - RID reflection_atlas_create() override; - int reflection_atlas_get_size(RID p_ref_atlas) const override; - void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override; - - RID reflection_probe_instance_create(RID p_probe) override; - void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; - void reflection_probe_release_atlas_index(RID p_instance) override; - bool reflection_probe_instance_needs_redraw(RID p_instance) override; - bool reflection_probe_instance_has_reflection(RID p_instance) override; - bool reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) override; - bool reflection_probe_instance_postprocess_step(RID p_instance) override; - - RID decal_instance_create(RID p_decal) override; - void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override; - - RID lightmap_instance_create(RID p_lightmap) override; - void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override; - - RID voxel_gi_instance_create(RID p_voxel_gi) override; - void voxel_gi_instance_set_transform_to_data(RID p_probe, const Transform3D &p_xform) override; - bool voxel_gi_needs_update(RID p_probe) const override; - void voxel_gi_update(RID p_probe, bool p_update_light_instances, const Vector &p_light_instances, const PagedArray &p_dynamic_objects) override; - - void voxel_gi_set_quality(RS::VoxelGIQuality) override; - - void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray &p_instances, const PagedArray &p_lights, const PagedArray &p_reflection_probes, const PagedArray &p_voxel_gi_instances, const PagedArray &p_decals, const PagedArray &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override; - void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray &p_instances, RID p_framebuffer, const Rect2i &p_region) override; - void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray &p_instances) override; - - void set_scene_pass(uint64_t p_pass) override; - void set_time(double p_time, double p_step) override; - void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override; - - RID render_buffers_create() override; - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; - void gi_set_use_half_resolution(bool p_enable) override; - - void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override; - bool screen_space_roughness_limiter_is_active() const override; - - void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) override; - void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) override; - - TypedArray bake_render_uv2(RID p_base, const Vector &p_material_overrides, const Size2i &p_image_size) override; - - bool free(RID p_rid) override; - void update() override; - void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override; - - void decals_set_filter(RS::DecalFilter p_filter) override; - void light_projectors_set_filter(RS::LightProjectorFilter p_filter) override; - - RasterizerSceneOpenGL(); -}; - -#endif // OPENGL_BACKEND_ENABLED - -#endif // RASTERIZER_SCENE_OPENGL_H diff --git a/drivers/opengl/rasterizer_storage_common.h b/drivers/opengl/rasterizer_storage_common.h deleted file mode 100644 index ed64b8c50a..0000000000 --- a/drivers/opengl/rasterizer_storage_common.h +++ /dev/null @@ -1,77 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_common.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_STORAGE_COMMON_H -#define RASTERIZER_STORAGE_COMMON_H - -class RasterizerStorageCommon { -public: - enum FVF { - FVF_UNBATCHED, - FVF_REGULAR, - FVF_COLOR, - FVF_LIGHT_ANGLE, - FVF_MODULATED, - FVF_LARGE, - }; - - // these flags are specifically for batching - // some of the logic is thus in rasterizer_storage.cpp - // we could alternatively set bitflags for each 'uses' and test on the fly - enum BatchFlags { - PREVENT_COLOR_BAKING = 1 << 0, - PREVENT_VERTEX_BAKING = 1 << 1, - - // custom vertex shaders using BUILTINS that vary per item - PREVENT_ITEM_JOINING = 1 << 2, - - USE_MODULATE_FVF = 1 << 3, - USE_LARGE_FVF = 1 << 4, - }; - - enum BatchType : uint16_t { - BT_DEFAULT = 0, - BT_RECT = 1, - BT_LINE = 2, - BT_LINE_AA = 3, - BT_POLY = 4, - BT_DUMMY = 5, // dummy batch is just used to keep the batch creation loop simple - }; - - enum BatchTypeFlags { - BTF_DEFAULT = 1 << BT_DEFAULT, - BTF_RECT = 1 << BT_RECT, - BTF_LINE = 1 << BT_LINE, - BTF_LINE_AA = 1 << BT_LINE_AA, - BTF_POLY = 1 << BT_POLY, - }; -}; - -#endif // RASTERIZER_STORAGE_COMMON_H diff --git a/drivers/opengl/rasterizer_storage_opengl.cpp b/drivers/opengl/rasterizer_storage_opengl.cpp deleted file mode 100644 index 99665dcbb8..0000000000 --- a/drivers/opengl/rasterizer_storage_opengl.cpp +++ /dev/null @@ -1,4818 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_opengl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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. */ -/*************************************************************************/ - -//#define OPENGL_DISABLE_RENDER_TARGETS - -#include "rasterizer_storage_opengl.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/config/project_settings.h" -#include "core/math/transform_3d.h" -#include "drivers/opengl/rasterizer_storage_common.h" -#include "rasterizer_canvas_opengl.h" -#include "rasterizer_scene_opengl.h" -#include "servers/rendering/shader_language.h" - -GLuint RasterizerStorageOpenGL::system_fbo = 0; - -/* TEXTURE API */ - -#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_COMPRESSED_RED_RGTC1_EXT 0x8DBB -#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB -#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC -#define _EXT_COMPRESSED_RG_RGTC2 0x8DBD -#define _EXT_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE -#define _EXT_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC -#define _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD -#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE -#define _EXT_ETC1_RGB8_OES 0x8D64 - -#define _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 -#define _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 -#define _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 -#define _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 - -#define _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 -#define _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 -#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 -#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 - -#define _EXT_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C -#define _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D -#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E -#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F - -#define _GL_TEXTURE_EXTERNAL_OES 0x8D65 - -#ifdef GLES_OVER_GL -#define _GL_HALF_FLOAT_OES 0x140B -#else -#define _GL_HALF_FLOAT_OES 0x8D61 -#endif - -#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F - -#define _RED_OES 0x1903 - -#define _DEPTH_COMPONENT24_OES 0x81A6 - -#ifndef GLES_OVER_GL -#define glClearDepth glClearDepthf - -// enable extensions manually for android and ios -#ifndef UWP_ENABLED -#include // needed to load extensions -#endif - -#ifdef IPHONE_ENABLED - -#include -//void *glRenderbufferStorageMultisampleAPPLE; -//void *glResolveMultisampleFramebufferAPPLE; -#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE -#elif defined(ANDROID_ENABLED) - -#include -PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; -PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT; -#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT -#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT - -#elif defined(UWP_ENABLED) -#include -#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleANGLE -#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleANGLE -#endif - -#define GL_TEXTURE_3D 0x806F -#define GL_MAX_SAMPLES 0x8D57 -#endif //!GLES_OVER_GL - -void RasterizerStorageOpenGL::bind_quad_array() const { - glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); - glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); - glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); - - glEnableVertexAttribArray(RS::ARRAY_VERTEX); - glEnableVertexAttribArray(RS::ARRAY_TEX_UV); -} - -bool RasterizerStorageOpenGL::can_create_resources_async() const { - return false; -} - -Ref RasterizerStorageOpenGL::_get_gl_image_and_format(const Ref &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const { - r_gl_format = 0; - Ref image = p_image; - r_compressed = false; - r_real_format = p_format; - - bool need_decompress = false; - - switch (p_format) { - case Image::FORMAT_L8: { - r_gl_internal_format = GL_LUMINANCE; - r_gl_format = GL_LUMINANCE; - r_gl_type = GL_UNSIGNED_BYTE; - } break; - case Image::FORMAT_LA8: { - r_gl_internal_format = GL_LUMINANCE_ALPHA; - r_gl_format = GL_LUMINANCE_ALPHA; - r_gl_type = GL_UNSIGNED_BYTE; - } break; - case Image::FORMAT_R8: { - r_gl_internal_format = GL_ALPHA; - r_gl_format = GL_ALPHA; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RG8: { - ERR_PRINT("RG texture not supported, converting to RGB8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGB8); - r_real_format = Image::FORMAT_RGB8; - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RGB8: { - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RGBA8: { - r_gl_format = GL_RGBA; - r_gl_internal_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - - } break; - case Image::FORMAT_RGBA4444: { - r_gl_internal_format = GL_RGBA; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_SHORT_4_4_4_4; - - } break; - // case Image::FORMAT_RGBA5551: { - // r_gl_internal_format = GL_RGB5_A1; - // r_gl_format = GL_RGBA; - // r_gl_type = GL_UNSIGNED_SHORT_5_5_5_1; - - // } break; - case Image::FORMAT_RF: { - if (!config.float_texture_supported) { - ERR_PRINT("R float texture not supported, converting to RGB8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGB8); - r_real_format = Image::FORMAT_RGB8; - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - } else { - r_gl_internal_format = GL_ALPHA; - r_gl_format = GL_ALPHA; - r_gl_type = GL_FLOAT; - } - } break; - case Image::FORMAT_RGF: { - ERR_PRINT("RG float texture not supported, converting to RGB8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGB8); - r_real_format = Image::FORMAT_RGB8; - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - } break; - case Image::FORMAT_RGBF: { - if (!config.float_texture_supported) { - ERR_PRINT("RGB float texture not supported, converting to RGB8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGB8); - r_real_format = Image::FORMAT_RGB8; - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - } else { - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - } - } break; - case Image::FORMAT_RGBAF: { - if (!config.float_texture_supported) { - ERR_PRINT("RGBA float texture not supported, converting to RGBA8."); - if (image.is_valid()) - image->convert(Image::FORMAT_RGBA8); - r_real_format = Image::FORMAT_RGBA8; - r_gl_internal_format = GL_RGBA; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - } else { - r_gl_internal_format = GL_RGBA; - r_gl_format = GL_RGBA; - r_gl_type = GL_FLOAT; - } - } break; - case Image::FORMAT_RH: { - need_decompress = true; - } break; - case Image::FORMAT_RGH: { - need_decompress = true; - } break; - case Image::FORMAT_RGBH: { - need_decompress = true; - } break; - case Image::FORMAT_RGBAH: { - need_decompress = true; - } break; - case Image::FORMAT_RGBE9995: { - 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: { - 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; - r_compressed = true; - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_DXT3: { - 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: { - 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: { - if (config.rgtc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_RGTC_RG: { - if (config.rgtc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_BPTC_RGBA: { - if (config.bptc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGBA_BPTC_UNORM; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - need_decompress = true; - } - } break; - case Image::FORMAT_BPTC_RGBF: { - if (config.bptc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - r_compressed = true; - } else { - need_decompress = true; - } - } break; - case Image::FORMAT_BPTC_RGBFU: { - if (config.bptc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - r_compressed = true; - } else { - need_decompress = true; - } - } break; - case Image::FORMAT_PVRTC1_2: { - if (config.pvrtc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - need_decompress = true; - } - } break; - case Image::FORMAT_PVRTC1_2A: { - if (config.pvrtc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_PVRTC1_4: { - if (config.pvrtc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_PVRTC1_4A: { - if (config.pvrtc_supported) { - r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; - r_gl_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_compressed = true; - - } else { - need_decompress = true; - } - - } break; - case Image::FORMAT_ETC: { - if (config.etc1_supported) { - 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: { - need_decompress = true; - } break; - case Image::FORMAT_ETC2_R11S: { - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RG11: { - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RG11S: { - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RGB8: { - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RGBA8: { - need_decompress = true; - } break; - case Image::FORMAT_ETC2_RGB8A1: { - need_decompress = true; - } break; - default: { - ERR_FAIL_V(p_image); - } - } - - if (need_decompress || p_force_decompress) { - if (!image.is_null()) { - image = image->duplicate(); - image->decompress(); - ERR_FAIL_COND_V(image->is_compressed(), image); - switch (image->get_format()) { - case Image::FORMAT_RGB8: { - r_gl_format = GL_RGB; - r_gl_internal_format = GL_RGB; - r_gl_type = GL_UNSIGNED_BYTE; - r_real_format = Image::FORMAT_RGB8; - r_compressed = false; - } break; - case Image::FORMAT_RGBA8: { - r_gl_format = GL_RGBA; - r_gl_internal_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_real_format = Image::FORMAT_RGBA8; - r_compressed = false; - } break; - default: { - image->convert(Image::FORMAT_RGBA8); - r_gl_format = GL_RGBA; - r_gl_internal_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_real_format = Image::FORMAT_RGBA8; - r_compressed = false; - - } break; - } - } - - return image; - } - - return p_image; -} - -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, -}; - -RID RasterizerStorageOpenGL::texture_allocate() { - RID id = texture_create(); - ERR_FAIL_COND_V(id == RID(), id); - return id; -} - -void RasterizerStorageOpenGL::texture_2d_initialize(RID p_texture, const Ref &p_image) { - Texture *tex = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!tex); - - int w = p_image->get_width(); - int h = p_image->get_height(); - - _texture_allocate_internal(p_texture, w, h, 1, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D, 0); - texture_set_data(p_texture, p_image); -} - -void RasterizerStorageOpenGL::texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) { -} - -void RasterizerStorageOpenGL::texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector> &p_data) { -} - -void RasterizerStorageOpenGL::texture_proxy_initialize(RID p_texture, RID p_base) { -} - -//RID RasterizerStorageOpenGL::texture_2d_create(const Ref &p_image) { -// RID id = texture_create(); -// ERR_FAIL_COND_V(id == RID(), id); - -// int w = p_image->get_width(); -// int h = p_image->get_height(); - -// texture_allocate(id, w, h, 1, p_image->get_format(), RenderingDevice::TEXTURE_TYPE_2D, 0); - -// texture_set_data(id, p_image); - -// return id; -//} - -//RID RasterizerStorageOpenGL::texture_2d_layered_create(const Vector> &p_layers, RS::TextureLayeredType p_layered_type) { -// return RID(); -//} - -//RID RasterizerStorageOpenGL::texture_proxy_create(RID p_base) { -// RID link = texture_create(); -// texture_set_proxy(link, p_base); -// return link; -//} - -//void RasterizerStorageOpenGL::texture_2d_update_immediate(RID p_texture, const Ref &p_image, int p_layer) { -// // only 1 layer so far -// texture_set_data(p_texture, p_image); -//} -void RasterizerStorageOpenGL::texture_2d_update(RID p_texture, const Ref &p_image, int p_layer) { - // only 1 layer so far - texture_set_data(p_texture, p_image); -} - -void RasterizerStorageOpenGL::texture_2d_placeholder_initialize(RID p_texture) { -} - -void RasterizerStorageOpenGL::texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) { -} - -void RasterizerStorageOpenGL::texture_3d_placeholder_initialize(RID p_texture) { -} - -Ref RasterizerStorageOpenGL::texture_2d_get(RID p_texture) const { - Texture *tex = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND_V(!tex, Ref()); - - /* -#ifdef TOOLS_ENABLED - if (tex->image_cache_2d.is_valid()) { - return tex->image_cache_2d; - } -#endif - Vector data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0); - ERR_FAIL_COND_V(data.size() == 0, Ref()); - Ref image; - image.instance(); - image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data); - ERR_FAIL_COND_V(image->empty(), Ref()); - if (tex->format != tex->validated_format) { - image->convert(tex->format); - } - -#ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { - tex->image_cache_2d = image; - } -#endif -*/ - ERR_FAIL_COND_V(!tex->images.size(), Ref()); - - return tex->images[0]; - - // return image; - - // return Ref(); -} - -void RasterizerStorageOpenGL::texture_replace(RID p_texture, RID p_by_texture) { - Texture *tex_to = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!tex_to); - Texture *tex_from = texture_owner.get_or_null(p_by_texture); - ERR_FAIL_COND(!tex_from); - - tex_to->destroy(); - tex_to->copy_from(*tex_from); - - // copy image data and upload to GL - tex_to->images.resize(tex_from->images.size()); - - for (int n = 0; n < tex_from->images.size(); n++) { - texture_set_data(p_texture, tex_from->images[n], n); - } -} - -bool RasterizerStorageOpenGL::_is_main_thread() { - //#if defined DEBUG_ENABLED && defined TOOLS_ENABLED - // must be called from main thread in OpenGL - bool is_main_thread = _main_thread_id == Thread::get_caller_id(); - //#endif - return is_main_thread; -} - -RID RasterizerStorageOpenGL::texture_create() { - ERR_FAIL_COND_V(!_is_main_thread(), RID()); - - Texture *texture = memnew(Texture); - ERR_FAIL_COND_V(!texture, RID()); - glGenTextures(1, &texture->tex_id); - texture->active = false; - texture->total_data_size = 0; - - return texture_owner.make_rid(texture); -} - -void RasterizerStorageOpenGL::_texture_allocate_internal(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags) { - // GLenum format; - // GLenum internal_format; - // GLenum type; - - // bool compressed = false; - - if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) { - p_flags &= ~TEXTURE_FLAG_MIPMAPS; // no mipies for video - } - - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - texture->width = p_width; - texture->height = p_height; - texture->format = p_format; - texture->flags = p_flags; - texture->stored_cube_sides = 0; - texture->type = p_type; - - switch (p_type) { - case RenderingDevice::TEXTURE_TYPE_2D: { - texture->target = GL_TEXTURE_2D; - texture->images.resize(1); - } break; - // case RenderingDevice::TEXTURE_TYPE_EXTERNAL: { - //#ifdef ANDROID_ENABLED - // texture->target = _GL_TEXTURE_EXTERNAL_OES; - //#else - // texture->target = GL_TEXTURE_2D; - //#endif - // texture->images.resize(0); - // } break; - case RenderingDevice::TEXTURE_TYPE_CUBE: { - texture->target = GL_TEXTURE_CUBE_MAP; - texture->images.resize(6); - } break; - case RenderingDevice::TEXTURE_TYPE_2D_ARRAY: - case RenderingDevice::TEXTURE_TYPE_3D: { - texture->target = GL_TEXTURE_3D; - ERR_PRINT("3D textures and Texture Arrays are not supported in OpenGL. Please switch to the Vulkan backend."); - return; - } break; - default: { - ERR_PRINT("Unknown texture type!"); - return; - } - } - -#if 0 - // if (p_type != RS::TEXTURE_TYPE_EXTERNAL) { - if (p_type == RenderingDevice::TEXTURE_TYPE_2D) { - texture->alloc_width = texture->width; - texture->alloc_height = texture->height; - texture->resize_to_po2 = false; - if (!config.support_npot_repeat_mipmap) { - int po2_width = next_power_of_2(p_width); - int po2_height = next_power_of_2(p_height); - - bool is_po2 = p_width == po2_width && p_height == po2_height; - - if (!is_po2 && (p_flags & TEXTURE_FLAG_REPEAT || p_flags & TEXTURE_FLAG_MIPMAPS)) { - if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) { - //not supported - ERR_PRINT("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled."); - texture->flags &= ~(TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS); - } else { - texture->alloc_height = po2_height; - texture->alloc_width = po2_width; - texture->resize_to_po2 = true; - } - } - } - - GLenum format; - GLenum internal_format; - GLenum type; - bool compressed = false; - - Image::Format real_format; - _get_gl_image_and_format(Ref(), - texture->format, - texture->flags, - real_format, - format, - internal_format, - type, - compressed, - texture->resize_to_po2); - - texture->gl_format_cache = format; - texture->gl_type_cache = type; - texture->gl_internal_format_cache = internal_format; - texture->data_size = 0; - texture->mipmaps = 1; - - texture->compressed = compressed; - } -#endif - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - // if (p_type == RS::TEXTURE_TYPE_EXTERNAL) { - // glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - // glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - // glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // } else if (p_flags & TEXTURE_FLAG_USED_FOR_STREAMING) { - // //prealloc if video - // glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL); - // } - - texture->active = true; -} - -void RasterizerStorageOpenGL::texture_set_data(RID p_texture, const Ref &p_image, int p_layer) { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND(!_is_main_thread()); - - ERR_FAIL_COND(!texture); - if (texture->target == GL_TEXTURE_3D) { - // Target is set to a 3D texture or array texture, exit early to avoid spamming errors - return; - } - ERR_FAIL_COND(!texture->active); - ERR_FAIL_COND(texture->render_target); - ERR_FAIL_COND(p_image.is_null()); - ERR_FAIL_COND(texture->format != p_image->get_format()); - - ERR_FAIL_COND(!p_image->get_width()); - ERR_FAIL_COND(!p_image->get_height()); - - // ERR_FAIL_COND(texture->type == RS::TEXTURE_TYPE_EXTERNAL); - - GLenum type; - GLenum format; - GLenum internal_format; - bool compressed = false; - - if (config.keep_original_textures && !(texture->flags & TEXTURE_FLAG_USED_FOR_STREAMING)) { - texture->images.write[p_layer] = p_image; - } - - // print_line("texture_set_data width " + itos (p_image->get_width()) + " height " + itos(p_image->get_height())); - - Image::Format real_format; - Ref img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); - - if (texture->resize_to_po2) { - if (p_image->is_compressed()) { - ERR_PRINT("Texture '" + texture->path + "' is required to be a power of 2 because it uses either mipmaps or repeat, so it was decompressed. This will hurt performance and memory usage."); - } - - if (img == p_image) { - img = img->duplicate(); - } - img->resize_to_po2(false); - } - - if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & TEXTURE_FLAG_USED_FOR_STREAMING)) { - texture->alloc_height = MAX(1, texture->alloc_height / 2); - texture->alloc_width = MAX(1, texture->alloc_width / 2); - - if (texture->alloc_width == img->get_width() / 2 && texture->alloc_height == img->get_height() / 2) { - img->shrink_x2(); - } else if (img->get_format() <= Image::FORMAT_RGBA8) { - img->resize(texture->alloc_width, texture->alloc_height, Image::INTERPOLATE_BILINEAR); - } - } - - GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D; - - texture->data_size = img->get_data().size(); - Vector read = img->get_data(); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - texture->ignore_mipmaps = compressed && !img->has_mipmaps(); - - // set filtering and repeat state - _texture_set_state_from_flags(texture); - - int mipmaps = ((texture->flags & TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; - - int w = img->get_width(); - int h = img->get_height(); - - int tsize = 0; - - for (int i = 0; i < mipmaps; i++) { - int size, ofs; - img->get_mipmap_offset_and_size(i, ofs, size); - - if (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 { - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - if (texture->flags & 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; - - w = MAX(1, w >> 1); - h = MAX(1, h >> 1); - } - - info.texture_mem -= texture->total_data_size; - texture->total_data_size = tsize; - info.texture_mem += texture->total_data_size; - - // printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem); - - texture->stored_cube_sides |= (1 << p_layer); - - if ((texture->flags & TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != RenderingDevice::TEXTURE_TYPE_CUBE || texture->stored_cube_sides == (1 << 6) - 1)) { - //generate mipmaps if they were requested and the image does not contain them - glGenerateMipmap(texture->target); - } - - texture->mipmaps = mipmaps; -} - -void RasterizerStorageOpenGL::texture_set_data_partial(RID p_texture, const Ref &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 RasterizerStorageOpenGL::texture_get_data(RID p_texture, int p_layer) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, Ref()); - ERR_FAIL_COND_V(!texture->active, Ref()); - ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref()); - - if (texture->type == RS::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(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, false); - - PoolVector data; - - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); - - data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers - PoolVector::Write wb = data.write(); - - glActiveTexture(GL_TEXTURE0); - - glBindTexture(texture->target, texture->tex_id); - - glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - - for (int i = 0; i < texture->mipmaps; i++) { - int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i); - - 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.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, real_format, data)); - - return Ref(img); -#else - - Image::Format real_format; - GLenum gl_format; - GLenum gl_internal_format; - GLenum gl_type; - bool compressed; - _get_gl_image_and_format(Ref(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, texture->resize_to_po2); - - PoolVector data; - - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); - - data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers - PoolVector::Write wb = data.write(); - - GLuint temp_framebuffer; - glGenFramebuffers(1, &temp_framebuffer); - - GLuint temp_color_texture; - glGenTextures(1, &temp_color_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); - - glBindTexture(GL_TEXTURE_2D, temp_color_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture->tex_id); - - glViewport(0, 0, texture->alloc_width, texture->alloc_height); - - shaders.copy.bind(); - - glClearColor(0.0, 0.0, 0.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - bind_quad_array(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); - - glDeleteTextures(1, &temp_color_texture); - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - glDeleteFramebuffers(1, &temp_framebuffer); - - wb.release(); - - data.resize(data_size); - - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); - if (!texture->compressed) { - img->convert(real_format); - } - - return Ref(img); - -#endif -} -*/ - -void RasterizerStorageOpenGL::_texture_set_state_from_flags(Texture *p_tex) { - if ((p_tex->flags & TEXTURE_FLAG_MIPMAPS) && !p_tex->ignore_mipmaps) - if (p_tex->flags & TEXTURE_FLAG_FILTER) { - // these do not exactly correspond ... - p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS); - //texture->glTexParam_MinFilter(texture->target, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); - } else { - p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS); - //texture->glTexParam_MinFilter(texture->target, config.use_fast_texture_filter ? GL_NEAREST_MIPMAP_NEAREST : GL_NEAREST_MIPMAP_LINEAR); - } - else { - if (p_tex->flags & TEXTURE_FLAG_FILTER) { - p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR); - //texture->glTexParam_MinFilter(texture->target, GL_LINEAR); - } else { - p_tex->GLSetFilter(p_tex->target, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST); - // texture->glTexParam_MinFilter(texture->target, GL_NEAREST); - } - } - - if (((p_tex->flags & TEXTURE_FLAG_REPEAT) || (p_tex->flags & TEXTURE_FLAG_MIRRORED_REPEAT)) && p_tex->target != GL_TEXTURE_CUBE_MAP) { - if (p_tex->flags & TEXTURE_FLAG_MIRRORED_REPEAT) { - p_tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR); - } else { - p_tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - } - } else { - p_tex->GLSetRepeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - } -} - -void RasterizerStorageOpenGL::texture_set_flags(RID p_texture, uint32_t p_flags) { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - - bool had_mipmaps = texture->flags & TEXTURE_FLAG_MIPMAPS; - - texture->flags = p_flags; - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - // set filtering and repeat state - _texture_set_state_from_flags(texture); - - if ((texture->flags & TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) { - if (!had_mipmaps && texture->mipmaps == 1) { - glGenerateMipmap(texture->target); - } - } -} - -uint32_t RasterizerStorageOpenGL::texture_get_flags(RID p_texture) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->flags; -} - -Image::Format RasterizerStorageOpenGL::texture_get_format(RID p_texture) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, Image::FORMAT_L8); - - return texture->format; -} - -RenderingDevice::TextureType RasterizerStorageOpenGL::texture_get_type(RID p_texture) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, RenderingDevice::TEXTURE_TYPE_2D); - - return texture->type; -} - -uint32_t RasterizerStorageOpenGL::texture_get_texid(RID p_texture) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->tex_id; -} - -void RasterizerStorageOpenGL::texture_bind(RID p_texture, uint32_t p_texture_no) { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND(!texture); - - glActiveTexture(GL_TEXTURE0 + p_texture_no); - glBindTexture(texture->target, texture->tex_id); -} - -uint32_t RasterizerStorageOpenGL::texture_get_width(RID p_texture) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->width; -} - -uint32_t RasterizerStorageOpenGL::texture_get_height(RID p_texture) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->height; -} - -uint32_t RasterizerStorageOpenGL::texture_get_depth(RID p_texture) const { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND_V(!texture, 0); - - return texture->depth; -} - -void RasterizerStorageOpenGL::texture_set_size_override(RID p_texture, int p_width, int p_height) { - Texture *texture = texture_owner.get_or_null(p_texture); - - ERR_FAIL_COND(!texture); - ERR_FAIL_COND(texture->render_target); - - ERR_FAIL_COND(p_width <= 0 || p_width > 16384); - ERR_FAIL_COND(p_height <= 0 || p_height > 16384); - //real texture size is in alloc width and height - texture->width = p_width; - texture->height = p_height; -} - -void RasterizerStorageOpenGL::texture_set_path(RID p_texture, const String &p_path) { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - - texture->path = p_path; -} - -String RasterizerStorageOpenGL::texture_get_path(RID p_texture) const { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND_V(!texture, ""); - - return texture->path; -} - -void RasterizerStorageOpenGL::texture_debug_usage(List *r_info) { - List textures; - texture_owner.get_owned_list(&textures); - - for (List::Element *E = textures.front(); E; E = E->next()) { - Texture *t = texture_owner.get_or_null(E->get()); - if (!t) - continue; - RS::TextureInfo tinfo; - tinfo.path = t->path; - tinfo.format = t->format; - tinfo.width = t->alloc_width; - tinfo.height = t->alloc_height; - tinfo.depth = 0; - tinfo.bytes = t->total_data_size; - r_info->push_back(tinfo); - } -} - -void RasterizerStorageOpenGL::texture_set_shrink_all_x2_on_set_data(bool p_enable) { - config.shrink_textures_x2 = p_enable; -} - -void RasterizerStorageOpenGL::textures_keep_original(bool p_enable) { - config.keep_original_textures = p_enable; -} - -Size2 RasterizerStorageOpenGL::texture_size_with_proxy(RID p_texture) { - const Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND_V(!texture, Size2()); - if (texture->proxy) { - return Size2(texture->proxy->width, texture->proxy->height); - } else { - return Size2(texture->width, texture->height); - } -} - -// example use in 3.2 -// VS::get_singleton()->texture_set_proxy(default_texture->proxy, texture_rid); - -// p_proxy is the source (pre-existing) texture? -// and p_texture is the one that is being made into a proxy? -//This naming is confusing. Comments!!! - -// The naming of the parameters seemed to be reversed? -// The p_proxy is the source texture -// and p_texture is actually the proxy???? - -void RasterizerStorageOpenGL::texture_set_proxy(RID p_texture, RID p_proxy) { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - - if (texture->proxy) { - texture->proxy->proxy_owners.erase(texture); - texture->proxy = NULL; - } - - if (p_proxy.is_valid()) { - Texture *proxy = texture_owner.get_or_null(p_proxy); - ERR_FAIL_COND(!proxy); - ERR_FAIL_COND(proxy == texture); - proxy->proxy_owners.insert(texture); - texture->proxy = proxy; - } -} - -void RasterizerStorageOpenGL::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - - texture->redraw_if_visible = p_enable; -} - -void RasterizerStorageOpenGL::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_3d = p_callback; - texture->detect_3d_ud = p_userdata; -} - -void RasterizerStorageOpenGL::texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_srgb = p_callback; - texture->detect_srgb_ud = p_userdata; -} - -void RasterizerStorageOpenGL::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { - Texture *texture = texture_owner.get_or_null(p_texture); - ERR_FAIL_COND(!texture); - - texture->detect_normal = p_callback; - texture->detect_normal_ud = p_userdata; -} - -RID RasterizerStorageOpenGL::texture_create_radiance_cubemap(RID p_source, int p_resolution) const { - return RID(); -} - -RID RasterizerStorageOpenGL::canvas_texture_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::canvas_texture_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { -} - -void RasterizerStorageOpenGL::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) { -} - -void RasterizerStorageOpenGL::canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) { -} -void RasterizerStorageOpenGL::canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) { -} - -RID RasterizerStorageOpenGL::sky_create() { - Sky *sky = memnew(Sky); - sky->radiance = 0; - return sky_owner.make_rid(sky); -} - -void RasterizerStorageOpenGL::sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size) { - Sky *sky = sky_owner.get_or_null(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.get_or_null(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 < RS::ARRAY_MAX - 1; i++) { - glDisableVertexAttribArray(i); - } - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(texture->target, texture->tex_id); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(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); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - // 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); - - int size = p_radiance_size / 2; //divide by two because its a cubemap (this is an approximation because GLES3 uses a dual paraboloid) - - GLenum internal_format = GL_RGB; - GLenum format = GL_RGB; - GLenum type = GL_UNSIGNED_BYTE; - - // Set the initial (empty) mipmaps - // Mobile hardware (PowerVR specially) prefers this approach, - // the previous approach with manual lod levels kills the game. - for (int i = 0; i < 6; i++) { - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL); - } - - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); - - // No filters for now - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - 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); - - // Framebuffer - - bind_framebuffer(resources.mipmap_blur_fbo); - - int mipmaps = 6; - int lod = 0; - int mm_level = mipmaps; - size = p_radiance_size / 2; - shaders.cubemap_filter.set_conditional(CubemapFilterShaderOpenGL::USE_SOURCE_PANORAMA, true); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderOpenGL::USE_DIRECT_WRITE, true); - shaders.cubemap_filter.bind(); - - // third, render to the framebuffer using separate textures, then copy to mipmaps - while (size >= 1) { - //make framebuffer size the texture size, need to use a separate texture for compatibility - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, resources.mipmap_blur_color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resources.mipmap_blur_color, 0); - - if (lod == 1) { - //bind panorama for smaller lods - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderOpenGL::USE_SOURCE_PANORAMA, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderOpenGL::USE_DIRECT_WRITE, false); - shaders.cubemap_filter.bind(); - } - glViewport(0, 0, size, size); - bind_quad_array(); - - glActiveTexture(GL_TEXTURE2); //back to panorama - - for (int i = 0; i < 6; i++) { - shaders.cubemap_filter.set_uniform(CubemapFilterShaderOpenGL::FACE_ID, i); - - float roughness = mm_level >= 0 ? lod / (float)(mipmaps - 1) : 1; - roughness = MIN(1.0, roughness); //keep max at 1 - shaders.cubemap_filter.set_uniform(CubemapFilterShaderOpenGL::ROUGHNESS, roughness); - shaders.cubemap_filter.set_uniform(CubemapFilterShaderOpenGL::Z_FLIP, false); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glCopyTexSubImage2D(_cube_side_enum[i], lod, 0, 0, 0, 0, size, size); - } - - size >>= 1; - - mm_level--; - - lod++; - } - - shaders.cubemap_filter.set_conditional(CubemapFilterShaderOpenGL::USE_SOURCE_PANORAMA, false); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderOpenGL::USE_DIRECT_WRITE, false); - - // restore ranges - glActiveTexture(GL_TEXTURE2); //back to panorama - - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - 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); - - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE3); //back to panorama - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, 0); - - //reset flags on Sky Texture that may have changed - texture_set_flags(sky->panorama, texture->flags); - - // Framebuffer did its job. thank mr framebuffer - glActiveTexture(GL_TEXTURE0); //back to panorama - bind_framebuffer_system(); -} - -/* SHADER API */ - -RID RasterizerStorageOpenGL::shader_allocate() { - Shader *shader = memnew(Shader); - shader->mode = RS::SHADER_SPATIAL; - shader->shader = &scene->state.scene_shader; - RID rid = shader_owner.make_rid(shader); - _shader_make_dirty(shader); - shader->self = rid; - - return rid; -} - -void RasterizerStorageOpenGL::shader_initialize(RID p_rid) { - // noop -} - -//RID RasterizerStorageOpenGL::shader_create() { -// Shader *shader = memnew(Shader); -// shader->mode = RS::SHADER_SPATIAL; -// shader->shader = &scene->state.scene_shader; -// RID rid = shader_owner.make_rid(shader); -// _shader_make_dirty(shader); -// shader->self = rid; - -// return rid; -//} - -void RasterizerStorageOpenGL::_shader_make_dirty(Shader *p_shader) { - if (p_shader->dirty_list.in_list()) - return; - - _shader_dirty_list.add(&p_shader->dirty_list); -} - -void RasterizerStorageOpenGL::shader_set_code(RID p_shader, const String &p_code) { - Shader *shader = shader_owner.get_or_null(p_shader); - ERR_FAIL_COND(!shader); - - shader->code = p_code; - - String mode_string = ShaderLanguage::get_shader_type(p_code); - RS::ShaderMode mode; - - if (mode_string == "canvas_item") - mode = RS::SHADER_CANVAS_ITEM; - else if (mode_string == "particles") - mode = RS::SHADER_PARTICLES; - else - mode = RS::SHADER_SPATIAL; - - if (shader->custom_code_id && mode != shader->mode) { - shader->shader->free_custom_shader(shader->custom_code_id); - shader->custom_code_id = 0; - } - - shader->mode = mode; - - // TODO handle all shader types - if (mode == RS::SHADER_CANVAS_ITEM) { - shader->shader = &canvas->state.canvas_shader; - - } else if (mode == RS::SHADER_SPATIAL) { - shader->shader = &scene->state.scene_shader; - } else { - return; - } - - if (shader->custom_code_id == 0) { - shader->custom_code_id = shader->shader->create_custom_shader(); - } - - _shader_make_dirty(shader); -} - -String RasterizerStorageOpenGL::shader_get_code(RID p_shader) const { - const Shader *shader = shader_owner.get_or_null(p_shader); - ERR_FAIL_COND_V(!shader, ""); - - return shader->code; -} - -void RasterizerStorageOpenGL::_update_shader(Shader *p_shader) const { - _shader_dirty_list.remove(&p_shader->dirty_list); - - p_shader->valid = false; - - p_shader->uniforms.clear(); - - if (p_shader->code == String()) { - return; //just invalid, but no error - } - - ShaderCompilerOpenGL::GeneratedCode gen_code; - ShaderCompilerOpenGL::IdentifierActions *actions = NULL; - - switch (p_shader->mode) { - case RS::SHADER_CANVAS_ITEM: { - p_shader->canvas_item.light_mode = Shader::CanvasItem::LIGHT_MODE_NORMAL; - p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX; - - p_shader->canvas_item.uses_screen_texture = false; - p_shader->canvas_item.uses_screen_uv = false; - p_shader->canvas_item.uses_time = false; - p_shader->canvas_item.uses_modulate = false; - p_shader->canvas_item.uses_color = false; - p_shader->canvas_item.uses_vertex = false; - p_shader->canvas_item.batch_flags = 0; - - p_shader->canvas_item.uses_world_matrix = false; - p_shader->canvas_item.uses_extra_matrix = false; - p_shader->canvas_item.uses_projection_matrix = false; - p_shader->canvas_item.uses_instance_custom = false; - - shaders.actions_canvas.render_mode_values["blend_add"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD); - shaders.actions_canvas.render_mode_values["blend_mix"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX); - shaders.actions_canvas.render_mode_values["blend_sub"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_SUB); - shaders.actions_canvas.render_mode_values["blend_mul"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MUL); - shaders.actions_canvas.render_mode_values["blend_premul_alpha"] = Pair(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_PMALPHA); - - shaders.actions_canvas.render_mode_values["unshaded"] = Pair(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED); - shaders.actions_canvas.render_mode_values["light_only"] = Pair(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY); - - shaders.actions_canvas.usage_flag_pointers["SCREEN_UV"] = &p_shader->canvas_item.uses_screen_uv; - shaders.actions_canvas.usage_flag_pointers["SCREEN_PIXEL_SIZE"] = &p_shader->canvas_item.uses_screen_uv; - shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture; - shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time; - shaders.actions_canvas.usage_flag_pointers["MODULATE"] = &p_shader->canvas_item.uses_modulate; - shaders.actions_canvas.usage_flag_pointers["COLOR"] = &p_shader->canvas_item.uses_color; - - shaders.actions_canvas.usage_flag_pointers["VERTEX"] = &p_shader->canvas_item.uses_vertex; - - shaders.actions_canvas.usage_flag_pointers["WORLD_MATRIX"] = &p_shader->canvas_item.uses_world_matrix; - shaders.actions_canvas.usage_flag_pointers["EXTRA_MATRIX"] = &p_shader->canvas_item.uses_extra_matrix; - shaders.actions_canvas.usage_flag_pointers["PROJECTION_MATRIX"] = &p_shader->canvas_item.uses_projection_matrix; - shaders.actions_canvas.usage_flag_pointers["INSTANCE_CUSTOM"] = &p_shader->canvas_item.uses_instance_custom; - - actions = &shaders.actions_canvas; - actions->uniforms = &p_shader->uniforms; - } break; - - case RS::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.uses_tangent = false; - p_shader->spatial.uses_ensure_correct_normals = 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(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_ADD); - shaders.actions_scene.render_mode_values["blend_mix"] = Pair(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MIX); - shaders.actions_scene.render_mode_values["blend_sub"] = Pair(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_SUB); - shaders.actions_scene.render_mode_values["blend_mul"] = Pair(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MUL); - - shaders.actions_scene.render_mode_values["depth_draw_opaque"] = Pair(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_OPAQUE); - shaders.actions_scene.render_mode_values["depth_draw_always"] = Pair(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALWAYS); - shaders.actions_scene.render_mode_values["depth_draw_never"] = Pair(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_NEVER); - shaders.actions_scene.render_mode_values["depth_draw_alpha_prepass"] = Pair(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS); - - shaders.actions_scene.render_mode_values["cull_front"] = Pair(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_FRONT); - shaders.actions_scene.render_mode_values["cull_back"] = Pair(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_BACK); - shaders.actions_scene.render_mode_values["cull_disabled"] = Pair(&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.render_mode_flags["ensure_correct_normals"] = &p_shader->spatial.uses_ensure_correct_normals; - - 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; - - // Use of any of these BUILTINS indicate the need for transformed tangents. - // This is needed to know when to transform tangents in software skinning. - shaders.actions_scene.usage_flag_pointers["TANGENT"] = &p_shader->spatial.uses_tangent; - shaders.actions_scene.usage_flag_pointers["NORMALMAP"] = &p_shader->spatial.uses_tangent; - - 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; - - if (p_shader->spatial.uses_screen_texture && p_shader->spatial.uses_depth_texture) { - ERR_PRINT_ONCE("Using both SCREEN_TEXTURE and DEPTH_TEXTURE is not supported in OpenGL"); - } - - if (p_shader->spatial.uses_depth_texture && !config.support_depth_texture) { - ERR_PRINT_ONCE("Using DEPTH_TEXTURE is not permitted on this hardware, operation will fail."); - } - } break; - - default: { - return; - } break; - } - - Error err = shaders.compiler.compile(p_shader->mode, p_shader->code, actions, p_shader->path, gen_code); - if (err != OK) { - return; - } - - p_shader->shader->set_custom_shader_code(p_shader->custom_code_id, gen_code.vertex, gen_code.vertex_global, gen_code.fragment, gen_code.light, gen_code.fragment_global, gen_code.uniforms, gen_code.texture_uniforms, gen_code.custom_defines); - - p_shader->texture_count = gen_code.texture_uniforms.size(); - p_shader->texture_hints = gen_code.texture_hints; - - p_shader->uses_vertex_time = gen_code.uses_vertex_time; - p_shader->uses_fragment_time = gen_code.uses_fragment_time; - - // some logic for batching - if (p_shader->mode == RS::SHADER_CANVAS_ITEM) { - if (p_shader->canvas_item.uses_modulate | p_shader->canvas_item.uses_color) { - p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_COLOR_BAKING; - } - if (p_shader->canvas_item.uses_vertex) { - p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_VERTEX_BAKING; - } - if (p_shader->canvas_item.uses_world_matrix | p_shader->canvas_item.uses_extra_matrix | p_shader->canvas_item.uses_projection_matrix | p_shader->canvas_item.uses_instance_custom) { - p_shader->canvas_item.batch_flags |= RasterizerStorageCommon::PREVENT_ITEM_JOINING; - } - } - - p_shader->shader->set_custom_shader(p_shader->custom_code_id); - p_shader->shader->bind(); - - // cache uniform locations - - for (SelfList *E = p_shader->materials.first(); E; E = E->next()) { - _material_make_dirty(E->self()); - } - - p_shader->valid = true; - p_shader->version++; -} - -void RasterizerStorageOpenGL::update_dirty_shaders() { - while (_shader_dirty_list.first()) { - _update_shader(_shader_dirty_list.first()->self()); - } -} - -void RasterizerStorageOpenGL::shader_get_param_list(RID p_shader, List *p_param_list) const { - Shader *shader = shader_owner.get_or_null(p_shader); - ERR_FAIL_COND(!shader); - - if (shader->dirty_list.in_list()) { - _update_shader(shader); - } - - Map order; - - for (Map::Element *E = shader->uniforms.front(); E; E = E->next()) { - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); - } else { - order[E->get().order] = E->key(); - } - } - - for (Map::Element *E = order.front(); E; E = E->next()) { - PropertyInfo pi; - ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[E->get()]; - - pi.name = E->get(); - - switch (u.type) { - case ShaderLanguage::TYPE_VOID: { - pi.type = Variant::NIL; - } break; - - case ShaderLanguage::TYPE_BOOL: { - pi.type = Variant::BOOL; - } break; - - // bool vectors - case ShaderLanguage::TYPE_BVEC2: { - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y"; - } break; - case ShaderLanguage::TYPE_BVEC3: { - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z"; - } break; - case ShaderLanguage::TYPE_BVEC4: { - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z,w"; - } break; - - // int stuff - case ShaderLanguage::TYPE_UINT: - case ShaderLanguage::TYPE_INT: { - pi.type = Variant::INT; - - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); - } - } break; - - case ShaderLanguage::TYPE_IVEC2: - case ShaderLanguage::TYPE_UVEC2: - case ShaderLanguage::TYPE_IVEC3: - case ShaderLanguage::TYPE_UVEC3: - case ShaderLanguage::TYPE_IVEC4: - case ShaderLanguage::TYPE_UVEC4: { - // not sure what this should be in godot 4 - // pi.type = Variant::POOL_INT_ARRAY; - pi.type = Variant::PACKED_INT32_ARRAY; - } break; - - case ShaderLanguage::TYPE_FLOAT: { - pi.type = Variant::FLOAT; - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); - } - } break; - - case ShaderLanguage::TYPE_VEC2: { - pi.type = Variant::VECTOR2; - } break; - case ShaderLanguage::TYPE_VEC3: { - pi.type = Variant::VECTOR3; - } break; - - case ShaderLanguage::TYPE_VEC4: { - if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { - pi.type = Variant::COLOR; - } else { - pi.type = Variant::PLANE; - } - } break; - - case ShaderLanguage::TYPE_MAT2: { - pi.type = Variant::TRANSFORM2D; - } break; - - case ShaderLanguage::TYPE_MAT3: { - pi.type = Variant::BASIS; - } break; - - case ShaderLanguage::TYPE_MAT4: { - pi.type = Variant::TRANSFORM3D; - } break; - - case ShaderLanguage::TYPE_SAMPLER2D: - // case ShaderLanguage::TYPE_SAMPLEREXT: - case ShaderLanguage::TYPE_ISAMPLER2D: - case ShaderLanguage::TYPE_USAMPLER2D: { - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "Texture"; - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - pi.type = Variant::OBJECT; - pi.hint = PROPERTY_HINT_RESOURCE_TYPE; - pi.hint_string = "CubeMap"; - } break; - - case ShaderLanguage::TYPE_SAMPLER2DARRAY: - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: - case ShaderLanguage::TYPE_SAMPLER3D: - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: { - // Not implemented in OpenGL - } break; - // new for godot 4 - case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: - case ShaderLanguage::TYPE_STRUCT: - case ShaderLanguage::TYPE_MAX: { - } break; - } - - p_param_list->push_back(pi); - } -} - -void RasterizerStorageOpenGL::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { - Shader *shader = shader_owner.get_or_null(p_shader); - ERR_FAIL_COND(!shader); - ERR_FAIL_COND(p_texture.is_valid() && !texture_owner.owns(p_texture)); - - if (p_texture.is_valid()) { - shader->default_textures[p_name] = p_texture; - } else { - shader->default_textures.erase(p_name); - } - - _shader_make_dirty(shader); -} - -RID RasterizerStorageOpenGL::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { - const Shader *shader = shader_owner.get_or_null(p_shader); - ERR_FAIL_COND_V(!shader, RID()); - - const Map::Element *E = shader->default_textures.find(p_name); - - if (!E) { - return RID(); - } - - return E->get(); -} - -void RasterizerStorageOpenGL::shader_add_custom_define(RID p_shader, const String &p_define) { - Shader *shader = shader_owner.get_or_null(p_shader); - ERR_FAIL_COND(!shader); - - shader->shader->add_custom_define(p_define); - - _shader_make_dirty(shader); -} - -void RasterizerStorageOpenGL::shader_get_custom_defines(RID p_shader, Vector *p_defines) const { - Shader *shader = shader_owner.get_or_null(p_shader); - ERR_FAIL_COND(!shader); - - shader->shader->get_custom_defines(p_defines); -} - -void RasterizerStorageOpenGL::shader_remove_custom_define(RID p_shader, const String &p_define) { - Shader *shader = shader_owner.get_or_null(p_shader); - ERR_FAIL_COND(!shader); - - shader->shader->remove_custom_define(p_define); - - _shader_make_dirty(shader); -} - -/* COMMON MATERIAL API */ - -void RasterizerStorageOpenGL::_material_make_dirty(Material *p_material) const { - if (p_material->dirty_list.in_list()) - return; - - _material_dirty_list.add(&p_material->dirty_list); -} - -RID RasterizerStorageOpenGL::material_allocate() { - Material *material = memnew(Material); - return material_owner.make_rid(material); -} - -void RasterizerStorageOpenGL::material_initialize(RID p_rid) { -} - -//RID RasterizerStorageOpenGL::material_create() { -// Material *material = memnew(Material); - -// return material_owner.make_rid(material); -//} - -void RasterizerStorageOpenGL::material_set_shader(RID p_material, RID p_shader) { - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - Shader *shader = shader_owner.get_or_null(p_shader); - - if (material->shader) { - // if a shader is present, remove the old shader - material->shader->materials.remove(&material->list); - } - - material->shader = shader; - - if (shader) { - shader->materials.add(&material->list); - } - - _material_make_dirty(material); -} - -RID RasterizerStorageOpenGL::material_get_shader(RID p_material) const { - const Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND_V(!material, RID()); - - if (material->shader) { - return material->shader->self; - } - - return RID(); -} - -void RasterizerStorageOpenGL::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - if (p_value.get_type() == Variant::NIL) { - material->params.erase(p_param); - } else { - material->params[p_param] = p_value; - } - - _material_make_dirty(material); -} - -Variant RasterizerStorageOpenGL::material_get_param(RID p_material, const StringName &p_param) const { - const Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND_V(!material, RID()); - - if (material->params.has(p_param)) { - return material->params[p_param]; - } - - return material_get_param_default(p_material, p_param); -} - -Variant RasterizerStorageOpenGL::material_get_param_default(RID p_material, const StringName &p_param) const { - const Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND_V(!material, Variant()); - - if (material->shader) { - if (material->shader->uniforms.has(p_param)) { - ShaderLanguage::ShaderNode::Uniform uniform = material->shader->uniforms[p_param]; - Vector default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); - } - } - return Variant(); -} - -void RasterizerStorageOpenGL::material_set_line_width(RID p_material, float p_width) { - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - material->line_width = p_width; -} - -void RasterizerStorageOpenGL::material_set_next_pass(RID p_material, RID p_next_material) { - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - material->next_pass = p_next_material; -} - -bool RasterizerStorageOpenGL::material_is_animated(RID p_material) { - Material *material = material_owner.get_or_null(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 RasterizerStorageOpenGL::material_casts_shadows(RID p_material) { - Material *material = material_owner.get_or_null(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; -} - -bool RasterizerStorageOpenGL::material_uses_tangents(RID p_material) { - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND_V(!material, false); - - if (!material->shader) { - return false; - } - - if (material->shader->dirty_list.in_list()) { - _update_shader(material->shader); - } - - return material->shader->spatial.uses_tangent; -} - -bool RasterizerStorageOpenGL::material_uses_ensure_correct_normals(RID p_material) { - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND_V(!material, false); - - if (!material->shader) { - return false; - } - - if (material->shader->dirty_list.in_list()) { - _update_shader(material->shader); - } - - return material->shader->spatial.uses_ensure_correct_normals; -} - -void RasterizerStorageOpenGL::material_add_instance_owner(RID p_material, DependencyTracker *p_instance) { - /* - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - Map::Element *E = material->instance_owners.find(p_instance); - if (E) { - E->get()++; - } else { - material->instance_owners[p_instance] = 1; - } -*/ -} - -void RasterizerStorageOpenGL::material_remove_instance_owner(RID p_material, DependencyTracker *p_instance) { - /* - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - Map::Element *E = material->instance_owners.find(p_instance); - ERR_FAIL_COND(!E); - - E->get()--; - - if (E->get() == 0) { - material->instance_owners.erase(E); - } -*/ -} - -void RasterizerStorageOpenGL::material_set_render_priority(RID p_material, int priority) { - ERR_FAIL_COND(priority < RS::MATERIAL_RENDER_PRIORITY_MIN); - ERR_FAIL_COND(priority > RS::MATERIAL_RENDER_PRIORITY_MAX); - - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - material->render_priority = priority; -} - -void RasterizerStorageOpenGL::_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 == RS::SHADER_SPATIAL) { - if (p_material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX && - (!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::Element *E = p_material->geometry_owners.front(); E; E = E->next()) { - E->key()->material_changed_notify(); - } - - for (Map::Element *E = p_material->instance_owners.front(); E; E = E->next()) { - E->key()->base_changed(false, true); - } - */ - } - } - } - - // uniforms and other things will be set in the use_material method in ShaderOpenGL - - if (p_material->shader && p_material->shader->texture_count > 0) { - p_material->textures.resize(p_material->shader->texture_count); - - for (Map::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::Element *V = p_material->params.find(E->key()); - - if (V) { - texture = V->get(); - } - - if (!texture.is_valid()) { - Map::Element *W = p_material->shader->default_textures.find(E->key()); - - if (W) { - texture = W->get(); - } - } - - p_material->textures.write[E->get().texture_order] = Pair(E->key(), texture); - } - } else { - p_material->textures.clear(); - } -} -/* -void RasterizerStorageOpenGL::_material_add_geometry(RID p_material, Geometry *p_geometry) { - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - Map::Element *I = material->geometry_owners.find(p_geometry); - - if (I) { - I->get()++; - } else { - material->geometry_owners[p_geometry] = 1; - } -} - -void RasterizerStorageOpenGL::_material_remove_geometry(RID p_material, Geometry *p_geometry) { - Material *material = material_owner.get_or_null(p_material); - ERR_FAIL_COND(!material); - - Map::Element *I = material->geometry_owners.find(p_geometry); - ERR_FAIL_COND(!I); - - I->get()--; - - if (I->get() == 0) { - material->geometry_owners.erase(I); - } -} -*/ -void RasterizerStorageOpenGL::update_dirty_materials() { - while (_material_dirty_list.first()) { - Material *material = _material_dirty_list.first()->self(); - _update_material(material); - } -} - -/* MESH API */ - -RID RasterizerStorageOpenGL::mesh_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::mesh_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) { -} - -bool RasterizerStorageOpenGL::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) { - return false; -} - -RID RasterizerStorageOpenGL::mesh_instance_create(RID p_base) { - return RID(); -} - -void RasterizerStorageOpenGL::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) { -} - -void RasterizerStorageOpenGL::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) { -} - -void RasterizerStorageOpenGL::mesh_instance_check_for_update(RID p_mesh_instance) { -} - -void RasterizerStorageOpenGL::update_mesh_instances() { -} - -void RasterizerStorageOpenGL::reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) { -} - -float RasterizerStorageOpenGL::reflection_probe_get_lod_threshold(RID p_probe) const { - return 0.0; -} - -void RasterizerStorageOpenGL::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) { -} - -int RasterizerStorageOpenGL::mesh_get_blend_shape_count(RID p_mesh) const { - return 0; -} - -void RasterizerStorageOpenGL::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { -} - -RS::BlendShapeMode RasterizerStorageOpenGL::mesh_get_blend_shape_mode(RID p_mesh) const { - return RS::BLEND_SHAPE_MODE_NORMALIZED; -} - -void RasterizerStorageOpenGL::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) { -} - -void RasterizerStorageOpenGL::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) { -} - -void RasterizerStorageOpenGL::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) { -} - -void RasterizerStorageOpenGL::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { -} - -RID RasterizerStorageOpenGL::mesh_surface_get_material(RID p_mesh, int p_surface) const { - return RID(); -} - -RS::SurfaceData RasterizerStorageOpenGL::mesh_get_surface(RID p_mesh, int p_surface) const { - return RS::SurfaceData(); -} - -int RasterizerStorageOpenGL::mesh_get_surface_count(RID p_mesh) const { - return 0; -} - -void RasterizerStorageOpenGL::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { -} - -AABB RasterizerStorageOpenGL::mesh_get_custom_aabb(RID p_mesh) const { - return AABB(); -} - -AABB RasterizerStorageOpenGL::mesh_get_aabb(RID p_mesh, RID p_skeleton) { - return AABB(); -} - -void RasterizerStorageOpenGL::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) { -} - -void RasterizerStorageOpenGL::mesh_clear(RID p_mesh) { -} - -/* MULTIMESH API */ - -RID RasterizerStorageOpenGL::multimesh_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::multimesh_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) { -} - -int RasterizerStorageOpenGL::multimesh_get_instance_count(RID p_multimesh) const { - return 0; -} - -void RasterizerStorageOpenGL::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { -} - -void RasterizerStorageOpenGL::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) { -} - -void RasterizerStorageOpenGL::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { -} - -void RasterizerStorageOpenGL::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { -} - -void RasterizerStorageOpenGL::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) { -} - -RID RasterizerStorageOpenGL::multimesh_get_mesh(RID p_multimesh) const { - return RID(); -} - -AABB RasterizerStorageOpenGL::multimesh_get_aabb(RID p_multimesh) const { - return AABB(); -} - -Transform3D RasterizerStorageOpenGL::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { - return Transform3D(); -} - -Transform2D RasterizerStorageOpenGL::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { - return Transform2D(); -} - -Color RasterizerStorageOpenGL::multimesh_instance_get_color(RID p_multimesh, int p_index) const { - return Color(); -} - -Color RasterizerStorageOpenGL::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { - return Color(); -} - -void RasterizerStorageOpenGL::multimesh_set_buffer(RID p_multimesh, const Vector &p_buffer) { -} - -Vector RasterizerStorageOpenGL::multimesh_get_buffer(RID p_multimesh) const { - return Vector(); -} - -void RasterizerStorageOpenGL::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { -} - -int RasterizerStorageOpenGL::multimesh_get_visible_instances(RID p_multimesh) const { - return 0; -} - -/* SKELETON API */ - -RID RasterizerStorageOpenGL::skeleton_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::skeleton_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) { -} - -void RasterizerStorageOpenGL::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { -} - -int RasterizerStorageOpenGL::skeleton_get_bone_count(RID p_skeleton) const { - return 0; -} - -void RasterizerStorageOpenGL::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) { -} - -Transform3D RasterizerStorageOpenGL::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { - return Transform3D(); -} - -void RasterizerStorageOpenGL::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { -} - -Transform2D RasterizerStorageOpenGL::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { - return Transform2D(); -} - -/* Light API */ - -RID RasterizerStorageOpenGL::directional_light_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::directional_light_initialize(RID p_rid) { -} - -RID RasterizerStorageOpenGL::omni_light_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::omni_light_initialize(RID p_rid) { -} - -RID RasterizerStorageOpenGL::spot_light_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::spot_light_initialize(RID p_rid) { -} - -RID RasterizerStorageOpenGL::reflection_probe_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::reflection_probe_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::light_set_color(RID p_light, const Color &p_color) { -} - -void RasterizerStorageOpenGL::light_set_param(RID p_light, RS::LightParam p_param, float p_value) { -} - -void RasterizerStorageOpenGL::light_set_shadow(RID p_light, bool p_enabled) { -} - -void RasterizerStorageOpenGL::light_set_shadow_color(RID p_light, const Color &p_color) { -} - -void RasterizerStorageOpenGL::light_set_projector(RID p_light, RID p_texture) { -} - -void RasterizerStorageOpenGL::light_set_negative(RID p_light, bool p_enable) { -} - -void RasterizerStorageOpenGL::light_set_cull_mask(RID p_light, uint32_t p_mask) { -} - -void RasterizerStorageOpenGL::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { -} - -void RasterizerStorageOpenGL::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { -} - -void RasterizerStorageOpenGL::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) { -} - -void RasterizerStorageOpenGL::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { -} - -void RasterizerStorageOpenGL::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) { -} - -void RasterizerStorageOpenGL::light_directional_set_blend_splits(RID p_light, bool p_enable) { -} - -bool RasterizerStorageOpenGL::light_directional_get_blend_splits(RID p_light) const { - return false; -} - -void RasterizerStorageOpenGL::light_directional_set_sky_only(RID p_light, bool p_sky_only) { -} - -bool RasterizerStorageOpenGL::light_directional_is_sky_only(RID p_light) const { - return false; -} - -RS::LightDirectionalShadowMode RasterizerStorageOpenGL::light_directional_get_shadow_mode(RID p_light) { - return RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL; -} - -RS::LightOmniShadowMode RasterizerStorageOpenGL::light_omni_get_shadow_mode(RID p_light) { - return RS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; -} - -bool RasterizerStorageOpenGL::light_has_shadow(RID p_light) const { - return false; -} - -bool RasterizerStorageOpenGL::light_has_projector(RID p_light) const { - return false; -} - -RS::LightType RasterizerStorageOpenGL::light_get_type(RID p_light) const { - return RS::LIGHT_OMNI; -} - -AABB RasterizerStorageOpenGL::light_get_aabb(RID p_light) const { - return AABB(); -} - -float RasterizerStorageOpenGL::light_get_param(RID p_light, RS::LightParam p_param) { - return 0.0; -} - -Color RasterizerStorageOpenGL::light_get_color(RID p_light) { - return Color(); -} - -RS::LightBakeMode RasterizerStorageOpenGL::light_get_bake_mode(RID p_light) { - return RS::LIGHT_BAKE_DISABLED; -} - -uint32_t RasterizerStorageOpenGL::light_get_max_sdfgi_cascade(RID p_light) { - return 0; -} - -uint64_t RasterizerStorageOpenGL::light_get_version(RID p_light) const { - return 0; -} - -/* PROBE API */ - -void RasterizerStorageOpenGL::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_intensity(RID p_probe, float p_intensity) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_max_distance(RID p_probe, float p_distance) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { -} - -void RasterizerStorageOpenGL::reflection_probe_set_resolution(RID p_probe, int p_resolution) { -} - -AABB RasterizerStorageOpenGL::reflection_probe_get_aabb(RID p_probe) const { - return AABB(); -} - -RS::ReflectionProbeUpdateMode RasterizerStorageOpenGL::reflection_probe_get_update_mode(RID p_probe) const { - return RenderingServer::REFLECTION_PROBE_UPDATE_ONCE; -} - -uint32_t RasterizerStorageOpenGL::reflection_probe_get_cull_mask(RID p_probe) const { - return 0; -} - -Vector3 RasterizerStorageOpenGL::reflection_probe_get_extents(RID p_probe) const { - return Vector3(); -} - -Vector3 RasterizerStorageOpenGL::reflection_probe_get_origin_offset(RID p_probe) const { - return Vector3(); -} - -float RasterizerStorageOpenGL::reflection_probe_get_origin_max_distance(RID p_probe) const { - return 0.0; -} - -bool RasterizerStorageOpenGL::reflection_probe_renders_shadows(RID p_probe) const { - return false; -} - -void RasterizerStorageOpenGL::base_update_dependency(RID p_base, DependencyTracker *p_instance) { -} - -void RasterizerStorageOpenGL::skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) { -} - -/* DECAL API */ - -RID RasterizerStorageOpenGL::decal_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::decal_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::decal_set_extents(RID p_decal, const Vector3 &p_extents) { -} - -void RasterizerStorageOpenGL::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { -} - -void RasterizerStorageOpenGL::decal_set_emission_energy(RID p_decal, float p_energy) { -} - -void RasterizerStorageOpenGL::decal_set_albedo_mix(RID p_decal, float p_mix) { -} - -void RasterizerStorageOpenGL::decal_set_modulate(RID p_decal, const Color &p_modulate) { -} - -void RasterizerStorageOpenGL::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { -} - -void RasterizerStorageOpenGL::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { -} - -void RasterizerStorageOpenGL::decal_set_fade(RID p_decal, float p_above, float p_below) { -} - -void RasterizerStorageOpenGL::decal_set_normal_fade(RID p_decal, float p_fade) { -} - -AABB RasterizerStorageOpenGL::decal_get_aabb(RID p_decal) const { - return AABB(); -} - -/* VOXEL GI API */ - -RID RasterizerStorageOpenGL::voxel_gi_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::voxel_gi_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector &p_octree_cells, const Vector &p_data_cells, const Vector &p_distance_field, const Vector &p_level_counts) { -} - -AABB RasterizerStorageOpenGL::voxel_gi_get_bounds(RID p_voxel_gi) const { - return AABB(); -} - -Vector3i RasterizerStorageOpenGL::voxel_gi_get_octree_size(RID p_voxel_gi) const { - return Vector3i(); -} - -Vector RasterizerStorageOpenGL::voxel_gi_get_octree_cells(RID p_voxel_gi) const { - return Vector(); -} - -Vector RasterizerStorageOpenGL::voxel_gi_get_data_cells(RID p_voxel_gi) const { - return Vector(); -} - -Vector RasterizerStorageOpenGL::voxel_gi_get_distance_field(RID p_voxel_gi) const { - return Vector(); -} - -Vector RasterizerStorageOpenGL::voxel_gi_get_level_counts(RID p_voxel_gi) const { - return Vector(); -} - -Transform3D RasterizerStorageOpenGL::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const { - return Transform3D(); -} - -void RasterizerStorageOpenGL::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageOpenGL::voxel_gi_get_dynamic_range(RID p_voxel_gi) const { - return 0; -} - -void RasterizerStorageOpenGL::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageOpenGL::voxel_gi_get_propagation(RID p_voxel_gi) const { - return 0; -} - -void RasterizerStorageOpenGL::voxel_gi_set_energy(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageOpenGL::voxel_gi_get_energy(RID p_voxel_gi) const { - return 0.0; -} - -void RasterizerStorageOpenGL::voxel_gi_set_bias(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageOpenGL::voxel_gi_get_bias(RID p_voxel_gi) const { - return 0.0; -} - -void RasterizerStorageOpenGL::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) { -} - -float RasterizerStorageOpenGL::voxel_gi_get_normal_bias(RID p_voxel_gi) const { - return 0.0; -} - -void RasterizerStorageOpenGL::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) { -} - -bool RasterizerStorageOpenGL::voxel_gi_is_interior(RID p_voxel_gi) const { - return false; -} - -void RasterizerStorageOpenGL::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) { -} - -bool RasterizerStorageOpenGL::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const { - return false; -} - -void RasterizerStorageOpenGL::voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) { -} - -float RasterizerStorageOpenGL::voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const { - return 0; -} - -uint32_t RasterizerStorageOpenGL::voxel_gi_get_version(RID p_voxel_gi) { - return 0; -} - -/* LIGHTMAP CAPTURE */ -RID RasterizerStorageOpenGL::lightmap_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::lightmap_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) { -} - -void RasterizerStorageOpenGL::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) { -} - -void RasterizerStorageOpenGL::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) { -} - -void RasterizerStorageOpenGL::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { -} - -PackedVector3Array RasterizerStorageOpenGL::lightmap_get_probe_capture_points(RID p_lightmap) const { - return PackedVector3Array(); -} - -PackedColorArray RasterizerStorageOpenGL::lightmap_get_probe_capture_sh(RID p_lightmap) const { - return PackedColorArray(); -} - -PackedInt32Array RasterizerStorageOpenGL::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const { - return PackedInt32Array(); -} - -PackedInt32Array RasterizerStorageOpenGL::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const { - return PackedInt32Array(); -} - -AABB RasterizerStorageOpenGL::lightmap_get_aabb(RID p_lightmap) const { - return AABB(); -} - -void RasterizerStorageOpenGL::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) { -} - -bool RasterizerStorageOpenGL::lightmap_is_interior(RID p_lightmap) const { - return false; -} - -void RasterizerStorageOpenGL::lightmap_set_probe_capture_update_speed(float p_speed) { -} - -float RasterizerStorageOpenGL::lightmap_get_probe_capture_update_speed() const { - return 0; -} - -/* OCCLUDER */ - -void RasterizerStorageOpenGL::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) { -} - -/* PARTICLES */ - -RID RasterizerStorageOpenGL::particles_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::particles_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) { -} - -void RasterizerStorageOpenGL::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { -} - -void RasterizerStorageOpenGL::particles_set_emitting(RID p_particles, bool p_emitting) { -} - -void RasterizerStorageOpenGL::particles_set_amount(RID p_particles, int p_amount) { -} - -void RasterizerStorageOpenGL::particles_set_lifetime(RID p_particles, double p_lifetime) { -} - -void RasterizerStorageOpenGL::particles_set_one_shot(RID p_particles, bool p_one_shot) { -} - -void RasterizerStorageOpenGL::particles_set_pre_process_time(RID p_particles, double p_time) { -} - -void RasterizerStorageOpenGL::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) { -} - -void RasterizerStorageOpenGL::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) { -} - -void RasterizerStorageOpenGL::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { -} - -void RasterizerStorageOpenGL::particles_set_speed_scale(RID p_particles, double p_scale) { -} - -void RasterizerStorageOpenGL::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { -} - -void RasterizerStorageOpenGL::particles_set_process_material(RID p_particles, RID p_material) { -} - -void RasterizerStorageOpenGL::particles_set_fixed_fps(RID p_particles, int p_fps) { -} - -void RasterizerStorageOpenGL::particles_set_interpolate(RID p_particles, bool p_enable) { -} - -void RasterizerStorageOpenGL::particles_set_fractional_delta(RID p_particles, bool p_enable) { -} - -void RasterizerStorageOpenGL::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { -} - -void RasterizerStorageOpenGL::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) { -} - -void RasterizerStorageOpenGL::particles_set_collision_base_size(RID p_particles, real_t p_size) { -} - -void RasterizerStorageOpenGL::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) { -} - -void RasterizerStorageOpenGL::particles_set_trails(RID p_particles, bool p_enable, double p_length) { -} - -void RasterizerStorageOpenGL::particles_set_trail_bind_poses(RID p_particles, const Vector &p_bind_poses) { -} - -void RasterizerStorageOpenGL::particles_restart(RID p_particles) { -} - -void RasterizerStorageOpenGL::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { -} - -void RasterizerStorageOpenGL::particles_set_draw_passes(RID p_particles, int p_count) { -} - -void RasterizerStorageOpenGL::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { -} - -void RasterizerStorageOpenGL::particles_request_process(RID p_particles) { -} - -AABB RasterizerStorageOpenGL::particles_get_current_aabb(RID p_particles) { - return AABB(); -} - -AABB RasterizerStorageOpenGL::particles_get_aabb(RID p_particles) const { - return AABB(); -} - -void RasterizerStorageOpenGL::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) { -} - -bool RasterizerStorageOpenGL::particles_get_emitting(RID p_particles) { - return false; -} - -int RasterizerStorageOpenGL::particles_get_draw_passes(RID p_particles) const { - return 0; -} - -RID RasterizerStorageOpenGL::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { - return RID(); -} - -void RasterizerStorageOpenGL::particles_add_collision(RID p_particles, RID p_instance) { -} - -void RasterizerStorageOpenGL::particles_remove_collision(RID p_particles, RID p_instance) { -} - -void RasterizerStorageOpenGL::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) { -} - -void RasterizerStorageOpenGL::update_particles() { -} - -/* PARTICLES COLLISION */ - -RID RasterizerStorageOpenGL::particles_collision_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::particles_collision_initialize(RID p_rid) { -} - -void RasterizerStorageOpenGL::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { -} - -void RasterizerStorageOpenGL::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { -} - -void RasterizerStorageOpenGL::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) { -} - -void RasterizerStorageOpenGL::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { -} - -void RasterizerStorageOpenGL::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) { -} - -void RasterizerStorageOpenGL::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) { -} - -void RasterizerStorageOpenGL::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) { -} - -void RasterizerStorageOpenGL::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { -} - -void RasterizerStorageOpenGL::particles_collision_height_field_update(RID p_particles_collision) { -} - -void RasterizerStorageOpenGL::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { -} - -AABB RasterizerStorageOpenGL::particles_collision_get_aabb(RID p_particles_collision) const { - return AABB(); -} - -bool RasterizerStorageOpenGL::particles_collision_is_heightfield(RID p_particles_collision) const { - return false; -} - -RID RasterizerStorageOpenGL::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { - return RID(); -} - -RID RasterizerStorageOpenGL::particles_collision_instance_create(RID p_collision) { - return RID(); -} - -void RasterizerStorageOpenGL::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) { -} - -void RasterizerStorageOpenGL::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) { -} - -/* VISIBILITY NOTIFIER */ -RID RasterizerStorageOpenGL::visibility_notifier_allocate() { - return RID(); -} - -void RasterizerStorageOpenGL::visibility_notifier_initialize(RID p_notifier) { -} - -void RasterizerStorageOpenGL::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) { -} - -void RasterizerStorageOpenGL::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) { -} - -AABB RasterizerStorageOpenGL::visibility_notifier_get_aabb(RID p_notifier) const { - return AABB(); -} - -void RasterizerStorageOpenGL::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) { -} - -/* GLOBAL VARIABLES */ - -void RasterizerStorageOpenGL::global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) { -} - -void RasterizerStorageOpenGL::global_variable_remove(const StringName &p_name) { -} - -Vector RasterizerStorageOpenGL::global_variable_get_list() const { - return Vector(); -} - -void RasterizerStorageOpenGL::global_variable_set(const StringName &p_name, const Variant &p_value) { -} - -void RasterizerStorageOpenGL::global_variable_set_override(const StringName &p_name, const Variant &p_value) { -} - -Variant RasterizerStorageOpenGL::global_variable_get(const StringName &p_name) const { - return Variant(); -} - -RS::GlobalVariableType RasterizerStorageOpenGL::global_variable_get_type(const StringName &p_name) const { - return RS::GLOBAL_VAR_TYPE_MAX; -} - -void RasterizerStorageOpenGL::global_variables_load_settings(bool p_load_textures) { -} - -void RasterizerStorageOpenGL::global_variables_clear() { -} - -int32_t RasterizerStorageOpenGL::global_variables_instance_allocate(RID p_instance) { - return 0; -} - -void RasterizerStorageOpenGL::global_variables_instance_free(RID p_instance) { -} - -void RasterizerStorageOpenGL::global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) { -} - -bool RasterizerStorageOpenGL::particles_is_inactive(RID p_particles) const { - return false; -} - -/* RENDER TARGET */ - -void RasterizerStorageOpenGL::_set_current_render_target(RID p_render_target) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - - // FTODO - // if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) { - // // pending clear request. Do that first. - // glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - // glClearColor(storage->frame.clear_request_color.r, - // storage->frame.clear_request_color.g, - // storage->frame.clear_request_color.b, - // storage->frame.clear_request_color.a); - // glClear(GL_COLOR_BUFFER_BIT); - // } - - if (rt) { - if (rt->allocate_is_dirty) { - rt->allocate_is_dirty = false; - _render_target_allocate(rt); - } - - // if (p_render_target.is_valid()) { - // RasterizerStorageOpenGL::RenderTarget *rt = storage.render_target_owner.get_or_null(p_render_target); - frame.current_rt = rt; - ERR_FAIL_COND(!rt); - frame.clear_request = false; - - glViewport(0, 0, rt->width, rt->height); - - // print_line("_set_current_render_target w " + itos(rt->width) + " h " + itos(rt->height)); - - _dims.rt_width = rt->width; - _dims.rt_height = rt->height; - _dims.win_width = rt->width; - _dims.win_height = rt->height; - - } else { - frame.current_rt = NULL; - frame.clear_request = false; - // FTODO - // glViewport(0, 0, OS::get_singleton()->get_window_size().width, OS::get_singleton()->get_window_size().height); - bind_framebuffer_system(); - } -} - -void RasterizerStorageOpenGL::_render_target_allocate(RenderTarget *rt) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - // do not allocate a render target with no size - if (rt->width <= 0 || rt->height <= 0) - return; - - // do not allocate a render target that is attached to the screen - if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { - rt->fbo = RasterizerStorageOpenGL::system_fbo; - return; - } - - GLuint color_internal_format; - GLuint color_format; - GLuint color_type = GL_UNSIGNED_BYTE; - Image::Format image_format; - - if (rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { -#ifdef GLES_OVER_GL - color_internal_format = GL_RGBA8; -#else - color_internal_format = GL_RGBA; -#endif - color_format = GL_RGBA; - image_format = Image::FORMAT_RGBA8; - } else { -#ifdef GLES_OVER_GL - color_internal_format = GL_RGB8; -#else - color_internal_format = GL_RGB; -#endif - color_format = GL_RGB; - image_format = Image::FORMAT_RGB8; - } - - rt->used_dof_blur_near = false; - rt->mip_maps_allocated = false; - - { - /* Front FBO */ - - Texture *texture = texture_owner.get_or_null(rt->texture); - ERR_FAIL_COND(!texture); - - // framebuffer - glGenFramebuffers(1, &rt->fbo); - bind_framebuffer(rt->fbo); - - // color - glGenTextures(1, &rt->color); - glBindTexture(GL_TEXTURE_2D, rt->color); - - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); - - if (texture->flags & TEXTURE_FLAG_FILTER) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); - - // depth - - if (config.support_depth_texture) { - glGenTextures(1, &rt->depth); - glBindTexture(GL_TEXTURE_2D, rt->depth); - glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); - } else { - glGenRenderbuffers(1, &rt->depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->depth); - - glRenderbufferStorage(GL_RENDERBUFFER, config.depth_buffer_internalformat, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - } - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - glDeleteFramebuffers(1, &rt->fbo); - if (config.support_depth_texture) { - glDeleteTextures(1, &rt->depth); - } else { - glDeleteRenderbuffers(1, &rt->depth); - } - - glDeleteTextures(1, &rt->color); - rt->fbo = 0; - rt->width = 0; - rt->height = 0; - rt->color = 0; - rt->depth = 0; - texture->tex_id = 0; - texture->active = false; - WARN_PRINT("Could not create framebuffer!!"); - return; - } - - texture->format = image_format; - texture->gl_format_cache = color_format; - texture->gl_type_cache = GL_UNSIGNED_BYTE; - texture->gl_internal_format_cache = color_internal_format; - texture->tex_id = rt->color; - texture->width = rt->width; - texture->alloc_width = rt->width; - texture->height = rt->height; - texture->alloc_height = rt->height; - texture->active = true; - - texture_set_flags(rt->texture, texture->flags); - } - - /* BACK FBO */ - /* For MSAA */ - -#ifndef JAVASCRIPT_ENABLED - if (rt->msaa >= RS::VIEWPORT_MSAA_2X && rt->msaa <= RS::VIEWPORT_MSAA_8X && config.multisample_supported) { - rt->multisample_active = true; - - static const int msaa_value[] = { 0, 2, 4, 8, 16 }; - int msaa = msaa_value[rt->msaa]; - - int max_samples = 0; - glGetIntegerv(GL_MAX_SAMPLES, &max_samples); - if (msaa > max_samples) { - WARN_PRINT("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); - msaa = max_samples; - } - - //regular fbo - glGenFramebuffers(1, &rt->multisample_fbo); - bind_framebuffer(rt->multisample_fbo); - - glGenRenderbuffers(1, &rt->multisample_depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_depth); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_buffer_internalformat, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->multisample_depth); - -#if defined(GLES_OVER_GL) || defined(IPHONE_ENABLED) - - glGenRenderbuffers(1, &rt->multisample_color); - glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_color); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height); - - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color); -#elif ANDROID_ENABLED - // Render to a texture in android - glGenTextures(1, &rt->multisample_color); - glBindTexture(GL_TEXTURE_2D, rt->multisample_color); - - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); - - // multisample buffer is same size as front buffer, so just use nearest - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - glFramebufferTexture2DMultisample(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->multisample_color, 0, msaa); -#endif - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - // Delete allocated resources and default to no MSAA - WARN_PRINT_ONCE("Cannot allocate back framebuffer for MSAA"); - printf("err status: %x\n", status); - config.multisample_supported = false; - rt->multisample_active = false; - - glDeleteFramebuffers(1, &rt->multisample_fbo); - rt->multisample_fbo = 0; - - glDeleteRenderbuffers(1, &rt->multisample_depth); - rt->multisample_depth = 0; -#ifdef ANDROID_ENABLED - glDeleteTextures(1, &rt->multisample_color); -#else - glDeleteRenderbuffers(1, &rt->multisample_color); -#endif - rt->multisample_color = 0; - } - - glBindRenderbuffer(GL_RENDERBUFFER, 0); - bind_framebuffer(0); -#ifdef ANDROID_ENABLED - glBindTexture(GL_TEXTURE_2D, 0); -#endif - - } else -#endif // JAVASCRIPT_ENABLED - { - rt->multisample_active = false; - } - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // copy texscreen buffers - // if (!(rt->flags[RendererStorage::RENDER_TARGET_NO_SAMPLING])) { - if (true) { - glGenTextures(1, &rt->copy_screen_effect.color); - glBindTexture(GL_TEXTURE_2D, rt->copy_screen_effect.color); - - if (rt->flags[RendererStorage::RENDER_TARGET_TRANSPARENT]) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } else { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->width, rt->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glGenFramebuffers(1, &rt->copy_screen_effect.fbo); - bind_framebuffer(rt->copy_screen_effect.fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->copy_screen_effect.color, 0); - - glClearColor(0, 0, 0, 0); - glClear(GL_COLOR_BUFFER_BIT); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - _render_target_clear(rt); - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } - } - - // Allocate mipmap chains for post_process effects - // if (!rt->flags[RendererStorage::RENDER_TARGET_NO_3D] && rt->width >= 2 && rt->height >= 2) { - if (rt->width >= 2 && rt->height >= 2) { - for (int i = 0; i < 2; i++) { - ERR_FAIL_COND(rt->mip_maps[i].sizes.size()); - int w = rt->width; - int h = rt->height; - - if (i > 0) { - w >>= 1; - h >>= 1; - } - - int level = 0; - int fb_w = w; - int fb_h = h; - - while (true) { - RenderTarget::MipMaps::Size mm; - mm.width = w; - mm.height = h; - rt->mip_maps[i].sizes.push_back(mm); - - w >>= 1; - h >>= 1; - - if (w < 2 || h < 2) - break; - - level++; - } - - GLsizei width = fb_w; - GLsizei height = fb_h; - - if (config.render_to_mipmap_supported) { - glGenTextures(1, &rt->mip_maps[i].color); - glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].color); - - for (int l = 0; l < level + 1; l++) { - glTexImage2D(GL_TEXTURE_2D, l, color_internal_format, width, height, 0, color_format, color_type, NULL); - width = MAX(1, (width / 2)); - height = MAX(1, (height / 2)); - } -#ifdef GLES_OVER_GL - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); -#endif - } else { - // Can't render to specific levels of a mipmap in ES 2.0 or Webgl so create a texture for each level - for (int l = 0; l < level + 1; l++) { - glGenTextures(1, &rt->mip_maps[i].sizes.write[l].color); - glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[l].color); - glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, width, height, 0, color_format, color_type, NULL); - width = MAX(1, (width / 2)); - height = MAX(1, (height / 2)); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } - - glDisable(GL_SCISSOR_TEST); - glColorMask(1, 1, 1, 1); - glDepthMask(GL_TRUE); - - for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { - RenderTarget::MipMaps::Size &mm = rt->mip_maps[i].sizes.write[j]; - - glGenFramebuffers(1, &mm.fbo); - bind_framebuffer(mm.fbo); - - if (config.render_to_mipmap_supported) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].color, j); - } else { - glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[j].color); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].sizes[j].color, 0); - } - - bool used_depth = false; - if (j == 0 && i == 0) { //use always - if (config.support_depth_texture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); - } else { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - } - used_depth = true; - } - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - WARN_PRINT_ONCE("Cannot allocate mipmaps for 3D post processing effects"); - bind_framebuffer_system(); - return; - } - - glClearColor(1.0, 0.0, 1.0, 0.0); - glClear(GL_COLOR_BUFFER_BIT); - if (used_depth) { - glClearDepth(1.0); - glClear(GL_DEPTH_BUFFER_BIT); - } - } - - rt->mip_maps[i].levels = level; - - if (config.render_to_mipmap_supported) { - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - } - rt->mip_maps_allocated = true; - } - - bind_framebuffer_system(); -} - -void RasterizerStorageOpenGL::_render_target_clear(RenderTarget *rt) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - // there is nothing to clear when DIRECT_TO_SCREEN is used - if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) - return; - - if (rt->fbo) { - glDeleteFramebuffers(1, &rt->fbo); - glDeleteTextures(1, &rt->color); - rt->fbo = 0; - } - - if (rt->external.fbo != 0) { - // free this - glDeleteFramebuffers(1, &rt->external.fbo); - - // clean up our texture - Texture *t = texture_owner.get_or_null(rt->external.texture); - t->alloc_height = 0; - t->alloc_width = 0; - t->width = 0; - t->height = 0; - t->active = false; - texture_owner.free(rt->external.texture); - memdelete(t); - - rt->external.fbo = 0; - } - - if (rt->depth) { - if (config.support_depth_texture) { - glDeleteTextures(1, &rt->depth); - } else { - glDeleteRenderbuffers(1, &rt->depth); - } - - rt->depth = 0; - } - - Texture *tex = texture_owner.get_or_null(rt->texture); - tex->alloc_height = 0; - tex->alloc_width = 0; - tex->width = 0; - tex->height = 0; - tex->active = false; - - if (rt->copy_screen_effect.color) { - glDeleteFramebuffers(1, &rt->copy_screen_effect.fbo); - rt->copy_screen_effect.fbo = 0; - - glDeleteTextures(1, &rt->copy_screen_effect.color); - rt->copy_screen_effect.color = 0; - } - - for (int i = 0; i < 2; i++) { - if (rt->mip_maps[i].sizes.size()) { - for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { - glDeleteFramebuffers(1, &rt->mip_maps[i].sizes[j].fbo); - glDeleteTextures(1, &rt->mip_maps[i].sizes[j].color); - } - - glDeleteTextures(1, &rt->mip_maps[i].color); - rt->mip_maps[i].sizes.clear(); - rt->mip_maps[i].levels = 0; - rt->mip_maps[i].color = 0; - } - } - - if (rt->multisample_active) { - glDeleteFramebuffers(1, &rt->multisample_fbo); - rt->multisample_fbo = 0; - - glDeleteRenderbuffers(1, &rt->multisample_depth); - rt->multisample_depth = 0; -#ifdef ANDROID_ENABLED - glDeleteTextures(1, &rt->multisample_color); -#else - glDeleteRenderbuffers(1, &rt->multisample_color); -#endif - rt->multisample_color = 0; - } -} - -RID RasterizerStorageOpenGL::render_target_create() { -#ifdef OPENGL_DISABLE_RENDER_TARGETS -// return RID(); -#endif - - RenderTarget *rt = memnew(RenderTarget); - Texture *t = memnew(Texture); - - t->type = RenderingDevice::TEXTURE_TYPE_2D; - t->flags = 0; - t->width = 0; - t->height = 0; - t->alloc_height = 0; - t->alloc_width = 0; - t->format = Image::FORMAT_R8; - t->target = GL_TEXTURE_2D; - t->gl_format_cache = 0; - t->gl_internal_format_cache = 0; - t->gl_type_cache = 0; - t->data_size = 0; - t->total_data_size = 0; - t->ignore_mipmaps = false; - t->compressed = false; - t->mipmaps = 1; - t->active = true; - t->tex_id = 0; - t->render_target = rt; - - rt->texture = texture_owner.make_rid(t); - return render_target_owner.make_rid(rt); -} - -void RasterizerStorageOpenGL::render_target_set_position(RID p_render_target, int p_x, int p_y) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - rt->x = p_x; - rt->y = p_y; -} - -void RasterizerStorageOpenGL::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - if (p_width == rt->width && p_height == rt->height) - return; - - _render_target_clear(rt); - - rt->width = p_width; - rt->height = p_height; - - // print_line("render_target_set_size " + itos(p_render_target.get_id()) + ", w " + itos(p_width) + " h " + itos(p_height)); - - rt->allocate_is_dirty = true; - //_render_target_allocate(rt); -} - -RID RasterizerStorageOpenGL::render_target_get_texture(RID p_render_target) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return RID(); -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND_V(!rt, RID()); - - if (rt->external.fbo == 0) { - return rt->texture; - } else { - return rt->external.texture; - } -} - -void RasterizerStorageOpenGL::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - if (p_texture_id == 0) { - if (rt->external.fbo != 0) { - // free this - glDeleteFramebuffers(1, &rt->external.fbo); - - // and this - if (rt->external.depth != 0) { - glDeleteRenderbuffers(1, &rt->external.depth); - } - - // clean up our texture - Texture *t = texture_owner.get_or_null(rt->external.texture); - t->alloc_height = 0; - t->alloc_width = 0; - t->width = 0; - t->height = 0; - t->active = false; - texture_owner.free(rt->external.texture); - memdelete(t); - - rt->external.fbo = 0; - rt->external.color = 0; - rt->external.depth = 0; - } - } else { - Texture *t; - - if (rt->external.fbo == 0) { - // create our fbo - glGenFramebuffers(1, &rt->external.fbo); - bind_framebuffer(rt->external.fbo); - - // allocate a texture - t = memnew(Texture); - - t->type = RenderingDevice::TEXTURE_TYPE_2D; - t->flags = 0; - t->width = 0; - t->height = 0; - t->alloc_height = 0; - t->alloc_width = 0; - t->format = Image::FORMAT_RGBA8; - t->target = GL_TEXTURE_2D; - t->gl_format_cache = 0; - t->gl_internal_format_cache = 0; - t->gl_type_cache = 0; - t->data_size = 0; - t->compressed = false; - t->srgb = false; - t->total_data_size = 0; - t->ignore_mipmaps = false; - t->mipmaps = 1; - t->active = true; - t->tex_id = 0; - t->render_target = rt; - - rt->external.texture = texture_owner.make_rid(t); - - } else { - // bind our frame buffer - bind_framebuffer(rt->external.fbo); - - // find our texture - t = texture_owner.get_or_null(rt->external.texture); - } - - // set our texture - t->tex_id = p_texture_id; - rt->external.color = p_texture_id; - - // size shouldn't be different - t->width = rt->width; - t->height = rt->height; - t->alloc_height = rt->width; - t->alloc_width = rt->height; - - // Switch our texture on our frame buffer -#if ANDROID_ENABLED - if (rt->msaa >= RS::VIEWPORT_MSAA_2X && rt->msaa <= RS::VIEWPORT_MSAA_4X) { - // This code only applies to the Oculus Go and Oculus Quest. Due to the the tiled nature - // of the GPU we can do a single render pass by rendering directly into our texture chains - // texture and apply MSAA as we render. - - // On any other hardware these two modes are ignored and we do not have any MSAA, - // the normal MSAA modes need to be used to enable our two pass approach - - static const int msaa_value[] = { 2, 4 }; - int msaa = msaa_value[rt->msaa - RS::VIEWPORT_MSAA_2X]; - - if (rt->external.depth == 0) { - // create a multisample depth buffer, we're not reusing Godots because Godot's didn't get created.. - glGenRenderbuffers(1, &rt->external.depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->external.depth); - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_buffer_internalformat, rt->width, rt->height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->external.depth); - } - - // and set our external texture as the texture... - glFramebufferTexture2DMultisample(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0, msaa); - - } else -#endif - { - // set our texture as the destination for our framebuffer - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0); - - // seeing we're rendering into this directly, better also use our depth buffer, just use our existing one :) - if (config.support_depth_texture) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); - } else { - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); - } - } - - // check status and unbind - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - bind_framebuffer_system(); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - printf("framebuffer fail, status: %x\n", status); - } - - ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); - } -} - -void RasterizerStorageOpenGL::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - // When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as - // those functions change how they operate depending on the value of DIRECT_TO_SCREEN - if (p_flag == RENDER_TARGET_DIRECT_TO_SCREEN && p_value != rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { - _render_target_clear(rt); - rt->flags[p_flag] = p_value; - _render_target_allocate(rt); - } - - rt->flags[p_flag] = p_value; - - switch (p_flag) { - case RENDER_TARGET_TRANSPARENT: - /* - case RENDER_TARGET_HDR: - case RENDER_TARGET_NO_3D: - case RENDER_TARGET_NO_SAMPLING: - case RENDER_TARGET_NO_3D_EFFECTS: */ - { - //must reset for these formats - _render_target_clear(rt); - _render_target_allocate(rt); - } - break; - default: { - } - } -} - -bool RasterizerStorageOpenGL::render_target_was_used(RID p_render_target) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return false; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND_V(!rt, false); - - return rt->used_in_frame; -} - -void RasterizerStorageOpenGL::render_target_clear_used(RID p_render_target) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - rt->used_in_frame = false; -} - -void RasterizerStorageOpenGL::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - if (rt->msaa == p_msaa) - return; - - if (!config.multisample_supported) { - ERR_PRINT("MSAA not supported on this hardware."); - return; - } - - _render_target_clear(rt); - rt->msaa = p_msaa; - _render_target_allocate(rt); -} - -//RasterizerStorageOpenGL::RenderTarget * RasterizerStorageOpenGL::render_target_get(RID p_render_target) -//{ -// return render_target_owner.get_or_null(p_render_target); -//} - -void RasterizerStorageOpenGL::render_target_set_use_fxaa(RID p_render_target, bool p_fxaa) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - rt->use_fxaa = p_fxaa; -} - -void RasterizerStorageOpenGL::render_target_set_use_debanding(RID p_render_target, bool p_debanding) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - - if (p_debanding) { - WARN_PRINT_ONCE("Debanding is not supported in the OpenGL backend. Switch to the Vulkan backend and make sure HDR is enabled."); - } - - rt->use_debanding = p_debanding; -} - -void RasterizerStorageOpenGL::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - rt->clear_requested = true; - rt->clear_color = p_clear_color; - - // ERR_FAIL_COND(!frame.current_rt); - // frame.clear_request = true; - // frame.clear_request_color = p_color; -} - -bool RasterizerStorageOpenGL::render_target_is_clear_requested(RID p_render_target) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return false; -#endif - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND_V(!rt, false); - return rt->clear_requested; -} -Color RasterizerStorageOpenGL::render_target_get_clear_request_color(RID p_render_target) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return Color(); -#endif - - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND_V(!rt, Color()); - return rt->clear_color; -} - -void RasterizerStorageOpenGL::render_target_disable_clear_request(RID p_render_target) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - rt->clear_requested = false; -} - -void RasterizerStorageOpenGL::render_target_do_clear_request(RID p_render_target) { -#ifdef OPENGL_DISABLE_RENDER_TARGETS - return; -#endif - - // NEW for GLES... - // This is being called at the wrong time. Instead it will be performed - // at canvas begin - return; - - /* - RenderTarget *rt = render_target_owner.get_or_null(p_render_target); - ERR_FAIL_COND(!rt); - if (!rt->clear_requested) { - return; - } - - const Color &c = rt->clear_color; - - glClearColor(c.r, c.g, c.b, c.a); - // more bits? - glClear(GL_COLOR_BUFFER_BIT); - */ -} - -void RasterizerStorageOpenGL::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { -} - -Rect2i RasterizerStorageOpenGL::render_target_get_sdf_rect(RID p_render_target) const { - return Rect2i(); -} - -void RasterizerStorageOpenGL::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) { -} - -/* CANVAS SHADOW */ - -RID RasterizerStorageOpenGL::canvas_light_shadow_buffer_create(int p_width) { - CanvasLightShadow *cls = memnew(CanvasLightShadow); - - if (p_width > config.max_texture_size) - p_width = config.max_texture_size; - - cls->size = p_width; - cls->height = 16; - - glActiveTexture(GL_TEXTURE0); - - glGenFramebuffers(1, &cls->fbo); - bind_framebuffer(cls->fbo); - - glGenRenderbuffers(1, &cls->depth); - glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); - glRenderbufferStorage(GL_RENDERBUFFER, config.depth_buffer_internalformat, cls->size, cls->height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); - - glGenTextures(1, &cls->distance); - glBindTexture(GL_TEXTURE_2D, cls->distance); - if (config.use_rgba_2d_shadows) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - } else { -#ifdef GLES_OVER_GL - glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, NULL); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_FLOAT, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, NULL); -#endif - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - 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_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - //printf("errnum: %x\n",status); - bind_framebuffer_system(); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - memdelete(cls); - ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); - } - - return canvas_light_shadow_owner.make_rid(cls); -} - -/* LIGHT SHADOW MAPPING */ -/* - -RID RasterizerStorageOpenGL::canvas_light_occluder_create() { - CanvasOccluder *co = memnew(CanvasOccluder); - co->index_id = 0; - co->vertex_id = 0; - co->len = 0; - - return canvas_occluder_owner.make_rid(co); -} - -void RasterizerStorageOpenGL::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector &p_lines) { - CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); - ERR_FAIL_COND(!co); - - co->lines = p_lines; - - if (p_lines.size() != co->len) { - if (co->index_id) - glDeleteBuffers(1, &co->index_id); - if (co->vertex_id) - glDeleteBuffers(1, &co->vertex_id); - - co->index_id = 0; - co->vertex_id = 0; - co->len = 0; - } - - if (p_lines.size()) { - PoolVector geometry; - PoolVector indices; - int lc = p_lines.size(); - - geometry.resize(lc * 6); - indices.resize(lc * 3); - - PoolVector::Write vw = geometry.write(); - PoolVector::Write iw = indices.write(); - - PoolVector::Read lr = p_lines.read(); - - const int POLY_HEIGHT = 16384; - - for (int i = 0; i < lc / 2; i++) { - vw[i * 12 + 0] = lr[i * 2 + 0].x; - vw[i * 12 + 1] = lr[i * 2 + 0].y; - vw[i * 12 + 2] = POLY_HEIGHT; - - vw[i * 12 + 3] = lr[i * 2 + 1].x; - vw[i * 12 + 4] = lr[i * 2 + 1].y; - vw[i * 12 + 5] = POLY_HEIGHT; - - vw[i * 12 + 6] = lr[i * 2 + 1].x; - vw[i * 12 + 7] = lr[i * 2 + 1].y; - vw[i * 12 + 8] = -POLY_HEIGHT; - - vw[i * 12 + 9] = lr[i * 2 + 0].x; - vw[i * 12 + 10] = lr[i * 2 + 0].y; - vw[i * 12 + 11] = -POLY_HEIGHT; - - iw[i * 6 + 0] = i * 4 + 0; - iw[i * 6 + 1] = i * 4 + 1; - iw[i * 6 + 2] = i * 4 + 2; - - iw[i * 6 + 3] = i * 4 + 2; - iw[i * 6 + 4] = i * 4 + 3; - iw[i * 6 + 5] = i * 4 + 0; - } - - //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush - - if (!co->vertex_id) { - glGenBuffers(1, &co->vertex_id); - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); - } else { - glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); - glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr()); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind - - if (!co->index_id) { - glGenBuffers(1, &co->index_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW); - } else { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr()); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind - - co->len = lc; - } -} -*/ - -RS::InstanceType RasterizerStorageOpenGL::get_base_type(RID p_rid) const { - return RS::INSTANCE_NONE; - - /* - if (mesh_owner.owns(p_rid)) { - return RS::INSTANCE_MESH; - } else if (light_owner.owns(p_rid)) { - return RS::INSTANCE_LIGHT; - } else if (multimesh_owner.owns(p_rid)) { - return RS::INSTANCE_MULTIMESH; - } else if (immediate_owner.owns(p_rid)) { - return RS::INSTANCE_IMMEDIATE; - } else if (reflection_probe_owner.owns(p_rid)) { - return RS::INSTANCE_REFLECTION_PROBE; - } else if (lightmap_capture_data_owner.owns(p_rid)) { - return RS::INSTANCE_LIGHTMAP_CAPTURE; - } else { - return RS::INSTANCE_NONE; - } -*/ -} - -bool RasterizerStorageOpenGL::free(RID p_rid) { - if (render_target_owner.owns(p_rid)) { - RenderTarget *rt = render_target_owner.get_or_null(p_rid); - _render_target_clear(rt); - - Texture *t = texture_owner.get_or_null(rt->texture); - if (t) { - 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_or_null(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_or_null(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_or_null(p_rid); - - if (shader->shader && shader->custom_code_id) { - 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_or_null(p_rid); - - if (m->shader) { - m->shader->materials.remove(&m->list); - } - - /* - for (Map::Element *E = m->geometry_owners.front(); E; E = E->next()) { - Geometry *g = E->key(); - g->material = RID(); - } - - for (Map::Element *E = m->instance_owners.front(); E; E = E->next()) { - InstanceBaseDependency *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 { - return false; - } - /* - } else if (skeleton_owner.owns(p_rid)) { - Skeleton *s = skeleton_owner.get_or_null(p_rid); - - if (s->update_list.in_list()) { - skeleton_update_list.remove(&s->update_list); - } - - for (Set::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_or_null(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_or_null(p_rid); - multimesh->instance_remove_deps(); - - if (multimesh->mesh.is_valid()) { - Mesh *mesh = mesh_owner.get_or_null(multimesh->mesh); - if (mesh) { - mesh->multimeshes.remove(&multimesh->mesh_list); - } - } - - multimesh_allocate(p_rid, 0, RS::MULTIMESH_TRANSFORM_3D, RS::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_or_null(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_or_null(p_rid); - light->instance_remove_deps(); - - light_owner.free(p_rid); - memdelete(light); - - return true; - } else if (reflection_probe_owner.owns(p_rid)) { - // delete the texture - ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid); - reflection_probe->instance_remove_deps(); - - reflection_probe_owner.free(p_rid); - memdelete(reflection_probe); - - return true; - } else if (lightmap_capture_data_owner.owns(p_rid)) { - // delete the texture - LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get_or_null(p_rid); - lightmap_capture->instance_remove_deps(); - - lightmap_capture_data_owner.free(p_rid); - memdelete(lightmap_capture); - return true; - - } else if (canvas_occluder_owner.owns(p_rid)) { - CanvasOccluder *co = canvas_occluder_owner.get_or_null(p_rid); - if (co->index_id) - glDeleteBuffers(1, &co->index_id); - if (co->vertex_id) - glDeleteBuffers(1, &co->vertex_id); - - canvas_occluder_owner.free(p_rid); - memdelete(co); - - return true; - - } else if (canvas_light_shadow_owner.owns(p_rid)) { - CanvasLightShadow *cls = canvas_light_shadow_owner.get_or_null(p_rid); - glDeleteFramebuffers(1, &cls->fbo); - glDeleteRenderbuffers(1, &cls->depth); - glDeleteTextures(1, &cls->distance); - canvas_light_shadow_owner.free(p_rid); - memdelete(cls); - - return true; - */ -} - -bool RasterizerStorageOpenGL::has_os_feature(const String &p_feature) const { - if (p_feature == "pvrtc") - return config.pvrtc_supported; - - if (p_feature == "s3tc") - return config.s3tc_supported; - - if (p_feature == "etc") - return config.etc1_supported; - - if (p_feature == "skinning_fallback") - return config.use_skeleton_software; - - return false; -} - -//////////////////////////////////////////// - -void RasterizerStorageOpenGL::set_debug_generate_wireframes(bool p_generate) { -} - -//void RasterizerStorageOpenGL::render_info_begin_capture() { -// info.snap = info.render; -//} - -//void RasterizerStorageOpenGL::render_info_end_capture() { -// info.snap.object_count = info.render.object_count - info.snap.object_count; -// info.snap.draw_call_count = info.render.draw_call_count - info.snap.draw_call_count; -// info.snap.material_switch_count = info.render.material_switch_count - info.snap.material_switch_count; -// info.snap.surface_switch_count = info.render.surface_switch_count - info.snap.surface_switch_count; -// info.snap.shader_rebind_count = info.render.shader_rebind_count - info.snap.shader_rebind_count; -// info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count; -// info.snap._2d_item_count = info.render._2d_item_count - info.snap._2d_item_count; -// info.snap._2d_draw_call_count = info.render._2d_draw_call_count - info.snap._2d_draw_call_count; -//} - -//int RasterizerStorageOpenGL::get_captured_render_info(RS::RenderInfo p_info) { -// switch (p_info) { -// case RS::INFO_OBJECTS_IN_FRAME: { -// return info.snap.object_count; -// } break; -// case RS::INFO_VERTICES_IN_FRAME: { -// return info.snap.vertices_count; -// } break; -// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: { -// return info.snap.material_switch_count; -// } break; -// case RS::INFO_SHADER_CHANGES_IN_FRAME: { -// return info.snap.shader_rebind_count; -// } break; -// case RS::INFO_SURFACE_CHANGES_IN_FRAME: { -// return info.snap.surface_switch_count; -// } break; -// case RS::INFO_DRAW_CALLS_IN_FRAME: { -// return info.snap.draw_call_count; -// } break; -// /* -// case RS::INFO_2D_ITEMS_IN_FRAME: { -// return info.snap._2d_item_count; -// } break; -// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: { -// return info.snap._2d_draw_call_count; -// } break; -// */ -// default: { -// return get_render_info(p_info); -// } -// } -//} - -//int RasterizerStorageOpenGL::get_render_info(RS::RenderInfo p_info) { -// switch (p_info) { -// case RS::INFO_OBJECTS_IN_FRAME: -// return info.render_final.object_count; -// case RS::INFO_VERTICES_IN_FRAME: -// return info.render_final.vertices_count; -// case RS::INFO_MATERIAL_CHANGES_IN_FRAME: -// return info.render_final.material_switch_count; -// case RS::INFO_SHADER_CHANGES_IN_FRAME: -// return info.render_final.shader_rebind_count; -// case RS::INFO_SURFACE_CHANGES_IN_FRAME: -// return info.render_final.surface_switch_count; -// case RS::INFO_DRAW_CALLS_IN_FRAME: -// return info.render_final.draw_call_count; -// /* -// case RS::INFO_2D_ITEMS_IN_FRAME: -// return info.render_final._2d_item_count; -// case RS::INFO_2D_DRAW_CALLS_IN_FRAME: -// return info.render_final._2d_draw_call_count; -//*/ -// case RS::INFO_USAGE_VIDEO_MEM_TOTAL: -// return 0; //no idea -// case RS::INFO_VIDEO_MEM_USED: -// return info.vertex_mem + info.texture_mem; -// case RS::INFO_TEXTURE_MEM_USED: -// return info.texture_mem; -// case RS::INFO_VERTEX_MEM_USED: -// return info.vertex_mem; -// default: -// return 0; //no idea either -// } -//} - -String RasterizerStorageOpenGL::get_video_adapter_name() const { - return (const char *)glGetString(GL_RENDERER); -} - -String RasterizerStorageOpenGL::get_video_adapter_vendor() const { - return (const char *)glGetString(GL_VENDOR); -} - -void RasterizerStorageOpenGL::initialize() { - RasterizerStorageOpenGL::system_fbo = 0; - - { - const GLubyte *extension_string = glGetString(GL_EXTENSIONS); - - Vector extensions = String((const char *)extension_string).split(" "); - - for (int i = 0; i < extensions.size(); i++) { - config.extensions.insert(extensions[i]); - } - } - - // FTODO - config.keep_original_textures = true; // false - config.shrink_textures_x2 = false; - config.depth_internalformat = GL_DEPTH_COMPONENT; - config.depth_type = GL_UNSIGNED_INT; - -#ifdef GLES_OVER_GL - config.float_texture_supported = true; - config.s3tc_supported = true; - config.pvrtc_supported = false; - config.etc1_supported = false; - config.support_npot_repeat_mipmap = true; - config.depth_buffer_internalformat = GL_DEPTH_COMPONENT24; -#else - config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); - config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); - config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1"); - config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc") || config.extensions.has("WEBGL_compressed_texture_pvrtc"); - config.support_npot_repeat_mipmap = config.extensions.has("GL_OES_texture_npot"); - -#ifdef JAVASCRIPT_ENABLED - // RenderBuffer internal format must be 16 bits in WebGL, - // but depth_texture should default to 32 always - // if the implementation doesn't support 32, it should just quietly use 16 instead - // https://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/ - config.depth_buffer_internalformat = GL_DEPTH_COMPONENT16; - config.depth_type = GL_UNSIGNED_INT; -#else - // on mobile check for 24 bit depth support for RenderBufferStorage - if (config.extensions.has("GL_OES_depth24")) { - config.depth_buffer_internalformat = _DEPTH_COMPONENT24_OES; - config.depth_type = GL_UNSIGNED_INT; - } else { - config.depth_buffer_internalformat = GL_DEPTH_COMPONENT16; - config.depth_type = GL_UNSIGNED_SHORT; - } -#endif -#endif - -#ifndef GLES_OVER_GL - //Manually load extensions for android and ios - -#ifdef IPHONE_ENABLED - // appears that IPhone doesn't need to dlopen TODO: test this rigorously before removing - //void *gles2_lib = dlopen(NULL, RTLD_LAZY); - //glRenderbufferStorageMultisampleAPPLE = dlsym(gles2_lib, "glRenderbufferStorageMultisampleAPPLE"); - //glResolveMultisampleFramebufferAPPLE = dlsym(gles2_lib, "glResolveMultisampleFramebufferAPPLE"); -#elif ANDROID_ENABLED - - void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY); - glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT"); - glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glFramebufferTexture2DMultisampleEXT"); -#endif -#endif - - // Check for multisample support - config.multisample_supported = config.extensions.has("GL_EXT_framebuffer_multisample") || config.extensions.has("GL_EXT_multisampled_render_to_texture") || config.extensions.has("GL_APPLE_framebuffer_multisample"); - -#ifdef GLES_OVER_GL - //TODO: causes huge problems with desktop video drivers. Making false for now, needs to be true to render SCREEN_TEXTURE mipmaps - config.render_to_mipmap_supported = false; -#else - //check if mipmaps can be used for SCREEN_TEXTURE and Glow on Mobile and web platforms - config.render_to_mipmap_supported = config.extensions.has("GL_OES_fbo_render_mipmap") && config.extensions.has("GL_EXT_texture_lod"); -#endif - -#ifdef GLES_OVER_GL - config.use_rgba_2d_shadows = false; - config.support_depth_texture = true; - config.use_rgba_3d_shadows = false; - config.support_depth_cubemaps = true; -#else - config.use_rgba_2d_shadows = !(config.float_texture_supported && config.extensions.has("GL_EXT_texture_rg")); - config.support_depth_texture = config.extensions.has("GL_OES_depth_texture") || config.extensions.has("WEBGL_depth_texture"); - config.use_rgba_3d_shadows = !config.support_depth_texture; - config.support_depth_cubemaps = config.extensions.has("GL_OES_depth_texture_cube_map"); -#endif - -#ifdef GLES_OVER_GL - config.support_32_bits_indices = true; -#else - config.support_32_bits_indices = config.extensions.has("GL_OES_element_index_uint"); -#endif - -#ifdef GLES_OVER_GL - config.support_write_depth = true; -#elif defined(JAVASCRIPT_ENABLED) - config.support_write_depth = false; -#else - config.support_write_depth = config.extensions.has("GL_EXT_frag_depth"); -#endif - - config.support_half_float_vertices = true; -//every platform should support this except web, iOS has issues with their support, so add option to disable -#ifdef JAVASCRIPT_ENABLED - config.support_half_float_vertices = false; -#endif - bool disable_half_float = GLOBAL_GET("rendering/opengl/compatibility/disable_half_float"); - if (disable_half_float) { - config.support_half_float_vertices = false; - } - - config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc") || config.extensions.has("EXT_texture_compression_rgtc"); - config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc") || config.extensions.has("EXT_texture_compression_bptc"); - - //determine formats for depth textures (or renderbuffers) - if (config.support_depth_texture) { - // Will use texture for depth - // have to manually see if we can create a valid framebuffer texture using UNSIGNED_INT, - // as there is no extension to test for this. - GLuint fbo; - glGenFramebuffers(1, &fbo); - bind_framebuffer(fbo); - GLuint depth; - glGenTextures(1, &depth); - glBindTexture(GL_TEXTURE_2D, depth); - glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); - - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - - bind_framebuffer_system(); - glDeleteFramebuffers(1, &fbo); - glBindTexture(GL_TEXTURE_2D, 0); - glDeleteTextures(1, &depth); - - if (status != GL_FRAMEBUFFER_COMPLETE) { - // If it fails, test to see if it supports a framebuffer texture using UNSIGNED_SHORT - // This is needed because many OSX devices don't support either UNSIGNED_INT or UNSIGNED_SHORT -#ifdef GLES_OVER_GL - config.depth_internalformat = GL_DEPTH_COMPONENT16; -#else - // OES_depth_texture extension only specifies GL_DEPTH_COMPONENT. - config.depth_internalformat = GL_DEPTH_COMPONENT; -#endif - config.depth_type = GL_UNSIGNED_SHORT; - - glGenFramebuffers(1, &fbo); - bind_framebuffer(fbo); - - glGenTextures(1, &depth); - glBindTexture(GL_TEXTURE_2D, depth); - glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, 32, 32, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); - - status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - //if it fails again depth textures aren't supported, use rgba shadows and renderbuffer for depth - config.support_depth_texture = false; - config.use_rgba_3d_shadows = true; - } - - bind_framebuffer_system(); - glDeleteFramebuffers(1, &fbo); - glBindTexture(GL_TEXTURE_2D, 0); - glDeleteTextures(1, &depth); - } - } - - //picky requirements for these - config.support_shadow_cubemaps = config.support_depth_texture && config.support_write_depth && config.support_depth_cubemaps; - - frame.count = 0; - frame.delta = 0; - frame.current_rt = NULL; - frame.clear_request = false; - - glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &config.max_vertex_texture_image_units); - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); - - // the use skeleton software path should be used if either float texture is not supported, - // OR max_vertex_texture_image_units is zero - config.use_skeleton_software = (config.float_texture_supported == false) || (config.max_vertex_texture_image_units == 0); - - shaders.copy.init(); - shaders.cubemap_filter.init(); - bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx"); - shaders.cubemap_filter.set_conditional(CubemapFilterShaderOpenGL::LOW_QUALITY, !ggx_hq); - - { - // 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 - - glGenTextures(1, &resources.white_tex); - unsigned char whitetexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i++) { - whitetexdata[i] = 255; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.white_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.black_tex); - unsigned char blacktexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i++) { - blacktexdata[i] = 0; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.black_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, blacktexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.normal_tex); - unsigned char normaltexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i += 3) { - normaltexdata[i + 0] = 128; - normaltexdata[i + 1] = 128; - normaltexdata[i + 2] = 255; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.normal_tex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, normaltexdata); - glGenerateMipmap(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, 0); - - glGenTextures(1, &resources.aniso_tex); - unsigned char anisotexdata[8 * 8 * 3]; - for (int i = 0; i < 8 * 8 * 3; i += 3) { - anisotexdata[i + 0] = 255; - anisotexdata[i + 1] = 128; - anisotexdata[i + 2] = 0; - } - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.aniso_tex); - 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); - } - - // skeleton buffer - { - resources.skeleton_transform_buffer_size = 0; - glGenBuffers(1, &resources.skeleton_transform_buffer); - } - - // radical inverse vdc cache texture - // used for cubemap filtering - if (true /*||config.float_texture_supported*/) { //uint8 is similar and works everywhere - glGenTextures(1, &resources.radical_inverse_vdc_cache_tex); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, resources.radical_inverse_vdc_cache_tex); - - uint8_t 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] = uint8_t(CLAMP(value * 255.0, 0, 255)); - } - - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, radical_inverse); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //need this for proper sampling - - glBindTexture(GL_TEXTURE_2D, 0); - } - - { - glGenFramebuffers(1, &resources.mipmap_blur_fbo); - glGenTextures(1, &resources.mipmap_blur_color); - } - -#ifdef GLES_OVER_GL - //this needs to be enabled manually in OpenGL 2.1 - - if (config.extensions.has("GL_ARB_seamless_cube_map")) { - glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); - } - glEnable(GL_POINT_SPRITE); - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif - - config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); - config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter"); - //config.should_orphan = GLOBAL_GET("rendering/options/api_usage_legacy/orphan_buffers"); -} - -void RasterizerStorageOpenGL::finalize() { -} - -void RasterizerStorageOpenGL::_copy_screen() { - bind_quad_array(); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -} - -void RasterizerStorageOpenGL::update_memory_info() { -} - -uint64_t RasterizerStorageOpenGL::get_rendering_info(RS::RenderingInfo p_info) { - return 0; -} - -void RasterizerStorageOpenGL::update_dirty_resources() { - update_dirty_shaders(); - update_dirty_materials(); - // update_dirty_skeletons(); - // update_dirty_multimeshes(); -} - -RasterizerStorageOpenGL::RasterizerStorageOpenGL() { - RasterizerStorageOpenGL::system_fbo = 0; - config.should_orphan = true; -} - -#endif // OPENGL_BACKEND_ENABLED diff --git a/drivers/opengl/rasterizer_storage_opengl.h b/drivers/opengl/rasterizer_storage_opengl.h deleted file mode 100644 index c054e47a66..0000000000 --- a/drivers/opengl/rasterizer_storage_opengl.h +++ /dev/null @@ -1,1440 +0,0 @@ -/*************************************************************************/ -/* rasterizer_storage_opengl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef RASTERIZER_STORAGE_OPENGL_H -#define RASTERIZER_STORAGE_OPENGL_H - -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/templates/local_vector.h" -#include "core/templates/rid_owner.h" -#include "core/templates/self_list.h" -#include "drivers/opengl/rasterizer_asserts.h" -#include "servers/rendering/renderer_compositor.h" -#include "servers/rendering/renderer_storage.h" -#include "servers/rendering/shader_language.h" -#include "shader_compiler_opengl.h" -#include "shader_opengl.h" - -#include "shaders/copy.glsl.gen.h" -#include "shaders/cubemap_filter.glsl.gen.h" - -class RasterizerCanvasOpenGL; -class RasterizerSceneOpenGL; - -class RasterizerStorageOpenGL : public RendererStorage { - friend class RasterizerOpenGL; - - Thread::ID _main_thread_id = 0; - bool _is_main_thread(); - -public: - RasterizerCanvasOpenGL *canvas; - RasterizerSceneOpenGL *scene; - - static GLuint system_fbo; - - struct Config { - bool shrink_textures_x2; - bool use_fast_texture_filter; - bool use_skeleton_software; - - int max_vertex_texture_image_units; - int max_texture_image_units; - int max_texture_size; - - // TODO implement wireframe in OpenGL - // bool generate_wireframes; - - Set extensions; - - bool float_texture_supported; - bool s3tc_supported; - bool etc1_supported; - bool pvrtc_supported; - bool rgtc_supported; - bool bptc_supported; - - bool keep_original_textures; - - bool force_vertex_shading; - - bool use_rgba_2d_shadows; - bool use_rgba_3d_shadows; - - bool support_32_bits_indices; - bool support_write_depth; - bool support_half_float_vertices; - bool support_npot_repeat_mipmap; - bool support_depth_texture; - bool support_depth_cubemaps; - - bool support_shadow_cubemaps; - - bool multisample_supported; - bool render_to_mipmap_supported; - - GLuint depth_internalformat; - GLuint depth_type; - GLuint depth_buffer_internalformat; - - // in some cases the legacy render didn't orphan. We will mark these - // so the user can switch orphaning off for them. - bool should_orphan; - } config; - - struct Resources { - GLuint white_tex; - GLuint black_tex; - GLuint normal_tex; - GLuint aniso_tex; - - GLuint mipmap_blur_fbo; - GLuint mipmap_blur_color; - - GLuint radical_inverse_vdc_cache_tex; - bool use_rgba_2d_shadows; - - GLuint quadie; - - size_t skeleton_transform_buffer_size; - GLuint skeleton_transform_buffer; - LocalVector skeleton_transform_cpu_buffer; - - } resources; - - mutable struct Shaders { - ShaderCompilerOpenGL compiler; - - CopyShaderOpenGL copy; - CubemapFilterShaderOpenGL cubemap_filter; - - ShaderCompilerOpenGL::IdentifierActions actions_canvas; - ShaderCompilerOpenGL::IdentifierActions actions_scene; - ShaderCompilerOpenGL::IdentifierActions actions_particles; - - } shaders; - - struct Info { - uint64_t texture_mem; - uint64_t vertex_mem; - - struct Render { - uint32_t object_count; - uint32_t draw_call_count; - uint32_t material_switch_count; - uint32_t surface_switch_count; - uint32_t shader_rebind_count; - uint32_t vertices_count; - uint32_t _2d_item_count; - uint32_t _2d_draw_call_count; - - void reset() { - object_count = 0; - draw_call_count = 0; - material_switch_count = 0; - surface_switch_count = 0; - shader_rebind_count = 0; - vertices_count = 0; - _2d_item_count = 0; - _2d_draw_call_count = 0; - } - } render, render_final, snap; - - Info() : - texture_mem(0), - vertex_mem(0) { - render.reset(); - render_final.reset(); - } - - } info; - - void bind_quad_array() const; - - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////DATA/////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////////// - - /* - struct Instantiable { - RID self; - - SelfList::List instance_list; - - _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { - SelfList *instances = instance_list.first(); - while (instances) { - instances->self()->base_changed(p_aabb, p_materials); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_remove_deps() { - SelfList *instances = instance_list.first(); - - while (instances) { - instances->self()->base_removed(); - instances = instances->next(); - } - } - - Instantiable() {} - - ~Instantiable() {} - }; - - struct GeometryOwner : public Instantiable { - }; - - struct Geometry : public Instantiable { - enum Type { - GEOMETRY_INVALID, - GEOMETRY_SURFACE, - GEOMETRY_IMMEDIATE, - GEOMETRY_MULTISURFACE - }; - - Type type; - RID material; - uint64_t last_pass; - uint32_t index; - - void material_changed_notify() {} - - Geometry() { - last_pass = 0; - index = 0; - } - }; -*/ - ///////////////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////API//////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////////////////// - - bool can_create_resources_async() const override; - - // TEXTURE API - - enum OpenGLTextureFlags { - TEXTURE_FLAG_MIPMAPS = 1, /// Enable automatic mipmap generation - when available - TEXTURE_FLAG_REPEAT = 2, /// Repeat texture (Tiling), otherwise Clamping - TEXTURE_FLAG_FILTER = 4, /// Create texture with linear (or available) filter - TEXTURE_FLAG_ANISOTROPIC_FILTER = 8, - TEXTURE_FLAG_CONVERT_TO_LINEAR = 16, - TEXTURE_FLAG_MIRRORED_REPEAT = 32, /// Repeat texture, with alternate sections mirrored - TEXTURE_FLAG_USED_FOR_STREAMING = 2048, - TEXTURE_FLAGS_DEFAULT = TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS | TEXTURE_FLAG_FILTER - }; - - struct RenderTarget; - - struct Texture { - RID self; - - Texture *proxy; - Set proxy_owners; - - String path; - uint32_t flags; - int width, height, depth; - int alloc_width, alloc_height; - Image::Format format; - RenderingDevice::TextureType type; - - GLenum target; - GLenum gl_format_cache; - GLenum gl_internal_format_cache; - GLenum gl_type_cache; - - int data_size; - int total_data_size; - bool ignore_mipmaps; - - bool compressed; - - bool srgb; - - int mipmaps; - - bool resize_to_po2; - - bool active; - GLenum tex_id; - - uint16_t stored_cube_sides; - - RenderTarget *render_target; - - Vector> images; - - bool redraw_if_visible; - - RS::TextureDetectCallback detect_3d; - void *detect_3d_ud; - - RS::TextureDetectCallback detect_srgb; - void *detect_srgb_ud; - - RS::TextureDetectCallback detect_normal; - void *detect_normal_ud; - - // some silly opengl shenanigans where - // texture coords start from bottom left, means we need to draw render target textures upside down - // to be compatible with vulkan etc. - bool is_upside_down() const { - if (proxy) - return proxy->is_upside_down(); - - return render_target != nullptr; - } - - Texture() { - create(); - } - - _ALWAYS_INLINE_ Texture *get_ptr() { - if (proxy) { - return proxy; //->get_ptr(); only one level of indirection, else not inlining possible. - } else { - return this; - } - } - - ~Texture() { - destroy(); - - if (tex_id != 0) { - glDeleteTextures(1, &tex_id); - } - } - - void copy_from(const Texture &o) { - proxy = o.proxy; - flags = o.flags; - width = o.width; - height = o.height; - alloc_width = o.alloc_width; - alloc_height = o.alloc_height; - format = o.format; - type = o.type; - target = o.target; - data_size = o.data_size; - total_data_size = o.total_data_size; - ignore_mipmaps = o.ignore_mipmaps; - compressed = o.compressed; - mipmaps = o.mipmaps; - resize_to_po2 = o.resize_to_po2; - active = o.active; - tex_id = o.tex_id; - stored_cube_sides = o.stored_cube_sides; - render_target = o.render_target; - redraw_if_visible = o.redraw_if_visible; - detect_3d = o.detect_3d; - detect_3d_ud = o.detect_3d_ud; - detect_srgb = o.detect_srgb; - detect_srgb_ud = o.detect_srgb_ud; - detect_normal = o.detect_normal; - detect_normal_ud = o.detect_normal_ud; - - images.clear(); - } - - void create() { - proxy = nullptr; - flags = 0; - width = 0; - height = 0; - alloc_width = 0; - alloc_height = 0; - format = Image::FORMAT_L8; - type = RenderingDevice::TEXTURE_TYPE_2D; - target = 0; - data_size = 0; - total_data_size = 0; - ignore_mipmaps = false; - compressed = false; - mipmaps = 0; - resize_to_po2 = false; - active = false; - tex_id = 0; - stored_cube_sides = 0; - render_target = nullptr; - redraw_if_visible = false; - detect_3d = nullptr; - detect_3d_ud = nullptr; - detect_srgb = nullptr; - detect_srgb_ud = nullptr; - detect_normal = nullptr; - detect_normal_ud = nullptr; - } - void destroy() { - images.clear(); - - for (Set::Element *E = proxy_owners.front(); E; E = E->next()) { - E->get()->proxy = NULL; - } - - if (proxy) { - proxy->proxy_owners.erase(this); - } - } - - // texture state - void GLSetFilter(GLenum p_target, RS::CanvasItemTextureFilter p_filter) { - if (p_filter == state_filter) - return; - state_filter = p_filter; - GLint pmin = GL_LINEAR; // param min - GLint pmag = GL_LINEAR; // param mag - switch (state_filter) { - default: { - } break; - case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: { - pmin = GL_LINEAR_MIPMAP_LINEAR; - pmag = GL_LINEAR; - } break; - case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: { - pmin = GL_NEAREST; - pmag = GL_NEAREST; - } break; - case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: { - pmin = GL_NEAREST_MIPMAP_NEAREST; - pmag = GL_NEAREST; - } break; - } - glTexParameteri(p_target, GL_TEXTURE_MIN_FILTER, pmin); - glTexParameteri(p_target, GL_TEXTURE_MAG_FILTER, pmag); - } - void GLSetRepeat(RS::CanvasItemTextureRepeat p_repeat) { - if (p_repeat == state_repeat) - return; - state_repeat = p_repeat; - GLint prep = GL_CLAMP_TO_EDGE; // parameter repeat - switch (state_repeat) { - default: { - } break; - case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: { - prep = GL_REPEAT; - } break; - case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: { - prep = GL_MIRRORED_REPEAT; - } break; - } - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, prep); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, prep); - } - - private: - RS::CanvasItemTextureFilter state_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR; - RS::CanvasItemTextureRepeat state_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED; - }; - - mutable RID_PtrOwner texture_owner; - - Ref _get_gl_image_and_format(const Ref &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_force_decompress) const; - - void _texture_set_state_from_flags(Texture *p_tex); - - // new - RID texture_allocate() override; - void texture_2d_initialize(RID p_texture, const Ref &p_image) override; - void texture_2d_layered_initialize(RID p_texture, const Vector> &p_layers, RS::TextureLayeredType p_layered_type) override; - void texture_3d_initialize(RID p_texture, Image::Format, int p_width, int p_height, int p_depth, bool p_mipmaps, const Vector> &p_data) override; - void texture_proxy_initialize(RID p_texture, RID p_base) override; //all slices, then all the mipmaps, must be coherent - - void texture_2d_update(RID p_texture, const Ref &p_image, int p_layer = 0) override; - void texture_3d_update(RID p_texture, const Vector> &p_data) override {} - void texture_proxy_update(RID p_proxy, RID p_base) override {} - - void texture_2d_placeholder_initialize(RID p_texture) override; - void texture_2d_layered_placeholder_initialize(RID p_texture, RenderingServer::TextureLayeredType p_layered_type) override; - void texture_3d_placeholder_initialize(RID p_texture) override; - - Ref texture_2d_get(RID p_texture) const override; - Ref texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref(); } - Vector> texture_3d_get(RID p_texture) const override { return Vector>(); } - - void texture_replace(RID p_texture, RID p_by_texture) override; - //void texture_set_size_override(RID p_texture, int p_width, int p_height) override {} - - void texture_add_to_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} - void texture_remove_from_decal_atlas(RID p_texture, bool p_panorama_to_dp = false) override {} - - // old - uint32_t texture_get_width(RID p_texture) const; - uint32_t texture_get_height(RID p_texture) const; - -private: - RID texture_create(); - - //void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT); - void _texture_allocate_internal(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, RenderingDevice::TextureType p_type, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT); - - void texture_set_data(RID p_texture, const Ref &p_image, int p_layer = 0); - void texture_set_data_partial(RID p_texture, const Ref &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); - //Ref texture_get_data(RID p_texture, int p_layer = 0) const; - void texture_set_flags(RID p_texture, uint32_t p_flags); - uint32_t texture_get_flags(RID p_texture) const; - Image::Format texture_get_format(RID p_texture) const; - RenderingDevice::TextureType texture_get_type(RID p_texture) const; - uint32_t texture_get_texid(RID p_texture) const; - uint32_t texture_get_depth(RID p_texture) const; - void texture_set_size_override(RID p_texture, int p_width, int p_height) override; - - void texture_bind(RID p_texture, uint32_t p_texture_no); - - void texture_set_path(RID p_texture, const String &p_path) override; - String texture_get_path(RID p_texture) const override; - - void texture_set_shrink_all_x2_on_set_data(bool p_enable); - - void texture_debug_usage(List *r_info) override; - - RID texture_create_radiance_cubemap(RID p_source, int p_resolution = -1) const; - - void textures_keep_original(bool p_enable); - - void texture_set_proxy(RID p_texture, RID p_proxy); - Size2 texture_size_with_proxy(RID p_texture) override; - - void texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override; - void texture_set_detect_srgb_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata); - void texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) override; - void texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) override {} - - void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) override; - -public: - RID canvas_texture_allocate() override; - void canvas_texture_initialize(RID p_rid) override; - - void canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) override; - void canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_base_color, float p_shininess) override; - - void canvas_texture_set_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) override; - void canvas_texture_set_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) override; - - /* SKY API */ - // not sure if used in godot 4? - struct Sky { - RID self; - RID panorama; - GLuint radiance; - int radiance_size; - }; - - mutable RID_PtrOwner sky_owner; - - RID sky_create(); - void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size); - - // SHADER API - - struct Material; - - struct Shader { - RID self; - - RS::ShaderMode mode; - ShaderOpenGL *shader; - String code; - SelfList::List materials; - - Map uniforms; - - uint32_t texture_count; - - uint32_t custom_code_id; - uint32_t version; - - SelfList dirty_list; - - Map default_textures; - - Vector texture_hints; - - bool valid; - - String path; - - uint32_t index; - uint64_t last_pass; - - struct CanvasItem { - enum BlendMode { - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - BLEND_MODE_PMALPHA, - }; - - int blend_mode; - - enum LightMode { - LIGHT_MODE_NORMAL, - LIGHT_MODE_UNSHADED, - LIGHT_MODE_LIGHT_ONLY - }; - - int light_mode; - - // these flags are specifically for batching - // some of the logic is thus in rasterizer_storage.cpp - // we could alternatively set bitflags for each 'uses' and test on the fly - // defined in RasterizerStorageCommon::BatchFlags - unsigned int batch_flags; - - bool uses_screen_texture; - bool uses_screen_uv; - bool uses_time; - bool uses_modulate; - bool uses_color; - bool uses_vertex; - - // all these should disable item joining if used in a custom shader - bool uses_world_matrix; - bool uses_extra_matrix; - bool uses_projection_matrix; - bool uses_instance_custom; - - } canvas_item; - - struct Spatial { - enum BlendMode { - BLEND_MODE_MIX, - BLEND_MODE_ADD, - BLEND_MODE_SUB, - BLEND_MODE_MUL, - }; - - int blend_mode; - - enum DepthDrawMode { - DEPTH_DRAW_OPAQUE, - DEPTH_DRAW_ALWAYS, - DEPTH_DRAW_NEVER, - DEPTH_DRAW_ALPHA_PREPASS, - }; - - int depth_draw_mode; - - enum CullMode { - CULL_MODE_FRONT, - CULL_MODE_BACK, - CULL_MODE_DISABLED, - }; - - int cull_mode; - - bool uses_alpha; - bool uses_alpha_scissor; - bool unshaded; - bool no_depth_test; - bool uses_vertex; - bool uses_discard; - bool uses_sss; - bool uses_screen_texture; - bool uses_depth_texture; - bool uses_time; - bool uses_tangent; - bool uses_ensure_correct_normals; - bool writes_modelview_or_projection; - bool uses_vertex_lighting; - bool uses_world_coordinates; - - } spatial; - - struct Particles { - } particles; - - bool uses_vertex_time; - bool uses_fragment_time; - - Shader() : - dirty_list(this) { - shader = NULL; - valid = false; - custom_code_id = 0; - version = 1; - last_pass = 0; - } - }; - - mutable RID_PtrOwner shader_owner; - mutable SelfList::List _shader_dirty_list; - - void _shader_make_dirty(Shader *p_shader); - - RID shader_allocate() override; - void shader_initialize(RID p_rid) override; - - //RID shader_create() override; - - void shader_set_code(RID p_shader, const String &p_code) override; - String shader_get_code(RID p_shader) const override; - void shader_get_param_list(RID p_shader, List *p_param_list) const override; - - void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) override; - RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const override; - - RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); }; - - void shader_add_custom_define(RID p_shader, const String &p_define); - void shader_get_custom_defines(RID p_shader, Vector *p_defines) const; - void shader_remove_custom_define(RID p_shader, const String &p_define); - - void _update_shader(Shader *p_shader) const; - void update_dirty_shaders(); - - // new - Variant shader_get_param_default(RID p_material, const StringName &p_param) const override { return Variant(); } - - // COMMON MATERIAL API - - struct Material { - RID self; - Shader *shader; - Map params; - SelfList list; - SelfList dirty_list; - Vector> textures; - float line_width; - int render_priority; - - RID next_pass; - - uint32_t index; - uint64_t last_pass; - - // Map geometry_owners; - // Map instance_owners; - - bool can_cast_shadow_cache; - bool is_animated_cache; - - Material() : - list(this), - dirty_list(this) { - can_cast_shadow_cache = false; - is_animated_cache = false; - shader = NULL; - line_width = 1.0; - last_pass = 0; - render_priority = 0; - } - }; - - mutable SelfList::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_PtrOwner material_owner; - - // new - void material_get_instance_shader_parameters(RID p_material, List *r_parameters) override {} - void material_update_dependency(RID p_material, DependencyTracker *p_instance) override {} - - // old - RID material_allocate() override; - void material_initialize(RID p_rid) override; - - //RID material_create() override; - - void material_set_shader(RID p_material, RID p_shader) override; - RID material_get_shader(RID p_material) const; - - void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) override; - Variant material_get_param(RID p_material, const StringName &p_param) const override; - Variant material_get_param_default(RID p_material, const StringName &p_param) const; - - void material_set_line_width(RID p_material, float p_width); - void material_set_next_pass(RID p_material, RID p_next_material) override; - - bool material_is_animated(RID p_material) override; - bool material_casts_shadows(RID p_material) override; - bool material_uses_tangents(RID p_material); - bool material_uses_ensure_correct_normals(RID p_material); - - void material_add_instance_owner(RID p_material, DependencyTracker *p_instance); - void material_remove_instance_owner(RID p_material, DependencyTracker *p_instance); - - void material_set_render_priority(RID p_material, int priority) override; - - void update_dirty_materials(); - - /* MESH API */ - - RID mesh_allocate() override; - void mesh_initialize(RID p_rid) override; - void mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) override; - bool mesh_needs_instance(RID p_mesh, bool p_has_skeleton) override; - RID mesh_instance_create(RID p_base) override; - void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override; - void mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) override; - void mesh_instance_check_for_update(RID p_mesh_instance) override; - void update_mesh_instances() override; - void reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) override; - float reflection_probe_get_lod_threshold(RID p_probe) const override; - - void mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) override; - - int mesh_get_blend_shape_count(RID p_mesh) const override; - - void mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) override; - RS::BlendShapeMode mesh_get_blend_shape_mode(RID p_mesh) const override; - - void mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) override; - void mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) override; - void mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector &p_data) override; - - void mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) override; - RID mesh_surface_get_material(RID p_mesh, int p_surface) const override; - - RS::SurfaceData mesh_get_surface(RID p_mesh, int p_surface) const override; - int mesh_get_surface_count(RID p_mesh) const override; - - void mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) override; - AABB mesh_get_custom_aabb(RID p_mesh) const override; - - AABB mesh_get_aabb(RID p_mesh, RID p_skeleton = RID()) override; - void mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) override; - void mesh_clear(RID p_mesh) override; - - /* MULTIMESH API */ - - RID multimesh_allocate() override; - void multimesh_initialize(RID p_rid) override; - void multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors = false, bool p_use_custom_data = false) override; - int multimesh_get_instance_count(RID p_multimesh) const override; - - void multimesh_set_mesh(RID p_multimesh, RID p_mesh) override; - void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) override; - void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) override; - void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) override; - void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) override; - - RID multimesh_get_mesh(RID p_multimesh) const override; - AABB multimesh_get_aabb(RID p_multimesh) const override; - - Transform3D multimesh_instance_get_transform(RID p_multimesh, int p_index) const override; - Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const override; - Color multimesh_instance_get_color(RID p_multimesh, int p_index) const override; - Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const override; - void multimesh_set_buffer(RID p_multimesh, const Vector &p_buffer) override; - Vector multimesh_get_buffer(RID p_multimesh) const override; - - void multimesh_set_visible_instances(RID p_multimesh, int p_visible) override; - int multimesh_get_visible_instances(RID p_multimesh) const override; - - /* SKELETON API */ - - RID skeleton_allocate() override; - void skeleton_initialize(RID p_rid) override; - void skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) override; - void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) override; - int skeleton_get_bone_count(RID p_skeleton) const override; - void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) override; - Transform3D skeleton_bone_get_transform(RID p_skeleton, int p_bone) const override; - void skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) override; - Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const override; - - /* Light API */ - - RID directional_light_allocate() override; - void directional_light_initialize(RID p_rid) override; - RID omni_light_allocate() override; - void omni_light_initialize(RID p_rid) override; - RID spot_light_allocate() override; - void spot_light_initialize(RID p_rid) override; - RID reflection_probe_allocate() override; - void reflection_probe_initialize(RID p_rid) override; - - void light_set_color(RID p_light, const Color &p_color) override; - void light_set_param(RID p_light, RS::LightParam p_param, float p_value) override; - void light_set_shadow(RID p_light, bool p_enabled) override; - void light_set_shadow_color(RID p_light, const Color &p_color) override; - void light_set_projector(RID p_light, RID p_texture) override; - void light_set_negative(RID p_light, bool p_enable) override; - void light_set_cull_mask(RID p_light, uint32_t p_mask) override; - void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) override; - void light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) override; - void light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) override; - - void light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) override; - - void light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) override; - void light_directional_set_blend_splits(RID p_light, bool p_enable) override; - bool light_directional_get_blend_splits(RID p_light) const override; - void light_directional_set_sky_only(RID p_light, bool p_sky_only) override; - bool light_directional_is_sky_only(RID p_light) const override; - - RS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light) override; - RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override; - - bool light_has_shadow(RID p_light) const override; - bool light_has_projector(RID p_light) const override; - - RS::LightType light_get_type(RID p_light) const override; - AABB light_get_aabb(RID p_light) const override; - float light_get_param(RID p_light, RS::LightParam p_param) override; - Color light_get_color(RID p_light) override; - RS::LightBakeMode light_get_bake_mode(RID p_light) override; - uint32_t light_get_max_sdfgi_cascade(RID p_light) override; - uint64_t light_get_version(RID p_light) const override; - - /* PROBE API */ - - void reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) override; - void reflection_probe_set_intensity(RID p_probe, float p_intensity) override; - void reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) override; - void reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) override; - void reflection_probe_set_ambient_energy(RID p_probe, float p_energy) override; - void reflection_probe_set_max_distance(RID p_probe, float p_distance) override; - void reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) override; - void reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) override; - void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override; - void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override; - void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override; - void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override; - void reflection_probe_set_resolution(RID p_probe, int p_resolution) override; - - AABB reflection_probe_get_aabb(RID p_probe) const override; - RS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const override; - uint32_t reflection_probe_get_cull_mask(RID p_probe) const override; - Vector3 reflection_probe_get_extents(RID p_probe) const override; - Vector3 reflection_probe_get_origin_offset(RID p_probe) const override; - float reflection_probe_get_origin_max_distance(RID p_probe) const override; - bool reflection_probe_renders_shadows(RID p_probe) const override; - - void base_update_dependency(RID p_base, DependencyTracker *p_instance) override; - void skeleton_update_dependency(RID p_base, DependencyTracker *p_instance) override; - - /* DECAL API */ - - RID decal_allocate() override; - void decal_initialize(RID p_rid) override; - void decal_set_extents(RID p_decal, const Vector3 &p_extents) override; - void decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) override; - void decal_set_emission_energy(RID p_decal, float p_energy) override; - void decal_set_albedo_mix(RID p_decal, float p_mix) override; - void decal_set_modulate(RID p_decal, const Color &p_modulate) override; - void decal_set_cull_mask(RID p_decal, uint32_t p_layers) override; - void decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) override; - void decal_set_fade(RID p_decal, float p_above, float p_below) override; - void decal_set_normal_fade(RID p_decal, float p_fade) override; - - AABB decal_get_aabb(RID p_decal) const override; - - /* VOXEL GI API */ - - RID voxel_gi_allocate() override; - void voxel_gi_initialize(RID p_rid) override; - void voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector &p_octree_cells, const Vector &p_data_cells, const Vector &p_distance_field, const Vector &p_level_counts) override; - - AABB voxel_gi_get_bounds(RID p_voxel_gi) const override; - Vector3i voxel_gi_get_octree_size(RID p_voxel_gi) const override; - Vector voxel_gi_get_octree_cells(RID p_voxel_gi) const override; - Vector voxel_gi_get_data_cells(RID p_voxel_gi) const override; - Vector voxel_gi_get_distance_field(RID p_voxel_gi) const override; - - Vector voxel_gi_get_level_counts(RID p_voxel_gi) const override; - Transform3D voxel_gi_get_to_cell_xform(RID p_voxel_gi) const override; - - void voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_dynamic_range(RID p_voxel_gi) const override; - - void voxel_gi_set_propagation(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_propagation(RID p_voxel_gi) const override; - - void voxel_gi_set_energy(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_energy(RID p_voxel_gi) const override; - - void voxel_gi_set_bias(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_bias(RID p_voxel_gi) const override; - - void voxel_gi_set_normal_bias(RID p_voxel_gi, float p_range) override; - float voxel_gi_get_normal_bias(RID p_voxel_gi) const override; - - void voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) override; - bool voxel_gi_is_interior(RID p_voxel_gi) const override; - - void voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) override; - bool voxel_gi_is_using_two_bounces(RID p_voxel_gi) const override; - - void voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) override; - float voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const override; - - uint32_t voxel_gi_get_version(RID p_voxel_gi) override; - - /* LIGHTMAP CAPTURE */ - RID lightmap_allocate() override; - void lightmap_initialize(RID p_rid) override; - void lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) override; - void lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) override; - void lightmap_set_probe_interior(RID p_lightmap, bool p_interior) override; - void lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) override; - PackedVector3Array lightmap_get_probe_capture_points(RID p_lightmap) const override; - PackedColorArray lightmap_get_probe_capture_sh(RID p_lightmap) const override; - PackedInt32Array lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const override; - PackedInt32Array lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const override; - AABB lightmap_get_aabb(RID p_lightmap) const override; - void lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) override; - bool lightmap_is_interior(RID p_lightmap) const override; - void lightmap_set_probe_capture_update_speed(float p_speed) override; - float lightmap_get_probe_capture_update_speed() const override; - - /* OCCLUDER */ - - void occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices); - - /* PARTICLES */ - - RID particles_allocate() override; - void particles_initialize(RID p_rid) override; - void particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) override; - void particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) override; - void particles_set_emitting(RID p_particles, bool p_emitting) override; - void particles_set_amount(RID p_particles, int p_amount) override; - void particles_set_lifetime(RID p_particles, double p_lifetime) override; - void particles_set_one_shot(RID p_particles, bool p_one_shot) override; - void particles_set_pre_process_time(RID p_particles, double p_time) override; - void particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) override; - void particles_set_randomness_ratio(RID p_particles, real_t p_ratio) override; - void particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) override; - void particles_set_speed_scale(RID p_particles, double p_scale) override; - void particles_set_use_local_coordinates(RID p_particles, bool p_enable) override; - void particles_set_process_material(RID p_particles, RID p_material) override; - void particles_set_fixed_fps(RID p_particles, int p_fps) override; - void particles_set_interpolate(RID p_particles, bool p_enable) override; - void particles_set_fractional_delta(RID p_particles, bool p_enable) override; - void particles_set_subemitter(RID p_particles, RID p_subemitter_particles) override; - void particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) override; - void particles_set_collision_base_size(RID p_particles, real_t p_size) override; - - void particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) override; - - void particles_set_trails(RID p_particles, bool p_enable, double p_length) override; - void particles_set_trail_bind_poses(RID p_particles, const Vector &p_bind_poses) override; - - void particles_restart(RID p_particles) override; - - void particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) override; - - void particles_set_draw_passes(RID p_particles, int p_count) override; - void particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) override; - - void particles_request_process(RID p_particles) override; - AABB particles_get_current_aabb(RID p_particles) override; - AABB particles_get_aabb(RID p_particles) const override; - - void particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) override; - - bool particles_get_emitting(RID p_particles) override; - int particles_get_draw_passes(RID p_particles) const override; - RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const override; - - void particles_add_collision(RID p_particles, RID p_instance) override; - void particles_remove_collision(RID p_particles, RID p_instance) override; - - void particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) override; - - void update_particles() override; - - /* PARTICLES COLLISION */ - - RID particles_collision_allocate() override; - void particles_collision_initialize(RID p_rid) override; - void particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) override; - void particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) override; - void particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) override; - void particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) override; - void particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) override; - void particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) override; - void particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) override; - void particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) override; - void particles_collision_height_field_update(RID p_particles_collision) override; - void particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) override; - AABB particles_collision_get_aabb(RID p_particles_collision) const override; - bool particles_collision_is_heightfield(RID p_particles_collision) const override; - RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const override; - - RID particles_collision_instance_create(RID p_collision) override; - void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override; - void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override; - - /* VISIBILITY NOTIFIER */ - RID visibility_notifier_allocate() override; - void visibility_notifier_initialize(RID p_notifier) override; - void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) override; - void visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) override; - - AABB visibility_notifier_get_aabb(RID p_notifier) const override; - void visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) override; - - /* GLOBAL VARIABLES */ - - void global_variable_add(const StringName &p_name, RS::GlobalVariableType p_type, const Variant &p_value) override; - void global_variable_remove(const StringName &p_name) override; - Vector global_variable_get_list() const override; - - void global_variable_set(const StringName &p_name, const Variant &p_value) override; - void global_variable_set_override(const StringName &p_name, const Variant &p_value) override; - Variant global_variable_get(const StringName &p_name) const override; - RS::GlobalVariableType global_variable_get_type(const StringName &p_name) const override; - - void global_variables_load_settings(bool p_load_textures = true) override; - void global_variables_clear() override; - - int32_t global_variables_instance_allocate(RID p_instance) override; - void global_variables_instance_free(RID p_instance) override; - void global_variables_instance_update(RID p_instance, int p_index, const Variant &p_value) override; - - bool particles_is_inactive(RID p_particles) const override; - - // RENDER TARGET - - struct RenderTarget { - RID self; - GLuint fbo; - GLuint color; - GLuint depth; - - GLuint multisample_fbo; - GLuint multisample_color; - GLuint multisample_depth; - bool multisample_active; - - struct Effect { - GLuint fbo; - int width; - int height; - - GLuint color; - - Effect() : - fbo(0), - width(0), - height(0), - color(0) { - } - }; - - Effect copy_screen_effect; - - struct MipMaps { - struct Size { - GLuint fbo; - GLuint color; - int width; - int height; - }; - - Vector sizes; - GLuint color; - int levels; - - MipMaps() : - color(0), - levels(0) { - } - }; - - MipMaps mip_maps[2]; - - struct External { - GLuint fbo; - GLuint color; - GLuint depth; - RID texture; - - External() : - fbo(0), - color(0), - depth(0) { - } - } external; - - int x, y, width, height; - - bool flags[RENDER_TARGET_FLAG_MAX]; - - // instead of allocating sized render targets immediately, - // defer this for faster startup - bool allocate_is_dirty = false; - bool used_in_frame; - RS::ViewportMSAA msaa; - - bool use_fxaa; - bool use_debanding; - - RID texture; - - bool used_dof_blur_near; - bool mip_maps_allocated; - - Color clear_color; - bool clear_requested; - - RenderTarget() : - fbo(0), - color(0), - depth(0), - multisample_fbo(0), - multisample_color(0), - multisample_depth(0), - multisample_active(false), - x(0), - y(0), - width(0), - height(0), - used_in_frame(false), - msaa(RS::VIEWPORT_MSAA_DISABLED), - use_fxaa(false), - use_debanding(false), - used_dof_blur_near(false), - mip_maps_allocated(false), - clear_color(Color(1, 1, 1, 1)), - clear_requested(false) { - for (int i = 0; i < RENDER_TARGET_FLAG_MAX; ++i) { - flags[i] = false; - } - external.fbo = 0; - } - }; - - mutable RID_PtrOwner render_target_owner; - - void _render_target_clear(RenderTarget *rt); - void _render_target_allocate(RenderTarget *rt); - void _set_current_render_target(RID p_render_target); - - RID render_target_create() override; - void render_target_set_position(RID p_render_target, int p_x, int p_y) override; - void render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) override; - RID render_target_get_texture(RID p_render_target) override; - void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) override; - - void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) override; - bool render_target_was_used(RID p_render_target) override; - void render_target_clear_used(RID p_render_target); - void render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa); - void render_target_set_use_fxaa(RID p_render_target, bool p_fxaa); - void render_target_set_use_debanding(RID p_render_target, bool p_debanding); - - // new - void render_target_set_as_unused(RID p_render_target) override { - render_target_clear_used(p_render_target); - } - - void render_target_request_clear(RID p_render_target, const Color &p_clear_color) override; - bool render_target_is_clear_requested(RID p_render_target) override; - Color render_target_get_clear_request_color(RID p_render_target) override; - void render_target_disable_clear_request(RID p_render_target) override; - void render_target_do_clear_request(RID p_render_target) override; - - void render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) override; - Rect2i render_target_get_sdf_rect(RID p_render_target) const override; - void render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) override; - - // access from canvas - // RenderTarget * render_target_get(RID p_render_target); - - /* CANVAS SHADOW */ - - struct CanvasLightShadow { - RID self; - int size; - int height; - GLuint fbo; - GLuint depth; - GLuint distance; //for older devices - }; - - RID_PtrOwner canvas_light_shadow_owner; - - RID canvas_light_shadow_buffer_create(int p_width); - - /* LIGHT SHADOW MAPPING */ - /* - struct CanvasOccluder { - RID self; - - GLuint vertex_id; // 0 means, unconfigured - GLuint index_id; // 0 means, unconfigured - LocalVector lines; - int len; - }; - - RID_Owner canvas_occluder_owner; - - RID canvas_light_occluder_create(); - void canvas_light_occluder_set_polylines(RID p_occluder, const LocalVector &p_lines); -*/ - - RS::InstanceType get_base_type(RID p_rid) const override; - - bool free(RID p_rid) override; - - struct Frame { - RenderTarget *current_rt; - - // these 2 may have been superceded by the equivalents in the render target. - // these may be able to be removed. - bool clear_request; - Color clear_request_color; - - float time[4]; - float delta; - uint64_t count; - - Frame() { - // current_rt = nullptr; - // clear_request = false; - } - } frame; - - void initialize(); - void finalize(); - - void _copy_screen(); - - void update_memory_info() override; - uint64_t get_rendering_info(RS::RenderingInfo p_info) override; - - bool has_os_feature(const String &p_feature) const override; - - void update_dirty_resources() override; - - void set_debug_generate_wireframes(bool p_generate) override; - - // void render_info_begin_capture() override; - // void render_info_end_capture() override; - // int get_captured_render_info(RS::RenderInfo p_info) override; - - // int get_render_info(RS::RenderInfo p_info) override; - String get_video_adapter_name() const override; - String get_video_adapter_vendor() const override; - - void capture_timestamps_begin() override {} - void capture_timestamp(const String &p_name) override {} - uint32_t get_captured_timestamps_count() const override { - return 0; - } - uint64_t get_captured_timestamps_frame() const override { - return 0; - } - uint64_t get_captured_timestamp_gpu_time(uint32_t p_index) const override { - return 0; - } - uint64_t get_captured_timestamp_cpu_time(uint32_t p_index) const override { - return 0; - } - String get_captured_timestamp_name(uint32_t p_index) const override { - return String(); - } - - // make access easier to these - struct Dimensions { - // render target - int rt_width; - int rt_height; - - // window - int win_width; - int win_height; - Dimensions() { - rt_width = 0; - rt_height = 0; - win_width = 0; - win_height = 0; - } - } _dims; - - void buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target = GL_ARRAY_BUFFER, GLenum p_usage = GL_DYNAMIC_DRAW, bool p_optional_orphan = false) const; - bool safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const; - - void bind_framebuffer(GLuint framebuffer) { - glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); - } - - void bind_framebuffer_system() { - glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageOpenGL::system_fbo); - } - - RasterizerStorageOpenGL(); -}; - -inline bool RasterizerStorageOpenGL::safe_buffer_sub_data(unsigned int p_total_buffer_size, GLenum p_target, unsigned int p_offset, unsigned int p_data_size, const void *p_data, unsigned int &r_offset_after) const { - r_offset_after = p_offset + p_data_size; -#ifdef DEBUG_ENABLED - // we are trying to write across the edge of the buffer - if (r_offset_after > p_total_buffer_size) - return false; -#endif - glBufferSubData(p_target, p_offset, p_data_size, p_data); - return true; -} - -// standardize the orphan / upload in one place so it can be changed per platform as necessary, and avoid future -// bugs causing pipeline stalls -inline void RasterizerStorageOpenGL::buffer_orphan_and_upload(unsigned int p_buffer_size, unsigned int p_offset, unsigned int p_data_size, const void *p_data, GLenum p_target, GLenum p_usage, bool p_optional_orphan) const { - // Orphan the buffer to avoid CPU/GPU sync points caused by glBufferSubData - // Was previously #ifndef GLES_OVER_GL however this causes stalls on desktop mac also (and possibly other) - if (!p_optional_orphan || (config.should_orphan)) { - glBufferData(p_target, p_buffer_size, NULL, p_usage); -#ifdef RASTERIZER_EXTRA_CHECKS - // fill with garbage off the end of the array - if (p_buffer_size) { - unsigned int start = p_offset + p_data_size; - unsigned int end = start + 1024; - if (end < p_buffer_size) { - uint8_t *garbage = (uint8_t *)alloca(1024); - for (int n = 0; n < 1024; n++) { - garbage[n] = Math::random(0, 255); - } - glBufferSubData(p_target, start, 1024, garbage); - } - } -#endif - } - RAST_DEV_DEBUG_ASSERT((p_offset + p_data_size) <= p_buffer_size); - glBufferSubData(p_target, p_offset, p_data_size, p_data); -} - -#endif // OPENGL_BACKEND_ENABLED - -#endif // RASTERIZER_STORAGE_OPENGL_H diff --git a/drivers/opengl/shader_compiler_opengl.cpp b/drivers/opengl/shader_compiler_opengl.cpp deleted file mode 100644 index 9638626d78..0000000000 --- a/drivers/opengl/shader_compiler_opengl.cpp +++ /dev/null @@ -1,1120 +0,0 @@ -/*************************************************************************/ -/* shader_compiler_opengl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "shader_compiler_opengl.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/config/project_settings.h" -#include "core/os/os.h" -#include "core/string/string_buffer.h" -#include "core/string/string_builder.h" - -#define SL ShaderLanguage - -static String _mktab(int p_level) { - String tb; - for (int i = 0; i < p_level; i++) { - tb += "\t"; - } - - return tb; -} - -static String _typestr(SL::DataType p_type) { - return ShaderLanguage::get_datatype_name(p_type); -} - -static String _prestr(SL::DataPrecision p_pres) { - switch (p_pres) { - case SL::PRECISION_LOWP: - return "lowp "; - case SL::PRECISION_MEDIUMP: - return "mediump "; - case SL::PRECISION_HIGHP: - return "highp "; - case SL::PRECISION_DEFAULT: - return ""; - } - return ""; -} - -static String _qualstr(SL::ArgumentQualifier p_qual) { - switch (p_qual) { - case SL::ARGUMENT_QUALIFIER_IN: - return "in "; - case SL::ARGUMENT_QUALIFIER_OUT: - return "out "; - case SL::ARGUMENT_QUALIFIER_INOUT: - return "inout "; - } - return ""; -} - -static String _opstr(SL::Operator p_op) { - return SL::get_operator_text(p_op); -} - -static String _mkid(const String &p_id) { - String id = "m_" + p_id.replace("__", "_dus_"); - return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl -} - -static String f2sp0(float p_float) { - String num = rtoss(p_float); - if (num.find(".") == -1 && num.find("e") == -1) { - num += ".0"; - } - return num; -} - -static String get_constant_text(SL::DataType p_type, const Vector &p_values) { - switch (p_type) { - case SL::TYPE_BOOL: - return p_values[0].boolean ? "true" : "false"; - case SL::TYPE_BVEC2: - case SL::TYPE_BVEC3: - case SL::TYPE_BVEC4: { - StringBuffer<> text; - - text += "bvec"; - text += itos(p_type - SL::TYPE_BOOL + 1); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += p_values[i].boolean ? "true" : "false"; - } - text += ")"; - return text.as_string(); - } - - // GLSL ES 2 doesn't support uints, so we just use signed ints instead... - case SL::TYPE_UINT: - return itos(p_values[0].uint); - case SL::TYPE_UVEC2: - case SL::TYPE_UVEC3: - case SL::TYPE_UVEC4: { - StringBuffer<> text; - - text += "ivec"; - text += itos(p_type - SL::TYPE_UINT + 1); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += itos(p_values[i].uint); - } - text += ")"; - return text.as_string(); - - } break; - - case SL::TYPE_INT: - return itos(p_values[0].sint); - case SL::TYPE_IVEC2: - case SL::TYPE_IVEC3: - case SL::TYPE_IVEC4: { - StringBuffer<> text; - - text += "ivec"; - text += itos(p_type - SL::TYPE_INT + 1); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += itos(p_values[i].sint); - } - text += ")"; - return text.as_string(); - - } break; - case SL::TYPE_FLOAT: - return f2sp0(p_values[0].real); - case SL::TYPE_VEC2: - case SL::TYPE_VEC3: - case SL::TYPE_VEC4: { - StringBuffer<> text; - - text += "vec"; - text += itos(p_type - SL::TYPE_FLOAT + 1); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += f2sp0(p_values[i].real); - } - text += ")"; - return text.as_string(); - - } break; - case SL::TYPE_MAT2: - case SL::TYPE_MAT3: - case SL::TYPE_MAT4: { - StringBuffer<> text; - - text += "mat"; - text += itos(p_type - SL::TYPE_MAT2 + 2); - text += "("; - - for (int i = 0; i < p_values.size(); i++) { - if (i > 0) - text += ","; - - text += f2sp0(p_values[i].real); - } - text += ")"; - return text.as_string(); - - } break; - default: - ERR_FAIL_V(String()); - } -} - -void ShaderCompilerOpenGL::_dump_function_deps(SL::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, StringBuilder &r_to_add, Set &r_added) { - int fidx = -1; - - for (int i = 0; i < p_node->functions.size(); i++) { - if (p_node->functions[i].name == p_for_func) { - fidx = i; - break; - } - } - - ERR_FAIL_COND(fidx == -1); - - for (Set::Element *E = p_node->functions[fidx].uses_function.front(); E; E = E->next()) { - if (r_added.has(E->get())) { - continue; - } - - _dump_function_deps(p_node, E->get(), p_func_code, r_to_add, r_added); - - SL::FunctionNode *fnode = NULL; - - for (int i = 0; i < p_node->functions.size(); i++) { - if (p_node->functions[i].name == E->get()) { - fnode = p_node->functions[i].function; - break; - } - } - - ERR_FAIL_COND(!fnode); - - r_to_add += "\n"; - - StringBuffer<128> header; - - header += _typestr(fnode->return_type); - header += " "; - header += _mkid(fnode->name); - header += "("; - - for (int i = 0; i < fnode->arguments.size(); i++) { - if (i > 0) - header += ", "; - - header += _qualstr(fnode->arguments[i].qualifier); - header += _prestr(fnode->arguments[i].precision); - header += _typestr(fnode->arguments[i].type); - header += " "; - header += _mkid(fnode->arguments[i].name); - } - - header += ")\n"; - r_to_add += header.as_string(); - r_to_add += p_func_code[E->get()]; - - r_added.insert(E->get()); - } -} - -String ShaderCompilerOpenGL::_dump_node_code(SL::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope) { - StringBuilder code; - - switch (p_node->type) { - default: { - } break; - case SL::Node::TYPE_SHADER: { - SL::ShaderNode *snode = (SL::ShaderNode *)p_node; - - for (int i = 0; i < snode->render_modes.size(); i++) { - if (p_default_actions.render_mode_defines.has(snode->render_modes[i]) && !used_rmode_defines.has(snode->render_modes[i])) { - r_gen_code.custom_defines.push_back(p_default_actions.render_mode_defines[snode->render_modes[i]].utf8()); - used_rmode_defines.insert(snode->render_modes[i]); - } - - if (p_actions.render_mode_flags.has(snode->render_modes[i])) { - *p_actions.render_mode_flags[snode->render_modes[i]] = true; - } - - if (p_actions.render_mode_values.has(snode->render_modes[i])) { - Pair &p = p_actions.render_mode_values[snode->render_modes[i]]; - *p.first = p.second; - } - } - - int max_texture_uniforms = 0; - int max_uniforms = 0; - - for (Map::Element *E = snode->uniforms.front(); E; E = E->next()) { - if (SL::is_sampler_type(E->get().type)) - max_texture_uniforms++; - else - max_uniforms++; - } - - r_gen_code.texture_uniforms.resize(max_texture_uniforms); - r_gen_code.texture_hints.resize(max_texture_uniforms); - - r_gen_code.uniforms.resize(max_uniforms + max_texture_uniforms); - - StringBuilder vertex_global; - StringBuilder fragment_global; - - // uniforms - - for (Map::Element *E = snode->uniforms.front(); E; E = E->next()) { - StringBuffer<> uniform_code; - - // use highp if no precision is specified to prevent different default values in fragment and vertex shader - SL::DataPrecision precision = E->get().precision; - if (precision == SL::PRECISION_DEFAULT && E->get().type != SL::TYPE_BOOL) { - precision = SL::PRECISION_HIGHP; - } - - uniform_code += "uniform "; - uniform_code += _prestr(precision); - uniform_code += _typestr(E->get().type); - uniform_code += " "; - uniform_code += _mkid(E->key()); - uniform_code += ";\n"; - - if (SL::is_sampler_type(E->get().type)) { - 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.write[E->get().order] = E->key(); - } - - vertex_global += uniform_code.as_string(); - fragment_global += uniform_code.as_string(); - - p_actions.uniforms->insert(E->key(), E->get()); - } - - // varyings - - for (Map::Element *E = snode->varyings.front(); E; E = E->next()) { - StringBuffer<> varying_code; - - varying_code += "varying "; - varying_code += _prestr(E->get().precision); - varying_code += _typestr(E->get().type); - varying_code += " "; - varying_code += _mkid(E->key()); - if (E->get().array_size > 0) { - varying_code += "["; - varying_code += itos(E->get().array_size); - varying_code += "]"; - } - varying_code += ";\n"; - - String final_code = varying_code.as_string(); - - vertex_global += final_code; - fragment_global += final_code; - } - - // constants - - for (int i = 0; i < snode->vconstants.size(); i++) { - String gcode; - gcode += "const "; - gcode += _prestr(snode->vconstants[i].precision); - gcode += _typestr(snode->vconstants[i].type); - gcode += " " + _mkid(String(snode->vconstants[i].name)); - gcode += "="; - gcode += _dump_node_code(snode->vconstants[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - gcode += ";\n"; - vertex_global += gcode; - fragment_global += gcode; - } - - // functions - - Map function_code; - - for (int i = 0; i < snode->functions.size(); i++) { - SL::FunctionNode *fnode = snode->functions[i].function; - current_func_name = fnode->name; - function_code[fnode->name] = _dump_node_code(fnode->body, 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } - - Set added_vertex; - Set added_fragment; - - for (int i = 0; i < snode->functions.size(); i++) { - SL::FunctionNode *fnode = snode->functions[i].function; - - current_func_name = fnode->name; - - if (fnode->name == vertex_name) { - _dump_function_deps(snode, fnode->name, function_code, vertex_global, added_vertex); - r_gen_code.vertex = function_code[vertex_name]; - - } else if (fnode->name == fragment_name) { - _dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment); - r_gen_code.fragment = function_code[fragment_name]; - - } else if (fnode->name == light_name) { - _dump_function_deps(snode, fnode->name, function_code, fragment_global, added_fragment); - r_gen_code.light = function_code[light_name]; - } - } - - r_gen_code.vertex_global = vertex_global.as_string(); - r_gen_code.fragment_global = fragment_global.as_string(); - - } break; - - case SL::Node::TYPE_FUNCTION: { - } break; - - case SL::Node::TYPE_BLOCK: { - SL::BlockNode *bnode = (SL::BlockNode *)p_node; - - if (!bnode->single_statement) { - code += _mktab(p_level - 1); - code += "{\n"; - } - - for (int i = 0; i < bnode->statements.size(); i++) { - String statement_code = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - - if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) { - code += statement_code; - } else { - code += _mktab(p_level); - code += statement_code; - code += ";\n"; - } - } - - if (!bnode->single_statement) { - code += _mktab(p_level - 1); - code += "}\n"; - } - } break; - - case SL::Node::TYPE_VARIABLE_DECLARATION: { - SL::VariableDeclarationNode *var_dec_node = (SL::VariableDeclarationNode *)p_node; - - StringBuffer<> declaration; - if (var_dec_node->is_const) { - declaration += "const "; - } - declaration += _prestr(var_dec_node->precision); - declaration += _typestr(var_dec_node->datatype); - - for (int i = 0; i < var_dec_node->declarations.size(); i++) { - if (i > 0) { - declaration += ","; - } - - declaration += " "; - - declaration += _mkid(var_dec_node->declarations[i].name); - - if (var_dec_node->declarations[i].initializer) { - declaration += " = "; - declaration += _dump_node_code(var_dec_node->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - } - - code += declaration.as_string(); - } break; - - case SL::Node::TYPE_VARIABLE: { - SL::VariableNode *var_node = (SL::VariableNode *)p_node; - - if (p_assigning && p_actions.write_flag_pointers.has(var_node->name)) { - *p_actions.write_flag_pointers[var_node->name] = true; - } - - if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { - String define = p_default_actions.usage_defines[var_node->name]; - String node_name = define.substr(1, define.length()); - - if (define.begins_with("@")) { - define = p_default_actions.usage_defines[node_name]; - } - - if (!used_name_defines.has(node_name)) { - r_gen_code.custom_defines.push_back(define.utf8()); - } - used_name_defines.insert(var_node->name); - } - - if (p_actions.usage_flag_pointers.has(var_node->name) && !used_flag_pointers.has(var_node->name)) { - *p_actions.usage_flag_pointers[var_node->name] = true; - used_flag_pointers.insert(var_node->name); - } - - if (p_default_actions.renames.has(var_node->name)) { - code += p_default_actions.renames[var_node->name]; - } else { - code += _mkid(var_node->name); - } - - if (var_node->name == time_name) { - if (current_func_name == vertex_name) { - r_gen_code.uses_vertex_time = true; - } - if (current_func_name == fragment_name || current_func_name == light_name) { - r_gen_code.uses_fragment_time = true; - } - } - } break; - case SL::Node::TYPE_ARRAY_DECLARATION: { - SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node; - - StringBuffer<> declaration; - declaration += _prestr(arr_dec_node->precision); - declaration += _typestr(arr_dec_node->datatype); - - for (int i = 0; i < arr_dec_node->declarations.size(); i++) { - if (i > 0) { - declaration += ","; - } - - declaration += " "; - - declaration += _mkid(arr_dec_node->declarations[i].name); - declaration += "["; - declaration += itos(arr_dec_node->declarations[i].size); - declaration += "]"; - } - - code += declaration.as_string(); - } break; - case SL::Node::TYPE_ARRAY: { - SL::ArrayNode *arr_node = (SL::ArrayNode *)p_node; - - if (p_assigning && p_actions.write_flag_pointers.has(arr_node->name)) { - *p_actions.write_flag_pointers[arr_node->name] = true; - } - - if (p_default_actions.usage_defines.has(arr_node->name) && !used_name_defines.has(arr_node->name)) { - String define = p_default_actions.usage_defines[arr_node->name]; - String node_name = define.substr(1, define.length()); - - if (define.begins_with("@")) { - define = p_default_actions.usage_defines[node_name]; - } - - if (!used_name_defines.has(node_name)) { - r_gen_code.custom_defines.push_back(define.utf8()); - } - used_name_defines.insert(arr_node->name); - } - - if (p_actions.usage_flag_pointers.has(arr_node->name) && !used_flag_pointers.has(arr_node->name)) { - *p_actions.usage_flag_pointers[arr_node->name] = true; - used_flag_pointers.insert(arr_node->name); - } - - if (p_default_actions.renames.has(arr_node->name)) { - code += p_default_actions.renames[arr_node->name]; - } else { - code += _mkid(arr_node->name); - } - - if (arr_node->call_expression != NULL) { - code += "."; - code += _dump_node_code(arr_node->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning, false); - } - - if (arr_node->index_expression != NULL) { - code += "["; - code += _dump_node_code(arr_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "]"; - } - - if (arr_node->name == time_name) { - if (current_func_name == vertex_name) { - r_gen_code.uses_vertex_time = true; - } - if (current_func_name == fragment_name || current_func_name == light_name) { - r_gen_code.uses_fragment_time = true; - } - } - - } break; - case SL::Node::TYPE_CONSTANT: { - SL::ConstantNode *const_node = (SL::ConstantNode *)p_node; - - return get_constant_text(const_node->datatype, const_node->values); - } break; - - case SL::Node::TYPE_OPERATOR: { - SL::OperatorNode *op_node = (SL::OperatorNode *)p_node; - - switch (op_node->op) { - case SL::OP_ASSIGN: - case SL::OP_ASSIGN_ADD: - case SL::OP_ASSIGN_SUB: - case SL::OP_ASSIGN_MUL: - case SL::OP_ASSIGN_DIV: - case SL::OP_ASSIGN_SHIFT_LEFT: - case SL::OP_ASSIGN_SHIFT_RIGHT: - case SL::OP_ASSIGN_BIT_AND: - case SL::OP_ASSIGN_BIT_OR: - case SL::OP_ASSIGN_BIT_XOR: { - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true); - code += " "; - code += _opstr(op_node->op); - code += " "; - 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: { - String a = _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - String n = _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += a + " = " + n + " == 0 ? 0 : "; - code += a + " - " + n + " * (" + a + " / " + n + ")"; - } break; - - case SL::OP_BIT_INVERT: - case SL::OP_NEGATE: - case SL::OP_NOT: - case SL::OP_DECREMENT: - case SL::OP_INCREMENT: { - code += _opstr(op_node->op); - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } break; - - case SL::OP_POST_DECREMENT: - case SL::OP_POST_INCREMENT: { - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += _opstr(op_node->op); - } break; - - case SL::OP_CALL: - case SL::OP_CONSTRUCT: { - ERR_FAIL_COND_V(op_node->arguments[0]->type != SL::Node::TYPE_VARIABLE, String()); - - SL::VariableNode *var_node = (SL::VariableNode *)op_node->arguments[0]; - - if (op_node->op == SL::OP_CONSTRUCT) { - code += var_node->name; - } else { - if (var_node->name == "texture") { - // emit texture call - - if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D) { // || - // op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLEREXT) { - code += "texture2D"; - } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) { - 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)) { - code += var_node->name; - } else { - code += _mkid(var_node->name); - } - } - - code += "("; - - for (int i = 1; i < op_node->arguments.size(); i++) { - if (i > 1) { - code += ", "; - } - - code += _dump_node_code(op_node->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - - code += ")"; - - if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { - String define = p_default_actions.usage_defines[var_node->name]; - String node_name = define.substr(1, define.length()); - - if (define.begins_with("@")) { - define = p_default_actions.usage_defines[node_name]; - } - - if (!used_name_defines.has(node_name)) { - r_gen_code.custom_defines.push_back(define.utf8()); - } - used_name_defines.insert(var_node->name); - } - - } break; - - case SL::OP_INDEX: { - 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; - - case SL::OP_SELECT_IF: { - code += "("; - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += " ? "; - code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += " : "; - code += _dump_node_code(op_node->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")"; - } break; - - case SL::OP_MOD: { - String a = _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - String n = _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "(" + n + " == 0 ? 0 : "; - code += a + " - " + n + " * (" + a + " / " + n + "))"; - } break; - - default: { - if (p_use_scope) { - code += "("; - } - code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += " "; - code += _opstr(op_node->op); - code += " "; - code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - if (p_use_scope) { - code += ")"; - } - } break; - } - } break; - - case SL::Node::TYPE_CONTROL_FLOW: { - SL::ControlFlowNode *cf_node = (SL::ControlFlowNode *)p_node; - - if (cf_node->flow_op == SL::FLOW_OP_IF) { - code += _mktab(p_level); - code += "if ("; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")\n"; - code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - - if (cf_node->blocks.size() == 2) { - code += _mktab(p_level); - code += "else\n"; - code += _dump_node_code(cf_node->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } - } else if (cf_node->flow_op == SL::FLOW_OP_DO) { - code += _mktab(p_level); - code += "do"; - code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - code += _mktab(p_level); - code += "while ("; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ");"; - } else if (cf_node->flow_op == SL::FLOW_OP_WHILE) { - code += _mktab(p_level); - code += "while ("; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")\n"; - code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); - } else if (cf_node->flow_op == SL::FLOW_OP_FOR) { - code += _mktab(p_level); - code += "for ("; - code += _dump_node_code(cf_node->blocks[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "; "; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "; "; - code += _dump_node_code(cf_node->expressions[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")\n"; - - code += _dump_node_code(cf_node->blocks[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - - } else if (cf_node->flow_op == SL::FLOW_OP_RETURN) { - code += _mktab(p_level); - code += "return"; - - if (cf_node->expressions.size()) { - code += " "; - code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - } - 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;"; - } else if (cf_node->flow_op == SL::FLOW_OP_BREAK) { - code += "break;"; - } - } break; - - case SL::Node::TYPE_MEMBER: { - SL::MemberNode *member_node = (SL::MemberNode *)p_node; - code += _dump_node_code(member_node->owner, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += "."; - code += member_node->name; - } break; - } - - return code.as_string(); -} - -ShaderLanguage::DataType ShaderCompilerOpenGL::_get_variable_type(const StringName &p_type) { - // RS::GlobalVariableType gvt = ((RasterizerStorageRD *)(RendererStorage::base_singleton))->global_variable_get_type_internal(p_type); - RS::GlobalVariableType gvt = RS::GLOBAL_VAR_TYPE_MAX; - return RS::global_variable_type_get_shader_datatype(gvt); -} - -Error ShaderCompilerOpenGL::compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code) { - ShaderLanguage::VaryingFunctionNames var_names; - - Error err = parser.compile(p_code, ShaderTypes::get_singleton()->get_functions(p_mode), ShaderTypes::get_singleton()->get_modes(p_mode), var_names, ShaderTypes::get_singleton()->get_types(), _get_variable_type); - - // Error ShaderLanguage::compile(const String &p_code, const Map &p_functions, const Vector &p_render_modes, const Set &p_shader_types, GlobalVariableGetTypeFunc p_global_variable_type_func) { - if (err != OK) { - Vector shader = p_code.split("\n"); - for (int i = 0; i < shader.size(); i++) { - print_line(itos(i + 1) + " " + shader[i]); - } - - _err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER); - return err; - } - - r_gen_code.custom_defines.clear(); - r_gen_code.uniforms.clear(); - r_gen_code.texture_uniforms.clear(); - r_gen_code.texture_hints.clear(); - r_gen_code.vertex = String(); - r_gen_code.vertex_global = String(); - r_gen_code.fragment = String(); - r_gen_code.fragment_global = String(); - r_gen_code.light = String(); - r_gen_code.uses_fragment_time = false; - r_gen_code.uses_vertex_time = false; - - used_name_defines.clear(); - used_rmode_defines.clear(); - used_flag_pointers.clear(); - - _dump_node_code(parser.get_shader(), 1, r_gen_code, *p_actions, actions[p_mode], false); - - return OK; -} - -ShaderCompilerOpenGL::ShaderCompilerOpenGL() { - /** CANVAS ITEM SHADER **/ - - actions[RS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy"; - actions[RS::SHADER_CANVAS_ITEM].renames["UV"] = "uv"; - actions[RS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "point_size"; - - actions[RS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix"; - actions[RS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions[RS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] = "extra_matrix_instance"; - actions[RS::SHADER_CANVAS_ITEM].renames["TIME"] = "time"; - actions[RS::SHADER_CANVAS_ITEM].renames["PI"] = _MKSTR(Math_PI); - actions[RS::SHADER_CANVAS_ITEM].renames["TAU"] = _MKSTR(Math_TAU); - actions[RS::SHADER_CANVAS_ITEM].renames["E"] = _MKSTR(Math_E); - actions[RS::SHADER_CANVAS_ITEM].renames["AT_LIGHT_PASS"] = "at_light_pass"; - actions[RS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom"; - - actions[RS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; - actions[RS::SHADER_CANVAS_ITEM].renames["MODULATE"] = "final_modulate"; - actions[RS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; - actions[RS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map"; - actions[RS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth"; - actions[RS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture"; - actions[RS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size"; - actions[RS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture"; - actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"] = "screen_uv"; - actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"] = "screen_texture"; - actions[RS::SHADER_CANVAS_ITEM].renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size"; - actions[RS::SHADER_CANVAS_ITEM].renames["FRAGCOORD"] = "gl_FragCoord"; - actions[RS::SHADER_CANVAS_ITEM].renames["POINT_COORD"] = "gl_PointCoord"; - - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_VEC"] = "light_vec"; - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"] = "light_height"; - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"] = "light_color"; - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv"; - actions[RS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light"; - actions[RS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color"; - actions[RS::SHADER_CANVAS_ITEM].renames["SHADOW_VEC"] = "shadow_vec"; - - actions[RS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["MODULATE"] = "#define MODULATE_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[RS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_VEC"] = "#define SHADOW_VEC_USED\n"; - - // Ported from GLES3 - - actions[RS::SHADER_CANVAS_ITEM].usage_defines["sinh"] = "#define SINH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["cosh"] = "#define COSH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["tanh"] = "#define TANH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["asinh"] = "#define ASINH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["acosh"] = "#define ACOSH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["atanh"] = "#define ATANH_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["determinant"] = "#define DETERMINANT_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["transpose"] = "#define TRANSPOSE_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["round"] = "#define ROUND_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["inverse"] = "#define INVERSE_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["isinf"] = "#define IS_INF_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["isnan"] = "#define IS_NAN_USED\n"; - actions[RS::SHADER_CANVAS_ITEM].usage_defines["trunc"] = "#define TRUNC_USED\n"; - - /** SPATIAL SHADER **/ - - actions[RS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform"; - actions[RS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix"; - actions[RS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix"; - actions[RS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions[RS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "projection_inverse_matrix"; - actions[RS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; - - actions[RS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz"; - actions[RS::SHADER_SPATIAL].renames["NORMAL"] = "normal"; - actions[RS::SHADER_SPATIAL].renames["TANGENT"] = "tangent"; - actions[RS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal"; - actions[RS::SHADER_SPATIAL].renames["POSITION"] = "position"; - actions[RS::SHADER_SPATIAL].renames["UV"] = "uv_interp"; - actions[RS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; - actions[RS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; - actions[RS::SHADER_SPATIAL].renames["POINT_SIZE"] = "point_size"; - // gl_InstanceID is not available in OpenGL ES 2.0 - actions[RS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0"; - - //builtins - - actions[RS::SHADER_SPATIAL].renames["TIME"] = "time"; - actions[RS::SHADER_SPATIAL].renames["PI"] = _MKSTR(Math_PI); - actions[RS::SHADER_SPATIAL].renames["TAU"] = _MKSTR(Math_TAU); - actions[RS::SHADER_SPATIAL].renames["E"] = _MKSTR(Math_E); - actions[RS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size"; - - actions[RS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord"; - actions[RS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing"; - actions[RS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap"; - actions[RS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth"; - actions[RS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo"; - actions[RS::SHADER_SPATIAL].renames["ALPHA"] = "alpha"; - actions[RS::SHADER_SPATIAL].renames["METALLIC"] = "metallic"; - actions[RS::SHADER_SPATIAL].renames["SPECULAR"] = "specular"; - actions[RS::SHADER_SPATIAL].renames["ROUGHNESS"] = "roughness"; - actions[RS::SHADER_SPATIAL].renames["RIM"] = "rim"; - actions[RS::SHADER_SPATIAL].renames["RIM_TINT"] = "rim_tint"; - actions[RS::SHADER_SPATIAL].renames["CLEARCOAT"] = "clearcoat"; - actions[RS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; - actions[RS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy"; - actions[RS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - actions[RS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; - actions[RS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission"; - actions[RS::SHADER_SPATIAL].renames["AO"] = "ao"; - actions[RS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; - actions[RS::SHADER_SPATIAL].renames["EMISSION"] = "emission"; - actions[RS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; - actions[RS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; - actions[RS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; - actions[RS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; - actions[RS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_texture"; - // Defined in GLES3, but not available in GLES2 - //actions[RS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth"; - actions[RS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; - actions[RS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; - - //for light - actions[RS::SHADER_SPATIAL].renames["VIEW"] = "view"; - actions[RS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; - actions[RS::SHADER_SPATIAL].renames["LIGHT"] = "light"; - actions[RS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation"; - actions[RS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light"; - actions[RS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light"; - - actions[RS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT"; - actions[RS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n"; - actions[RS::SHADER_SPATIAL].usage_defines["RIM_TINT"] = "@RIM"; - actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT"] = "#define LIGHT_USE_CLEARCOAT\n"; - actions[RS::SHADER_SPATIAL].usage_defines["CLEARCOAT_GLOSS"] = "@CLEARCOAT"; - actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n"; - actions[RS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; - actions[RS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n"; - actions[RS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n"; - actions[RS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["NORMALMAP_DEPTH"] = "@NORMALMAP"; - actions[RS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; - actions[RS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; - actions[RS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; - - actions[RS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; - actions[RS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["DEPTH_TEXTURE"] = "#define DEPTH_TEXTURE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; - - actions[RS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[RS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - - // Ported from GLES3 - - actions[RS::SHADER_SPATIAL].usage_defines["sinh"] = "#define SINH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["cosh"] = "#define COSH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["tanh"] = "#define TANH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["asinh"] = "#define ASINH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["acosh"] = "#define ACOSH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["atanh"] = "#define ATANH_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["determinant"] = "#define DETERMINANT_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["transpose"] = "#define TRANSPOSE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["round"] = "#define ROUND_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["inverse"] = "#define INVERSE_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["isinf"] = "#define IS_INF_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["isnan"] = "#define IS_NAN_USED\n"; - actions[RS::SHADER_SPATIAL].usage_defines["trunc"] = "#define TRUNC_USED\n"; - - actions[RS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; - - // Defined in GLES3, could be implemented in GLES2 too if there's a need for it - //actions[RS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; - // Defined in GLES3, might not be possible in GLES2 as gl_FrontFacing is not available - //actions[RS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; - //actions[RS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - - bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); - - if (!force_lambert) { - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; - } - - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - - bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); - - if (!force_blinn) { - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; - } else { - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; - } - - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; - actions[RS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; - - // No defines for particle shaders in OpenGL, there are no GPU particles - - vertex_name = "vertex"; - fragment_name = "fragment"; - light_name = "light"; - time_name = "TIME"; - - List func_list; - - ShaderLanguage::get_builtin_funcs(&func_list); - - for (List::Element *E = func_list.front(); E; E = E->next()) { - internal_functions.insert(E->get()); - } -} - -#endif // OPENGL_BACKEND_ENABLED diff --git a/drivers/opengl/shader_compiler_opengl.h b/drivers/opengl/shader_compiler_opengl.h deleted file mode 100644 index b57d28ffe5..0000000000 --- a/drivers/opengl/shader_compiler_opengl.h +++ /dev/null @@ -1,106 +0,0 @@ -/*************************************************************************/ -/* shader_compiler_opengl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SHADER_COMPILER_OPENGL_H -#define SHADER_COMPILER_OPENGL_H - -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/string/string_builder.h" -#include "core/templates/pair.h" -#include "servers/rendering/shader_language.h" -#include "servers/rendering/shader_types.h" -#include "servers/rendering_server.h" - -class ShaderCompilerOpenGL { -public: - struct IdentifierActions { - Map> render_mode_values; - Map render_mode_flags; - Map usage_flag_pointers; - Map write_flag_pointers; - - Map *uniforms; - }; - - struct GeneratedCode { - Vector custom_defines; - Vector uniforms; - Vector texture_uniforms; - Vector texture_hints; - - String vertex_global; - String vertex; - String fragment_global; - String fragment; - String light; - - bool uses_fragment_time; - bool uses_vertex_time; - }; - -private: - ShaderLanguage parser; - - struct DefaultIdentifierActions { - Map renames; - Map render_mode_defines; - Map usage_defines; - }; - - void _dump_function_deps(ShaderLanguage::ShaderNode *p_node, const StringName &p_for_func, const Map &p_func_code, StringBuilder &r_to_add, Set &r_added); - String _dump_node_code(ShaderLanguage::Node *p_node, int p_level, GeneratedCode &r_gen_code, IdentifierActions &p_actions, const DefaultIdentifierActions &p_default_actions, bool p_assigning, bool p_use_scope = true); - - StringName current_func_name; - StringName vertex_name; - StringName fragment_name; - StringName light_name; - StringName time_name; - - Set used_name_defines; - Set used_flag_pointers; - Set used_rmode_defines; - Set internal_functions; - - DefaultIdentifierActions actions[RS::SHADER_MAX]; - - // compatibility with godot 4 - static ShaderLanguage::DataType _get_variable_type(const StringName &p_type); - -public: - Error compile(RS::ShaderMode p_mode, const String &p_code, IdentifierActions *p_actions, const String &p_path, GeneratedCode &r_gen_code); - - ShaderCompilerOpenGL(); -}; - -#endif // OPENGL_BACKEND_ENABLED - -#endif // SHADER_COMPILER_OPENGL_H diff --git a/drivers/opengl/shader_opengl.cpp b/drivers/opengl/shader_opengl.cpp deleted file mode 100644 index a80a745047..0000000000 --- a/drivers/opengl/shader_opengl.cpp +++ /dev/null @@ -1,1128 +0,0 @@ -/*************************************************************************/ -/* shader_opengl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "shader_opengl.h" -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "rasterizer_opengl.h" -#include "rasterizer_storage_opengl.h" - -#include "core/config/project_settings.h" -#include "core/os/memory.h" -#include "core/string/print_string.h" -#include "core/string/string_builder.h" - -// #define DEBUG_OPENGL - -// #include "shaders/copy.glsl.gen.h" - -#ifdef DEBUG_OPENGL - -#define DEBUG_TEST_ERROR(m_section) \ - { \ - uint32_t err = glGetError(); \ - if (err) { \ - print_line("OpenGL Error #" + itos(err) + " at: " + m_section); \ - } \ - } -#else - -#define DEBUG_TEST_ERROR(m_section) - -#endif - -ShaderOpenGL *ShaderOpenGL::active = NULL; - -//#define DEBUG_SHADER - -#ifdef DEBUG_SHADER - -#define DEBUG_PRINT(m_text) print_line(m_text); - -#else - -#define DEBUG_PRINT(m_text) - -#endif - -GLint ShaderOpenGL::get_uniform_location(int p_index) const { - ERR_FAIL_COND_V(!version, -1); - - return version->uniform_location[p_index]; -} - -bool ShaderOpenGL::bind() { - if (active != this || !version || new_conditional_version.key != conditional_version.key) { - conditional_version = new_conditional_version; - version = get_current_version(); - } else { - return false; - } - - ERR_FAIL_COND_V(!version, false); - - if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation). - glUseProgram(0); - return false; - } - - glUseProgram(version->id); - - DEBUG_TEST_ERROR("use program"); - - active = this; - uniforms_dirty = true; - - return true; -} - -void ShaderOpenGL::unbind() { - version = NULL; - glUseProgram(0); - uniforms_dirty = true; - active = NULL; -} - -static void _display_error_with_code(const String &p_error, const Vector &p_code) { - int line = 1; - String total_code; - - for (int i = 0; i < p_code.size(); i++) { - total_code += String(p_code[i]); - } - - Vector lines = String(total_code).split("\n"); - - for (int j = 0; j < lines.size(); j++) { - print_line(itos(line) + ": " + lines[j]); - line++; - } - - ERR_PRINT(p_error); -} - -static String _mkid(const String &p_id) { - String id = "m_" + p_id; - return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl -} - -ShaderOpenGL::Version *ShaderOpenGL::get_current_version() { - if (!valid) - return nullptr; - - Version *_v = version_map.getptr(conditional_version); - - if (_v) { - if (conditional_version.code_version != 0) { - CustomCode *cc = custom_code_map.getptr(conditional_version.code_version); - ERR_FAIL_COND_V(!cc, _v); - if (cc->version == _v->code_version) - return _v; - } else { - return _v; - } - } - - if (!_v) - version_map[conditional_version] = Version(); - - Version &v = version_map[conditional_version]; - - if (!_v) { - v.uniform_location = memnew_arr(GLint, uniform_count); - } else { - if (v.ok) { - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - v.id = 0; - } - } - - v.ok = false; - - Vector strings; - -#ifdef GLES_OVER_GL - strings.push_back("#version 120\n"); - strings.push_back("#define USE_GLES_OVER_GL\n"); - - // test - strings.push_back("#define highp\n"); - //#ifdef USE_GLES_OVER_GL - //#define lowp - //#define mediump - //#define highp - //#else - // precision highp float; - // precision highp int; - //#endif - -#else - strings.push_back("#version 100\n"); -//angle does not like -#ifdef JAVASCRIPT_ENABLED - strings.push_back("#define USE_HIGHP_PRECISION\n"); -#endif - - if (GLOBAL_GET("rendering/opengl/compatibility/enable_high_float.Android")) { - // enable USE_HIGHP_PRECISION but safeguarded by an availability check as highp support is optional in OpenGL - // see Section 4.5.4 of the GLSL_ES_Specification_1.00 - strings.push_back("#ifdef GL_FRAGMENT_PRECISION_HIGH\n #define USE_HIGHP_PRECISION\n#endif\n"); - } - -#endif - -#ifdef ANDROID_ENABLED - strings.push_back("#define ANDROID_ENABLED\n"); -#endif - - for (int i = 0; i < custom_defines.size(); i++) { - strings.push_back(custom_defines[i].get_data()); - strings.push_back("\n"); - } - - for (int j = 0; j < conditional_count; j++) { - bool enable = (conditional_version.version & (1 << j)) > 0; - - if (enable) { - strings.push_back(conditional_defines[j]); - DEBUG_PRINT(conditional_defines[j]); - } - } - - // keep them around during the function - CharString code_string; - CharString code_string2; - CharString code_globals; - - CustomCode *cc = NULL; - - if (conditional_version.code_version > 0) { - cc = custom_code_map.getptr(conditional_version.code_version); - - ERR_FAIL_COND_V(!cc, NULL); - v.code_version = cc->version; - } - - // program - - v.id = glCreateProgram(); - ERR_FAIL_COND_V(v.id == 0, NULL); - - if (cc) { - for (int i = 0; i < cc->custom_defines.size(); i++) { - strings.push_back(cc->custom_defines.write[i]); - DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data())); - } - } - - // vertex shader - - int string_base_size = strings.size(); - - strings.push_back(vertex_code0.get_data()); - - if (cc) { - code_globals = cc->vertex_globals.ascii(); - strings.push_back(code_globals.get_data()); - } - - strings.push_back(vertex_code1.get_data()); - - if (cc) { - code_string = cc->vertex.ascii(); - strings.push_back(code_string.get_data()); - } - - strings.push_back(vertex_code2.get_data()); - -#ifdef DEBUG_SHADER - - DEBUG_PRINT("\nVertex Code:\n\n" + String(code_string.get_data())); - -#endif - - v.vert_id = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(v.vert_id, strings.size(), &strings[0], NULL); - glCompileShader(v.vert_id); - - GLint status; - - glGetShaderiv(v.vert_id, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLsizei iloglen; - glGetShaderiv(v.vert_id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_PRINT("No OpenGL vertex shader compiler log. What the frick?"); - } else { - if (iloglen == 0) { - iloglen = 4096; // buggy driver (Adreno 220+) - } - - char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); - ilogmem[iloglen] = '\0'; - glGetShaderInfoLog(v.vert_id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Vertex shader compilation failed:\n"; - - err_string += ilogmem; - - _display_error_with_code(err_string, strings); - - Memory::free_static(ilogmem); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - } - - ERR_FAIL_V(NULL); - } - - strings.resize(string_base_size); - - // fragment shader - - strings.push_back(fragment_code0.get_data()); - - if (cc) { - code_globals = cc->fragment_globals.ascii(); - strings.push_back(code_globals.get_data()); - } - - strings.push_back(fragment_code1.get_data()); - - if (cc) { - code_string = cc->light.ascii(); - strings.push_back(code_string.get_data()); - } - - strings.push_back(fragment_code2.get_data()); - - if (cc) { - code_string2 = cc->fragment.ascii(); - strings.push_back(code_string2.get_data()); - } - - 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 - - v.frag_id = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(v.frag_id, strings.size(), &strings[0], NULL); - glCompileShader(v.frag_id); - - glGetShaderiv(v.frag_id, GL_COMPILE_STATUS, &status); - if (status == GL_FALSE) { - GLsizei iloglen; - glGetShaderiv(v.frag_id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_PRINT("No OpenGL fragment shader compiler log. What the frick?"); - } else { - if (iloglen == 0) { - iloglen = 4096; // buggy driver (Adreno 220+) - } - - char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); - ilogmem[iloglen] = '\0'; - glGetShaderInfoLog(v.frag_id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Fragment shader compilation failed:\n"; - - err_string += ilogmem; - - _display_error_with_code(err_string, strings); - - Memory::free_static(ilogmem); - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - } - - ERR_FAIL_V(NULL); - } - - glAttachShader(v.id, v.frag_id); - glAttachShader(v.id, v.vert_id); - - // bind the attribute locations. This has to be done before linking so that the - // linker doesn't assign some random indices - - for (int i = 0; i < attribute_pair_count; i++) { - glBindAttribLocation(v.id, attribute_pairs[i].index, attribute_pairs[i].name); - } - - glLinkProgram(v.id); - - glGetProgramiv(v.id, GL_LINK_STATUS, &status); - if (status == GL_FALSE) { - GLsizei iloglen; - glGetProgramiv(v.id, GL_INFO_LOG_LENGTH, &iloglen); - - if (iloglen < 0) { - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_PRINT("No OpenGL program link log. What the frick?"); - ERR_FAIL_V(NULL); - } - - if (iloglen == 0) { - iloglen = 4096; // buggy driver (Adreno 220+) - } - - char *ilogmem = (char *)Memory::alloc_static(iloglen + 1); - ilogmem[iloglen] = '\0'; - glGetProgramInfoLog(v.id, iloglen, &iloglen, ilogmem); - - String err_string = get_shader_name() + ": Program linking failed:\n"; - - err_string += ilogmem; - - _display_error_with_code(err_string, strings); - - Memory::free_static(ilogmem); - glDeleteShader(v.frag_id); - glDeleteShader(v.vert_id); - glDeleteProgram(v.id); - v.id = 0; - - ERR_FAIL_V(NULL); - } - - // get uniform locations - - glUseProgram(v.id); - - for (int i = 0; i < uniform_count; i++) { - v.uniform_location[i] = glGetUniformLocation(v.id, uniform_names[i]); - } - - for (int i = 0; i < texunit_pair_count; i++) { - GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name); - 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) { - // uniforms - for (int i = 0; i < cc->custom_uniforms.size(); i++) { - String native_uniform_name = _mkid(cc->custom_uniforms[i]); - GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); - v.custom_uniform_locations[cc->custom_uniforms[i]] = location; - } - - // textures - for (int i = 0; i < cc->texture_uniforms.size(); i++) { - String native_uniform_name = _mkid(cc->texture_uniforms[i]); - GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); - v.custom_uniform_locations[cc->texture_uniforms[i]] = location; - glUniform1i(location, i); - } - } - - glUseProgram(0); - v.ok = true; - - if (cc) { - cc->versions.insert(conditional_version.version); - } - - return &v; -} - -GLint ShaderOpenGL::get_uniform_location(const String &p_name) const { - ERR_FAIL_COND_V(!version, -1); - return glGetUniformLocation(version->id, p_name.ascii().get_data()); -} - -void ShaderOpenGL::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) { - ERR_FAIL_COND(version); - - conditional_version.key = 0; - new_conditional_version.key = 0; - uniform_count = p_uniform_count; - conditional_count = p_conditional_count; - conditional_defines = p_conditional_defines; - uniform_names = p_uniform_names; - vertex_code = p_vertex_code; - fragment_code = p_fragment_code; - texunit_pairs = p_texunit_pairs; - texunit_pair_count = p_texunit_pair_count; - vertex_code_start = p_vertex_code_start; - fragment_code_start = p_fragment_code_start; - attribute_pairs = p_attribute_pairs; - attribute_pair_count = p_attribute_count; - - { - String globals_tag = "\nVERTEX_SHADER_GLOBALS"; - String code_tag = "\nVERTEX_SHADER_CODE"; - String code = vertex_code; - int cpos = code.find(globals_tag); - if (cpos == -1) { - vertex_code0 = code.ascii(); - } else { - vertex_code0 = code.substr(0, cpos).ascii(); - code = code.substr(cpos + globals_tag.length(), code.length()); - - cpos = code.find(code_tag); - - if (cpos == -1) { - vertex_code1 = code.ascii(); - } else { - vertex_code1 = code.substr(0, cpos).ascii(); - vertex_code2 = code.substr(cpos + code_tag.length(), code.length()).ascii(); - } - } - } - - { - String globals_tag = "\nFRAGMENT_SHADER_GLOBALS"; - String code_tag = "\nFRAGMENT_SHADER_CODE"; - String light_code_tag = "\nLIGHT_SHADER_CODE"; - String code = fragment_code; - int cpos = code.find(globals_tag); - if (cpos == -1) { - fragment_code0 = code.ascii(); - } else { - fragment_code0 = code.substr(0, cpos).ascii(); - code = code.substr(cpos + globals_tag.length(), code.length()); - - cpos = code.find(light_code_tag); - - String code2; - - if (cpos != -1) { - fragment_code1 = code.substr(0, cpos).ascii(); - code2 = code.substr(cpos + light_code_tag.length(), code.length()); - } else { - code2 = code; - } - - cpos = code2.find(code_tag); - if (cpos == -1) { - fragment_code2 = code2.ascii(); - } else { - fragment_code2 = code2.substr(0, cpos).ascii(); - fragment_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); - } - } - } - - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units); - - valid = true; -} - -void ShaderOpenGL::finish() { - const VersionKey *V = NULL; - - while ((V = version_map.next(V))) { - Version &v = version_map[*V]; - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - - if (v.uniform_location) - memdelete_arr(v.uniform_location); - } -} - -void ShaderOpenGL::clear_caches() { - const VersionKey *V = NULL; - - while ((V = version_map.next(V))) { - Version &v = version_map[*V]; - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - memdelete_arr(v.uniform_location); - } - - version_map.clear(); - - custom_code_map.clear(); - version = NULL; - last_custom_code = 1; - uniforms_dirty = true; -} - -uint32_t ShaderOpenGL::create_custom_shader() { - custom_code_map[last_custom_code] = CustomCode(); - custom_code_map[last_custom_code].version = 1; - return last_custom_code++; -} - -void ShaderOpenGL::set_custom_shader_code(uint32_t p_code_id, - const String &p_vertex, - const String &p_vertex_globals, - const String &p_fragment, - const String &p_light, - const String &p_fragment_globals, - const Vector &p_uniforms, - const Vector &p_texture_uniforms, - const Vector &p_custom_defines) { - CustomCode *cc = custom_code_map.getptr(p_code_id); - ERR_FAIL_COND(!cc); - - cc->vertex = p_vertex; - cc->vertex_globals = p_vertex_globals; - cc->fragment = p_fragment; - cc->fragment_globals = p_fragment_globals; - cc->light = p_light; - cc->custom_uniforms = p_uniforms; - cc->custom_defines = p_custom_defines; - cc->texture_uniforms = p_texture_uniforms; - cc->version++; -} - -void ShaderOpenGL::set_custom_shader(uint32_t p_code_id) { - new_conditional_version.code_version = p_code_id; -} - -void ShaderOpenGL::free_custom_shader(uint32_t p_code_id) { - ERR_FAIL_COND(!custom_code_map.has(p_code_id)); - if (conditional_version.code_version == p_code_id) { - conditional_version.code_version = 0; //do not keep using a version that is going away - unbind(); - } - - VersionKey key; - key.code_version = p_code_id; - for (Set::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) { - key.version = E->get(); - ERR_CONTINUE(!version_map.has(key)); - Version &v = version_map[key]; - - glDeleteShader(v.vert_id); - glDeleteShader(v.frag_id); - glDeleteProgram(v.id); - memdelete_arr(v.uniform_location); - v.id = 0; - - version_map.erase(key); - } - - custom_code_map.erase(p_code_id); -} - -void ShaderOpenGL::use_material(void *p_material) { - RasterizerStorageOpenGL::Material *material = (RasterizerStorageOpenGL::Material *)p_material; - - if (!material) { - return; - } - - if (!material->shader) { - return; - } - - Version *v = version_map.getptr(conditional_version); - - // bind uniforms - for (Map::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::Element *L = v->custom_uniform_locations.find(E->key()); - if (!L || L->get() < 0) - continue; //uniform not valid - - GLuint location = L->get(); - - Map::Element *V = material->params.find(E->key()); - - if (V) { - switch (E->get().type) { - case ShaderLanguage::TYPE_BOOL: { - bool boolean = V->get(); - glUniform1i(location, boolean ? 1 : 0); - } break; - - case ShaderLanguage::TYPE_BVEC2: { - int flags = V->get(); - glUniform2i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0); - } break; - - case ShaderLanguage::TYPE_BVEC3: { - int flags = V->get(); - glUniform3i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0); - - } break; - - case ShaderLanguage::TYPE_BVEC4: { - int flags = V->get(); - glUniform4i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0, (flags & 8) ? 1 : 0); - - } break; - - case ShaderLanguage::TYPE_INT: - case ShaderLanguage::TYPE_UINT: { - int value = V->get(); - glUniform1i(location, value); - } break; - - case ShaderLanguage::TYPE_IVEC2: - case ShaderLanguage::TYPE_UVEC2: { - Array r = V->get(); - const int count = 2; - if (r.size() == count) { - int values[count]; - for (int i = 0; i < count; i++) { - values[i] = r[i]; - } - glUniform2i(location, values[0], values[1]); - } - - } break; - - case ShaderLanguage::TYPE_IVEC3: - case ShaderLanguage::TYPE_UVEC3: { - Array r = V->get(); - const int count = 3; - if (r.size() == count) { - int values[count]; - for (int i = 0; i < count; i++) { - values[i] = r[i]; - } - glUniform3i(location, values[0], values[1], values[2]); - } - - } break; - - case ShaderLanguage::TYPE_IVEC4: - case ShaderLanguage::TYPE_UVEC4: { - Array r = V->get(); - const int count = 4; - if (r.size() == count) { - int values[count]; - for (int i = 0; i < count; i++) { - values[i] = r[i]; - } - glUniform4i(location, values[0], values[1], values[2], values[3]); - } - - } break; - - case ShaderLanguage::TYPE_FLOAT: { - float value = V->get(); - glUniform1f(location, value); - - } break; - - case ShaderLanguage::TYPE_VEC2: { - Vector2 value = V->get(); - glUniform2f(location, value.x, value.y); - } break; - - case ShaderLanguage::TYPE_VEC3: { - Vector3 value = V->get(); - glUniform3f(location, value.x, value.y, value.z); - } break; - - case ShaderLanguage::TYPE_VEC4: { - if (V->get().get_type() == Variant::COLOR) { - Color value = V->get(); - glUniform4f(location, value.r, value.g, value.b, value.a); - } else if (V->get().get_type() == Variant::QUATERNION) { - Quaternion value = V->get(); - glUniform4f(location, value.x, value.y, value.z, value.w); - } else { - Plane value = V->get(); - glUniform4f(location, value.normal.x, value.normal.y, value.normal.z, value.d); - } - - } break; - - case ShaderLanguage::TYPE_MAT2: { - Transform2D tr = V->get(); - GLfloat matrix[4] = { - /* build a 16x16 matrix */ - tr.elements[0][0], - tr.elements[0][1], - tr.elements[1][0], - tr.elements[1][1], - }; - glUniformMatrix2fv(location, 1, GL_FALSE, matrix); - - } break; - - case ShaderLanguage::TYPE_MAT3: { - Basis val = V->get(); - - GLfloat mat[9] = { - val.elements[0][0], - val.elements[1][0], - val.elements[2][0], - val.elements[0][1], - val.elements[1][1], - val.elements[2][1], - val.elements[0][2], - val.elements[1][2], - val.elements[2][2], - }; - - glUniformMatrix3fv(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_MAT4: { - Transform2D tr = V->get(); - GLfloat matrix[16] = { /* build a 16x16 matrix */ - tr.elements[0][0], - tr.elements[0][1], - 0, - 0, - tr.elements[1][0], - tr.elements[1][1], - 0, - 0, - 0, - 0, - 1, - 0, - tr.elements[2][0], - tr.elements[2][1], - 0, - 1 - }; - - glUniformMatrix4fv(location, 1, GL_FALSE, matrix); - - } break; - - default: { - ERR_PRINT("ShaderNode type missing, bug?"); - } break; - } - } else if (E->get().default_value.size()) { - const Vector &values = E->get().default_value; - switch (E->get().type) { - case ShaderLanguage::TYPE_BOOL: { - glUniform1i(location, values[0].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC2: { - glUniform2i(location, values[0].boolean, values[1].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC3: { - glUniform3i(location, values[0].boolean, values[1].boolean, values[2].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC4: { - glUniform4i(location, values[0].boolean, values[1].boolean, values[2].boolean, values[3].boolean); - } break; - - case ShaderLanguage::TYPE_INT: { - glUniform1i(location, values[0].sint); - } break; - - case ShaderLanguage::TYPE_IVEC2: { - glUniform2i(location, values[0].sint, values[1].sint); - } break; - - case ShaderLanguage::TYPE_IVEC3: { - glUniform3i(location, values[0].sint, values[1].sint, values[2].sint); - } break; - - case ShaderLanguage::TYPE_IVEC4: { - glUniform4i(location, values[0].sint, values[1].sint, values[2].sint, values[3].sint); - } break; - - case ShaderLanguage::TYPE_UINT: { - glUniform1i(location, values[0].uint); - } break; - - case ShaderLanguage::TYPE_UVEC2: { - glUniform2i(location, values[0].uint, values[1].uint); - } break; - - case ShaderLanguage::TYPE_UVEC3: { - glUniform3i(location, values[0].uint, values[1].uint, values[2].uint); - } break; - - case ShaderLanguage::TYPE_UVEC4: { - glUniform4i(location, values[0].uint, values[1].uint, values[2].uint, values[3].uint); - } break; - - case ShaderLanguage::TYPE_FLOAT: { - glUniform1f(location, values[0].real); - } break; - - case ShaderLanguage::TYPE_VEC2: { - glUniform2f(location, values[0].real, values[1].real); - } break; - - case ShaderLanguage::TYPE_VEC3: { - glUniform3f(location, values[0].real, values[1].real, values[2].real); - } break; - - case ShaderLanguage::TYPE_VEC4: { - glUniform4f(location, 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(location, 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(location, 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(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_SAMPLER2D: { - } break; - - /* - case ShaderLanguage::TYPE_SAMPLEREXT: { - } break; -*/ - case ShaderLanguage::TYPE_ISAMPLER2D: { - } break; - - case ShaderLanguage::TYPE_USAMPLER2D: { - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - } break; - - case ShaderLanguage::TYPE_SAMPLER2DARRAY: - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: - case ShaderLanguage::TYPE_SAMPLER3D: - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: { - // Not implemented in OpenGL - } break; - - case ShaderLanguage::TYPE_VOID: { - // Nothing to do? - } break; - default: { - ERR_PRINT("ShaderNode type missing, bug?"); - } break; - } - } else { //zero - - switch (E->get().type) { - case ShaderLanguage::TYPE_BOOL: { - glUniform1i(location, GL_FALSE); - } break; - - case ShaderLanguage::TYPE_BVEC2: { - glUniform2i(location, GL_FALSE, GL_FALSE); - } break; - - case ShaderLanguage::TYPE_BVEC3: { - glUniform3i(location, GL_FALSE, GL_FALSE, GL_FALSE); - } break; - - case ShaderLanguage::TYPE_BVEC4: { - glUniform4i(location, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - } break; - - case ShaderLanguage::TYPE_INT: { - glUniform1i(location, 0); - } break; - - case ShaderLanguage::TYPE_IVEC2: { - glUniform2i(location, 0, 0); - } break; - - case ShaderLanguage::TYPE_IVEC3: { - glUniform3i(location, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_IVEC4: { - glUniform4i(location, 0, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_UINT: { - glUniform1i(location, 0); - } break; - - case ShaderLanguage::TYPE_UVEC2: { - glUniform2i(location, 0, 0); - } break; - - case ShaderLanguage::TYPE_UVEC3: { - glUniform3i(location, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_UVEC4: { - glUniform4i(location, 0, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_FLOAT: { - glUniform1f(location, 0); - } break; - - case ShaderLanguage::TYPE_VEC2: { - glUniform2f(location, 0, 0); - } break; - - case ShaderLanguage::TYPE_VEC3: { - glUniform3f(location, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_VEC4: { - glUniform4f(location, 0, 0, 0, 0); - } break; - - case ShaderLanguage::TYPE_MAT2: { - GLfloat mat[4] = { 0, 0, 0, 0 }; - - glUniformMatrix2fv(location, 1, GL_FALSE, mat); - } break; - - case ShaderLanguage::TYPE_MAT3: { - GLfloat mat[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - glUniformMatrix3fv(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_MAT4: { - GLfloat mat[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - - glUniformMatrix4fv(location, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_SAMPLER2D: { - } break; - - /* - case ShaderLanguage::TYPE_SAMPLEREXT: { - } break; -*/ - - case ShaderLanguage::TYPE_ISAMPLER2D: { - } break; - - case ShaderLanguage::TYPE_USAMPLER2D: { - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - } break; - - case ShaderLanguage::TYPE_SAMPLER2DARRAY: - case ShaderLanguage::TYPE_ISAMPLER2DARRAY: - case ShaderLanguage::TYPE_USAMPLER2DARRAY: - case ShaderLanguage::TYPE_SAMPLER3D: - case ShaderLanguage::TYPE_ISAMPLER3D: - case ShaderLanguage::TYPE_USAMPLER3D: { - // Not implemented in OpenGL - } break; - - case ShaderLanguage::TYPE_VOID: { - // Nothing to do? - } break; - default: { - ERR_PRINT("ShaderNode type missing, bug?"); - } break; - } - } - } -} - -ShaderOpenGL::ShaderOpenGL() { - version = NULL; - last_custom_code = 1; - uniforms_dirty = true; -} - -ShaderOpenGL::~ShaderOpenGL() { - finish(); -} - -#endif // OPENGL_BACKEND_ENABLED diff --git a/drivers/opengl/shader_opengl.h b/drivers/opengl/shader_opengl.h deleted file mode 100644 index 4896bd6f2b..0000000000 --- a/drivers/opengl/shader_opengl.h +++ /dev/null @@ -1,277 +0,0 @@ -/*************************************************************************/ -/* shader_opengl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SHADER_OPENGL_H -#define SHADER_OPENGL_H - -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -// This must come first to avoid windows.h mess -#include "platform_config.h" -#ifndef OPENGL_INCLUDE_H -#include -#else -#include OPENGL_INCLUDE_H -#endif - -#include "core/math/camera_matrix.h" -#include "core/templates/hash_map.h" -#include "core/templates/map.h" -#include "core/templates/pair.h" -#include "core/variant/variant.h" -#include "servers/rendering/shader_language.h" - -#include - -class RasterizerStorageOpenGL; - -class ShaderOpenGL { -protected: - struct Enum { - uint64_t mask; - uint64_t shift; - const char *defines[16]; - }; - - struct EnumValue { - uint64_t set_mask; - uint64_t clear_mask; - }; - - struct AttributePair { - const char *name; - int index; - }; - - struct UniformPair { - const char *name; - Variant::Type type_hint; - }; - - struct TexUnitPair { - const char *name; - int index; - }; - - bool uniforms_dirty; - -private: - bool valid = false; - - //@TODO Optimize to a fixed set of shader pools and use a LRU - int uniform_count; - int texunit_pair_count; - int conditional_count; - int vertex_code_start; - int fragment_code_start; - int attribute_pair_count; - - struct CustomCode { - String vertex; - String vertex_globals; - String fragment; - String fragment_globals; - String light; - uint32_t version; - Vector texture_uniforms; - Vector custom_uniforms; - Vector custom_defines; - Set versions; - }; - - struct Version { - GLuint id; - GLuint vert_id; - GLuint frag_id; - GLint *uniform_location; - Vector texture_uniform_locations; - Map custom_uniform_locations; - uint32_t code_version; - bool ok; - Version() { - id = 0; - vert_id = 0; - frag_id = 0; - uniform_location = NULL; - code_version = 0; - ok = false; - } - }; - - Version *version; - - union VersionKey { - struct { - uint32_t version; - uint32_t code_version; - }; - uint64_t key; - bool operator==(const VersionKey &p_key) const { return key == p_key.key; } - bool operator<(const VersionKey &p_key) const { return key < p_key.key; } - }; - - struct VersionKeyHash { - static _FORCE_INLINE_ uint32_t hash(const VersionKey &p_key) { return HashMapHasherDefault::hash(p_key.key); } - }; - - //this should use a way more cachefriendly version.. - HashMap version_map; - - HashMap custom_code_map; - uint32_t last_custom_code; - - VersionKey conditional_version; - VersionKey new_conditional_version; - - virtual String get_shader_name() const = 0; - - const char **conditional_defines; - const char **uniform_names; - const AttributePair *attribute_pairs; - const TexUnitPair *texunit_pairs; - const char *vertex_code; - const char *fragment_code; - CharString fragment_code0; - CharString fragment_code1; - CharString fragment_code2; - CharString fragment_code3; - - CharString vertex_code0; - CharString vertex_code1; - CharString vertex_code2; - - Vector custom_defines; - - Version *get_current_version(); - - static ShaderOpenGL *active; - - int max_image_units; - - Map>> 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); - - ShaderOpenGL(); - -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_ ShaderOpenGL *get_active() { return active; } - bool bind(); - void unbind(); - - 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, - const String &p_vertex_globals, - const String &p_fragment, - const String &p_light, - const String &p_fragment_globals, - const Vector &p_uniforms, - const Vector &p_texture_uniforms, - const Vector &p_custom_defines); - - void set_custom_shader(uint32_t p_code_id); - void free_custom_shader(uint32_t p_code_id); - - uint32_t get_version_key() const { return conditional_version.version; } - - // this void* is actually a RasterizerStorageOpenGL::Material, but C++ doesn't - // like forward declared nested classes. - void use_material(void *p_material); - - _FORCE_INLINE_ uint32_t get_version() const { return new_conditional_version.version; } - _FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; } - - virtual void init() = 0; - void finish(); - - void add_custom_define(const String &p_define) { - custom_defines.push_back(p_define.utf8()); - } - - void get_custom_defines(Vector *p_defines) { - for (int i = 0; i < custom_defines.size(); i++) { - p_defines->push_back(custom_defines[i].get_data()); - } - } - - void remove_custom_define(const String &p_define) { - custom_defines.erase(p_define.utf8()); - } - - virtual ~ShaderOpenGL(); -}; - -// called a lot, made inline - -int ShaderOpenGL::_get_uniform(int p_which) const { - ERR_FAIL_INDEX_V(p_which, uniform_count, -1); - ERR_FAIL_COND_V(!version, -1); - return version->uniform_location[p_which]; -} - -void ShaderOpenGL::_set_conditional(int p_which, bool p_value) { - ERR_FAIL_INDEX(p_which, conditional_count); - if (p_value) - new_conditional_version.version |= (1 << p_which); - else - new_conditional_version.version &= ~(1 << p_which); -} - -#endif // OPENGL_BACKEND_ENABLED - -#endif // SHADER_OPENGL_H diff --git a/drivers/opengl/shaders/SCsub b/drivers/opengl/shaders/SCsub deleted file mode 100644 index dcd8bf6030..0000000000 --- a/drivers/opengl/shaders/SCsub +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -if "OpenGL_GLSL" in env["BUILDERS"]: - env.OpenGL_GLSL("copy.glsl") - env.OpenGL_GLSL("canvas.glsl") - env.OpenGL_GLSL("canvas_shadow.glsl") - env.OpenGL_GLSL("scene.glsl") - env.OpenGL_GLSL("cubemap_filter.glsl") - env.OpenGL_GLSL("cube_to_dp.glsl") - env.OpenGL_GLSL("effect_blur.glsl") - env.OpenGL_GLSL("tonemap.glsl") - env.OpenGL_GLSL("lens_distorted.glsl") diff --git a/drivers/opengl/shaders/canvas.glsl b/drivers/opengl/shaders/canvas.glsl deleted file mode 100644 index 3dee2faa88..0000000000 --- a/drivers/opengl/shaders/canvas.glsl +++ /dev/null @@ -1,686 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -uniform highp mat4 projection_matrix; -/* clang-format on */ - -#include "stdlib.glsl" - -uniform highp mat4 modelview_matrix; -uniform highp mat4 extra_matrix; -attribute highp vec2 vertex; // attrib:0 - -#ifdef USE_ATTRIB_LIGHT_ANGLE -// shared with tangent, not used in canvas shader -attribute highp float light_angle; // attrib:2 -#endif - -attribute vec4 color_attrib; // attrib:3 -attribute vec2 uv_attrib; // attrib:4 - -#ifdef USE_ATTRIB_MODULATE -attribute highp vec4 modulate_attrib; // attrib:5 -#endif - -#ifdef USE_ATTRIB_LARGE_VERTEX -// shared with skeleton attributes, not used in batched shader -attribute highp vec2 translate_attrib; // attrib:6 -attribute highp vec4 basis_attrib; // attrib:7 -#endif - -#ifdef USE_SKELETON -attribute highp vec4 bone_indices; // attrib:6 -attribute highp vec4 bone_weights; // attrib:7 -#endif - -#ifdef USE_INSTANCING - -attribute highp vec4 instance_xform0; //attrib:8 -attribute highp vec4 instance_xform1; //attrib:9 -attribute highp vec4 instance_xform2; //attrib:10 -attribute highp vec4 instance_color; //attrib:11 - -#ifdef USE_INSTANCE_CUSTOM -attribute highp vec4 instance_custom_data; //attrib:12 -#endif - -#endif - -#ifdef USE_SKELETON -uniform highp sampler2D skeleton_texture; // texunit:-3 -uniform highp ivec2 skeleton_texture_size; -uniform highp mat4 skeleton_transform; -uniform highp mat4 skeleton_transform_inverse; -#endif - -varying vec2 uv_interp; -varying vec4 color_interp; - -#ifdef USE_ATTRIB_MODULATE -// modulate doesn't need interpolating but we need to send it to the fragment shader -varying vec4 modulate_interp; -#endif - -#ifdef MODULATE_USED -uniform vec4 final_modulate; -#endif - -uniform highp vec2 color_texpixel_size; - -#ifdef USE_TEXTURE_RECT - -uniform vec4 dst_rect; -uniform vec4 src_rect; - -#endif - -uniform highp float time; - -#ifdef USE_LIGHTING - -// light matrices -uniform highp mat4 light_matrix; -uniform highp mat4 light_matrix_inverse; -uniform highp mat4 light_local_matrix; -uniform highp mat4 shadow_matrix; -uniform highp vec4 light_color; -uniform highp vec4 light_shadow_color; -uniform highp vec2 light_pos; -uniform highp float shadowpixel_size; -uniform highp float shadow_gradient; -uniform highp float light_height; -uniform highp float light_outside_alpha; -uniform highp float shadow_distance_mult; - -varying vec4 light_uv_interp; -varying vec2 transformed_light_uv; -varying vec4 local_rot; - -#ifdef USE_SHADOWS -varying highp vec2 pos; -#endif - -const bool at_light_pass = true; -#else -const bool at_light_pass = false; -#endif - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -vec2 select(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; -} - -void main() { - vec4 color = color_attrib; - vec2 uv; - -#ifdef USE_INSTANCING - mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); - color *= instance_color; - -#ifdef USE_INSTANCE_CUSTOM - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); -#endif - -#else - mat4 extra_matrix_instance = extra_matrix; - vec4 instance_custom = vec4(0.0); -#endif - -#ifdef USE_TEXTURE_RECT - - if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z - uv = src_rect.xy + abs(src_rect.zw) * vertex.yx; - } else { - uv = src_rect.xy + abs(src_rect.zw) * vertex; - } - - vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); - - // This is what is done in the GLES 3 bindings and should - // take care of flipped rects. - // - // But it doesn't. - // I don't know why, will need to investigate further. - - outvec.xy = dst_rect.xy + abs(dst_rect.zw) * select(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))); - - // outvec.xy = dst_rect.xy + abs(dst_rect.zw) * vertex; -#else - vec4 outvec = vec4(vertex.xy, 0.0, 1.0); - - uv = uv_attrib; -#endif - - float point_size = 1.0; - - { - vec2 src_vtx = outvec.xy; - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - - gl_PointSize = point_size; - -#ifdef USE_ATTRIB_MODULATE - // modulate doesn't need interpolating but we need to send it to the fragment shader - modulate_interp = modulate_attrib; -#endif - -#ifdef USE_ATTRIB_LARGE_VERTEX - // transform is in attributes - vec2 temp; - - temp = outvec.xy; - temp.x = (outvec.x * basis_attrib.x) + (outvec.y * basis_attrib.z); - temp.y = (outvec.x * basis_attrib.y) + (outvec.y * basis_attrib.w); - - temp += translate_attrib; - outvec.xy = temp; - -#else - - // transform is in uniforms -#if !defined(SKIP_TRANSFORM_USED) - outvec = extra_matrix_instance * outvec; - outvec = modelview_matrix * outvec; -#endif - -#endif // not large integer - - color_interp = color; - -#ifdef USE_PIXEL_SNAP - outvec.xy = floor(outvec + 0.5).xy; - // precision issue on some hardware creates artifacts within texture - // offset uv by a small amount to avoid - uv += 1e-5; -#endif - -#ifdef USE_SKELETON - - // look up transform from the "pose texture" - if (bone_weights != vec4(0.0)) { - highp mat4 bone_transform = mat4(0.0); - - for (int i = 0; i < 4; i++) { - ivec2 tex_ofs = ivec2(int(bone_indices[i]) * 2, 0); - - highp mat4 b = mat4( - texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(0, 0)), - texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(1, 0)), - vec4(0.0, 0.0, 1.0, 0.0), - vec4(0.0, 0.0, 0.0, 1.0)); - - bone_transform += b * bone_weights[i]; - } - - mat4 bone_matrix = skeleton_transform * transpose(bone_transform) * skeleton_transform_inverse; - - outvec = bone_matrix * outvec; - } - -#endif - - uv_interp = uv; - gl_Position = projection_matrix * outvec; - -#ifdef USE_LIGHTING - - light_uv_interp.xy = (light_matrix * outvec).xy; - light_uv_interp.zw = (light_local_matrix * outvec).xy; - - transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping - -#ifdef USE_SHADOWS - pos = outvec.xy; -#endif - -#ifdef USE_ATTRIB_LIGHT_ANGLE - // we add a fixed offset because we are using the sign later, - // and don't want floating point error around 0.0 - float la = abs(light_angle) - 1.0; - - // vector light angle - vec4 vla; - vla.xy = vec2(cos(la), sin(la)); - vla.zw = vec2(-vla.y, vla.x); - - // vertical flip encoded in the sign - vla.zw *= sign(light_angle); - - // apply the transform matrix. - // The rotate will be encoded in the transform matrix for single rects, - // and just the flips in the light angle. - // For batching we will encode the rotation and the flips - // in the light angle, and can use the same shader. - local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.xy, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(vla.zw, 0.0, 0.0))).xy); -#else - local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy); -#ifdef USE_TEXTURE_RECT - local_rot.xy *= sign(src_rect.z); - local_rot.zw *= sign(src_rect.w); -#endif -#endif // not using light angle - -#endif -} - -/* clang-format off */ -[fragment] - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#include "stdlib.glsl" - -uniform sampler2D color_texture; // texunit:-1 -/* clang-format on */ -uniform highp vec2 color_texpixel_size; -uniform mediump sampler2D normal_texture; // texunit:-2 - -varying mediump vec2 uv_interp; -varying mediump vec4 color_interp; - -#ifdef USE_ATTRIB_MODULATE -varying mediump vec4 modulate_interp; -#endif - -uniform highp float time; - -uniform vec4 final_modulate; - -#ifdef SCREEN_TEXTURE_USED - -uniform sampler2D screen_texture; // texunit:-4 - -#endif - -#ifdef SCREEN_UV_USED - -uniform vec2 screen_pixel_size; - -#endif - -#ifdef USE_LIGHTING - -uniform highp mat4 light_matrix; -uniform highp mat4 light_local_matrix; -uniform highp mat4 shadow_matrix; -uniform highp vec4 light_color; -uniform highp vec4 light_shadow_color; -uniform highp vec2 light_pos; -uniform highp float shadowpixel_size; -uniform highp float shadow_gradient; -uniform highp float light_height; -uniform highp float light_outside_alpha; -uniform highp float shadow_distance_mult; - -uniform lowp sampler2D light_texture; // texunit:-6 -varying vec4 light_uv_interp; -varying vec2 transformed_light_uv; - -varying vec4 local_rot; - -#ifdef USE_SHADOWS - -uniform highp sampler2D shadow_texture; // texunit:-5 -varying highp vec2 pos; - -#endif - -const bool at_light_pass = true; -#else -const bool at_light_pass = false; -#endif - -uniform bool use_default_normal; - -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ - -void light_compute( - inout vec4 light, - inout vec2 light_vec, - inout float light_height, - inout vec4 light_color, - vec2 light_uv, - inout vec4 shadow_color, - inout vec2 shadow_vec, - vec3 normal, - vec2 uv, -#if defined(SCREEN_UV_USED) - vec2 screen_uv, -#endif - vec4 color) { - -#if defined(USE_LIGHT_SHADER_CODE) - - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - -#endif -} - -void main() { - vec4 color = color_interp; - vec2 uv = uv_interp; -#ifdef USE_FORCE_REPEAT - //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it - uv = mod(uv, vec2(1.0, 1.0)); -#endif - -#if !defined(COLOR_USED) - //default behavior, texture by color - color *= texture2D(color_texture, uv); -#endif - -#ifdef SCREEN_UV_USED - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; -#endif - - vec3 normal; - -#if defined(NORMAL_USED) - - bool normal_used = true; -#else - bool normal_used = false; -#endif - - if (use_default_normal) { - normal.xy = texture2D(normal_texture, uv).xy * 2.0 - 1.0; - normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); - normal_used = true; - } else { - normal = vec3(0.0, 0.0, 1.0); - } - - { - float normal_depth = 1.0; - -#if defined(NORMALMAP_USED) - vec3 normal_map = vec3(0.0, 0.0, 1.0); - normal_used = true; -#endif - - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ - -#if defined(NORMALMAP_USED) - normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); -#endif - } - -#ifdef USE_ATTRIB_MODULATE - color *= modulate_interp; -#else -#if !defined(MODULATE_USED) - color *= final_modulate; -#endif -#endif - -#ifdef USE_LIGHTING - - vec2 light_vec = transformed_light_uv; - vec2 shadow_vec = transformed_light_uv; - - if (normal_used) { - normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy; - } - - float att = 1.0; - - vec2 light_uv = light_uv_interp.xy; - vec4 light = texture2D(light_texture, light_uv); - - if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) { - color.a *= light_outside_alpha; //invisible - - } else { - float real_light_height = light_height; - vec4 real_light_color = light_color; - vec4 real_light_shadow_color = light_shadow_color; - -#if defined(USE_LIGHT_SHADER_CODE) - //light is written by the light shader - light_compute( - light, - light_vec, - real_light_height, - real_light_color, - light_uv, - real_light_shadow_color, - shadow_vec, - normal, - uv, -#if defined(SCREEN_UV_USED) - screen_uv, -#endif - color); -#endif - - light *= real_light_color; - - if (normal_used) { - vec3 light_normal = normalize(vec3(light_vec, -real_light_height)); - light *= max(dot(-light_normal, normal), 0.0); - } - - color *= light; - -#ifdef USE_SHADOWS - -#ifdef SHADOW_VEC_USED - mat3 inverse_light_matrix = mat3(light_matrix); - inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); - inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); - inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); - shadow_vec = (inverse_light_matrix * vec3(shadow_vec, 0.0)).xy; -#else - shadow_vec = light_uv_interp.zw; -#endif - - float angle_to_light = -atan(shadow_vec.x, shadow_vec.y); - float PI = 3.14159265358979323846264; - /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays - float ang*/ - - float su, sz; - - float abs_angle = abs(angle_to_light); - vec2 point; - float sh; - if (abs_angle < 45.0 * PI / 180.0) { - point = shadow_vec; - sh = 0.0 + (1.0 / 8.0); - } else if (abs_angle > 135.0 * PI / 180.0) { - point = -shadow_vec; - sh = 0.5 + (1.0 / 8.0); - } else if (angle_to_light > 0.0) { - point = vec2(shadow_vec.y, -shadow_vec.x); - sh = 0.25 + (1.0 / 8.0); - } else { - point = vec2(-shadow_vec.y, shadow_vec.x); - sh = 0.75 + (1.0 / 8.0); - } - - highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0); - s.xyz /= s.w; - su = s.x * 0.5 + 0.5; - sz = s.z * 0.5 + 0.5; - //sz=lightlength(light_vec); - - highp float shadow_attenuation = 0.0; - -#ifdef USE_RGBA_SHADOWS -#define SHADOW_DEPTH(m_tex, m_uv) dot(texture2D((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) - -#else - -#define SHADOW_DEPTH(m_tex, m_uv) (texture2D((m_tex), (m_uv)).r) - -#endif - -#ifdef SHADOW_USE_GRADIENT - - /* clang-format off */ - /* GLSL es 100 doesn't support line continuation characters(backslashes) */ -#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); } - -#else - -#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += step(sz, sd); } - /* clang-format on */ - -#endif - -#ifdef SHADOW_FILTER_NEAREST - - SHADOW_TEST(su); - -#endif - -#ifdef SHADOW_FILTER_PCF3 - - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - shadow_attenuation /= 3.0; - -#endif - -#ifdef SHADOW_FILTER_PCF5 - - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - shadow_attenuation /= 5.0; - -#endif - -#ifdef SHADOW_FILTER_PCF7 - - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - shadow_attenuation /= 7.0; - -#endif - -#ifdef SHADOW_FILTER_PCF9 - - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - shadow_attenuation /= 9.0; - -#endif - -#ifdef SHADOW_FILTER_PCF13 - - SHADOW_TEST(su + shadowpixel_size * 6.0); - SHADOW_TEST(su + shadowpixel_size * 5.0); - SHADOW_TEST(su + shadowpixel_size * 4.0); - SHADOW_TEST(su + shadowpixel_size * 3.0); - SHADOW_TEST(su + shadowpixel_size * 2.0); - SHADOW_TEST(su + shadowpixel_size); - SHADOW_TEST(su); - SHADOW_TEST(su - shadowpixel_size); - SHADOW_TEST(su - shadowpixel_size * 2.0); - SHADOW_TEST(su - shadowpixel_size * 3.0); - SHADOW_TEST(su - shadowpixel_size * 4.0); - SHADOW_TEST(su - shadowpixel_size * 5.0); - SHADOW_TEST(su - shadowpixel_size * 6.0); - shadow_attenuation /= 13.0; - -#endif - - //color *= shadow_attenuation; - color = mix(real_light_shadow_color, color, shadow_attenuation); -//use shadows -#endif - } - -//use lighting -#endif - - gl_FragColor = color; -} diff --git a/drivers/opengl/shaders/canvas_shadow.glsl b/drivers/opengl/shaders/canvas_shadow.glsl deleted file mode 100644 index 2abcd5e67c..0000000000 --- a/drivers/opengl/shaders/canvas_shadow.glsl +++ /dev/null @@ -1,60 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute highp vec3 vertex; // attrib:0 - -uniform highp mat4 projection_matrix; -/* clang-format on */ -uniform highp mat4 light_matrix; -uniform highp mat4 world_matrix; -uniform highp float distance_norm; - -varying highp vec4 position_interp; - -void main() { - gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex, 1.0))); - position_interp = gl_Position; -} - -/* clang-format off */ -[fragment] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -varying highp vec4 position_interp; -/* clang-format on */ - -void main() { - highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias - -#ifdef USE_RGBA_SHADOWS - - highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); - comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); - gl_FragColor = comp; -#else - - gl_FragColor = vec4(depth); -#endif -} diff --git a/drivers/opengl/shaders/copy.glsl b/drivers/opengl/shaders/copy.glsl deleted file mode 100644 index e833722ac3..0000000000 --- a/drivers/opengl/shaders/copy.glsl +++ /dev/null @@ -1,191 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute highp 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; - -// These definitions are here because the shader-wrapper builder does -// not understand `#elif defined()` -#ifdef USE_DISPLAY_TRANSFORM -#endif - -#ifdef USE_COPY_SECTION -uniform highp vec4 copy_section; -#elif defined(USE_DISPLAY_TRANSFORM) -uniform highp mat4 display_transform; -#endif - -void main() { -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) - cube_interp = cube_in; -#elif defined(USE_ASYM_PANO) - uv_interp = vertex_attrib.xy; -#else - uv_interp = uv_in; -#endif - - uv2_interp = uv2_in; - gl_Position = vertex_attrib; - -#ifdef USE_COPY_SECTION - uv_interp = copy_section.xy + uv_interp * copy_section.zw; - gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; -#elif defined(USE_DISPLAY_TRANSFORM) - uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy; -#endif -} - -/* clang-format off */ -[fragment] - -#define M_PI 3.14159265359 - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#if defined(USE_CUBEMAP) || defined(USE_PANORAMA) -varying vec3 cube_interp; -#else -varying vec2 uv_interp; -#endif -/* clang-format on */ - -#ifdef USE_ASYM_PANO -uniform highp mat4 pano_transform; -uniform highp vec4 asym_proj; -#endif - -#ifdef USE_CUBEMAP -uniform samplerCube source_cube; // texunit:0 -#else -uniform sampler2D source; // texunit:0 -#endif - -#ifdef SEP_CBCR_TEXTURE -uniform sampler2D CbCr; //texunit:1 -#endif - -varying vec2 uv2_interp; - -#ifdef USE_MULTIPLIER -uniform float multiplier; -#endif - -#ifdef USE_CUSTOM_ALPHA -uniform float custom_alpha; -#endif - -#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO) -uniform highp mat4 sky_transform; - -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() { -#ifdef USE_PANORAMA - - vec3 cube_normal = normalize(cube_interp); - cube_normal.z = -cube_normal.z; - cube_normal = mat3(sky_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(source, cube_normal); - -#elif defined(USE_ASYM_PANO) - - // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. - // Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted. - // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. - - vec3 cube_normal; - cube_normal.z = -1.0; - cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; - cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; - cube_normal = mat3(sky_transform) * mat3(pano_transform) * cube_normal; - cube_normal.z = -cube_normal.z; - - vec4 color = texturePanorama(source, normalize(cube_normal.xyz)); - -#elif defined(USE_CUBEMAP) - vec4 color = textureCube(source_cube, normalize(cube_interp)); -#elif defined(SEP_CBCR_TEXTURE) - vec4 color; - color.r = texture2D(source, uv_interp).r; - color.gb = texture2D(CbCr, uv_interp).rg - vec2(0.5, 0.5); - color.a = 1.0; -#else - vec4 color = texture2D(source, uv_interp); -#endif - -#ifdef YCBCR_TO_RGB - // YCbCr -> RGB conversion - - // Using BT.601, which is the standard for SDTV is provided as a reference - color.rgb = mat3( - vec3(1.00000, 1.00000, 1.00000), - vec3(0.00000, -0.34413, 1.77200), - vec3(1.40200, -0.71414, 0.00000)) * - color.rgb; -#endif - -#ifdef USE_NO_ALPHA - color.a = 1.0; -#endif - -#ifdef USE_CUSTOM_ALPHA - color.a = custom_alpha; -#endif - -#ifdef USE_MULTIPLIER - color.rgb *= multiplier; -#endif - - gl_FragColor = color; -} diff --git a/drivers/opengl/shaders/cube_to_dp.glsl b/drivers/opengl/shaders/cube_to_dp.glsl deleted file mode 100644 index 1612ec3d5a..0000000000 --- a/drivers/opengl/shaders/cube_to_dp.glsl +++ /dev/null @@ -1,100 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision mediump float; -precision mediump int; -#endif - -attribute highp vec4 vertex_attrib; // attrib:0 -/* clang-format on */ -attribute vec2 uv_in; // attrib:4 - -varying vec2 uv_interp; - -void main() { - uv_interp = uv_in; - gl_Position = vertex_attrib; -} - -/* clang-format off */ -[fragment] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -uniform highp samplerCube source_cube; //texunit:0 -/* clang-format on */ -varying vec2 uv_interp; - -uniform bool z_flip; -uniform highp float z_far; -uniform highp float z_near; -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)); - } else { - 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 = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y)); - normal = normalize(normal); - /* - normal.z = 0.5; - normal = normalize(normal); - */ - - if (!z_flip) { - normal.z = -normal.z; - } - - //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 )); - 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); - } else { - // 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); - - 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; -} diff --git a/drivers/opengl/shaders/cubemap_filter.glsl b/drivers/opengl/shaders/cubemap_filter.glsl deleted file mode 100644 index f5c91cc707..0000000000 --- a/drivers/opengl/shaders/cubemap_filter.glsl +++ /dev/null @@ -1,231 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute highp vec2 vertex; // attrib:0 -/* clang-format on */ -attribute highp vec2 uv; // attrib:4 - -varying highp vec2 uv_interp; - -void main() { - uv_interp = uv; - gl_Position = vec4(vertex, 0, 1); -} - -/* clang-format off */ -[fragment] - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif - -#endif - -#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; -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 - -#else - -#define SAMPLE_COUNT 512 - -#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); - - return texture2DLod(pano, st, 0.0); -} - -#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; - for (int i = 0; i < 6; i++) { - if (i == faceID) { - result = (faceUvVectors[i][0] * uv.x) + (faceUvVectors[i][1] * uv.y) + faceUvVectors[i][2]; - break; - } - } - return normalize(result); -} - -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 SinTheta = sqrt(1.0 - CosTheta * CosTheta); - - // Convert to spherical direction - vec3 H; - H.x = SinTheta * cos(Phi); - H.y = SinTheta * sin(Phi); - H.z = CosTheta; - - vec3 UpVector = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); - vec3 TangentX = normalize(cross(UpVector, N)); - vec3 TangentY = cross(N, TangentX); - - // Tangent to world space - return TangentX * H.x + TangentY * H.y + N * H.z; -} - -float radical_inverse_VdC(int i) { - return texture2D(radical_inverse_vdc_cache, vec2(float(i) / 512.0, 0.0)).x; -} - -vec2 Hammersley(int i, int N) { - return vec2(float(i) / float(N), radical_inverse_VdC(i)); -} - -uniform bool z_flip; - -void main() { - vec3 color = vec3(0.0); - - vec2 uv = (uv_interp * 2.0) - 1.0; - vec3 N = texelCoordToVec(uv, face_id); - -#ifdef USE_DIRECT_WRITE - -#ifdef USE_SOURCE_PANORAMA - - gl_FragColor = vec4(texturePanorama(source_panorama, N).rgb, 1.0); -#else - - gl_FragColor = vec4(textureCube(source_cube, N).rgb, 1.0); -#endif //USE_SOURCE_PANORAMA - -#else - - vec4 sum = vec4(0.0); - - for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) { - vec2 xi = Hammersley(sample_num, SAMPLE_COUNT); - - 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); - - if (NdotL > 0.0) { - -#ifdef USE_SOURCE_PANORAMA - vec3 val = texturePanorama(source_panorama, L).rgb; -#else - vec3 val = textureCubeLod(source_cube, L, 0.0).rgb; -#endif - //mix using Linear, to approximate high end back-end - val = mix(pow((val + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), val * (1.0 / 12.92), vec3(lessThan(val, vec3(0.04045)))); - - sum.rgb += val * NdotL; - - sum.a += NdotL; - } - } - - sum /= sum.a; - - vec3 a = vec3(0.055); - sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308)))); - - gl_FragColor = vec4(sum.rgb, 1.0); -#endif -} diff --git a/drivers/opengl/shaders/effect_blur.glsl b/drivers/opengl/shaders/effect_blur.glsl deleted file mode 100644 index 7b607dd76a..0000000000 --- a/drivers/opengl/shaders/effect_blur.glsl +++ /dev/null @@ -1,308 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute vec2 vertex_attrib; // attrib:0 -/* clang-format on */ -attribute vec2 uv_in; // attrib:4 - -varying vec2 uv_interp; - -#ifdef USE_BLUR_SECTION - -uniform vec4 blur_section; - -#endif - -void main() { - uv_interp = uv_in; - gl_Position = vec4(vertex_attrib, 0.0, 1.0); -#ifdef USE_BLUR_SECTION - - uv_interp = blur_section.xy + uv_interp * blur_section.zw; - gl_Position.xy = (blur_section.xy + (gl_Position.xy * 0.5 + 0.5) * blur_section.zw) * 2.0 - 1.0; -#endif -} - -/* clang-format off */ -[fragment] - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -varying vec2 uv_interp; -/* clang-format on */ -uniform sampler2D source_color; //texunit:0 - -uniform float lod; -uniform vec2 pixel_size; - -#if defined(GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL) - -uniform float glow_strength; - -#endif - -#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR) - -#ifdef USE_GLES_OVER_GL -#ifdef DOF_QUALITY_LOW -const int dof_kernel_size = 5; -const int dof_kernel_from = 2; -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); - -#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); -#endif -#endif - -uniform sampler2D dof_source_depth; //texunit:1 -uniform float dof_begin; -uniform float dof_end; -uniform vec2 dof_dir; -uniform float dof_radius; - -#endif - -#ifdef GLOW_FIRST_PASS - -uniform highp float luminance_cap; - -uniform float glow_bloom; -uniform float glow_hdr_threshold; -uniform float glow_hdr_scale; - -#endif - -uniform float camera_z_far; -uniform float camera_z_near; - -void main() { -#ifdef GLOW_GAUSSIAN_HORIZONTAL - vec2 pix_size = pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = texture2DLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.174938; - color += texture2DLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.165569; - color += texture2DLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.140367; - color += texture2DLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.106595; - color += texture2DLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.165569; - color += texture2DLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.140367; - color += texture2DLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.106595; - color *= glow_strength; - gl_FragColor = color; -#endif - -#ifdef GLOW_GAUSSIAN_VERTICAL - vec4 color = texture2DLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.288713; - color += texture2DLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.233062; - color += texture2DLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.122581; - color += texture2DLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062; - color += texture2DLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581; - color *= glow_strength; - gl_FragColor = color; -#endif - -#ifndef USE_GLES_OVER_GL -#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; - float dof_kernel[5]; - dof_kernel[0] = 0.153388; - dof_kernel[1] = 0.221461; - dof_kernel[2] = 0.250301; - dof_kernel[3] = 0.221461; - dof_kernel[4] = 0.153388; -#endif - -#ifdef DOF_QUALITY_MEDIUM - const int dof_kernel_size = 11; - const int dof_kernel_from = 5; - float dof_kernel[11]; - dof_kernel[0] = 0.055037; - dof_kernel[1] = 0.072806; - dof_kernel[2] = 0.090506; - dof_kernel[3] = 0.105726; - dof_kernel[4] = 0.116061; - dof_kernel[5] = 0.119726; - dof_kernel[6] = 0.116061; - dof_kernel[7] = 0.105726; - dof_kernel[8] = 0.090506; - dof_kernel[9] = 0.072806; - dof_kernel[10] = 0.055037; -#endif - -#ifdef DOF_QUALITY_HIGH - const int dof_kernel_size = 21; - const int dof_kernel_from = 10; - float dof_kernel[21]; - dof_kernel[0] = 0.028174; - dof_kernel[1] = 0.032676; - dof_kernel[2] = 0.037311; - dof_kernel[3] = 0.041944; - dof_kernel[4] = 0.046421; - dof_kernel[5] = 0.050582; - dof_kernel[6] = 0.054261; - dof_kernel[7] = 0.057307; - dof_kernel[8] = 0.059587; - dof_kernel[9] = 0.060998; - dof_kernel[10] = 0.061476; - dof_kernel[11] = 0.060998; - dof_kernel[12] = 0.059587; - dof_kernel[13] = 0.057307; - dof_kernel[14] = 0.054261; - dof_kernel[15] = 0.050582; - dof_kernel[16] = 0.046421; - dof_kernel[17] = 0.041944; - dof_kernel[18] = 0.037311; - dof_kernel[19] = 0.032676; - dof_kernel[20] = 0.028174; -#endif -#endif -#endif //!USE_GLES_OVER_GL - -#ifdef DOF_FAR_BLUR - - vec4 color_accum = vec4(0.0); - - float depth = texture2DLod(dof_source_depth, uv_interp, 0.0).r; - depth = depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#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; - - for (int i = 0; i < dof_kernel_size; i++) { - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius; - - float tap_k = dof_kernel[i]; - - float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); -#endif - float tap_amount = int_ofs == 0 ? 1.0 : smoothstep(dof_begin, dof_end, tap_depth); - tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - - vec4 tap_color = texture2DLod(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; - } - - gl_FragColor = color_accum; ///k_accum; - -#endif - -#ifdef DOF_NEAR_BLUR - - vec4 color_accum = vec4(0.0); - - float max_accum = 0.0; - - for (int i = 0; i < dof_kernel_size; i++) { - int int_ofs = i - dof_kernel_from; - vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius; - float ofs_influence = max(0.0, 1.0 - abs(float(int_ofs)) / float(dof_kernel_from)); - - float tap_k = dof_kernel[i]; - - vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0); - - float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r; - tap_depth = tap_depth * 2.0 - 1.0; -#ifdef USE_ORTHOGONAL_PROJECTION - tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; -#else - tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); -#endif - float tap_amount = 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); - -#endif - - 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)); - - gl_FragColor = color_accum; - -#endif - -#ifdef GLOW_FIRST_PASS - - float luminance = max(gl_FragColor.r, max(gl_FragColor.g, gl_FragColor.b)); - float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom); - - gl_FragColor = min(gl_FragColor * feedback, vec4(luminance_cap)); - -#endif -} diff --git a/drivers/opengl/shaders/lens_distorted.glsl b/drivers/opengl/shaders/lens_distorted.glsl deleted file mode 100644 index d568006ccc..0000000000 --- a/drivers/opengl/shaders/lens_distorted.glsl +++ /dev/null @@ -1,84 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute highp vec2 vertex; // attrib:0 -/* clang-format on */ - -uniform vec2 offset; -uniform vec2 scale; - -varying vec2 uv_interp; - -void main() { - uv_interp = vertex.xy * 2.0 - 1.0; - - vec2 v = vertex.xy * scale + offset; - gl_Position = vec4(v, 0.0, 1.0); -} - -/* clang-format off */ -[fragment] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -uniform sampler2D source; //texunit:0 -/* clang-format on */ - -uniform vec2 eye_center; -uniform float k1; -uniform float k2; -uniform float upscale; -uniform float aspect_ratio; - -varying vec2 uv_interp; - -void main() { - vec2 coords = uv_interp; - vec2 offset = coords - eye_center; - - // take aspect ratio into account - offset.y /= aspect_ratio; - - // distort - vec2 offset_sq = offset * offset; - float radius_sq = offset_sq.x + offset_sq.y; - float radius_s4 = radius_sq * radius_sq; - float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); - offset *= distortion_scale; - - // reapply aspect ratio - offset.y *= aspect_ratio; - - // add our eye center back in - coords = offset + eye_center; - coords /= upscale; - - // and check our color - if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { - gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); - } else { - coords = (coords + vec2(1.0)) / vec2(2.0); - gl_FragColor = texture2D(source, coords); - } -} diff --git a/drivers/opengl/shaders/scene.glsl b/drivers/opengl/shaders/scene.glsl deleted file mode 100644 index ba3a81a532..0000000000 --- a/drivers/opengl/shaders/scene.glsl +++ /dev/null @@ -1,2176 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -/* clang-format on */ -#include "stdlib.glsl" -/* clang-format off */ - -#define SHADER_IS_SRGB true - -#define M_PI 3.14159265359 - -// -// attributes -// - -attribute highp vec4 vertex_attrib; // attrib:0 -/* clang-format on */ -attribute vec3 normal_attrib; // attrib:1 - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -attribute vec4 tangent_attrib; // attrib:2 -#endif - -#if defined(ENABLE_COLOR_INTERP) -attribute vec4 color_attrib; // attrib:3 -#endif - -#if defined(ENABLE_UV_INTERP) -attribute vec2 uv_attrib; // attrib:4 -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -attribute vec2 uv2_attrib; // attrib:5 -#endif - -#ifdef USE_SKELETON - -#ifdef USE_SKELETON_SOFTWARE - -attribute highp vec4 bone_transform_row_0; // attrib:13 -attribute highp vec4 bone_transform_row_1; // attrib:14 -attribute highp vec4 bone_transform_row_2; // attrib:15 - -#else - -attribute vec4 bone_ids; // attrib:6 -attribute highp vec4 bone_weights; // attrib:7 - -uniform highp sampler2D bone_transforms; // texunit:-1 -uniform ivec2 skeleton_texture_size; - -#endif - -#endif - -#ifdef USE_INSTANCING - -attribute highp vec4 instance_xform_row_0; // attrib:8 -attribute highp vec4 instance_xform_row_1; // attrib:9 -attribute highp vec4 instance_xform_row_2; // attrib:10 - -attribute highp vec4 instance_color; // attrib:11 -attribute highp vec4 instance_custom_data; // attrib:12 - -#endif - -// -// uniforms -// - -uniform highp mat4 camera_matrix; -uniform highp mat4 camera_inverse_matrix; -uniform highp mat4 projection_matrix; -uniform highp mat4 projection_inverse_matrix; - -uniform highp mat4 world_transform; - -uniform highp float time; - -uniform highp vec2 viewport_size; - -#ifdef RENDER_DEPTH -uniform float light_bias; -uniform float light_normal_bias; -#endif - -// -// varyings -// - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) -varying highp vec4 position_interp; -#endif - -varying highp vec3 vertex_interp; -varying vec3 normal_interp; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -varying vec3 tangent_interp; -varying vec3 binormal_interp; -#endif - -#if defined(ENABLE_COLOR_INTERP) -varying vec4 color_interp; -#endif - -#if defined(ENABLE_UV_INTERP) -varying vec2 uv_interp; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -varying vec2 uv2_interp; -#endif - -/* clang-format off */ - -VERTEX_SHADER_GLOBALS - -/* clang-format on */ - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - -varying highp float dp_clip; -uniform highp float shadow_dual_paraboloid_render_zfar; -uniform highp float shadow_dual_paraboloid_render_side; - -#endif - -#if defined(USE_SHADOW) && defined(USE_LIGHTING) - -uniform highp mat4 light_shadow_matrix; -varying highp vec4 shadow_coord; - -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) -uniform highp mat4 light_shadow_matrix2; -varying highp vec4 shadow_coord2; -#endif - -#if defined(LIGHT_USE_PSSM4) - -uniform highp mat4 light_shadow_matrix3; -uniform highp mat4 light_shadow_matrix4; -varying highp vec4 shadow_coord3; -varying highp vec4 shadow_coord4; - -#endif - -#endif - -#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) - -varying highp vec3 diffuse_interp; -varying highp vec3 specular_interp; - -// general for all lights -uniform highp vec4 light_color; -uniform highp vec4 shadow_color; -uniform highp float light_specular; - -// directional -uniform highp vec3 light_direction; - -// omni -uniform highp vec3 light_position; - -uniform highp float light_range; -uniform highp float light_attenuation; - -// spot -uniform highp float light_spot_attenuation; -uniform highp float light_spot_range; -uniform highp float light_spot_angle; - -void light_compute( - vec3 N, - vec3 L, - vec3 V, - vec3 light_color, - vec3 attenuation, - float roughness) { -//this makes lights behave closer to linear, but then addition of lights looks bad -//better left disabled - -//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); -/* -#define SRGB_APPROX(m_var) {\ - float S1 = sqrt(m_var);\ - float S2 = sqrt(S1);\ - float S3 = sqrt(S2);\ - m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ - } -*/ -#define SRGB_APPROX(m_var) - - float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); - -#if defined(DIFFUSE_OREN_NAYAR) - vec3 diffuse_brdf_NL; -#else - float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance -#endif - -#if defined(DIFFUSE_LAMBERT_WRAP) - // energy conserving lambert wrap shader - diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - -#elif defined(DIFFUSE_OREN_NAYAR) - - { - // see http://mimosa-pudica.net/improved-oren-nayar.html - float LdotV = dot(L, V); - - float s = LdotV - NdotL * NdotV; - float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); - - float sigma2 = roughness * roughness; // TODO: this needs checking - vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); - - diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); - } -#else - // lambert by default for everything else - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - SRGB_APPROX(diffuse_brdf_NL) - - diffuse_interp += light_color * diffuse_brdf_NL * attenuation; - - if (roughness > 0.0) { - // D - float specular_brdf_NL = 0.0; - -#if !defined(SPECULAR_DISABLED) - //normalized blinn always unless disabled - vec3 H = normalize(V + L); - float cNdotH = max(dot(N, H), 0.0); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = blinn; -#endif - - SRGB_APPROX(specular_brdf_NL) - specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI); - } -} - -#endif - -#ifdef USE_VERTEX_LIGHTING - -#ifdef USE_REFLECTION_PROBE1 - -uniform highp mat4 refprobe1_local_matrix; -varying mediump vec4 refprobe1_reflection_normal_blend; -uniform highp vec3 refprobe1_box_extents; - -#ifndef USE_LIGHTMAP -varying mediump vec3 refprobe1_ambient_normal; -#endif - -#endif //reflection probe1 - -#ifdef USE_REFLECTION_PROBE2 - -uniform highp mat4 refprobe2_local_matrix; -varying mediump vec4 refprobe2_reflection_normal_blend; -uniform highp vec3 refprobe2_box_extents; - -#ifndef USE_LIGHTMAP -varying mediump vec3 refprobe2_ambient_normal; -#endif - -#endif //reflection probe2 - -#endif //vertex lighting for refprobes - -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -varying vec4 fog_interp; - -uniform mediump vec4 fog_color_base; -#ifdef LIGHT_MODE_DIRECTIONAL -uniform mediump vec4 fog_sun_color_amount; -#endif - -uniform bool fog_transmit_enabled; -uniform mediump float fog_transmit_curve; - -#ifdef FOG_DEPTH_ENABLED -uniform highp float fog_depth_begin; -uniform mediump float fog_depth_curve; -uniform mediump float fog_max_distance; -#endif - -#ifdef FOG_HEIGHT_ENABLED -uniform highp float fog_height_min; -uniform highp float fog_height_max; -uniform mediump float fog_height_curve; -#endif - -#endif //fog - -void main() { - highp vec4 vertex = vertex_attrib; - - mat4 world_matrix = world_transform; - -#ifdef USE_INSTANCING - { - 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; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - vec3 tangent = tangent_attrib.xyz; - float binormalf = tangent_attrib.a; - vec3 binormal = normalize(cross(normal, tangent) * binormalf); -#endif - -#if defined(ENABLE_COLOR_INTERP) - color_interp = color_attrib; -#ifdef USE_INSTANCING - color_interp *= instance_color; -#endif -#endif - -#if defined(ENABLE_UV_INTERP) - uv_interp = uv_attrib; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) - uv2_interp = uv2_attrib; -#endif - -#if defined(OVERRIDE_POSITION) - highp vec4 position; -#endif - -#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - vertex = world_matrix * vertex; - normal = normalize((world_matrix * vec4(normal, 0.0)).xyz); -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - - tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz); -#endif -#endif - -#ifdef USE_SKELETON - - highp mat4 bone_transform = mat4(0.0); - -#ifdef USE_SKELETON_SOFTWARE - // passing the transform as attributes - - 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); - -#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); - - 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)); - - bone_transform += transpose(b) * bone_weights[i]; - } - } - -#endif - - world_matrix = world_matrix * bone_transform; - -#endif - -#ifdef USE_INSTANCING - vec4 instance_custom = instance_custom_data; -#else - vec4 instance_custom = vec4(0.0); - -#endif - - mat4 local_projection_matrix = projection_matrix; - - mat4 modelview = camera_inverse_matrix * world_matrix; - float roughness = 1.0; - -#define projection_matrix local_projection_matrix -#define world_transform world_matrix - - float point_size = 1.0; - - { - /* clang-format off */ - -VERTEX_SHADER_CODE - - /* clang-format on */ - } - - gl_PointSize = point_size; - vec4 outvec = vertex; - - // 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) - tangent = normalize((modelview * vec4(tangent, 0.0)).xyz); - binormal = normalize((modelview * vec4(binormal, 0.0)).xyz); -#endif -#endif - -#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) - 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) - 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; - - dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias - - //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges - - highp vec3 vtx = vertex_interp + normalize(vertex_interp) * light_bias; - highp float distance = length(vtx); - vtx = normalize(vtx); - vtx.xy /= 1.0 - vtx.z; - vtx.z = (distance / shadow_dual_paraboloid_render_zfar); - vtx.z = vtx.z * 2.0 - 1.0; - - vertex_interp = vtx; - -#else - float z_ofs = light_bias; - z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias; - - vertex_interp.z -= z_ofs; -#endif //dual parabolloid - -#endif //depth - -//vertex lighting -#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) - //vertex shaded version of lighting (more limited) - vec3 L; - vec3 light_att; - -#ifdef LIGHT_MODE_OMNI - vec3 light_vec = light_position - vertex_interp; - float light_length = length(light_vec); - - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - - vec3 attenuation = vec3(omni_attenuation); - light_att = vec3(omni_attenuation); - } else { - light_att = vec3(0.0); - } - - L = normalize(light_vec); - -#endif - -#ifdef LIGHT_MODE_SPOT - - vec3 light_rel_vec = light_position - vertex_interp; - float light_length = length(light_rel_vec); - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; - - float angle = dot(-normalize(light_rel_vec), spot_dir); - - if (angle > spot_cutoff) { - float scos = max(angle, spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - - light_att = vec3(spot_attenuation); - } else { - light_att = vec3(0.0); - } - } else { - light_att = vec3(0.0); - } - - L = normalize(light_rel_vec); - -#endif - -#ifdef LIGHT_MODE_DIRECTIONAL - vec3 light_vec = -light_direction; - light_att = vec3(1.0); //no base attenuation - L = normalize(light_vec); -#endif - - diffuse_interp = vec3(0.0); - specular_interp = vec3(0.0); - light_compute(normal_interp, L, -normalize(vertex_interp), light_color.rgb, light_att, roughness); - -#endif - -//shadows (for both vertex and fragment) -#if defined(USE_SHADOW) && defined(USE_LIGHTING) - - vec4 vi4 = vec4(vertex_interp, 1.0); - shadow_coord = light_shadow_matrix * vi4; - -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) - shadow_coord2 = light_shadow_matrix2 * vi4; -#endif - -#if defined(LIGHT_USE_PSSM4) - shadow_coord3 = light_shadow_matrix3 * vi4; - shadow_coord4 = light_shadow_matrix4 * vi4; - -#endif - -#endif //use shadow and use lighting - -#ifdef USE_VERTEX_LIGHTING - -#ifdef USE_REFLECTION_PROBE1 - { - vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); - vec3 local_pos = (refprobe1_local_matrix * vec4(vertex_interp, 1.0)).xyz; - vec3 inner_pos = abs(local_pos / refprobe1_box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - { - vec3 local_ref_vec = (refprobe1_local_matrix * vec4(ref_normal, 0.0)).xyz; - refprobe1_reflection_normal_blend.xyz = local_ref_vec; - refprobe1_reflection_normal_blend.a = blend; - } -#ifndef USE_LIGHTMAP - - refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz; -#endif - } - -#endif //USE_REFLECTION_PROBE1 - -#ifdef USE_REFLECTION_PROBE2 - { - vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); - vec3 local_pos = (refprobe2_local_matrix * vec4(vertex_interp, 1.0)).xyz; - vec3 inner_pos = abs(local_pos / refprobe2_box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - - { - vec3 local_ref_vec = (refprobe2_local_matrix * vec4(ref_normal, 0.0)).xyz; - refprobe2_reflection_normal_blend.xyz = local_ref_vec; - refprobe2_reflection_normal_blend.a = blend; - } -#ifndef USE_LIGHTMAP - - refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz; -#endif - } - -#endif //USE_REFLECTION_PROBE2 - -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - - float fog_amount = 0.0; - -#ifdef LIGHT_MODE_DIRECTIONAL - - vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex_interp), light_direction), 0.0), 8.0)); -#else - vec3 fog_color = fog_color_base.rgb; -#endif - -#ifdef FOG_DEPTH_ENABLED - - { - float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); - - fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; - } -#endif - -#ifdef FOG_HEIGHT_ENABLED - { - float y = (camera_matrix * vec4(vertex_interp, 1.0)).y; - fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); - } -#endif - fog_interp = vec4(fog_color, fog_amount); - -#endif //fog - -#endif //use vertex lighting - -#if defined(OVERRIDE_POSITION) - gl_Position = position; -#else - gl_Position = projection_matrix * vec4(vertex_interp, 1.0); -#endif - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) - position_interp = gl_Position; -#endif -} - -/* clang-format off */ -[fragment] - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#include "stdlib.glsl" - -#define M_PI 3.14159265359 -#define SHADER_IS_SRGB true - -// -// uniforms -// - -uniform highp mat4 camera_matrix; -/* clang-format on */ -uniform highp mat4 camera_inverse_matrix; -uniform highp mat4 projection_matrix; -uniform highp mat4 projection_inverse_matrix; - -uniform highp mat4 world_transform; - -uniform highp float time; - -uniform highp vec2 viewport_size; - -#if defined(SCREEN_UV_USED) -uniform vec2 screen_pixel_size; -#endif - -#if defined(SCREEN_TEXTURE_USED) -uniform highp sampler2D screen_texture; //texunit:-4 -#endif -#if defined(DEPTH_TEXTURE_USED) -uniform highp sampler2D depth_texture; //texunit:-4 -#endif - -#ifdef USE_REFLECTION_PROBE1 - -#ifdef USE_VERTEX_LIGHTING - -varying mediump vec4 refprobe1_reflection_normal_blend; -#ifndef USE_LIGHTMAP -varying mediump vec3 refprobe1_ambient_normal; -#endif - -#else - -uniform bool refprobe1_use_box_project; -uniform highp vec3 refprobe1_box_extents; -uniform vec3 refprobe1_box_offset; -uniform highp mat4 refprobe1_local_matrix; - -#endif //use vertex lighting - -uniform bool refprobe1_exterior; - -uniform highp samplerCube reflection_probe1; //texunit:-5 - -uniform float refprobe1_intensity; -uniform vec4 refprobe1_ambient; - -#endif //USE_REFLECTION_PROBE1 - -#ifdef USE_REFLECTION_PROBE2 - -#ifdef USE_VERTEX_LIGHTING - -varying mediump vec4 refprobe2_reflection_normal_blend; -#ifndef USE_LIGHTMAP -varying mediump vec3 refprobe2_ambient_normal; -#endif - -#else - -uniform bool refprobe2_use_box_project; -uniform highp vec3 refprobe2_box_extents; -uniform vec3 refprobe2_box_offset; -uniform highp mat4 refprobe2_local_matrix; - -#endif //use vertex lighting - -uniform bool refprobe2_exterior; - -uniform highp samplerCube reflection_probe2; //texunit:-6 - -uniform float refprobe2_intensity; -uniform vec4 refprobe2_ambient; - -#endif //USE_REFLECTION_PROBE2 - -#define RADIANCE_MAX_LOD 6.0 - -#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) - -void reflection_process(samplerCube reflection_map, -#ifdef USE_VERTEX_LIGHTING - vec3 ref_normal, -#ifndef USE_LIGHTMAP - vec3 amb_normal, -#endif - float ref_blend, - -#else //no vertex lighting - vec3 normal, vec3 vertex, - mat4 local_matrix, - bool use_box_project, vec3 box_extents, vec3 box_offset, -#endif //vertex lighting - bool exterior, float intensity, vec4 ref_ambient, float roughness, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { - vec4 reflection; - -#ifdef USE_VERTEX_LIGHTING - - reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; - - float blend = ref_blend; //crappier blend formula for vertex - blend *= blend; - blend = max(0.0, 1.0 - blend); - -#else //fragment lighting - - vec3 local_pos = (local_matrix * vec4(vertex, 1.0)).xyz; - - if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box - return; - } - - vec3 inner_pos = abs(local_pos / box_extents); - float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); - blend = mix(length(inner_pos), blend, blend); - blend *= blend; - blend = max(0.0, 1.0 - blend); - - //reflect and make local - vec3 ref_normal = normalize(reflect(vertex, normal)); - ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz; - - if (use_box_project) { //box project - - vec3 nrdir = normalize(ref_normal); - vec3 rbmax = (box_extents - local_pos) / nrdir; - vec3 rbmin = (-box_extents - local_pos) / nrdir; - - vec3 rbminmax = mix(rbmin, rbmax, vec3(greaterThan(nrdir, vec3(0.0, 0.0, 0.0)))); - - float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); - vec3 posonbox = local_pos + nrdir * fa; - ref_normal = posonbox - box_offset.xyz; - } - - reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; -#endif - - if (exterior) { - reflection.rgb = mix(skybox, reflection.rgb, blend); - } - reflection.rgb *= intensity; - reflection.a = blend; - reflection.rgb *= blend; - - reflection_accum += reflection; - -#ifndef USE_LIGHTMAP - - vec4 ambient_out; -#ifndef USE_VERTEX_LIGHTING - - vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz; -#endif - - ambient_out.rgb = textureCubeLod(reflection_map, amb_normal, RADIANCE_MAX_LOD).rgb; - ambient_out.rgb = mix(ref_ambient.rgb, ambient_out.rgb, ref_ambient.a); - if (exterior) { - ambient_out.rgb = mix(ambient, ambient_out.rgb, blend); - } - - ambient_out.a = blend; - ambient_out.rgb *= blend; - ambient_accum += ambient_out; - -#endif -} - -#endif //use refprobe 1 or 2 - -#ifdef USE_LIGHTMAP -uniform mediump sampler2D lightmap; //texunit:-4 -uniform mediump float lightmap_energy; -#endif - -#ifdef USE_LIGHTMAP_CAPTURE -uniform mediump vec4[12] lightmap_captures; -uniform bool lightmap_capture_sky; - -#endif - -#ifdef USE_RADIANCE_MAP - -uniform samplerCube radiance_map; // texunit:-2 - -uniform mat4 radiance_inverse_xform; - -#endif - -uniform vec4 bg_color; -uniform float bg_energy; - -uniform float ambient_sky_contribution; -uniform vec4 ambient_color; -uniform float ambient_energy; - -#ifdef USE_LIGHTING - -uniform highp vec4 shadow_color; - -#ifdef USE_VERTEX_LIGHTING - -//get from vertex -varying highp vec3 diffuse_interp; -varying highp vec3 specular_interp; - -uniform highp vec3 light_direction; //may be used by fog, so leave here - -#else -//done in fragment -// general for all lights -uniform highp vec4 light_color; - -uniform highp float light_specular; - -// directional -uniform highp vec3 light_direction; -// omni -uniform highp vec3 light_position; - -uniform highp float light_attenuation; - -// spot -uniform highp float light_spot_attenuation; -uniform highp float light_spot_range; -uniform highp float light_spot_angle; -#endif - -//this is needed outside above if because dual paraboloid wants it -uniform highp float light_range; - -#ifdef USE_SHADOW - -uniform highp vec2 shadow_pixel_size; - -#if defined(LIGHT_MODE_OMNI) || defined(LIGHT_MODE_SPOT) -uniform highp sampler2D light_shadow_atlas; //texunit:-3 -#endif - -#ifdef LIGHT_MODE_DIRECTIONAL -uniform highp sampler2D light_directional_shadow; // texunit:-3 -uniform highp vec4 light_split_offsets; -#endif - -varying highp vec4 shadow_coord; - -#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) -varying highp vec4 shadow_coord2; -#endif - -#if defined(LIGHT_USE_PSSM4) - -varying highp vec4 shadow_coord3; -varying highp vec4 shadow_coord4; - -#endif - -uniform vec4 light_clamp; - -#endif // light shadow - -// directional shadow - -#endif - -// -// varyings -// - -#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) -varying highp vec4 position_interp; -#endif - -varying highp vec3 vertex_interp; -varying vec3 normal_interp; - -#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) -varying vec3 tangent_interp; -varying vec3 binormal_interp; -#endif - -#if defined(ENABLE_COLOR_INTERP) -varying vec4 color_interp; -#endif - -#if defined(ENABLE_UV_INTERP) -varying vec2 uv_interp; -#endif - -#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) -varying vec2 uv2_interp; -#endif - -varying vec3 view_interp; - -vec3 F0(float metallic, float specular, vec3 albedo) { - float dielectric = 0.16 * specular * specular; - // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; - // see https://google.github.io/filament/Filament.md.html - return mix(vec3(dielectric), albedo, vec3(metallic)); -} - -/* clang-format off */ - -FRAGMENT_SHADER_GLOBALS - -/* clang-format on */ - -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - -varying highp float dp_clip; - -#endif - -#ifdef USE_LIGHTING - -// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. -// We're dividing this factor off because the overall term we'll end up looks like -// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): -// -// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) -// -// We're basically regouping this as -// -// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] -// -// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. -// -// The contents of the D and G (G1) functions (GGX) are taken from -// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). -// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). - -/* -float G_GGX_2cos(float cos_theta_m, float alpha) { - // Schlick's approximation - // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) - // Eq. (19), although see Heitz (2014) the about the problems with his derivation. - // It nevertheless approximates GGX well with k = alpha/2. - float k = 0.5 * alpha; - return 0.5 / (cos_theta_m * (1.0 - k) + k); - - // float cos2 = cos_theta_m * cos_theta_m; - // float sin2 = (1.0 - cos2); - // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); -} -*/ - -// This approximates G_GGX_2cos(cos_theta_l, alpha) * G_GGX_2cos(cos_theta_v, alpha) -// See Filament docs, Specular G section. -float V_GGX(float cos_theta_l, float cos_theta_v, float alpha) { - return 0.5 / mix(2.0 * cos_theta_l * cos_theta_v, cos_theta_l + cos_theta_v, alpha); -} - -float D_GGX(float cos_theta_m, float alpha) { - float alpha2 = alpha * alpha; - float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; - return alpha2 / (M_PI * d * d); -} - -/* -float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float s_x = alpha_x * cos_phi; - float s_y = alpha_y * sin_phi; - return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); -} -*/ - -// This approximates G_GGX_anisotropic_2cos(cos_theta_l, ...) * G_GGX_anisotropic_2cos(cos_theta_v, ...) -// See Filament docs, Anisotropic specular BRDF section. -float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { - float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); - float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); - return 0.5 / (Lambda_V + Lambda_L); -} - -float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) { - float alpha2 = alpha_x * alpha_y; - highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH); - highp float v2 = dot(v, v); - float w2 = alpha2 / v2; - float D = alpha2 * w2 * w2 * (1.0 / M_PI); - return D; - - /* float cos2 = cos_theta_m * cos_theta_m; - float sin2 = (1.0 - cos2); - float r_x = cos_phi / alpha_x; - float r_y = sin_phi / alpha_y; - float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); - return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); */ -} - -float SchlickFresnel(float u) { - float m = 1.0 - u; - float m2 = m * m; - return m2 * m2 * m; // pow(m,5) -} - -float GTR1(float NdotH, float a) { - if (a >= 1.0) - return 1.0 / M_PI; - float a2 = a * a; - float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; - return (a2 - 1.0) / (M_PI * log(a2) * t); -} - -void light_compute( - vec3 N, - vec3 L, - vec3 V, - vec3 B, - vec3 T, - vec3 light_color, - vec3 attenuation, - vec3 diffuse_color, - vec3 transmission, - float specular_blob_intensity, - float roughness, - float metallic, - float specular, - float rim, - float rim_tint, - float clearcoat, - float clearcoat_gloss, - float anisotropy, - inout vec3 diffuse_light, - inout vec3 specular_light, - inout float alpha) { -//this makes lights behave closer to linear, but then addition of lights looks bad -//better left disabled - -//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); -/* -#define SRGB_APPROX(m_var) {\ - float S1 = sqrt(m_var);\ - float S2 = sqrt(S1);\ - float S3 = sqrt(S2);\ - m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ - } -*/ -#define SRGB_APPROX(m_var) - -#if defined(USE_LIGHT_SHADER_CODE) - // light is written by the light shader - - vec3 normal = N; - vec3 albedo = diffuse_color; - vec3 light = L; - vec3 view = V; - - /* clang-format off */ - -LIGHT_SHADER_CODE - - /* clang-format on */ - -#else - float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); // clamped NdotL - float NdotV = dot(N, V); - float cNdotV = max(abs(NdotV), 1e-6); - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - vec3 H = normalize(V + L); -#endif - -#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - float cNdotH = max(dot(N, H), 0.0); -#endif - -#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) - float cLdotH = max(dot(L, H), 0.0); -#endif - - if (metallic < 1.0) { -#if defined(DIFFUSE_OREN_NAYAR) - 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) - - { - float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; - float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); - float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); - diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; - /* - float energyBias = mix(roughness, 0.0, 0.5); - float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); - float fd90 = energyBias + 2.0 * VoH * VoH * roughness; - float f0 = 1.0; - float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); - float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); - - diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; - */ - } -#else - // lambert - diffuse_brdf_NL = cNdotL * (1.0 / M_PI); -#endif - - SRGB_APPROX(diffuse_brdf_NL) - - diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; - -#if defined(TRANSMISSION_USED) - diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; -#endif - -#if defined(LIGHT_USE_RIM) - float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; -#endif - } - - if (roughness > 0.0) { - -#if defined(SPECULAR_SCHLICK_GGX) - vec3 specular_brdf_NL = vec3(0.0); -#else - float specular_brdf_NL = 0.0; -#endif - -#if defined(SPECULAR_BLINN) - - //normalized blinn - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float blinn = pow(cNdotH, shininess) * cNdotL; - blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = blinn; - -#elif defined(SPECULAR_PHONG) - - vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(0.0, dot(R, V)); - float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; - float phong = pow(cRdotV, shininess); - phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); - specular_brdf_NL = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); - -#elif defined(SPECULAR_TOON) - - vec3 R = normalize(-reflect(L, N)); - float RdotV = dot(R, V); - float mid = 1.0 - roughness; - mid *= mid; - specular_brdf_NL = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; - -#elif defined(SPECULAR_DISABLED) - // none.. -#elif defined(SPECULAR_SCHLICK_GGX) - // shlick+ggx as default - -#if defined(LIGHT_USE_ANISOTROPY) - float alpha_ggx = roughness * roughness; - float aspect = sqrt(1.0 - anisotropy * 0.9); - float ax = alpha_ggx / aspect; - float ay = alpha_ggx * aspect; - float XdotH = dot(T, H); - float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH, cNdotH); - //float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); - float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL); - -#else - float alpha_ggx = roughness * roughness; - float D = D_GGX(cNdotH, alpha_ggx); - //float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); - float G = V_GGX(cNdotL, cNdotV, alpha_ggx); -#endif - // F - vec3 f0 = F0(metallic, specular, diffuse_color); - float cLdotH5 = SchlickFresnel(cLdotH); - vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); - - specular_brdf_NL = cNdotL * D * F * G; - -#endif - - SRGB_APPROX(specular_brdf_NL) - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; - -#if defined(LIGHT_USE_CLEARCOAT) - -#if !defined(SPECULAR_SCHLICK_GGX) - float cLdotH5 = SchlickFresnel(cLdotH); -#endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); - float Fr = mix(.04, 1.0, cLdotH5); - //float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - float Gr = V_GGX(cNdotL, cNdotV, 0.25); - - float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - - specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; -#endif - } - -#ifdef USE_SHADOW_TO_OPACITY - alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); -#endif - -#endif //defined(USE_LIGHT_SHADER_CODE) -} - -#endif -// shadows - -#ifdef USE_SHADOW - -#ifdef USE_RGBA_SHADOWS - -#define SHADOW_DEPTH(m_val) dot(m_val, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) - -#else - -#define SHADOW_DEPTH(m_val) (m_val).r - -#endif - -#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, SHADOW_DEPTH(texture2D(p_shadow, p_pos))) -#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, SHADOW_DEPTH(texture2DProj(p_shadow, p_pos))) - -float sample_shadow(highp sampler2D shadow, highp vec4 spos) { -#ifdef SHADOW_MODE_PCF_13 - - spos.xyz /= spos.w; - vec2 pos = spos.xy; - float depth = spos.z; - - float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth); - return avg * (1.0 / 13.0); -#endif - -#ifdef SHADOW_MODE_PCF_5 - - spos.xyz /= spos.w; - vec2 pos = spos.xy; - float depth = spos.z; - - float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); - avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); - return avg * (1.0 / 5.0); - -#endif - -#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) - - return SAMPLE_SHADOW_TEXEL_PROJ(shadow, spos); -#endif -} - -#endif - -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -#if defined(USE_VERTEX_LIGHTING) - -varying vec4 fog_interp; - -#else -uniform mediump vec4 fog_color_base; -#ifdef LIGHT_MODE_DIRECTIONAL -uniform mediump vec4 fog_sun_color_amount; -#endif - -uniform bool fog_transmit_enabled; -uniform mediump float fog_transmit_curve; - -#ifdef FOG_DEPTH_ENABLED -uniform highp float fog_depth_begin; -uniform mediump float fog_depth_curve; -uniform mediump float fog_max_distance; -#endif - -#ifdef FOG_HEIGHT_ENABLED -uniform highp float fog_height_min; -uniform highp float fog_height_max; -uniform mediump float fog_height_curve; -#endif - -#endif //vertex lit -#endif //fog - -void main() { -#ifdef RENDER_DEPTH_DUAL_PARABOLOID - - if (dp_clip > 0.0) - discard; -#endif - highp vec3 vertex = vertex_interp; - vec3 view = -normalize(vertex_interp); - vec3 albedo = vec3(1.0); - vec3 transmission = vec3(0.0); - float metallic = 0.0; - float specular = 0.5; - 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 = 0.0; - vec2 anisotropy_flow = vec2(1.0, 0.0); - float sss_strength = 0.0; //unused - // gl_FragDepth is not available in GLES2, so writing to DEPTH is not converted to gl_FragDepth by Godot compiler resulting in a - // compile error because DEPTH is not a variable. - float m_DEPTH = 0.0; - - float alpha = 1.0; - float side = 1.0; - - float specular_blob_intensity = 1.0; -#if defined(SPECULAR_TOON) - specular_blob_intensity *= specular * 2.0; -#endif - -#if defined(ENABLE_AO) - float ao = 1.0; - float ao_light_affect = 0.0; -#endif - -#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_NORMALMAP) - vec3 normalmap = vec3(0.5); -#endif - float normaldepth = 1.0; - -#if defined(ALPHA_SCISSOR_USED) - float alpha_scissor = 0.5; -#endif - -#if defined(SCREEN_UV_USED) - vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; -#endif - - { - /* clang-format off */ - -FRAGMENT_SHADER_CODE - - /* clang-format on */ - } - -#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))); - - normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; - //normal = normalmap; -#endif - - normal = normalize(normal); - - vec3 N = normal; - - vec3 specular_light = vec3(0.0, 0.0, 0.0); - vec3 diffuse_light = vec3(0.0, 0.0, 0.0); - vec3 ambient_light = vec3(0.0, 0.0, 0.0); - - vec3 eye_position = view; - -#if !defined(USE_SHADOW_TO_OPACITY) - -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } -#endif // ALPHA_SCISSOR_USED - -#ifdef USE_DEPTH_PREPASS - if (alpha < 0.1) { - discard; - } -#endif // USE_DEPTH_PREPASS - -#endif // !USE_SHADOW_TO_OPACITY - -#ifdef BASE_PASS - - // IBL precalculations - float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); - vec3 f0 = F0(metallic, specular, albedo); - vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0); - -#ifdef AMBIENT_LIGHT_DISABLED - ambient_light = vec3(0.0, 0.0, 0.0); -#else - -#ifdef USE_RADIANCE_MAP - - vec3 ref_vec = reflect(-eye_position, N); - ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); - - ref_vec.z *= -1.0; - - specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; -#ifndef USE_LIGHTMAP - { - vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz); - vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, 4.0).xyz * bg_energy; - env_ambient *= 1.0 - F; - - ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); - } -#endif - -#else - - ambient_light = ambient_color.rgb; - specular_light = bg_color.rgb * bg_energy; - -#endif -#endif // AMBIENT_LIGHT_DISABLED - ambient_light *= ambient_energy; - -#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) - - vec4 ambient_accum = vec4(0.0); - vec4 reflection_accum = vec4(0.0); - -#ifdef USE_REFLECTION_PROBE1 - - reflection_process(reflection_probe1, -#ifdef USE_VERTEX_LIGHTING - refprobe1_reflection_normal_blend.rgb, -#ifndef USE_LIGHTMAP - refprobe1_ambient_normal, -#endif - refprobe1_reflection_normal_blend.a, -#else - normal_interp, vertex_interp, refprobe1_local_matrix, - refprobe1_use_box_project, refprobe1_box_extents, refprobe1_box_offset, -#endif - refprobe1_exterior, refprobe1_intensity, refprobe1_ambient, roughness, - ambient_light, specular_light, reflection_accum, ambient_accum); - -#endif // USE_REFLECTION_PROBE1 - -#ifdef USE_REFLECTION_PROBE2 - - reflection_process(reflection_probe2, -#ifdef USE_VERTEX_LIGHTING - refprobe2_reflection_normal_blend.rgb, -#ifndef USE_LIGHTMAP - refprobe2_ambient_normal, -#endif - refprobe2_reflection_normal_blend.a, -#else - normal_interp, vertex_interp, refprobe2_local_matrix, - refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset, -#endif - refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness, - ambient_light, specular_light, reflection_accum, ambient_accum); - -#endif // USE_REFLECTION_PROBE2 - - if (reflection_accum.a > 0.0) { - specular_light = reflection_accum.rgb / reflection_accum.a; - } - -#ifndef USE_LIGHTMAP - if (ambient_accum.a > 0.0) { - ambient_light = ambient_accum.rgb / ambient_accum.a; - } -#endif - -#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) - - // environment BRDF approximation - { -#if defined(DIFFUSE_TOON) - //simplify for toon, as - specular_light *= specular * metallic * albedo * 2.0; -#else - - // scales the specular reflections, needs to be be computed before lighting happens, - // but after environment and reflection probes are added - //TODO: this curve is not really designed for gammaspace, should be adjusted - const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); - const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); - vec4 r = roughness * c0 + c1; - float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; - vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - specular_light *= env.x * F + env.y; - -#endif - } - -#ifdef USE_LIGHTMAP - //ambient light will come entirely from lightmap is lightmap is used - ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy; -#endif - -#ifdef USE_LIGHTMAP_CAPTURE - { - vec3 cone_dirs[12]; - cone_dirs[0] = vec3(0.0, 0.0, 1.0); - cone_dirs[1] = vec3(0.866025, 0.0, 0.5); - cone_dirs[2] = vec3(0.267617, 0.823639, 0.5); - cone_dirs[3] = vec3(-0.700629, 0.509037, 0.5); - cone_dirs[4] = vec3(-0.700629, -0.509037, 0.5); - cone_dirs[5] = vec3(0.267617, -0.823639, 0.5); - cone_dirs[6] = vec3(0.0, 0.0, -1.0); - cone_dirs[7] = vec3(0.866025, 0.0, -0.5); - cone_dirs[8] = vec3(0.267617, 0.823639, -0.5); - cone_dirs[9] = vec3(-0.700629, 0.509037, -0.5); - cone_dirs[10] = vec3(-0.700629, -0.509037, -0.5); - cone_dirs[11] = vec3(0.267617, -0.823639, -0.5); - - vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz; - vec4 captured = vec4(0.0); - float sum = 0.0; - for (int i = 0; i < 12; i++) { - float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect - captured += lightmap_captures[i] * amount; - sum += amount; - } - - captured /= sum; - - if (lightmap_capture_sky) { - ambient_light = mix(ambient_light, captured.rgb, captured.a); - } else { - ambient_light = captured.rgb; - } - } -#endif - -#endif //BASE PASS - -// -// Lighting -// -#ifdef USE_LIGHTING - -#ifndef USE_VERTEX_LIGHTING - vec3 L; -#endif - vec3 light_att = vec3(1.0); - -#ifdef LIGHT_MODE_OMNI - -#ifndef USE_VERTEX_LIGHTING - vec3 light_vec = light_position - vertex; - float light_length = length(light_vec); - - float normalized_distance = light_length / light_range; - if (normalized_distance < 1.0) { - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - - light_att = vec3(omni_attenuation); - } else { - light_att = vec3(0.0); - } - L = normalize(light_vec); - -#endif - -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - { - highp vec4 splane = shadow_coord; - float shadow_len = length(splane.xyz); - - splane.xyz = normalize(splane.xyz); - - vec4 clamp_rect = light_clamp; - - if (splane.z >= 0.0) { - splane.z += 1.0; - - clamp_rect.y += clamp_rect.w; - } else { - splane.z = 1.0 - splane.z; - } - - 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; - splane.w = 1.0; - - float shadow = sample_shadow(light_shadow_atlas, splane); - - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); - } -#endif - -#endif //SHADOWS_DISABLED - -#endif //type omni - -#ifdef LIGHT_MODE_DIRECTIONAL - -#ifndef USE_VERTEX_LIGHTING - vec3 light_vec = -light_direction; - L = normalize(light_vec); -#endif - float depth_z = -vertex.z; - -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - -#ifdef USE_VERTEX_LIGHTING - //compute shadows in a mobile friendly way - -#ifdef LIGHT_USE_PSSM4 - //take advantage of prefetch - float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); - float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); - float shadow3 = sample_shadow(light_directional_shadow, shadow_coord3); - float shadow4 = sample_shadow(light_directional_shadow, shadow_coord4); - - if (depth_z < light_split_offsets.w) { - float pssm_fade = 0.0; - float shadow_att = 1.0; -#ifdef LIGHT_USE_PSSM_BLEND - float shadow_att2 = 1.0; - float pssm_blend = 0.0; - bool use_blend = true; -#endif - if (depth_z < light_split_offsets.y) { - if (depth_z < light_split_offsets.x) { - shadow_att = shadow1; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow2; - - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - shadow_att = shadow2; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow3; - - pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#endif - } - } else { - if (depth_z < light_split_offsets.z) { - shadow_att = shadow3; - -#if defined(LIGHT_USE_PSSM_BLEND) - shadow_att2 = shadow4; - pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); -#endif - - } else { - shadow_att = shadow4; - pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); - -#if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; -#endif - } - } -#if defined(LIGHT_USE_PSSM_BLEND) - if (use_blend) { - shadow_att = mix(shadow_att, shadow_att2, pssm_blend); - } -#endif - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att); - } - -#endif //LIGHT_USE_PSSM4 - -#ifdef LIGHT_USE_PSSM2 - - //take advantage of prefetch - float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); - float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); - - if (depth_z < light_split_offsets.y) { - float shadow_att = 1.0; - float pssm_fade = 0.0; - -#ifdef LIGHT_USE_PSSM_BLEND - float shadow_att2 = 1.0; - float pssm_blend = 0.0; - bool use_blend = true; -#endif - if (depth_z < light_split_offsets.x) { - float pssm_fade = 0.0; - shadow_att = shadow1; - -#ifdef LIGHT_USE_PSSM_BLEND - shadow_att2 = shadow2; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - shadow_att = shadow2; - pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#ifdef LIGHT_USE_PSSM_BLEND - use_blend = false; -#endif - } -#ifdef LIGHT_USE_PSSM_BLEND - if (use_blend) { - shadow_att = mix(shadow_att, shadow_att2, pssm_blend); - } -#endif - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att); - } - -#endif //LIGHT_USE_PSSM2 - -#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - - light_att *= mix(shadow_color.rgb, vec3(1.0), sample_shadow(light_directional_shadow, shadow_coord)); -#endif //orthogonal - -#else //fragment version of pssm - - { -#ifdef LIGHT_USE_PSSM4 - if (depth_z < light_split_offsets.w) { -#elif defined(LIGHT_USE_PSSM2) - if (depth_z < light_split_offsets.y) { -#else - if (depth_z < light_split_offsets.x) { -#endif //pssm2 - - highp vec4 pssm_coord; - float pssm_fade = 0.0; - -#ifdef LIGHT_USE_PSSM_BLEND - float pssm_blend; - highp vec4 pssm_coord2; - bool use_blend = true; -#endif - -#ifdef LIGHT_USE_PSSM4 - - if (depth_z < light_split_offsets.y) { - if (depth_z < light_split_offsets.x) { - pssm_coord = shadow_coord; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord2; - - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - pssm_coord = shadow_coord2; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord3; - - pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#endif - } - } else { - if (depth_z < light_split_offsets.z) { - pssm_coord = shadow_coord3; - -#if defined(LIGHT_USE_PSSM_BLEND) - pssm_coord2 = shadow_coord4; - pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); -#endif - - } else { - pssm_coord = shadow_coord4; - pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); - -#if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; -#endif - } - } - -#endif // LIGHT_USE_PSSM4 - -#ifdef LIGHT_USE_PSSM2 - if (depth_z < light_split_offsets.x) { - pssm_coord = shadow_coord; - -#ifdef LIGHT_USE_PSSM_BLEND - pssm_coord2 = shadow_coord2; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); -#endif - } else { - pssm_coord = shadow_coord2; - pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); -#ifdef LIGHT_USE_PSSM_BLEND - use_blend = false; -#endif - } - -#endif // LIGHT_USE_PSSM2 - -#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - { - pssm_coord = shadow_coord; - } -#endif - - float shadow = sample_shadow(light_directional_shadow, pssm_coord); - -#ifdef LIGHT_USE_PSSM_BLEND - if (use_blend) { - shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2), pssm_blend); - } -#endif - - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); - } - } -#endif //use vertex lighting - -#endif //use shadow - -#endif // SHADOWS_DISABLED - -#endif - -#ifdef LIGHT_MODE_SPOT - - light_att = vec3(1.0); - -#ifndef USE_VERTEX_LIGHTING - - vec3 light_rel_vec = light_position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length / light_range; - - if (normalized_distance < 1.0) { - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; - float angle = dot(-normalize(light_rel_vec), spot_dir); - - if (angle > spot_cutoff) { - float scos = max(angle, spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - - light_att = vec3(spot_attenuation); - } else { - light_att = vec3(0.0); - } - } else { - light_att = vec3(0.0); - } - - L = normalize(light_rel_vec); - -#endif - -#if !defined(SHADOWS_DISABLED) - -#ifdef USE_SHADOW - { - highp vec4 splane = shadow_coord; - - float shadow = sample_shadow(light_shadow_atlas, splane); - light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); - } -#endif - -#endif // SHADOWS_DISABLED - -#endif // LIGHT_MODE_SPOT - -#ifdef USE_VERTEX_LIGHTING - //vertex lighting - - specular_light += specular_interp * specular_blob_intensity * light_att; - diffuse_light += diffuse_interp * albedo * light_att; - -#else - //fragment lighting - light_compute( - normal, - L, - eye_position, - binormal, - tangent, - light_color.xyz, - light_att, - albedo, - transmission, - specular_blob_intensity * light_specular, - roughness, - metallic, - specular, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light, - alpha); - -#endif //vertex lighting - -#endif //USE_LIGHTING - //compute and merge - -#ifdef USE_SHADOW_TO_OPACITY - - alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); - -#if defined(ALPHA_SCISSOR_USED) - if (alpha < alpha_scissor) { - discard; - } -#endif // ALPHA_SCISSOR_USED - -#ifdef USE_DEPTH_PREPASS - if (alpha < 0.1) { - discard; - } -#endif // USE_DEPTH_PREPASS - -#endif // !USE_SHADOW_TO_OPACITY - -#ifndef RENDER_DEPTH - -#ifdef SHADELESS - - gl_FragColor = vec4(albedo, alpha); -#else - - 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; -#endif - - diffuse_light *= 1.0 - metallic; - ambient_light *= 1.0 - metallic; - - gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); - - //add emission if in base pass -#ifdef BASE_PASS - gl_FragColor.rgb += emission; -#endif - // gl_FragColor = vec4(normal, 1.0); - -//apply fog -#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -#if defined(USE_VERTEX_LIGHTING) - -#if defined(BASE_PASS) - gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_interp.rgb, fog_interp.a); -#else - gl_FragColor.rgb *= (1.0 - fog_interp.a); -#endif // BASE_PASS - -#else //pixel based fog - float fog_amount = 0.0; - -#ifdef LIGHT_MODE_DIRECTIONAL - - vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(eye_position, light_direction), 0.0), 8.0)); -#else - vec3 fog_color = fog_color_base.rgb; -#endif - -#ifdef FOG_DEPTH_ENABLED - - { - float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); - - fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; - - if (fog_transmit_enabled) { - vec3 total_light = gl_FragColor.rgb; - float transmit = pow(fog_z, fog_transmit_curve); - fog_color = mix(max(total_light, fog_color), fog_color, transmit); - } - } -#endif - -#ifdef FOG_HEIGHT_ENABLED - { - float y = (camera_matrix * vec4(vertex, 1.0)).y; - fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); - } -#endif - -#if defined(BASE_PASS) - gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_color, fog_amount); -#else - gl_FragColor.rgb *= (1.0 - fog_amount); -#endif // BASE_PASS - -#endif //use vertex lit - -#endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) - -#endif //unshaded - -#else // not RENDER_DEPTH -//depth render -#ifdef USE_RGBA_SHADOWS - - highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias - highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); - comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); - gl_FragColor = comp; - -#endif -#endif -} diff --git a/drivers/opengl/shaders/stdlib.glsl b/drivers/opengl/shaders/stdlib.glsl deleted file mode 100644 index 9c74418743..0000000000 --- a/drivers/opengl/shaders/stdlib.glsl +++ /dev/null @@ -1,420 +0,0 @@ - -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); -} - -#if defined(SINH_USED) - -highp float sinh(highp float x) { - return 0.5 * (exp(x) - exp(-x)); -} - -highp vec2 sinh(highp vec2 x) { - return 0.5 * vec2(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y)); -} - -highp vec3 sinh(highp vec3 x) { - return 0.5 * vec3(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y), exp(x.z) - exp(-x.z)); -} - -highp vec4 sinh(highp vec4 x) { - return 0.5 * vec4(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y), exp(x.z) - exp(-x.z), exp(x.w) - exp(-x.w)); -} - -#endif - -#if defined(COSH_USED) - -highp float cosh(highp float x) { - return 0.5 * (exp(x) + exp(-x)); -} - -highp vec2 cosh(highp vec2 x) { - return 0.5 * vec2(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y)); -} - -highp vec3 cosh(highp vec3 x) { - return 0.5 * vec3(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y), exp(x.z) + exp(-x.z)); -} - -highp vec4 cosh(highp vec4 x) { - return 0.5 * vec4(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y), exp(x.z) + exp(-x.z), exp(x.w) + exp(-x.w)); -} - -#endif - -#if defined(TANH_USED) - -highp float tanh(highp float x) { - highp float exp2x = exp(2.0 * x); - return (exp2x - 1.0) / (exp2x + 1.0); -} - -highp vec2 tanh(highp vec2 x) { - highp float exp2x = exp(2.0 * x.x); - highp float exp2y = exp(2.0 * x.y); - return vec2((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0)); -} - -highp vec3 tanh(highp vec3 x) { - highp float exp2x = exp(2.0 * x.x); - highp float exp2y = exp(2.0 * x.y); - highp float exp2z = exp(2.0 * x.z); - return vec3((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0), (exp2z - 1.0) / (exp2z + 1.0)); -} - -highp vec4 tanh(highp vec4 x) { - highp float exp2x = exp(2.0 * x.x); - highp float exp2y = exp(2.0 * x.y); - highp float exp2z = exp(2.0 * x.z); - highp float exp2w = exp(2.0 * x.w); - return vec4((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0), (exp2z - 1.0) / (exp2z + 1.0), (exp2w - 1.0) / (exp2w + 1.0)); -} - -#endif - -#if defined(ASINH_USED) - -highp float asinh(highp float x) { - return sign(x) * log(abs(x) + sqrt(1.0 + x * x)); -} - -highp vec2 asinh(highp vec2 x) { - return vec2(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y))); -} - -highp vec3 asinh(highp vec3 x) { - return vec3(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y)), sign(x.z) * log(abs(x.z) + sqrt(1.0 + x.z * x.z))); -} - -highp vec4 asinh(highp vec4 x) { - return vec4(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y)), sign(x.z) * log(abs(x.z) + sqrt(1.0 + x.z * x.z)), sign(x.w) * log(abs(x.w) + sqrt(1.0 + x.w * x.w))); -} - -#endif - -#if defined(ACOSH_USED) - -highp float acosh(highp float x) { - return log(x + sqrt(x * x - 1.0)); -} - -highp vec2 acosh(highp vec2 x) { - return vec2(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0))); -} - -highp vec3 acosh(highp vec3 x) { - return vec3(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0)), log(x.z + sqrt(x.z * x.z - 1.0))); -} - -highp vec4 acosh(highp vec4 x) { - return vec4(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0)), log(x.z + sqrt(x.z * x.z - 1.0)), log(x.w + sqrt(x.w * x.w - 1.0))); -} - -#endif - -#if defined(ATANH_USED) - -highp float atanh(highp float x) { - return 0.5 * log((1.0 + x) / (1.0 - x)); -} - -highp vec2 atanh(highp vec2 x) { - return 0.5 * vec2(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y))); -} - -highp vec3 atanh(highp vec3 x) { - return 0.5 * vec3(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y)), log((1.0 + x.z) / (1.0 - x.z))); -} - -highp vec4 atanh(highp vec4 x) { - return 0.5 * vec4(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y)), log((1.0 + x.z) / (1.0 - x.z)), log((1.0 + x.w) / (1.0 - x.w))); -} - -#endif - -#if defined(ROUND_USED) - -highp float round(highp float x) { - return floor(x + 0.5); -} - -highp vec2 round(highp vec2 x) { - return floor(x + vec2(0.5)); -} - -highp vec3 round(highp vec3 x) { - return floor(x + vec3(0.5)); -} - -highp vec4 round(highp vec4 x) { - return floor(x + vec4(0.5)); -} - -#endif - -#if defined(ROUND_EVEN_USED) - -highp float roundEven(highp float x) { - highp float t = x + 0.5; - highp float f = floor(t); - highp float r; - if (t == f) { - if (x > 0) - r = f - mod(f, 2); - else - r = f + mod(f, 2); - } else - r = f; - return r; -} - -highp vec2 roundEven(highp vec2 x) { - return vec2(roundEven(x.x), roundEven(x.y)); -} - -highp vec3 roundEven(highp vec3 x) { - return vec3(roundEven(x.x), roundEven(x.y), roundEven(x.z)); -} - -highp vec4 roundEven(highp vec4 x) { - return vec4(roundEven(x.x), roundEven(x.y), roundEven(x.z), roundEven(x.w)); -} - -#endif - -#if defined(IS_INF_USED) - -bool isinf(highp float x) { - return (2 * x == x) && (x != 0); -} - -bvec2 isinf(highp vec2 x) { - return bvec2((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0)); -} - -bvec3 isinf(highp vec3 x) { - return bvec3((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0), (2 * x.z == x.z) && (x.z != 0)); -} - -bvec4 isinf(highp vec4 x) { - return bvec4((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0), (2 * x.z == x.z) && (x.z != 0), (2 * x.w == x.w) && (x.w != 0)); -} - -#endif - -#if defined(IS_NAN_USED) - -bool isnan(highp float x) { - return x != x; -} - -bvec2 isnan(highp vec2 x) { - return bvec2(x.x != x.x, x.y != x.y); -} - -bvec3 isnan(highp vec3 x) { - return bvec3(x.x != x.x, x.y != x.y, x.z != x.z); -} - -bvec4 isnan(highp vec4 x) { - return bvec4(x.x != x.x, x.y != x.y, x.z != x.z, x.w != x.w); -} - -#endif - -#if defined(TRUNC_USED) - -highp float trunc(highp float x) { - return x < 0 ? -floor(-x) : floor(x); -} - -highp vec2 trunc(highp vec2 x) { - return vec2(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y)); -} - -highp vec3 trunc(highp vec3 x) { - return vec3(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y), x.z < 0 ? -floor(-x.z) : floor(x.z)); -} - -highp vec4 trunc(highp vec4 x) { - return vec4(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y), x.z < 0 ? -floor(-x.z) : floor(x.z), x.w < 0 ? -floor(-x.w) : floor(x.w)); -} - -#endif - -#if defined(DETERMINANT_USED) - -highp float determinant(highp mat2 m) { - return m[0].x * m[1].y - m[1].x * m[0].y; -} - -highp float determinant(highp mat3 m) { - return m[0].x * (m[1].y * m[2].z - m[2].y * m[1].z) - m[1].x * (m[0].y * m[2].z - m[2].y * m[0].z) + m[2].x * (m[0].y * m[1].z - m[1].y * m[0].z); -} - -highp float determinant(highp mat4 m) { - highp float s00 = m[2].z * m[3].w - m[3].z * m[2].w; - highp float s01 = m[2].y * m[3].w - m[3].y * m[2].w; - highp float s02 = m[2].y * m[3].z - m[3].y * m[2].z; - highp float s03 = m[2].x * m[3].w - m[3].x * m[2].w; - highp float s04 = m[2].x * m[3].z - m[3].x * m[2].z; - highp float s05 = m[2].x * m[3].y - m[3].x * m[2].y; - highp vec4 c = vec4((m[1].y * s00 - m[1].z * s01 + m[1].w * s02), -(m[1].x * s00 - m[1].z * s03 + m[1].w * s04), (m[1].x * s01 - m[1].y * s03 + m[1].w * s05), -(m[1].x * s02 - m[1].y * s04 + m[1].z * s05)); - return m[0].x * c.x + m[0].y * c.y + m[0].z * c.z + m[0].w * c.w; -} - -#endif - -#if defined(INVERSE_USED) - -highp mat2 inverse(highp mat2 m) { - highp float d = 1.0 / (m[0].x * m[1].y - m[1].x * m[0].y); - return mat2( - vec2(m[1].y * d, -m[0].y * d), - vec2(-m[1].x * d, m[0].x * d)); -} - -highp mat3 inverse(highp mat3 m) { - highp float d = 1.0 / (m[0].x * (m[1].y * m[2].z - m[2].y * m[1].z) - m[1].x * (m[0].y * m[2].z - m[2].y * m[0].z) + m[2].x * (m[0].y * m[1].z - m[1].y * m[0].z)); - return mat3( - vec3((m[1].y * m[2].z - m[2].y * m[1].z), -(m[1].x * m[2].z - m[2].x * m[1].z), (m[1].x * m[2].y - m[2].x * m[1].y)) * d, - vec3(-(m[0].y * m[2].z - m[2].y * m[0].z), (m[0].x * m[2].z - m[2].x * m[0].z), -(m[0].x * m[2].y - m[2].x * m[0].y)) * d, - vec3((m[0].y * m[1].z - m[1].y * m[0].z), -(m[0].x * m[1].z - m[1].x * m[0].z), (m[0].x * m[1].y - m[1].x * m[0].y)) * d); -} - -highp mat4 inverse(highp mat4 m) { - highp float c00 = m[2].z * m[3].w - m[3].z * m[2].w; - highp float c02 = m[1].z * m[3].w - m[3].z * m[1].w; - highp float c03 = m[1].z * m[2].w - m[2].z * m[1].w; - - highp float c04 = m[2].y * m[3].w - m[3].y * m[2].w; - highp float c06 = m[1].y * m[3].w - m[3].y * m[1].w; - highp float c07 = m[1].y * m[2].w - m[2].y * m[1].w; - - highp float c08 = m[2].y * m[3].z - m[3].y * m[2].z; - highp float c10 = m[1].y * m[3].z - m[3].y * m[1].z; - highp float c11 = m[1].y * m[2].z - m[2].y * m[1].z; - - highp float c12 = m[2].x * m[3].w - m[3].x * m[2].w; - highp float c14 = m[1].x * m[3].w - m[3].x * m[1].w; - highp float c15 = m[1].x * m[2].w - m[2].x * m[1].w; - - highp float c16 = m[2].x * m[3].z - m[3].x * m[2].z; - highp float c18 = m[1].x * m[3].z - m[3].x * m[1].z; - highp float c19 = m[1].x * m[2].z - m[2].x * m[1].z; - - highp float c20 = m[2].x * m[3].y - m[3].x * m[2].y; - highp float c22 = m[1].x * m[3].y - m[3].x * m[1].y; - highp float c23 = m[1].x * m[2].y - m[2].x * m[1].y; - - vec4 f0 = vec4(c00, c00, c02, c03); - vec4 f1 = vec4(c04, c04, c06, c07); - vec4 f2 = vec4(c08, c08, c10, c11); - vec4 f3 = vec4(c12, c12, c14, c15); - vec4 f4 = vec4(c16, c16, c18, c19); - vec4 f5 = vec4(c20, c20, c22, c23); - - vec4 v0 = vec4(m[1].x, m[0].x, m[0].x, m[0].x); - vec4 v1 = vec4(m[1].y, m[0].y, m[0].y, m[0].y); - vec4 v2 = vec4(m[1].z, m[0].z, m[0].z, m[0].z); - vec4 v3 = vec4(m[1].w, m[0].w, m[0].w, m[0].w); - - vec4 inv0 = vec4(v1 * f0 - v2 * f1 + v3 * f2); - vec4 inv1 = vec4(v0 * f0 - v2 * f3 + v3 * f4); - vec4 inv2 = vec4(v0 * f1 - v1 * f3 + v3 * f5); - vec4 inv3 = vec4(v0 * f2 - v1 * f4 + v2 * f5); - - vec4 sa = vec4(+1, -1, +1, -1); - vec4 sb = vec4(-1, +1, -1, +1); - - mat4 inv = mat4(inv0 * sa, inv1 * sb, inv2 * sa, inv3 * sb); - - vec4 r0 = vec4(inv[0].x, inv[1].x, inv[2].x, inv[3].x); - vec4 d0 = vec4(m[0] * r0); - - highp float d1 = (d0.x + d0.y) + (d0.z + d0.w); - highp float d = 1.0 / d1; - - return inv * d; -} - -#endif - -#ifndef USE_GLES_OVER_GL - -#if defined(TRANSPOSE_USED) - -highp mat2 transpose(highp mat2 m) { - return mat2( - vec2(m[0].x, m[1].x), - vec2(m[0].y, m[1].y)); -} - -highp mat3 transpose(highp mat3 m) { - return mat3( - vec3(m[0].x, m[1].x, m[2].x), - vec3(m[0].y, m[1].y, m[2].y), - vec3(m[0].z, m[1].z, m[2].z)); -} - -#endif - -highp mat4 transpose(highp mat4 m) { - return mat4( - vec4(m[0].x, m[1].x, m[2].x, m[3].x), - vec4(m[0].y, m[1].y, m[2].y, m[3].y), - vec4(m[0].z, m[1].z, m[2].z, m[3].z), - vec4(m[0].w, m[1].w, m[2].w, m[3].w)); -} - -#if defined(OUTER_PRODUCT_USED) - -highp mat2 outerProduct(highp vec2 c, highp vec2 r) { - return mat2(c * r.x, c * r.y); -} - -highp mat3 outerProduct(highp vec3 c, highp vec3 r) { - return mat3(c * r.x, c * r.y, c * r.z); -} - -highp mat4 outerProduct(highp vec4 c, highp vec4 r) { - return mat4(c * r.x, c * r.y, c * r.z, c * r.w); -} - -#endif - -#endif diff --git a/drivers/opengl/shaders/tonemap.glsl b/drivers/opengl/shaders/tonemap.glsl deleted file mode 100644 index 0117bdb3d3..0000000000 --- a/drivers/opengl/shaders/tonemap.glsl +++ /dev/null @@ -1,343 +0,0 @@ -/* clang-format off */ -[vertex] - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -precision highp float; -precision highp int; -#endif - -attribute vec2 vertex_attrib; // attrib:0 -/* clang-format on */ -attribute vec2 uv_in; // attrib:4 - -varying vec2 uv_interp; - -void main() { - gl_Position = vec4(vertex_attrib, 0.0, 1.0); - - uv_interp = uv_in; -} - -/* clang-format off */ -[fragment] - -// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. -// Do not copy these defines in the vertex section. -#ifndef USE_GLES_OVER_GL -#ifdef GL_EXT_shader_texture_lod -#extension GL_EXT_shader_texture_lod : enable -#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) -#endif -#endif // !USE_GLES_OVER_GL - -#ifdef GL_ARB_shader_texture_lod -#extension GL_ARB_shader_texture_lod : enable -#endif - -#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) -#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) -#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) -#endif - -// Allows the use of bitshift operators for bicubic upscale -#ifdef GL_EXT_gpu_shader4 -#extension GL_EXT_gpu_shader4 : enable -#endif - -#ifdef USE_GLES_OVER_GL -#define lowp -#define mediump -#define highp -#else -#if defined(USE_HIGHP_PRECISION) -precision highp float; -precision highp int; -#else -precision mediump float; -precision mediump int; -#endif -#endif - -#include "stdlib.glsl" - -varying vec2 uv_interp; -/* clang-format on */ - -uniform highp sampler2D source; //texunit:0 - -#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) -#define USING_GLOW // only use glow when at least one glow level is selected - -#ifdef USE_MULTI_TEXTURE_GLOW -uniform highp sampler2D source_glow1; //texunit:2 -uniform highp sampler2D source_glow2; //texunit:3 -uniform highp sampler2D source_glow3; //texunit:4 -uniform highp sampler2D source_glow4; //texunit:5 -uniform highp sampler2D source_glow5; //texunit:6 -uniform highp sampler2D source_glow6; //texunit:7 -#ifdef USE_GLOW_LEVEL7 -uniform highp sampler2D source_glow7; //texunit:8 -#endif -#else -uniform highp sampler2D source_glow; //texunit:2 -#endif -uniform highp float glow_intensity; -#endif - -#ifdef USE_BCS -uniform vec3 bcs; -#endif - -#ifdef USE_FXAA -uniform vec2 pixel_size; -#endif - -#ifdef USE_COLOR_CORRECTION -uniform sampler2D color_correction; //texunit:1 -#endif - -#ifdef GL_EXT_gpu_shader4 -#ifdef USE_GLOW_FILTER_BICUBIC -// w0, w1, w2, and w3 are the four cubic B-spline basis functions -float w0(float a) { - return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0); -} - -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 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 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 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); - vec2 tex_size = vec2(glow_texture_size >> p_lod); - vec2 texel_size = vec2(1.0) / tex_size; - - uv = uv * tex_size + vec2(0.5); - - vec2 iuv = floor(uv); - vec2 fuv = fract(uv); - - float g0x = g0(fuv.x); - float g1x = g1(fuv.x); - float h0x = h0(fuv.x); - float h1x = h1(fuv.x); - float h0y = h0(fuv.y); - float h1y = h1(fuv.y); - - vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * texel_size; - vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * texel_size; - vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * texel_size; - vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * texel_size; - - return (g0(fuv.y) * (g0x * texture2DLod(tex, p0, lod) + g1x * texture2DLod(tex, p1, lod))) + - (g1(fuv.y) * (g0x * texture2DLod(tex, p2, lod) + g1x * texture2DLod(tex, p3, lod))); -} - -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) -#else //!USE_GLOW_FILTER_BICUBIC -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2DLod(m_tex, m_uv, float(m_lod)) -#endif //USE_GLOW_FILTER_BICUBIC - -#else //!GL_EXT_gpu_shader4 -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2DLod(m_tex, m_uv, float(m_lod)) -#endif //GL_EXT_gpu_shader4 - -vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode -#ifdef USE_GLOW_REPLACE - color = glow; -#endif - -#ifdef USE_GLOW_SCREEN - color = max((color + glow) - (color * glow), vec3(0.0)); -#endif - -#ifdef USE_GLOW_SOFTLIGHT - glow = glow * vec3(0.5) + vec3(0.5); - - color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); - color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); - color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); -#endif - -#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) // no other selected -> additive - color += glow; -#endif - - return color; -} - -vec3 apply_bcs(vec3 color, vec3 bcs) { - color = mix(vec3(0.0), color, bcs.x); - color = mix(vec3(0.5), color, bcs.y); - color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z); - - return color; -} - -vec3 apply_color_correction(vec3 color, sampler2D correction_tex) { - color.r = texture2D(correction_tex, vec2(color.r, 0.0)).r; - color.g = texture2D(correction_tex, vec2(color.g, 0.0)).g; - color.b = texture2D(correction_tex, vec2(color.b, 0.0)).b; - - return color; -} - -vec3 apply_fxaa(vec3 color, vec2 uv_interp, vec2 pixel_size) { - const float FXAA_REDUCE_MIN = (1.0 / 128.0); - const float FXAA_REDUCE_MUL = (1.0 / 8.0); - const float FXAA_SPAN_MAX = 8.0; - - vec3 rgbNW = texture2DLod(source, uv_interp + vec2(-1.0, -1.0) * pixel_size, 0.0).xyz; - vec3 rgbNE = texture2DLod(source, uv_interp + vec2(1.0, -1.0) * pixel_size, 0.0).xyz; - vec3 rgbSW = texture2DLod(source, uv_interp + vec2(-1.0, 1.0) * pixel_size, 0.0).xyz; - vec3 rgbSE = texture2DLod(source, uv_interp + vec2(1.0, 1.0) * pixel_size, 0.0).xyz; - vec3 rgbM = color; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), - FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * - pixel_size; - - vec3 rgbA = 0.5 * (texture2DLod(source, uv_interp + dir * (1.0 / 3.0 - 0.5), 0.0).xyz + texture2DLod(source, uv_interp + dir * (2.0 / 3.0 - 0.5), 0.0).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * (texture2DLod(source, uv_interp + dir * -0.5, 0.0).xyz + - texture2DLod(source, uv_interp + dir * 0.5, 0.0).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) { - return rgbA; - } else { - return rgbB; - } -} - -void main() { - vec3 color = texture2DLod(source, uv_interp, 0.0).rgb; - -#ifdef USE_FXAA - color = apply_fxaa(color, uv_interp, pixel_size); -#endif - - // Glow - -#ifdef USING_GLOW - vec3 glow = vec3(0.0); -#ifdef USE_MULTI_TEXTURE_GLOW -#ifdef USE_GLOW_LEVEL1 - glow += GLOW_TEXTURE_SAMPLE(source_glow1, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL2 - glow += GLOW_TEXTURE_SAMPLE(source_glow2, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL3 - glow += GLOW_TEXTURE_SAMPLE(source_glow3, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL4 - glow += GLOW_TEXTURE_SAMPLE(source_glow4, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL5 - glow += GLOW_TEXTURE_SAMPLE(source_glow5, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL6 - glow += GLOW_TEXTURE_SAMPLE(source_glow6, uv_interp, 0).rgb; -#ifdef USE_GLOW_LEVEL7 - glow += GLOW_TEXTURE_SAMPLE(source_glow7, uv_interp, 0).rgb; -#endif -#endif -#endif -#endif -#endif -#endif -#endif - -#else - -#ifdef USE_GLOW_LEVEL1 - 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; -#endif - -#ifdef USE_GLOW_LEVEL3 - 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; -#endif - -#ifdef USE_GLOW_LEVEL5 - 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; -#endif - -#ifdef USE_GLOW_LEVEL7 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 7).rgb; -#endif -#endif //USE_MULTI_TEXTURE_GLOW - - glow *= glow_intensity; - color = apply_glow(color, glow); -#endif - - // Additional effects - -#ifdef USE_BCS - color = apply_bcs(color, bcs); -#endif - -#ifdef USE_COLOR_CORRECTION - color = apply_color_correction(color, color_correction); -#endif - - gl_FragColor = vec4(color, 1.0); -} diff --git a/drivers/opengl/texture_loader_opengl.cpp b/drivers/opengl/texture_loader_opengl.cpp deleted file mode 100644 index f4ead75a86..0000000000 --- a/drivers/opengl/texture_loader_opengl.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/*************************************************************************/ -/* texture_loader_opengl.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "texture_loader_opengl.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/io/file_access.h" -#include "core/string/print_string.h" - -#include - -RES ResourceFormatGLES2Texture::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) { - unsigned int width = 8; - unsigned int height = 8; - - //We just use some format - Image::Format fmt = Image::FORMAT_RGB8; - int rowsize = 3 * width; - - Vector dstbuff; - - dstbuff.resize(rowsize * height); - - uint8_t **row_p = memnew_arr(uint8_t *, height); - - for (unsigned int i = 0; i < height; i++) { - row_p[i] = 0; //No colors any more, I want them to turn black - } - - memdelete_arr(row_p); - - Ref img = memnew(Image(width, height, 0, fmt, dstbuff)); - - Ref texture = memnew(ImageTexture); - texture->create_from_image(img); - - if (r_error) - *r_error = OK; - - return texture; -} - -void ResourceFormatGLES2Texture::get_recognized_extensions(List *p_extensions) const { - p_extensions->push_back("bmp"); - p_extensions->push_back("dds"); - p_extensions->push_back("exr"); - p_extensions->push_back("jpeg"); - p_extensions->push_back("jpg"); - p_extensions->push_back("hdr"); - p_extensions->push_back("pkm"); - p_extensions->push_back("png"); - p_extensions->push_back("pvr"); - p_extensions->push_back("svg"); - p_extensions->push_back("svgz"); - p_extensions->push_back("tga"); - p_extensions->push_back("webp"); -} - -bool ResourceFormatGLES2Texture::handles_type(const String &p_type) const { - return ClassDB::is_parent_class(p_type, "Texture2D"); -} - -String ResourceFormatGLES2Texture::get_resource_type(const String &p_path) const { - String extension = p_path.get_extension().to_lower(); - if ( - extension == "bmp" || - extension == "dds" || - extension == "exr" || - extension == "jpeg" || - extension == "jpg" || - extension == "hdr" || - extension == "pkm" || - extension == "png" || - extension == "pvr" || - extension == "svg" || - extension == "svgz" || - extension == "tga" || - extension == "webp") { - return "ImageTexture"; - } - - return ""; -} - -#endif diff --git a/drivers/opengl/texture_loader_opengl.h b/drivers/opengl/texture_loader_opengl.h deleted file mode 100644 index e98438624b..0000000000 --- a/drivers/opengl/texture_loader_opengl.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* texture_loader_opengl.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef TEXTURE_LOADER_OPENGL_H -#define TEXTURE_LOADER_OPENGL_H - -#include "drivers/opengl/rasterizer_platforms.h" -#ifdef OPENGL_BACKEND_ENABLED - -#include "core/io/resource_loader.h" -#include "scene/resources/texture.h" - -class ResourceFormatGLES2Texture : public ResourceFormatLoader { -public: - virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; - - virtual ~ResourceFormatGLES2Texture() {} -}; - -#endif // OPENGL_BACKEND_ENABLED - -#endif // TEXTURE_LOADER_OPENGL_H diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index bc4d9fb156..372d01d89a 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -1498,7 +1498,7 @@ String EditorExportPlatform::test_etc2() const { bool etc_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc"); bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2"); - if (driver == "OpenGL" && !etc_supported) { + if (driver == "OpenGL3" && !etc_supported) { return TTR("Target platform requires 'ETC' texture compression for OpenGL. Enable 'Import Etc' in Project Settings."); } else if (driver == "Vulkan" && !etc2_supported) { // FIXME: Review if this is true for Vulkan. @@ -1515,7 +1515,7 @@ String EditorExportPlatform::test_etc2_or_pvrtc() const { // bool etc2_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_etc2"); // bool pvrtc_supported = ProjectSettings::get_singleton()->get("rendering/textures/vram_compression/import_pvrtc"); - if (driver == "OpenGL" && !pvrtc_supported) { + if (driver == "OpenGL3" && !pvrtc_supported) { return TTR("Target platform requires 'PVRTC' texture compression for OpenGL. Enable 'Import Pvrtc' in Project Settings."); } else if (driver == "Vulkan" && !etc2_supported && !pvrtc_supported) { // FIXME: Review if this is true for Vulkan. diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index d3d055a009..9edf0a24fc 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -5596,7 +5596,7 @@ void EditorNode::_bottom_panel_raise_toggled(bool p_pressed) { } void EditorNode::_update_rendering_driver_color() { - if (rendering_driver->get_text() == "opengl") { + if (rendering_driver->get_text() == "opengl3") { rendering_driver->add_theme_color_override("font_color", Color::hex(0x5586a4ff)); } else if (rendering_driver->get_text() == "vulkan") { rendering_driver->add_theme_color_override("font_color", theme_base->get_theme_color("vulkan_color", "Editor")); @@ -6619,28 +6619,12 @@ EditorNode::EditorNode() { HBoxContainer *right_menu_hb = memnew(HBoxContainer); menu_hb->add_child(right_menu_hb); - // Toggle for video driver - // video_driver = memnew(OptionButton); - // video_driver->set_focus_mode(Control::FOCUS_NONE); - // video_driver->connect("item_selected", callable_mp(this, &EditorNode::_video_driver_selected)); - // video_driver->add_theme_font_override("font", gui_base->get_theme_font(SNAME("bold"), SNAME("EditorFonts"))); - // video_driver->add_theme_font_size_override("font_size", gui_base->get_theme_font_size(SNAME("bold_size"), SNAME("EditorFonts"))); - // // TODO: Show again when OpenGL is ported. - // video_driver->set_visible(false); - // right_menu_hb->add_child(video_driver); - - //#ifndef _MSC_VER - //#warning needs to be reimplemented - //#endif - //#if 0 - // String video_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/driver/driver_name"].hint_string; - // String current_video_driver = OS::get_singleton()->get_video_driver_name(OS::get_singleton()->get_current_video_driver()); - // video_driver_current = 0; - // for (int i = 0; i < video_drivers.get_slice_count(","); i++) { - // String driver = video_drivers.get_slice(",", i); - // video_driver->add_item(driver); - // video_driver->set_item_metadata(i, driver); rendering_driver = memnew(OptionButton); + + // Hide the renderer selection dropdown until OpenGL support is more mature. + // The renderer can still be changed in the project settings or using `--rendering-driver opengl3`. + rendering_driver->set_visible(false); + rendering_driver->set_flat(true); rendering_driver->set_focus_mode(Control::FOCUS_NONE); rendering_driver->connect("item_selected", callable_mp(this, &EditorNode::_rendering_driver_selected)); @@ -6649,53 +6633,30 @@ EditorNode::EditorNode() { right_menu_hb->add_child(rendering_driver); - // only display the render drivers that are available for this display driver + // Only display the render drivers that are available for this display driver. int display_driver_idx = OS::get_singleton()->get_display_driver_id(); Vector render_drivers = DisplayServer::get_create_function_rendering_drivers(display_driver_idx); String current_rendering_driver = OS::get_singleton()->get_current_rendering_driver_name(); - // as we are doing string comparisons, keep in standard case to prevent problems with capitals - // 'vulkan' in particular uses lower case v in the code, and upper case in the UI . + // As we are doing string comparisons, keep in standard case to prevent problems with capitals + // "vulkan" in particular uses lowercase "v" in the code, and uppercase in the UI. current_rendering_driver = current_rendering_driver.to_lower(); for (int i = 0; i < render_drivers.size(); i++) { String driver = render_drivers[i]; - // add the driver to the user interface - rendering_driver->add_item(driver); - rendering_driver->set_item_metadata(i, driver); - - // lower case for standard comparison - driver = driver.to_lower(); - - if (current_rendering_driver == driver) { - rendering_driver->select(i); - rendering_driver_current = i; - } - } -#if 0 - // commented out old version, gets the driver list from the project settings - // just in case we decide to revert to this method - String rendering_drivers = ProjectSettings::get_singleton()->get_custom_property_info()["rendering/driver/driver_name"].hint_string; - String current_rendering_driver = OS::get_singleton()->get_current_rendering_driver_name(); - current_rendering_driver = current_rendering_driver.to_lower(); - print_line("current_rendering_driver " + current_rendering_driver); - - rendering_driver_current = 0; - for (int i = 0; i < rendering_drivers.get_slice_count(","); i++) { - String driver = rendering_drivers.get_slice(",", i); + // Add the driver to the UI. rendering_driver->add_item(driver); rendering_driver->set_item_metadata(i, driver); + // Lowercase for standard comparison. driver = driver.to_lower(); - print_line("\tdriver " + driver); if (current_rendering_driver == driver) { rendering_driver->select(i); rendering_driver_current = i; } } -#endif _update_rendering_driver_color(); video_restart_dialog = memnew(ConfirmationDialog); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 2bd99debed..9189c75162 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1246,7 +1246,7 @@ void VisualShaderEditor::_update_options_menu() { Color unsupported_color = get_theme_color(SNAME("error_color"), SNAME("Editor")); Color supported_color = get_theme_color(SNAME("warning_color"), SNAME("Editor")); - static bool low_driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "opengl"; + static bool low_driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "opengl3"; Map folders; diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 8d14fa899e..dc35e01a56 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -478,7 +478,7 @@ private: if (rasterizer_button_group->get_pressed_button()->get_meta("driver_name") == "Vulkan") { initial_settings["rendering/driver/driver_name"] = "Vulkan"; } else { - initial_settings["rendering/driver/driver_name"] = "OpenGL"; + initial_settings["rendering/driver/driver_name"] = "OpenGL3"; initial_settings["rendering/textures/vram_compression/import_etc2"] = false; initial_settings["rendering/textures/vram_compression/import_etc"] = true; } diff --git a/gles3_builders.py b/gles3_builders.py new file mode 100644 index 0000000000..acaff28685 --- /dev/null +++ b/gles3_builders.py @@ -0,0 +1,528 @@ +"""Functions used to generate source files during build time + +All such functions are invoked in a subprocess on Windows to prevent build flakiness. + +""" +from platform_methods import subprocess_main + + +class LegacyGLHeaderStruct: + def __init__(self): + self.vertex_lines = [] + self.fragment_lines = [] + self.uniforms = [] + self.attributes = [] + self.feedbacks = [] + self.fbos = [] + self.conditionals = [] + self.enums = {} + self.texunits = [] + self.texunit_names = [] + self.ubos = [] + self.ubo_names = [] + + self.vertex_included_files = [] + self.fragment_included_files = [] + + self.reading = "" + self.line_offset = 0 + self.vertex_offset = 0 + self.fragment_offset = 0 + + +def include_file_in_legacygl_header(filename, header_data, depth): + fs = open(filename, "r") + line = fs.readline() + + while line: + + if line.find("[vertex]") != -1: + header_data.reading = "vertex" + line = fs.readline() + header_data.line_offset += 1 + header_data.vertex_offset = header_data.line_offset + continue + + if line.find("[fragment]") != -1: + header_data.reading = "fragment" + line = fs.readline() + header_data.line_offset += 1 + header_data.fragment_offset = header_data.line_offset + continue + + while line.find("#include ") != -1: + includeline = line.replace("#include ", "").strip()[1:-1] + + import os.path + + included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline) + if not included_file in header_data.vertex_included_files and header_data.reading == "vertex": + header_data.vertex_included_files += [included_file] + if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None: + print("Error in file '" + filename + "': #include " + includeline + "could not be found!") + elif not included_file in header_data.fragment_included_files and header_data.reading == "fragment": + header_data.fragment_included_files += [included_file] + if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None: + print("Error in file '" + filename + "': #include " + includeline + "could not be found!") + + line = fs.readline() + + if line.find("#ifdef ") != -1: + if line.find("#ifdef ") != -1: + ifdefline = line.replace("#ifdef ", "").strip() + + if line.find("_EN_") != -1: + enumbase = ifdefline[: ifdefline.find("_EN_")] + ifdefline = ifdefline.replace("_EN_", "_") + line = line.replace("_EN_", "_") + if enumbase not in header_data.enums: + header_data.enums[enumbase] = [] + if ifdefline not in header_data.enums[enumbase]: + header_data.enums[enumbase].append(ifdefline) + + elif not ifdefline in header_data.conditionals: + header_data.conditionals += [ifdefline] + + if line.find("uniform") != -1 and line.lower().find("texunit:") != -1: + # texture unit + texunitstr = line[line.find(":") + 1 :].strip() + if texunitstr == "auto": + texunit = "-1" + else: + texunit = str(int(texunitstr)) + uline = line[: line.lower().find("//")] + uline = uline.replace("uniform", "") + uline = uline.replace("highp", "") + uline = uline.replace(";", "") + lines = uline.split(",") + for x in lines: + + x = x.strip() + x = x[x.rfind(" ") + 1 :] + if x.find("[") != -1: + # unfiorm array + x = x[: x.find("[")] + + if not x in header_data.texunit_names: + header_data.texunits += [(x, texunit)] + header_data.texunit_names += [x] + + elif line.find("uniform") != -1 and line.lower().find("ubo:") != -1: + # uniform buffer object + ubostr = line[line.find(":") + 1 :].strip() + ubo = str(int(ubostr)) + uline = line[: line.lower().find("//")] + uline = uline[uline.find("uniform") + len("uniform") :] + uline = uline.replace("highp", "") + uline = uline.replace(";", "") + uline = uline.replace("{", "").strip() + lines = uline.split(",") + for x in lines: + + x = x.strip() + x = x[x.rfind(" ") + 1 :] + if x.find("[") != -1: + # unfiorm array + x = x[: x.find("[")] + + if not x in header_data.ubo_names: + header_data.ubos += [(x, ubo)] + header_data.ubo_names += [x] + + elif line.find("uniform") != -1 and line.find("{") == -1 and line.find(";") != -1: + uline = line.replace("uniform", "") + uline = uline.replace(";", "") + lines = uline.split(",") + for x in lines: + + x = x.strip() + x = x[x.rfind(" ") + 1 :] + if x.find("[") != -1: + # unfiorm array + x = x[: x.find("[")] + + if not x in header_data.uniforms: + header_data.uniforms += [x] + + if line.strip().find("attribute ") == 0 and line.find("attrib:") != -1: + uline = line.replace("in ", "") + uline = uline.replace("attribute ", "") + uline = uline.replace("highp ", "") + uline = uline.replace(";", "") + uline = uline[uline.find(" ") :].strip() + + if uline.find("//") != -1: + name, bind = uline.split("//") + if bind.find("attrib:") != -1: + name = name.strip() + bind = bind.replace("attrib:", "").strip() + header_data.attributes += [(name, bind)] + + if line.strip().find("out ") == 0 and line.find("tfb:") != -1: + uline = line.replace("out ", "") + uline = uline.replace("highp ", "") + uline = uline.replace(";", "") + uline = uline[uline.find(" ") :].strip() + + if uline.find("//") != -1: + name, bind = uline.split("//") + if bind.find("tfb:") != -1: + name = name.strip() + bind = bind.replace("tfb:", "").strip() + header_data.feedbacks += [(name, bind)] + + line = line.replace("\r", "") + line = line.replace("\n", "") + + if header_data.reading == "vertex": + header_data.vertex_lines += [line] + if header_data.reading == "fragment": + header_data.fragment_lines += [line] + + line = fs.readline() + header_data.line_offset += 1 + + fs.close() + + return header_data + + +def build_legacygl_header(filename, include, class_suffix, output_attribs): + header_data = LegacyGLHeaderStruct() + include_file_in_legacygl_header(filename, header_data, 0) + + out_file = filename + ".gen.h" + fd = open(out_file, "w") + + enum_constants = [] + + fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n") + + out_file_base = out_file + out_file_base = out_file_base[out_file_base.rfind("/") + 1 :] + out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :] + out_file_ifdef = out_file_base.replace(".", "_").upper() + fd.write("#ifndef " + out_file_ifdef + class_suffix + "_120\n") + fd.write("#define " + out_file_ifdef + class_suffix + "_120\n") + + out_file_class = ( + out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "Shader" + class_suffix + ) + fd.write("\n\n") + fd.write('#include "' + include + '"\n\n\n') + fd.write("class " + out_file_class + " : public Shader" + class_suffix + " {\n\n") + fd.write('\t virtual String get_shader_name() const { return "' + out_file_class + '"; }\n') + + fd.write("public:\n\n") + + if header_data.conditionals: + fd.write("\tenum Conditionals {\n") + for x in header_data.conditionals: + fd.write("\t\t" + x.upper() + ",\n") + fd.write("\t};\n\n") + + if header_data.uniforms: + fd.write("\tenum Uniforms {\n") + for x in header_data.uniforms: + fd.write("\t\t" + x.upper() + ",\n") + fd.write("\t};\n\n") + + fd.write("\t_FORCE_INLINE_ int get_uniform(Uniforms p_uniform) const { return _get_uniform(p_uniform); }\n\n") + if header_data.conditionals: + fd.write( + "\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n" + ) + fd.write("\t#ifdef DEBUG_ENABLED\n ") + fd.write( + "\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND( get_active()!=this ); \n\n " + ) + fd.write("\t#else\n ") + fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; \n\n ") + fd.write("\t#endif\n") + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Size2i& p_vec2) { _FU GLint vec2[2]={p_vec2.x,p_vec2.y}; glUniform2iv(get_uniform(p_uniform),1,vec2); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n" + ) + fd.write( + "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n" + ) + + fd.write( + """\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform3D& p_transform) { _FU + + const Transform3D &tr = p_transform; + + GLfloat matrix[16]={ /* build a 16x16 matrix */ + tr.basis.elements[0][0], + tr.basis.elements[1][0], + tr.basis.elements[2][0], + 0, + tr.basis.elements[0][1], + tr.basis.elements[1][1], + tr.basis.elements[2][1], + 0, + tr.basis.elements[0][2], + tr.basis.elements[1][2], + tr.basis.elements[2][2], + 0, + tr.origin.x, + tr.origin.y, + tr.origin.z, + 1 + }; + + + glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix); + + + } + + """ + ) + + fd.write( + """_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform2D& p_transform) { _FU + + const Transform2D &tr = p_transform; + + GLfloat matrix[16]={ /* build a 16x16 matrix */ + tr.elements[0][0], + tr.elements[0][1], + 0, + 0, + tr.elements[1][0], + tr.elements[1][1], + 0, + 0, + 0, + 0, + 1, + 0, + tr.elements[2][0], + tr.elements[2][1], + 0, + 1 + }; + + + glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix); + + + } + + """ + ) + + fd.write( + """_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) { _FU + + GLfloat matrix[16]; + + for (int i=0;i<4;i++) { + for (int j=0;j<4;j++) { + matrix[i*4+j]=p_matrix.matrix[i][j]; + } + } + + glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix); +}""" + ) + + fd.write("\n\n#undef _FU\n\n\n") + + fd.write("\tvirtual void init() {\n\n") + + enum_value_count = 0 + + if header_data.enums: + + fd.write("\t\t//Written using math, given nonstandarity of 64 bits integer constants..\n") + fd.write("\t\tstatic const Enum _enums[]={\n") + + bitofs = len(header_data.conditionals) + enum_vals = [] + + for xv in header_data.enums: + x = header_data.enums[xv] + bits = 1 + amt = len(x) + while 2 ** bits < amt: + bits += 1 + strs = "{" + for i in range(amt): + strs += '"#define ' + x[i] + '\\n",' + + c = {} + c["set_mask"] = "uint64_t(" + str(i) + ")<<" + str(bitofs) + c["clear_mask"] = ( + "((uint64_t(1)<<40)-1) ^ (((uint64_t(1)<<" + str(bits) + ") - 1)<<" + str(bitofs) + ")" + ) + enum_vals.append(c) + enum_constants.append(x[i]) + + strs += "NULL}" + + fd.write( + "\t\t\t{(uint64_t(1<<" + str(bits) + ")-1)<<" + str(bitofs) + "," + str(bitofs) + "," + strs + "},\n" + ) + bitofs += bits + + fd.write("\t\t};\n\n") + + fd.write("\t\tstatic const EnumValue _enum_values[]={\n") + + enum_value_count = len(enum_vals) + for x in enum_vals: + fd.write("\t\t\t{" + x["set_mask"] + "," + x["clear_mask"] + "},\n") + + fd.write("\t\t};\n\n") + + conditionals_found = [] + if header_data.conditionals: + + fd.write("\t\tstatic const char* _conditional_strings[]={\n") + if header_data.conditionals: + for x in header_data.conditionals: + fd.write('\t\t\t"#define ' + x + '\\n",\n') + conditionals_found.append(x) + fd.write("\t\t};\n\n") + else: + fd.write("\t\tstatic const char **_conditional_strings=NULL;\n") + + if header_data.uniforms: + + fd.write("\t\tstatic const char* _uniform_strings[]={\n") + if header_data.uniforms: + for x in header_data.uniforms: + fd.write('\t\t\t"' + x + '",\n') + fd.write("\t\t};\n\n") + else: + fd.write("\t\tstatic const char **_uniform_strings=NULL;\n") + + if output_attribs: + if header_data.attributes: + + fd.write("\t\tstatic AttributePair _attribute_pairs[]={\n") + for x in header_data.attributes: + fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n") + fd.write("\t\t};\n\n") + else: + fd.write("\t\tstatic AttributePair *_attribute_pairs=NULL;\n") + + feedback_count = 0 + + if header_data.texunits: + fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n") + for x in header_data.texunits: + fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n") + fd.write("\t\t};\n\n") + else: + fd.write("\t\tstatic TexUnitPair *_texunit_pairs=NULL;\n") + + fd.write("\t\tstatic const char _vertex_code[]={\n") + for x in header_data.vertex_lines: + for c in x: + fd.write(str(ord(c)) + ",") + + fd.write(str(ord("\n")) + ",") + fd.write("\t\t0};\n\n") + + fd.write("\t\tstatic const int _vertex_code_start=" + str(header_data.vertex_offset) + ";\n") + + fd.write("\t\tstatic const char _fragment_code[]={\n") + for x in header_data.fragment_lines: + for c in x: + fd.write(str(ord(c)) + ",") + + fd.write(str(ord("\n")) + ",") + fd.write("\t\t0};\n\n") + + fd.write("\t\tstatic const int _fragment_code_start=" + str(header_data.fragment_offset) + ";\n") + + if output_attribs: + fd.write( + "\t\tsetup(_conditional_strings," + + str(len(header_data.conditionals)) + + ",_uniform_strings," + + str(len(header_data.uniforms)) + + ",_attribute_pairs," + + str(len(header_data.attributes)) + + ", _texunit_pairs," + + str(len(header_data.texunits)) + + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n" + ) + else: + fd.write( + "\t\tsetup(_conditional_strings," + + str(len(header_data.conditionals)) + + ",_uniform_strings," + + str(len(header_data.uniforms)) + + ",_texunit_pairs," + + str(len(header_data.texunits)) + + ",_enums," + + str(len(header_data.enums)) + + ",_enum_values," + + str(enum_value_count) + + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n" + ) + + fd.write("\t}\n\n") + + if enum_constants: + + fd.write("\tenum EnumConditionals {\n") + for x in enum_constants: + fd.write("\t\t" + x.upper() + ",\n") + fd.write("\t};\n\n") + fd.write("\tvoid set_enum_conditional(EnumConditionals p_cond) { _set_enum_conditional(p_cond); }\n") + + fd.write("};\n\n") + fd.write("#endif\n\n") + fd.close() + + +def build_gles3_headers(target, source, env): + for x in source: + build_legacygl_header(str(x), include="drivers/gles3/shader_gles3.h", class_suffix="GLES3", output_attribs=True) + + +if __name__ == "__main__": + subprocess_main(globals()) diff --git a/main/main.cpp b/main/main.cpp index bc23d498dc..fe0f2693e4 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1573,8 +1573,6 @@ Error Main::setup2(Thread::ID p_main_tid_override) { String display_driver = DisplayServer::get_create_function_name(display_driver_idx); // rendering_driver now held in static global String in main and initialized in setup() - print_line("creating display driver : " + display_driver); - print_line("creating rendering driver : " + rendering_driver); Error err; display_server = DisplayServer::create(display_driver_idx, rendering_driver, window_mode, window_vsync_mode, window_flags, window_size, err); if (err != OK || display_server == nullptr) { diff --git a/opengl_builders.py b/opengl_builders.py deleted file mode 100644 index 179b5c69ab..0000000000 --- a/opengl_builders.py +++ /dev/null @@ -1,530 +0,0 @@ -"""Functions used to generate source files during build time - -All such functions are invoked in a subprocess on Windows to prevent build flakiness. - -""" -from platform_methods import subprocess_main - - -class LegacyGLHeaderStruct: - def __init__(self): - self.vertex_lines = [] - self.fragment_lines = [] - self.uniforms = [] - self.attributes = [] - self.feedbacks = [] - self.fbos = [] - self.conditionals = [] - self.enums = {} - self.texunits = [] - self.texunit_names = [] - self.ubos = [] - self.ubo_names = [] - - self.vertex_included_files = [] - self.fragment_included_files = [] - - self.reading = "" - self.line_offset = 0 - self.vertex_offset = 0 - self.fragment_offset = 0 - - -def include_file_in_legacygl_header(filename, header_data, depth): - fs = open(filename, "r") - line = fs.readline() - - while line: - - if line.find("[vertex]") != -1: - header_data.reading = "vertex" - line = fs.readline() - header_data.line_offset += 1 - header_data.vertex_offset = header_data.line_offset - continue - - if line.find("[fragment]") != -1: - header_data.reading = "fragment" - line = fs.readline() - header_data.line_offset += 1 - header_data.fragment_offset = header_data.line_offset - continue - - while line.find("#include ") != -1: - includeline = line.replace("#include ", "").strip()[1:-1] - - import os.path - - included_file = os.path.relpath(os.path.dirname(filename) + "/" + includeline) - if not included_file in header_data.vertex_included_files and header_data.reading == "vertex": - header_data.vertex_included_files += [included_file] - if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None: - print("Error in file '" + filename + "': #include " + includeline + "could not be found!") - elif not included_file in header_data.fragment_included_files and header_data.reading == "fragment": - header_data.fragment_included_files += [included_file] - if include_file_in_legacygl_header(included_file, header_data, depth + 1) is None: - print("Error in file '" + filename + "': #include " + includeline + "could not be found!") - - line = fs.readline() - - if line.find("#ifdef ") != -1: - if line.find("#ifdef ") != -1: - ifdefline = line.replace("#ifdef ", "").strip() - - if line.find("_EN_") != -1: - enumbase = ifdefline[: ifdefline.find("_EN_")] - ifdefline = ifdefline.replace("_EN_", "_") - line = line.replace("_EN_", "_") - if enumbase not in header_data.enums: - header_data.enums[enumbase] = [] - if ifdefline not in header_data.enums[enumbase]: - header_data.enums[enumbase].append(ifdefline) - - elif not ifdefline in header_data.conditionals: - header_data.conditionals += [ifdefline] - - if line.find("uniform") != -1 and line.lower().find("texunit:") != -1: - # texture unit - texunitstr = line[line.find(":") + 1 :].strip() - if texunitstr == "auto": - texunit = "-1" - else: - texunit = str(int(texunitstr)) - uline = line[: line.lower().find("//")] - uline = uline.replace("uniform", "") - uline = uline.replace("highp", "") - uline = uline.replace(";", "") - lines = uline.split(",") - for x in lines: - - x = x.strip() - x = x[x.rfind(" ") + 1 :] - if x.find("[") != -1: - # unfiorm array - x = x[: x.find("[")] - - if not x in header_data.texunit_names: - header_data.texunits += [(x, texunit)] - header_data.texunit_names += [x] - - elif line.find("uniform") != -1 and line.lower().find("ubo:") != -1: - # uniform buffer object - ubostr = line[line.find(":") + 1 :].strip() - ubo = str(int(ubostr)) - uline = line[: line.lower().find("//")] - uline = uline[uline.find("uniform") + len("uniform") :] - uline = uline.replace("highp", "") - uline = uline.replace(";", "") - uline = uline.replace("{", "").strip() - lines = uline.split(",") - for x in lines: - - x = x.strip() - x = x[x.rfind(" ") + 1 :] - if x.find("[") != -1: - # unfiorm array - x = x[: x.find("[")] - - if not x in header_data.ubo_names: - header_data.ubos += [(x, ubo)] - header_data.ubo_names += [x] - - elif line.find("uniform") != -1 and line.find("{") == -1 and line.find(";") != -1: - uline = line.replace("uniform", "") - uline = uline.replace(";", "") - lines = uline.split(",") - for x in lines: - - x = x.strip() - x = x[x.rfind(" ") + 1 :] - if x.find("[") != -1: - # unfiorm array - x = x[: x.find("[")] - - if not x in header_data.uniforms: - header_data.uniforms += [x] - - if line.strip().find("attribute ") == 0 and line.find("attrib:") != -1: - uline = line.replace("in ", "") - uline = uline.replace("attribute ", "") - uline = uline.replace("highp ", "") - uline = uline.replace(";", "") - uline = uline[uline.find(" ") :].strip() - - if uline.find("//") != -1: - name, bind = uline.split("//") - if bind.find("attrib:") != -1: - name = name.strip() - bind = bind.replace("attrib:", "").strip() - header_data.attributes += [(name, bind)] - - if line.strip().find("out ") == 0 and line.find("tfb:") != -1: - uline = line.replace("out ", "") - uline = uline.replace("highp ", "") - uline = uline.replace(";", "") - uline = uline[uline.find(" ") :].strip() - - if uline.find("//") != -1: - name, bind = uline.split("//") - if bind.find("tfb:") != -1: - name = name.strip() - bind = bind.replace("tfb:", "").strip() - header_data.feedbacks += [(name, bind)] - - line = line.replace("\r", "") - line = line.replace("\n", "") - - if header_data.reading == "vertex": - header_data.vertex_lines += [line] - if header_data.reading == "fragment": - header_data.fragment_lines += [line] - - line = fs.readline() - header_data.line_offset += 1 - - fs.close() - - return header_data - - -def build_legacygl_header(filename, include, class_suffix, output_attribs): - header_data = LegacyGLHeaderStruct() - include_file_in_legacygl_header(filename, header_data, 0) - - out_file = filename + ".gen.h" - fd = open(out_file, "w") - - enum_constants = [] - - fd.write("/* WARNING, THIS FILE WAS GENERATED, DO NOT EDIT */\n") - - out_file_base = out_file - out_file_base = out_file_base[out_file_base.rfind("/") + 1 :] - out_file_base = out_file_base[out_file_base.rfind("\\") + 1 :] - out_file_ifdef = out_file_base.replace(".", "_").upper() - fd.write("#ifndef " + out_file_ifdef + class_suffix + "_120\n") - fd.write("#define " + out_file_ifdef + class_suffix + "_120\n") - - out_file_class = ( - out_file_base.replace(".glsl.gen.h", "").title().replace("_", "").replace(".", "") + "Shader" + class_suffix - ) - fd.write("\n\n") - fd.write('#include "' + include + '"\n\n\n') - fd.write("class " + out_file_class + " : public Shader" + class_suffix + " {\n\n") - fd.write('\t virtual String get_shader_name() const { return "' + out_file_class + '"; }\n') - - fd.write("public:\n\n") - - if header_data.conditionals: - fd.write("\tenum Conditionals {\n") - for x in header_data.conditionals: - fd.write("\t\t" + x.upper() + ",\n") - fd.write("\t};\n\n") - - if header_data.uniforms: - fd.write("\tenum Uniforms {\n") - for x in header_data.uniforms: - fd.write("\t\t" + x.upper() + ",\n") - fd.write("\t};\n\n") - - fd.write("\t_FORCE_INLINE_ int get_uniform(Uniforms p_uniform) const { return _get_uniform(p_uniform); }\n\n") - if header_data.conditionals: - fd.write( - "\t_FORCE_INLINE_ void set_conditional(Conditionals p_conditional,bool p_enable) { _set_conditional(p_conditional,p_enable); }\n\n" - ) - fd.write("\t#ifdef DEBUG_ENABLED\n ") - fd.write( - "\t#define _FU if (get_uniform(p_uniform)<0) return; if (!is_version_valid()) return; ERR_FAIL_COND( get_active()!=this ); \n\n " - ) - fd.write("\t#else\n ") - fd.write("\t#define _FU if (get_uniform(p_uniform)<0) return; \n\n ") - fd.write("\t#endif\n") - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, double p_value) { _FU glUniform1f(get_uniform(p_uniform),p_value); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int8_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int16_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, uint32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, int32_t p_value) { _FU glUniform1i(get_uniform(p_uniform),p_value); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Color& p_color) { _FU GLfloat col[4]={p_color.r,p_color.g,p_color.b,p_color.a}; glUniform4fv(get_uniform(p_uniform),1,col); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector2& p_vec2) { _FU GLfloat vec2[2]={p_vec2.x,p_vec2.y}; glUniform2fv(get_uniform(p_uniform),1,vec2); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Size2i& p_vec2) { _FU GLint vec2[2]={p_vec2.x,p_vec2.y}; glUniform2iv(get_uniform(p_uniform),1,vec2); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Vector3& p_vec3) { _FU GLfloat vec3[3]={p_vec3.x,p_vec3.y,p_vec3.z}; glUniform3fv(get_uniform(p_uniform),1,vec3); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b) { _FU glUniform2f(get_uniform(p_uniform),p_a,p_b); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c) { _FU glUniform3f(get_uniform(p_uniform),p_a,p_b,p_c); }\n\n" - ) - fd.write( - "\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, float p_a, float p_b, float p_c, float p_d) { _FU glUniform4f(get_uniform(p_uniform),p_a,p_b,p_c,p_d); }\n\n" - ) - - fd.write( - """\t_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform3D& p_transform) { _FU - - const Transform3D &tr = p_transform; - - GLfloat matrix[16]={ /* build a 16x16 matrix */ - tr.basis.elements[0][0], - tr.basis.elements[1][0], - tr.basis.elements[2][0], - 0, - tr.basis.elements[0][1], - tr.basis.elements[1][1], - tr.basis.elements[2][1], - 0, - tr.basis.elements[0][2], - tr.basis.elements[1][2], - tr.basis.elements[2][2], - 0, - tr.origin.x, - tr.origin.y, - tr.origin.z, - 1 - }; - - - glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix); - - - } - - """ - ) - - fd.write( - """_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const Transform2D& p_transform) { _FU - - const Transform2D &tr = p_transform; - - GLfloat matrix[16]={ /* build a 16x16 matrix */ - tr.elements[0][0], - tr.elements[0][1], - 0, - 0, - tr.elements[1][0], - tr.elements[1][1], - 0, - 0, - 0, - 0, - 1, - 0, - tr.elements[2][0], - tr.elements[2][1], - 0, - 1 - }; - - - glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix); - - - } - - """ - ) - - fd.write( - """_FORCE_INLINE_ void set_uniform(Uniforms p_uniform, const CameraMatrix& p_matrix) { _FU - - GLfloat matrix[16]; - - for (int i=0;i<4;i++) { - for (int j=0;j<4;j++) { - matrix[i*4+j]=p_matrix.matrix[i][j]; - } - } - - glUniformMatrix4fv(get_uniform(p_uniform),1,false,matrix); -}""" - ) - - fd.write("\n\n#undef _FU\n\n\n") - - fd.write("\tvirtual void init() {\n\n") - - enum_value_count = 0 - - if header_data.enums: - - fd.write("\t\t//Written using math, given nonstandarity of 64 bits integer constants..\n") - fd.write("\t\tstatic const Enum _enums[]={\n") - - bitofs = len(header_data.conditionals) - enum_vals = [] - - for xv in header_data.enums: - x = header_data.enums[xv] - bits = 1 - amt = len(x) - while 2 ** bits < amt: - bits += 1 - strs = "{" - for i in range(amt): - strs += '"#define ' + x[i] + '\\n",' - - c = {} - c["set_mask"] = "uint64_t(" + str(i) + ")<<" + str(bitofs) - c["clear_mask"] = ( - "((uint64_t(1)<<40)-1) ^ (((uint64_t(1)<<" + str(bits) + ") - 1)<<" + str(bitofs) + ")" - ) - enum_vals.append(c) - enum_constants.append(x[i]) - - strs += "NULL}" - - fd.write( - "\t\t\t{(uint64_t(1<<" + str(bits) + ")-1)<<" + str(bitofs) + "," + str(bitofs) + "," + strs + "},\n" - ) - bitofs += bits - - fd.write("\t\t};\n\n") - - fd.write("\t\tstatic const EnumValue _enum_values[]={\n") - - enum_value_count = len(enum_vals) - for x in enum_vals: - fd.write("\t\t\t{" + x["set_mask"] + "," + x["clear_mask"] + "},\n") - - fd.write("\t\t};\n\n") - - conditionals_found = [] - if header_data.conditionals: - - fd.write("\t\tstatic const char* _conditional_strings[]={\n") - if header_data.conditionals: - for x in header_data.conditionals: - fd.write('\t\t\t"#define ' + x + '\\n",\n') - conditionals_found.append(x) - fd.write("\t\t};\n\n") - else: - fd.write("\t\tstatic const char **_conditional_strings=NULL;\n") - - if header_data.uniforms: - - fd.write("\t\tstatic const char* _uniform_strings[]={\n") - if header_data.uniforms: - for x in header_data.uniforms: - fd.write('\t\t\t"' + x + '",\n') - fd.write("\t\t};\n\n") - else: - fd.write("\t\tstatic const char **_uniform_strings=NULL;\n") - - if output_attribs: - if header_data.attributes: - - fd.write("\t\tstatic AttributePair _attribute_pairs[]={\n") - for x in header_data.attributes: - fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n") - fd.write("\t\t};\n\n") - else: - fd.write("\t\tstatic AttributePair *_attribute_pairs=NULL;\n") - - feedback_count = 0 - - if header_data.texunits: - fd.write("\t\tstatic TexUnitPair _texunit_pairs[]={\n") - for x in header_data.texunits: - fd.write('\t\t\t{"' + x[0] + '",' + x[1] + "},\n") - fd.write("\t\t};\n\n") - else: - fd.write("\t\tstatic TexUnitPair *_texunit_pairs=NULL;\n") - - fd.write("\t\tstatic const char _vertex_code[]={\n") - for x in header_data.vertex_lines: - for c in x: - fd.write(str(ord(c)) + ",") - - fd.write(str(ord("\n")) + ",") - fd.write("\t\t0};\n\n") - - fd.write("\t\tstatic const int _vertex_code_start=" + str(header_data.vertex_offset) + ";\n") - - fd.write("\t\tstatic const char _fragment_code[]={\n") - for x in header_data.fragment_lines: - for c in x: - fd.write(str(ord(c)) + ",") - - fd.write(str(ord("\n")) + ",") - fd.write("\t\t0};\n\n") - - fd.write("\t\tstatic const int _fragment_code_start=" + str(header_data.fragment_offset) + ";\n") - - if output_attribs: - fd.write( - "\t\tsetup(_conditional_strings," - + str(len(header_data.conditionals)) - + ",_uniform_strings," - + str(len(header_data.uniforms)) - + ",_attribute_pairs," - + str(len(header_data.attributes)) - + ", _texunit_pairs," - + str(len(header_data.texunits)) - + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n" - ) - else: - fd.write( - "\t\tsetup(_conditional_strings," - + str(len(header_data.conditionals)) - + ",_uniform_strings," - + str(len(header_data.uniforms)) - + ",_texunit_pairs," - + str(len(header_data.texunits)) - + ",_enums," - + str(len(header_data.enums)) - + ",_enum_values," - + str(enum_value_count) - + ",_vertex_code,_fragment_code,_vertex_code_start,_fragment_code_start);\n" - ) - - fd.write("\t}\n\n") - - if enum_constants: - - fd.write("\tenum EnumConditionals {\n") - for x in enum_constants: - fd.write("\t\t" + x.upper() + ",\n") - fd.write("\t};\n\n") - fd.write("\tvoid set_enum_conditional(EnumConditionals p_cond) { _set_enum_conditional(p_cond); }\n") - - fd.write("};\n\n") - fd.write("#endif\n\n") - fd.close() - - -def build_opengl_headers(target, source, env): - for x in source: - build_legacygl_header( - str(x), include="drivers/opengl/shader_opengl.h", class_suffix="OpenGL", output_attribs=True - ) - - -if __name__ == "__main__": - subprocess_main(globals()) diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 084761b794..34f0064a5e 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -344,8 +344,8 @@ void DisplayServerAndroid::process_events() { Vector DisplayServerAndroid::get_rendering_drivers_func() { Vector drivers; -#ifdef OPENGL_ENABLED - drivers.push_back("opengl"); +#ifdef GLES3_ENABLED + drivers.push_back("opengl3"); #endif #ifdef VULKAN_ENABLED drivers.push_back("vulkan"); @@ -407,13 +407,13 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis keep_screen_on = GLOBAL_GET("display/window/energy_saving/keep_screen_on"); -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl") { +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { bool gl_initialization_error = false; - if (RasterizerOpenGLis_viable() == OK) { - RasterizerOpenGLregister_config(); - RasterizerOpenGLmake_current(); + if (RasterizerGLES3::is_viable() == OK) { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); } else { gl_initialization_error = true; } diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp index 1cac0ed4ce..8df61831c2 100644 --- a/platform/android/export/export.cpp +++ b/platform/android/export/export.cpp @@ -31,2833 +31,6 @@ #include "export.h" #include "export_plugin.h" -//#include "core/config/project_settings.h" -//#include "core/io/image_loader.h" -//#include "core/io/marshalls.h" -//#include "core/io/zip_io.h" -//#include "core/os/dir_access.h" -//#include "core/os/file_access.h" -//#include "core/os/os.h" -//#include "core/version.h" -//#include "drivers/png/png_driver_common.h" -//#include "editor/editor_export.h" -//#include "editor/editor_log.h" -//#include "editor/editor_node.h" -//#include "editor/editor_settings.h" -//#include "main/splash.gen.h" -//#include "platform/android/export/gradle_export_util.h" -//#include "platform/android/logo.gen.h" -//#include "platform/android/plugin/godot_plugin_config.h" -//#include "platform/android/run_icon.gen.h" - -//#include - -//static const char *android_perms[] = { -// "ACCESS_CHECKIN_PROPERTIES", -// "ACCESS_COARSE_LOCATION", -// "ACCESS_FINE_LOCATION", -// "ACCESS_LOCATION_EXTRA_COMMANDS", -// "ACCESS_MOCK_LOCATION", -// "ACCESS_NETWORK_STATE", -// "ACCESS_SURFACE_FLINGER", -// "ACCESS_WIFI_STATE", -// "ACCOUNT_MANAGER", -// "ADD_VOICEMAIL", -// "AUTHENTICATE_ACCOUNTS", -// "BATTERY_STATS", -// "BIND_ACCESSIBILITY_SERVICE", -// "BIND_APPWIDGET", -// "BIND_DEVICE_ADMIN", -// "BIND_INPUT_METHOD", -// "BIND_NFC_SERVICE", -// "BIND_NOTIFICATION_LISTENER_SERVICE", -// "BIND_PRINT_SERVICE", -// "BIND_REMOTEVIEWS", -// "BIND_TEXT_SERVICE", -// "BIND_VPN_SERVICE", -// "BIND_WALLPAPER", -// "BLUETOOTH", -// "BLUETOOTH_ADMIN", -// "BLUETOOTH_PRIVILEGED", -// "BRICK", -// "BROADCAST_PACKAGE_REMOVED", -// "BROADCAST_SMS", -// "BROADCAST_STICKY", -// "BROADCAST_WAP_PUSH", -// "CALL_PHONE", -// "CALL_PRIVILEGED", -// "CAMERA", -// "CAPTURE_AUDIO_OUTPUT", -// "CAPTURE_SECURE_VIDEO_OUTPUT", -// "CAPTURE_VIDEO_OUTPUT", -// "CHANGE_COMPONENT_ENABLED_STATE", -// "CHANGE_CONFIGURATION", -// "CHANGE_NETWORK_STATE", -// "CHANGE_WIFI_MULTICAST_STATE", -// "CHANGE_WIFI_STATE", -// "CLEAR_APP_CACHE", -// "CLEAR_APP_USER_DATA", -// "CONTROL_LOCATION_UPDATES", -// "DELETE_CACHE_FILES", -// "DELETE_PACKAGES", -// "DEVICE_POWER", -// "DIAGNOSTIC", -// "DISABLE_KEYGUARD", -// "DUMP", -// "EXPAND_STATUS_BAR", -// "FACTORY_TEST", -// "FLASHLIGHT", -// "FORCE_BACK", -// "GET_ACCOUNTS", -// "GET_PACKAGE_SIZE", -// "GET_TASKS", -// "GET_TOP_ACTIVITY_INFO", -// "GLOBAL_SEARCH", -// "HARDWARE_TEST", -// "INJECT_EVENTS", -// "INSTALL_LOCATION_PROVIDER", -// "INSTALL_PACKAGES", -// "INSTALL_SHORTCUT", -// "INTERNAL_SYSTEM_WINDOW", -// "INTERNET", -// "KILL_BACKGROUND_PROCESSES", -// "LOCATION_HARDWARE", -// "MANAGE_ACCOUNTS", -// "MANAGE_APP_TOKENS", -// "MANAGE_DOCUMENTS", -// "MASTER_CLEAR", -// "MEDIA_CONTENT_CONTROL", -// "MODIFY_AUDIO_SETTINGS", -// "MODIFY_PHONE_STATE", -// "MOUNT_FORMAT_FILESYSTEMS", -// "MOUNT_UNMOUNT_FILESYSTEMS", -// "NFC", -// "PERSISTENT_ACTIVITY", -// "PROCESS_OUTGOING_CALLS", -// "READ_CALENDAR", -// "READ_CALL_LOG", -// "READ_CONTACTS", -// "READ_EXTERNAL_STORAGE", -// "READ_FRAME_BUFFER", -// "READ_HISTORY_BOOKMARKS", -// "READ_INPUT_STATE", -// "READ_LOGS", -// "READ_PHONE_STATE", -// "READ_PROFILE", -// "READ_SMS", -// "READ_SOCIAL_STREAM", -// "READ_SYNC_SETTINGS", -// "READ_SYNC_STATS", -// "READ_USER_DICTIONARY", -// "REBOOT", -// "RECEIVE_BOOT_COMPLETED", -// "RECEIVE_MMS", -// "RECEIVE_SMS", -// "RECEIVE_WAP_PUSH", -// "RECORD_AUDIO", -// "REORDER_TASKS", -// "RESTART_PACKAGES", -// "SEND_RESPOND_VIA_MESSAGE", -// "SEND_SMS", -// "SET_ACTIVITY_WATCHER", -// "SET_ALARM", -// "SET_ALWAYS_FINISH", -// "SET_ANIMATION_SCALE", -// "SET_DEBUG_APP", -// "SET_ORIENTATION", -// "SET_POINTER_SPEED", -// "SET_PREFERRED_APPLICATIONS", -// "SET_PROCESS_LIMIT", -// "SET_TIME", -// "SET_TIME_ZONE", -// "SET_WALLPAPER", -// "SET_WALLPAPER_HINTS", -// "SIGNAL_PERSISTENT_PROCESSES", -// "STATUS_BAR", -// "SUBSCRIBED_FEEDS_READ", -// "SUBSCRIBED_FEEDS_WRITE", -// "SYSTEM_ALERT_WINDOW", -// "TRANSMIT_IR", -// "UNINSTALL_SHORTCUT", -// "UPDATE_DEVICE_STATS", -// "USE_CREDENTIALS", -// "USE_SIP", -// "VIBRATE", -// "WAKE_LOCK", -// "WRITE_APN_SETTINGS", -// "WRITE_CALENDAR", -// "WRITE_CALL_LOG", -// "WRITE_CONTACTS", -// "WRITE_EXTERNAL_STORAGE", -// "WRITE_GSERVICES", -// "WRITE_HISTORY_BOOKMARKS", -// "WRITE_PROFILE", -// "WRITE_SECURE_SETTINGS", -// "WRITE_SETTINGS", -// "WRITE_SMS", -// "WRITE_SOCIAL_STREAM", -// "WRITE_SYNC_SETTINGS", -// "WRITE_USER_DICTIONARY", -// nullptr -//}; - -//static const char *SPLASH_IMAGE_EXPORT_PATH = "res/drawable/splash.png"; -//static const char *SPLASH_BG_COLOR_PATH = "res/drawable/splash_bg_color.png"; - -//struct LauncherIcon { -// const char *export_path; -// int dimensions = 0; -//}; - -//static const int icon_densities_count = 6; -//static const char *launcher_icon_option = "launcher_icons/main_192x192"; -//static const char *launcher_adaptive_icon_foreground_option = "launcher_icons/adaptive_foreground_432x432"; -//static const char *launcher_adaptive_icon_background_option = "launcher_icons/adaptive_background_432x432"; - -//static const LauncherIcon launcher_icons[icon_densities_count] = { -// { "res/mipmap-xxxhdpi-v4/icon.png", 192 }, -// { "res/mipmap-xxhdpi-v4/icon.png", 144 }, -// { "res/mipmap-xhdpi-v4/icon.png", 96 }, -// { "res/mipmap-hdpi-v4/icon.png", 72 }, -// { "res/mipmap-mdpi-v4/icon.png", 48 }, -// { "res/mipmap/icon.png", 192 } -//}; - -//static const LauncherIcon launcher_adaptive_icon_foregrounds[icon_densities_count] = { -// { "res/mipmap-xxxhdpi-v4/icon_foreground.png", 432 }, -// { "res/mipmap-xxhdpi-v4/icon_foreground.png", 324 }, -// { "res/mipmap-xhdpi-v4/icon_foreground.png", 216 }, -// { "res/mipmap-hdpi-v4/icon_foreground.png", 162 }, -// { "res/mipmap-mdpi-v4/icon_foreground.png", 108 }, -// { "res/mipmap/icon_foreground.png", 432 } -//}; - -//static const LauncherIcon launcher_adaptive_icon_backgrounds[icon_densities_count] = { -// { "res/mipmap-xxxhdpi-v4/icon_background.png", 432 }, -// { "res/mipmap-xxhdpi-v4/icon_background.png", 324 }, -// { "res/mipmap-xhdpi-v4/icon_background.png", 216 }, -// { "res/mipmap-hdpi-v4/icon_background.png", 162 }, -// { "res/mipmap-mdpi-v4/icon_background.png", 108 }, -// { "res/mipmap/icon_background.png", 432 } -//}; - -//static const int EXPORT_FORMAT_APK = 0; -//static const int EXPORT_FORMAT_AAB = 1; - -//class EditorExportPlatformAndroid : public EditorExportPlatform { -// GDCLASS(EditorExportPlatformAndroid, EditorExportPlatform); - -// Ref logo; -// Ref run_icon; - -// struct Device { -// String id; -// String name; -// String description; -// int api_level = 0; -// }; - -// struct APKExportData { -// zipFile apk; -// EditorProgress *ep = nullptr; -// }; - -// Vector plugins; -// String last_plugin_names; -// uint64_t last_custom_build_time = 0; -// volatile bool plugins_changed; -// Mutex plugins_lock; -// Vector devices; -// volatile bool devices_changed; -// Mutex device_lock; -// Thread *check_for_changes_thread; -// volatile bool quit_request; - -// static void _check_for_changes_poll_thread(void *ud) { -// EditorExportPlatformAndroid *ea = (EditorExportPlatformAndroid *)ud; - -// while (!ea->quit_request) { -// // Check for plugins updates -// { -// // Nothing to do if we already know the plugins have changed. -// if (!ea->plugins_changed) { -// Vector loaded_plugins = get_plugins(); - -// MutexLock lock(ea->plugins_lock); - -// if (ea->plugins.size() != loaded_plugins.size()) { -// ea->plugins_changed = true; -// } else { -// for (int i = 0; i < ea->plugins.size(); i++) { -// if (ea->plugins[i].name != loaded_plugins[i].name) { -// ea->plugins_changed = true; -// break; -// } -// } -// } - -// if (ea->plugins_changed) { -// ea->plugins = loaded_plugins; -// } -// } -// } - -// // Check for devices updates -// String adb = get_adb_path(); -// if (FileAccess::exists(adb)) { -// String devices; -// List args; -// args.push_back("devices"); -// int ec; -// OS::get_singleton()->execute(adb, args, true, nullptr, &devices, &ec); - -// Vector ds = devices.split("\n"); -// Vector ldevices; -// for (int i = 1; i < ds.size(); i++) { -// String d = ds[i]; -// int dpos = d.find("device"); -// if (dpos == -1) { -// continue; -// } -// d = d.substr(0, dpos).strip_edges(); -// ldevices.push_back(d); -// } - -// MutexLock lock(ea->device_lock); - -// bool different = false; - -// if (ea->devices.size() != ldevices.size()) { -// different = true; -// } else { -// for (int i = 0; i < ea->devices.size(); i++) { -// if (ea->devices[i].id != ldevices[i]) { -// different = true; -// break; -// } -// } -// } - -// if (different) { -// Vector ndevices; - -// for (int i = 0; i < ldevices.size(); i++) { -// Device d; -// d.id = ldevices[i]; -// for (int j = 0; j < ea->devices.size(); j++) { -// if (ea->devices[j].id == ldevices[i]) { -// d.description = ea->devices[j].description; -// d.name = ea->devices[j].name; -// d.api_level = ea->devices[j].api_level; -// } -// } - -// if (d.description == "") { -// //in the oven, request! -// args.clear(); -// args.push_back("-s"); -// args.push_back(d.id); -// args.push_back("shell"); -// args.push_back("getprop"); -// int ec2; -// String dp; - -// OS::get_singleton()->execute(adb, args, true, nullptr, &dp, &ec2); - -// Vector props = dp.split("\n"); -// String vendor; -// String device; -// d.description = "Device ID: " + d.id + "\n"; -// d.api_level = 0; -// for (int j = 0; j < props.size(); j++) { -// // got information by `shell cat /system/build.prop` before and its format is "property=value" -// // it's now changed to use `shell getporp` because of permission issue with Android 8.0 and above -// // its format is "[property]: [value]" so changed it as like build.prop -// String p = props[j]; -// p = p.replace("]: ", "="); -// p = p.replace("[", ""); -// p = p.replace("]", ""); - -// if (p.begins_with("ro.product.model=")) { -// device = p.get_slice("=", 1).strip_edges(); -// } else if (p.begins_with("ro.product.brand=")) { -// vendor = p.get_slice("=", 1).strip_edges().capitalize(); -// } else if (p.begins_with("ro.build.display.id=")) { -// d.description += "Build: " + p.get_slice("=", 1).strip_edges() + "\n"; -// } else if (p.begins_with("ro.build.version.release=")) { -// d.description += "Release: " + p.get_slice("=", 1).strip_edges() + "\n"; -// } else if (p.begins_with("ro.build.version.sdk=")) { -// d.api_level = p.get_slice("=", 1).to_int(); -// } else if (p.begins_with("ro.product.cpu.abi=")) { -// d.description += "CPU: " + p.get_slice("=", 1).strip_edges() + "\n"; -// } else if (p.begins_with("ro.product.manufacturer=")) { -// d.description += "Manufacturer: " + p.get_slice("=", 1).strip_edges() + "\n"; -// } else if (p.begins_with("ro.board.platform=")) { -// d.description += "Chipset: " + p.get_slice("=", 1).strip_edges() + "\n"; -// } else if (p.begins_with("ro.opengles.version=")) { -// uint32_t opengl = p.get_slice("=", 1).to_int(); -// d.description += "OpenGL: " + itos(opengl >> 16) + "." + itos((opengl >> 8) & 0xFF) + "." + itos((opengl)&0xFF) + "\n"; -// } -// } - -// d.name = vendor + " " + device; -// if (device == String()) { -// continue; -// } -// } - -// ndevices.push_back(d); -// } - -// ea->devices = ndevices; -// ea->devices_changed = true; -// } -// } - -// uint64_t sleep = 200; -// uint64_t wait = 3000000; -// uint64_t time = OS::get_singleton()->get_ticks_usec(); -// while (OS::get_singleton()->get_ticks_usec() - time < wait) { -// OS::get_singleton()->delay_usec(1000 * sleep); -// if (ea->quit_request) { -// break; -// } -// } -// } - -// if (EditorSettings::get_singleton()->get("export/android/shutdown_adb_on_exit")) { -// String adb = get_adb_path(); -// if (!FileAccess::exists(adb)) { -// return; //adb not configured -// } - -// List args; -// args.push_back("kill-server"); -// OS::get_singleton()->execute(adb, args, true); -// }; -// } - -// String get_project_name(const String &p_name) const { -// String aname; -// if (p_name != "") { -// aname = p_name; -// } else { -// aname = ProjectSettings::get_singleton()->get("application/config/name"); -// } - -// if (aname == "") { -// aname = VERSION_NAME; -// } - -// return aname; -// } - -// String get_package_name(const String &p_package) const { -// String pname = p_package; -// String basename = ProjectSettings::get_singleton()->get("application/config/name"); -// basename = basename.to_lower(); - -// String name; -// bool first = true; -// for (int i = 0; i < basename.length(); i++) { -// char32_t c = basename[i]; -// if (c >= '0' && c <= '9' && first) { -// continue; -// } -// if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) { -// name += String::chr(c); -// first = false; -// } -// } -// if (name == "") { -// name = "noname"; -// } - -// pname = pname.replace("$genname", name); - -// return pname; -// } - -// bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const { -// String pname = p_package; - -// if (pname.length() == 0) { -// if (r_error) { -// *r_error = TTR("Package name is missing."); -// } -// return false; -// } - -// int segments = 0; -// bool first = true; -// for (int i = 0; i < pname.length(); i++) { -// char32_t c = pname[i]; -// if (first && c == '.') { -// if (r_error) { -// *r_error = TTR("Package segments must be of non-zero length."); -// } -// return false; -// } -// if (c == '.') { -// segments++; -// first = true; -// continue; -// } -// if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_')) { -// if (r_error) { -// *r_error = vformat(TTR("The character '%s' is not allowed in Android application package names."), String::chr(c)); -// } -// return false; -// } -// if (first && (c >= '0' && c <= '9')) { -// if (r_error) { -// *r_error = TTR("A digit cannot be the first character in a package segment."); -// } -// return false; -// } -// if (first && c == '_') { -// if (r_error) { -// *r_error = vformat(TTR("The character '%s' cannot be the first character in a package segment."), String::chr(c)); -// } -// return false; -// } -// first = false; -// } - -// if (segments == 0) { -// if (r_error) { -// *r_error = TTR("The package must have at least one '.' separator."); -// } -// return false; -// } - -// if (first) { -// if (r_error) { -// *r_error = TTR("Package segments must be of non-zero length."); -// } -// return false; -// } - -// return true; -// } - -// static bool _should_compress_asset(const String &p_path, const Vector &p_data) { -// /* -// * By not compressing files with little or not benefit in doing so, -// * a performance gain is expected attime. Moreover, if the APK is -// * zip-aligned, assets stored as they are can be efficiently read by -// * Android by memory-mapping them. -// */ - -// // -- Unconditional uncompress to mimic AAPT plus some other - -// static const char *unconditional_compress_ext[] = { -// // From https://github.com/android/platform_frameworks_base/blob/master/tools/aapt/Package.cpp -// // These formats are already compressed, or don't compress well: -// ".jpg", ".jpeg", ".png", ".gif", -// ".wav", ".mp2", ".mp3", ".ogg", ".aac", -// ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet", -// ".rtttl", ".imy", ".xmf", ".mp4", ".m4a", -// ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2", -// ".amr", ".awb", ".wma", ".wmv", -// // Godot-specific: -// ".webp", // Same reasoning as .png -// ".cfb", // Don't let small config files slow-down startup -// ".scn", // Binary scenes are usually already compressed -// ".stex", // Streamable textures are usually already compressed -// // Trailer for easier processing -// nullptr -// }; - -// for (const char **ext = unconditional_compress_ext; *ext; ++ext) { -// if (p_path.to_lower().ends_with(String(*ext))) { -// return false; -// } -// } - -// // -- Compressed resource? - -// if (p_data.size() >= 4 && p_data[0] == 'R' && p_data[1] == 'S' && p_data[2] == 'C' && p_data[3] == 'C') { -// // Already compressed -// return false; -// } - -// // --- TODO: Decide on texture resources according to their image compression setting - -// return true; -// } - -// static zip_fileinfo get_zip_fileinfo() { -// OS::Time time = OS::get_singleton()->get_time(); -// OS::Date date = OS::get_singleton()->get_date(); - -// zip_fileinfo zipfi; -// zipfi.tmz_date.tm_hour = time.hour; -// zipfi.tmz_date.tm_mday = date.day; -// zipfi.tmz_date.tm_min = time.min; -// zipfi.tmz_date.tm_mon = date.month - 1; // tm_mon is zero indexed -// zipfi.tmz_date.tm_sec = time.sec; -// zipfi.tmz_date.tm_year = date.year; -// zipfi.dosDate = 0; -// zipfi.external_fa = 0; -// zipfi.internal_fa = 0; - -// return zipfi; -// } - -// static Vector get_abis() { -// Vector abis; -// abis.push_back("armeabi-v7a"); -// abis.push_back("arm64-v8a"); -// abis.push_back("x86"); -// abis.push_back("x86_64"); -// return abis; -// } - -// /// List the gdap files in the directory specified by the p_path parameter. -// static Vector list_gdap_files(const String &p_path) { -// Vector dir_files; -// DirAccessRef da = DirAccess::open(p_path); -// if (da) { -// da->list_dir_begin(); -// while (true) { -// String file = da->get_next(); -// if (file == "") { -// break; -// } - -// if (da->current_is_dir() || da->current_is_hidden()) { -// continue; -// } - -// if (file.ends_with(PLUGIN_CONFIG_EXT)) { -// dir_files.push_back(file); -// } -// } -// da->list_dir_end(); -// } - -// return dir_files; -// } - -// static Vector get_plugins() { -// Vector loaded_plugins; - -// String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/plugins"); - -// // Add the prebuilt plugins -// loaded_plugins.append_array(get_prebuilt_plugins(plugins_dir)); - -// if (DirAccess::exists(plugins_dir)) { -// Vector plugins_filenames = list_gdap_files(plugins_dir); - -// if (!plugins_filenames.is_empty()) { -// Ref config_file = memnew(ConfigFile); -// for (int i = 0; i < plugins_filenames.size(); i++) { -// PluginConfig config = load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i])); -// if (config.valid_config) { -// loaded_plugins.push_back(config); -// } else { -// print_error("Invalid plugin config file " + plugins_filenames[i]); -// } -// } -// } -// } - -// return loaded_plugins; -// } - -// static Vector get_enabled_plugins(const Ref &p_presets) { -// Vector enabled_plugins; -// Vector all_plugins = get_plugins(); -// for (int i = 0; i < all_plugins.size(); i++) { -// PluginConfig plugin = all_plugins[i]; -// bool enabled = p_presets->get("plugins/" + plugin.name); -// if (enabled) { -// enabled_plugins.push_back(plugin); -// } -// } - -// return enabled_plugins; -// } - -// static Error store_in_apk(APKExportData *ed, const String &p_path, const Vector &p_data, int compression_method = Z_DEFLATED) { -// zip_fileinfo zipfi = get_zip_fileinfo(); -// zipOpenNewFileInZip(ed->apk, -// p_path.utf8().get_data(), -// &zipfi, -// nullptr, -// 0, -// nullptr, -// 0, -// nullptr, -// compression_method, -// Z_DEFAULT_COMPRESSION); - -// zipWriteInFileInZip(ed->apk, p_data.ptr(), p_data.size()); -// zipCloseFileInZip(ed->apk); - -// return OK; -// } - -// static Error save_apk_so(void *p_userdata, const SharedObject &p_so) { -// if (!p_so.path.get_file().begins_with("lib")) { -// String err = "Android .so file names must start with \"lib\", but got: " + p_so.path; -// ERR_PRINT(err); -// return FAILED; -// } -// APKExportData *ed = (APKExportData *)p_userdata; -// Vector abis = get_abis(); -// bool exported = false; -// for (int i = 0; i < p_so.tags.size(); ++i) { -// // shared objects can be fat (compatible with multiple ABIs) -// int abi_index = abis.find(p_so.tags[i]); -// if (abi_index != -1) { -// exported = true; -// String abi = abis[abi_index]; -// String dst_path = String("lib").plus_file(abi).plus_file(p_so.path.get_file()); -// Vector array = FileAccess::get_file_as_array(p_so.path); -// Error store_err = store_in_apk(ed, dst_path, array); -// ERR_FAIL_COND_V_MSG(store_err, store_err, "Cannot store in apk file '" + dst_path + "'."); -// } -// } -// if (!exported) { -// String abis_string = String(" ").join(abis); -// String err = "Cannot determine ABI for library \"" + p_so.path + "\". One of the supported ABIs must be used as a tag: " + abis_string; -// ERR_PRINT(err); -// return FAILED; -// } -// return OK; -// } - -// static Error save_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { -// APKExportData *ed = (APKExportData *)p_userdata; -// String dst_path = p_path.replace_first("res://", "assets/"); - -// store_in_apk(ed, dst_path, p_data, _should_compress_asset(p_path, p_data) ? Z_DEFLATED : 0); -// return OK; -// } - -// static Error ignore_apk_file(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key) { -// return OK; -// } - -// void _get_permissions(const Ref &p_preset, bool p_give_internet, Vector &r_permissions) { -// const char **aperms = android_perms; -// while (*aperms) { -// bool enabled = p_preset->get("permissions/" + String(*aperms).to_lower()); -// if (enabled) { -// r_permissions.push_back("android.permission." + String(*aperms)); -// } -// aperms++; -// } -// PackedStringArray user_perms = p_preset->get("permissions/custom_permissions"); -// for (int i = 0; i < user_perms.size(); i++) { -// String user_perm = user_perms[i].strip_edges(); -// if (!user_perm.is_empty()) { -// r_permissions.push_back(user_perm); -// } -// } -// if (p_give_internet) { -// if (r_permissions.find("android.permission.INTERNET") == -1) { -// r_permissions.push_back("android.permission.INTERNET"); -// } -// } - -// int xr_mode_index = p_preset->get("xr_features/xr_mode"); -// if (xr_mode_index == 1 /* XRMode.OVR */) { -// int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required -// if (hand_tracking_index > 0) { -// if (r_permissions.find("com.oculus.permission.HAND_TRACKING") == -1) { -// r_permissions.push_back("com.oculus.permission.HAND_TRACKING"); -// } -// } -// } -// } - -// void _write_tmp_manifest(const Ref &p_preset, bool p_give_internet, bool p_debug) { -// String manifest_text = -// "\n" -// "\n"; - -// manifest_text += _get_screen_sizes_tag(p_preset); -// manifest_text += _get_gles_tag(); - -// Vector perms; -// _get_permissions(p_preset, p_give_internet, perms); -// for (int i = 0; i < perms.size(); i++) { -// manifest_text += vformat(" \n", perms.get(i)); -// } - -// manifest_text += _get_xr_features_tag(p_preset); -// manifest_text += _get_instrumentation_tag(p_preset); -// String plugins_names = get_plugins_names(get_enabled_plugins(p_preset)); -// manifest_text += _get_application_tag(p_preset, plugins_names); -// manifest_text += "\n"; -// String manifest_path = vformat("res://android/build/src/%s/AndroidManifest.xml", (p_debug ? "debug" : "release")); -// store_string_at_path(manifest_path, manifest_text); -// } - -// void _fix_manifest(const Ref &p_preset, Vector &p_manifest, bool p_give_internet) { -// // Leaving the unused types commented because looking these constants up -// // again later would be annoying -// // const int CHUNK_AXML_FILE = 0x00080003; -// // const int CHUNK_RESOURCEIDS = 0x00080180; -// const int CHUNK_STRINGS = 0x001C0001; -// // const int CHUNK_XML_END_NAMESPACE = 0x00100101; -// const int CHUNK_XML_END_TAG = 0x00100103; -// // const int CHUNK_XML_START_NAMESPACE = 0x00100100; -// const int CHUNK_XML_START_TAG = 0x00100102; -// // const int CHUNK_XML_TEXT = 0x00100104; -// const int UTF8_FLAG = 0x00000100; - -// Vector string_table; - -// uint32_t ofs = 8; - -// uint32_t string_count = 0; -// //uint32_t styles_count = 0; -// uint32_t string_flags = 0; -// uint32_t string_data_offset = 0; - -// //uint32_t styles_offset = 0; -// uint32_t string_table_begins = 0; -// uint32_t string_table_ends = 0; -// Vector stable_extra; - -// String version_name = p_preset->get("version/name"); -// int version_code = p_preset->get("version/code"); -// String package_name = p_preset->get("package/unique_name"); - -// const int screen_orientation = _get_android_orientation_value(_get_screen_orientation()); - -// bool screen_support_small = p_preset->get("screen/support_small"); -// bool screen_support_normal = p_preset->get("screen/support_normal"); -// bool screen_support_large = p_preset->get("screen/support_large"); -// bool screen_support_xlarge = p_preset->get("screen/support_xlarge"); - -// int xr_mode_index = p_preset->get("xr_features/xr_mode"); -// bool focus_awareness = p_preset->get("xr_features/focus_awareness"); - -// String plugins_names = get_plugins_names(get_enabled_plugins(p_preset)); - -// Vector perms; -// // Write permissions into the perms variable. -// _get_permissions(p_preset, p_give_internet, perms); - -// while (ofs < (uint32_t)p_manifest.size()) { -// uint32_t chunk = decode_uint32(&p_manifest[ofs]); -// uint32_t size = decode_uint32(&p_manifest[ofs + 4]); - -// switch (chunk) { -// case CHUNK_STRINGS: { -// int iofs = ofs + 8; - -// string_count = decode_uint32(&p_manifest[iofs]); -// //styles_count = decode_uint32(&p_manifest[iofs + 4]); -// string_flags = decode_uint32(&p_manifest[iofs + 8]); -// string_data_offset = decode_uint32(&p_manifest[iofs + 12]); -// //styles_offset = decode_uint32(&p_manifest[iofs + 16]); -// /* -// printf("string count: %i\n",string_count); -// printf("flags: %i\n",string_flags); -// printf("sdata ofs: %i\n",string_data_offset); -// printf("styles ofs: %i\n",styles_offset); -// */ -// uint32_t st_offset = iofs + 20; -// string_table.resize(string_count); -// uint32_t string_end = 0; - -// string_table_begins = st_offset; - -// for (uint32_t i = 0; i < string_count; i++) { -// uint32_t string_at = decode_uint32(&p_manifest[st_offset + i * 4]); -// string_at += st_offset + string_count * 4; - -// ERR_FAIL_COND_MSG(string_flags & UTF8_FLAG, "Unimplemented, can't read UTF-8 string table."); - -// if (string_flags & UTF8_FLAG) { -// } else { -// uint32_t len = decode_uint16(&p_manifest[string_at]); -// Vector ucstring; -// ucstring.resize(len + 1); -// for (uint32_t j = 0; j < len; j++) { -// uint16_t c = decode_uint16(&p_manifest[string_at + 2 + 2 * j]); -// ucstring.write[j] = c; -// } -// string_end = MAX(string_at + 2 + 2 * len, string_end); -// ucstring.write[len] = 0; -// string_table.write[i] = ucstring.ptr(); -// } -// } - -// for (uint32_t i = string_end; i < (ofs + size); i++) { -// stable_extra.push_back(p_manifest[i]); -// } - -// string_table_ends = ofs + size; - -// } break; -// case CHUNK_XML_START_TAG: { -// int iofs = ofs + 8; -// uint32_t name = decode_uint32(&p_manifest[iofs + 12]); - -// String tname = string_table[name]; -// uint32_t attrcount = decode_uint32(&p_manifest[iofs + 20]); -// iofs += 28; -// bool is_focus_aware_metadata = false; - -// for (uint32_t i = 0; i < attrcount; i++) { -// uint32_t attr_nspace = decode_uint32(&p_manifest[iofs]); -// uint32_t attr_name = decode_uint32(&p_manifest[iofs + 4]); -// uint32_t attr_value = decode_uint32(&p_manifest[iofs + 8]); -// uint32_t attr_resid = decode_uint32(&p_manifest[iofs + 16]); - -// const String value = (attr_value != 0xFFFFFFFF) ? string_table[attr_value] : "Res #" + itos(attr_resid); -// String attrname = string_table[attr_name]; -// const String nspace = (attr_nspace != 0xFFFFFFFF) ? string_table[attr_nspace] : ""; - -// //replace project information -// if (tname == "manifest" && attrname == "package") { -// string_table.write[attr_value] = get_package_name(package_name); -// } - -// if (tname == "manifest" && attrname == "versionCode") { -// encode_uint32(version_code, &p_manifest.write[iofs + 16]); -// } - -// if (tname == "manifest" && attrname == "versionName") { -// if (attr_value == 0xFFFFFFFF) { -// WARN_PRINT("Version name in a resource, should be plain text"); -// } else { -// string_table.write[attr_value] = version_name; -// } -// } - -// if (tname == "instrumentation" && attrname == "targetPackage") { -// string_table.write[attr_value] = get_package_name(package_name); -// } - -// if (tname == "activity" && attrname == "screenOrientation") { -// encode_uint32(screen_orientation, &p_manifest.write[iofs + 16]); -// } - -// if (tname == "supports-screens") { -// if (attrname == "smallScreens") { -// encode_uint32(screen_support_small ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); - -// } else if (attrname == "normalScreens") { -// encode_uint32(screen_support_normal ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); - -// } else if (attrname == "largeScreens") { -// encode_uint32(screen_support_large ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); - -// } else if (attrname == "xlargeScreens") { -// encode_uint32(screen_support_xlarge ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); -// } -// } - -// // FIXME: `attr_value != 0xFFFFFFFF` below added as a stopgap measure for GH-32553, -// // but the issue should be debugged further and properly addressed. -// if (tname == "meta-data" && attrname == "name" && value == "xr_mode_metadata_name") { -// // Update the meta-data 'android:name' attribute based on the selected XR mode. -// if (xr_mode_index == 1 /* XRMode.OVR */) { -// string_table.write[attr_value] = "com.samsung.android.vr.application.mode"; -// } -// } - -// if (tname == "meta-data" && attrname == "value" && value == "xr_mode_metadata_value") { -// // Update the meta-data 'android:value' attribute based on the selected XR mode. -// if (xr_mode_index == 1 /* XRMode.OVR */) { -// string_table.write[attr_value] = "vr_only"; -// } -// } - -// if (tname == "meta-data" && attrname == "value" && is_focus_aware_metadata) { -// // Update the focus awareness meta-data value -// encode_uint32(xr_mode_index == /* XRMode.OVR */ 1 && focus_awareness ? 0xFFFFFFFF : 0, &p_manifest.write[iofs + 16]); -// } - -// if (tname == "meta-data" && attrname == "value" && value == "plugins_value" && !plugins_names.is_empty()) { -// // Update the meta-data 'android:value' attribute with the list of enabled plugins. -// string_table.write[attr_value] = plugins_names; -// } - -// is_focus_aware_metadata = tname == "meta-data" && attrname == "name" && value == "com.oculus.vr.focusaware"; -// iofs += 20; -// } - -// } break; -// case CHUNK_XML_END_TAG: { -// int iofs = ofs + 8; -// uint32_t name = decode_uint32(&p_manifest[iofs + 12]); -// String tname = string_table[name]; - -// if (tname == "uses-feature") { -// Vector feature_names; -// Vector feature_required_list; -// Vector feature_versions; - -// if (xr_mode_index == 1 /* XRMode.OVR */) { -// // Check for degrees of freedom -// int dof_index = p_preset->get("xr_features/degrees_of_freedom"); // 0: none, 1: 3dof and 6dof, 2: 6dof - -// if (dof_index > 0) { -// feature_names.push_back("android.hardware.vr.headtracking"); -// feature_required_list.push_back(dof_index == 2); -// feature_versions.push_back(1); -// } - -// // Check for hand tracking -// int hand_tracking_index = p_preset->get("xr_features/hand_tracking"); // 0: none, 1: optional, 2: required -// if (hand_tracking_index > 0) { -// feature_names.push_back("oculus.software.handtracking"); -// feature_required_list.push_back(hand_tracking_index == 2); -// feature_versions.push_back(-1); // no version attribute should be added. -// } -// } - -// if (feature_names.size() > 0) { -// ofs += 24; // skip over end tag - -// // save manifest ending so we can restore it -// Vector manifest_end; -// uint32_t manifest_cur_size = p_manifest.size(); - -// manifest_end.resize(p_manifest.size() - ofs); -// memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size()); - -// int32_t attr_name_string = string_table.find("name"); -// ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute."); - -// int32_t ns_android_string = string_table.find("http://schemas.android.com/apk/res/android"); -// if (ns_android_string == -1) { -// string_table.push_back("http://schemas.android.com/apk/res/android"); -// ns_android_string = string_table.size() - 1; -// } - -// int32_t attr_uses_feature_string = string_table.find("uses-feature"); -// if (attr_uses_feature_string == -1) { -// string_table.push_back("uses-feature"); -// attr_uses_feature_string = string_table.size() - 1; -// } - -// int32_t attr_required_string = string_table.find("required"); -// if (attr_required_string == -1) { -// string_table.push_back("required"); -// attr_required_string = string_table.size() - 1; -// } - -// for (int i = 0; i < feature_names.size(); i++) { -// String feature_name = feature_names[i]; -// bool feature_required = feature_required_list[i]; -// int feature_version = feature_versions[i]; -// bool has_version_attribute = feature_version != -1; - -// print_line("Adding feature " + feature_name); - -// int32_t feature_string = string_table.find(feature_name); -// if (feature_string == -1) { -// string_table.push_back(feature_name); -// feature_string = string_table.size() - 1; -// } - -// String required_value_string = feature_required ? "true" : "false"; -// int32_t required_value = string_table.find(required_value_string); -// if (required_value == -1) { -// string_table.push_back(required_value_string); -// required_value = string_table.size() - 1; -// } - -// int32_t attr_version_string = -1; -// int32_t version_value = -1; -// int tag_size; -// int attr_count; -// if (has_version_attribute) { -// attr_version_string = string_table.find("version"); -// if (attr_version_string == -1) { -// string_table.push_back("version"); -// attr_version_string = string_table.size() - 1; -// } - -// version_value = string_table.find(itos(feature_version)); -// if (version_value == -1) { -// string_table.push_back(itos(feature_version)); -// version_value = string_table.size() - 1; -// } - -// tag_size = 96; // node and three attrs + end node -// attr_count = 3; -// } else { -// tag_size = 76; // node and two attrs + end node -// attr_count = 2; -// } -// manifest_cur_size += tag_size + 24; -// p_manifest.resize(manifest_cur_size); - -// // start tag -// encode_uint16(0x102, &p_manifest.write[ofs]); // type -// encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize -// encode_uint32(tag_size, &p_manifest.write[ofs + 4]); // size -// encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno -// encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment -// encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns -// encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name -// encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start -// encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size -// encode_uint16(attr_count, &p_manifest.write[ofs + 28]); // num_attrs -// encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index -// encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index -// encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index - -// // android:name attribute -// encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns -// encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name' -// encode_uint32(feature_string, &p_manifest.write[ofs + 44]); // raw_value -// encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size -// p_manifest.write[ofs + 50] = 0; // typedvalue_always0 -// p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string) -// encode_uint32(feature_string, &p_manifest.write[ofs + 52]); // typedvalue reference - -// // android:required attribute -// encode_uint32(ns_android_string, &p_manifest.write[ofs + 56]); // ns -// encode_uint32(attr_required_string, &p_manifest.write[ofs + 60]); // 'name' -// encode_uint32(required_value, &p_manifest.write[ofs + 64]); // raw_value -// encode_uint16(8, &p_manifest.write[ofs + 68]); // typedvalue_size -// p_manifest.write[ofs + 70] = 0; // typedvalue_always0 -// p_manifest.write[ofs + 71] = 0x03; // typedvalue_type (string) -// encode_uint32(required_value, &p_manifest.write[ofs + 72]); // typedvalue reference - -// ofs += 76; - -// if (has_version_attribute) { -// // android:version attribute -// encode_uint32(ns_android_string, &p_manifest.write[ofs]); // ns -// encode_uint32(attr_version_string, &p_manifest.write[ofs + 4]); // 'name' -// encode_uint32(version_value, &p_manifest.write[ofs + 8]); // raw_value -// encode_uint16(8, &p_manifest.write[ofs + 12]); // typedvalue_size -// p_manifest.write[ofs + 14] = 0; // typedvalue_always0 -// p_manifest.write[ofs + 15] = 0x03; // typedvalue_type (string) -// encode_uint32(version_value, &p_manifest.write[ofs + 16]); // typedvalue reference - -// ofs += 20; -// } - -// // end tag -// encode_uint16(0x103, &p_manifest.write[ofs]); // type -// encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize -// encode_uint32(24, &p_manifest.write[ofs + 4]); // size -// encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno -// encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment -// encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns -// encode_uint32(attr_uses_feature_string, &p_manifest.write[ofs + 20]); // name - -// ofs += 24; -// } -// memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size()); -// ofs -= 24; // go back over back end -// } -// } -// if (tname == "manifest") { -// // save manifest ending so we can restore it -// Vector manifest_end; -// uint32_t manifest_cur_size = p_manifest.size(); - -// manifest_end.resize(p_manifest.size() - ofs); -// memcpy(manifest_end.ptrw(), &p_manifest[ofs], manifest_end.size()); - -// int32_t attr_name_string = string_table.find("name"); -// ERR_FAIL_COND_MSG(attr_name_string == -1, "Template does not have 'name' attribute."); - -// int32_t ns_android_string = string_table.find("android"); -// ERR_FAIL_COND_MSG(ns_android_string == -1, "Template does not have 'android' namespace."); - -// int32_t attr_uses_permission_string = string_table.find("uses-permission"); -// if (attr_uses_permission_string == -1) { -// string_table.push_back("uses-permission"); -// attr_uses_permission_string = string_table.size() - 1; -// } - -// for (int i = 0; i < perms.size(); ++i) { -// print_line("Adding permission " + perms[i]); - -// manifest_cur_size += 56 + 24; // node + end node -// p_manifest.resize(manifest_cur_size); - -// // Add permission to the string pool -// int32_t perm_string = string_table.find(perms[i]); -// if (perm_string == -1) { -// string_table.push_back(perms[i]); -// perm_string = string_table.size() - 1; -// } - -// // start tag -// encode_uint16(0x102, &p_manifest.write[ofs]); // type -// encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize -// encode_uint32(56, &p_manifest.write[ofs + 4]); // size -// encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno -// encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment -// encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns -// encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name -// encode_uint16(20, &p_manifest.write[ofs + 24]); // attr_start -// encode_uint16(20, &p_manifest.write[ofs + 26]); // attr_size -// encode_uint16(1, &p_manifest.write[ofs + 28]); // num_attrs -// encode_uint16(0, &p_manifest.write[ofs + 30]); // id_index -// encode_uint16(0, &p_manifest.write[ofs + 32]); // class_index -// encode_uint16(0, &p_manifest.write[ofs + 34]); // style_index - -// // attribute -// encode_uint32(ns_android_string, &p_manifest.write[ofs + 36]); // ns -// encode_uint32(attr_name_string, &p_manifest.write[ofs + 40]); // 'name' -// encode_uint32(perm_string, &p_manifest.write[ofs + 44]); // raw_value -// encode_uint16(8, &p_manifest.write[ofs + 48]); // typedvalue_size -// p_manifest.write[ofs + 50] = 0; // typedvalue_always0 -// p_manifest.write[ofs + 51] = 0x03; // typedvalue_type (string) -// encode_uint32(perm_string, &p_manifest.write[ofs + 52]); // typedvalue reference - -// ofs += 56; - -// // end tag -// encode_uint16(0x103, &p_manifest.write[ofs]); // type -// encode_uint16(16, &p_manifest.write[ofs + 2]); // headersize -// encode_uint32(24, &p_manifest.write[ofs + 4]); // size -// encode_uint32(0, &p_manifest.write[ofs + 8]); // lineno -// encode_uint32(-1, &p_manifest.write[ofs + 12]); // comment -// encode_uint32(-1, &p_manifest.write[ofs + 16]); // ns -// encode_uint32(attr_uses_permission_string, &p_manifest.write[ofs + 20]); // name - -// ofs += 24; -// } - -// // copy footer back in -// memcpy(&p_manifest.write[ofs], manifest_end.ptr(), manifest_end.size()); -// } -// } break; -// } - -// ofs += size; -// } - -// //create new andriodmanifest binary - -// Vector ret; -// ret.resize(string_table_begins + string_table.size() * 4); - -// for (uint32_t i = 0; i < string_table_begins; i++) { -// ret.write[i] = p_manifest[i]; -// } - -// ofs = 0; -// for (int i = 0; i < string_table.size(); i++) { -// encode_uint32(ofs, &ret.write[string_table_begins + i * 4]); -// ofs += string_table[i].length() * 2 + 2 + 2; -// } - -// ret.resize(ret.size() + ofs); -// string_data_offset = ret.size() - ofs; -// uint8_t *chars = &ret.write[string_data_offset]; -// for (int i = 0; i < string_table.size(); i++) { -// String s = string_table[i]; -// encode_uint16(s.length(), chars); -// chars += 2; -// for (int j = 0; j < s.length(); j++) { -// encode_uint16(s[j], chars); -// chars += 2; -// } -// encode_uint16(0, chars); -// chars += 2; -// } - -// for (int i = 0; i < stable_extra.size(); i++) { -// ret.push_back(stable_extra[i]); -// } - -// //pad -// while (ret.size() % 4) { -// ret.push_back(0); -// } - -// uint32_t new_stable_end = ret.size(); - -// uint32_t extra = (p_manifest.size() - string_table_ends); -// ret.resize(new_stable_end + extra); -// for (uint32_t i = 0; i < extra; i++) { -// ret.write[new_stable_end + i] = p_manifest[string_table_ends + i]; -// } - -// while (ret.size() % 4) { -// ret.push_back(0); -// } -// encode_uint32(ret.size(), &ret.write[4]); //update new file size - -// encode_uint32(new_stable_end - 8, &ret.write[12]); //update new string table size -// encode_uint32(string_table.size(), &ret.write[16]); //update new number of strings -// encode_uint32(string_data_offset - 8, &ret.write[28]); //update new string data offset - -// p_manifest = ret; -// } - -// static String _parse_string(const uint8_t *p_bytes, bool p_utf8) { -// uint32_t offset = 0; -// uint32_t len = 0; - -// if (p_utf8) { -// uint8_t byte = p_bytes[offset]; -// if (byte & 0x80) { -// offset += 2; -// } else { -// offset += 1; -// } -// byte = p_bytes[offset]; -// offset++; -// if (byte & 0x80) { -// len = byte & 0x7F; -// len = (len << 8) + p_bytes[offset]; -// offset++; -// } else { -// len = byte; -// } -// } else { -// len = decode_uint16(&p_bytes[offset]); -// offset += 2; -// if (len & 0x8000) { -// len &= 0x7FFF; -// len = (len << 16) + decode_uint16(&p_bytes[offset]); -// offset += 2; -// } -// } - -// if (p_utf8) { -// Vector str8; -// str8.resize(len + 1); -// for (uint32_t i = 0; i < len; i++) { -// str8.write[i] = p_bytes[offset + i]; -// } -// str8.write[len] = 0; -// String str; -// str.parse_utf8((const char *)str8.ptr()); -// return str; -// } else { -// String str; -// for (uint32_t i = 0; i < len; i++) { -// char32_t c = decode_uint16(&p_bytes[offset + i * 2]); -// if (c == 0) { -// break; -// } -// str += String::chr(c); -// } -// return str; -// } -// } - -// void _fix_resources(const Ref &p_preset, Vector &r_manifest) { -// const int UTF8_FLAG = 0x00000100; - -// uint32_t string_block_len = decode_uint32(&r_manifest[16]); -// uint32_t string_count = decode_uint32(&r_manifest[20]); -// uint32_t string_flags = decode_uint32(&r_manifest[28]); -// const uint32_t string_table_begins = 40; - -// Vector string_table; - -// String package_name = p_preset->get("package/name"); - -// for (uint32_t i = 0; i < string_count; i++) { -// uint32_t offset = decode_uint32(&r_manifest[string_table_begins + i * 4]); -// offset += string_table_begins + string_count * 4; - -// String str = _parse_string(&r_manifest[offset], string_flags & UTF8_FLAG); - -// if (str.begins_with("godot-project-name")) { -// if (str == "godot-project-name") { -// //project name -// str = get_project_name(package_name); - -// } else { -// String lang = str.substr(str.rfind("-") + 1, str.length()).replace("-", "_"); -// String prop = "application/config/name_" + lang; -// if (ProjectSettings::get_singleton()->has_setting(prop)) { -// str = ProjectSettings::get_singleton()->get(prop); -// } else { -// str = get_project_name(package_name); -// } -// } -// } - -// string_table.push_back(str); -// } - -// //write a new string table, but use 16 bits -// Vector ret; -// ret.resize(string_table_begins + string_table.size() * 4); - -// for (uint32_t i = 0; i < string_table_begins; i++) { -// ret.write[i] = r_manifest[i]; -// } - -// int ofs = 0; -// for (int i = 0; i < string_table.size(); i++) { -// encode_uint32(ofs, &ret.write[string_table_begins + i * 4]); -// ofs += string_table[i].length() * 2 + 2 + 2; -// } - -// ret.resize(ret.size() + ofs); -// uint8_t *chars = &ret.write[ret.size() - ofs]; -// for (int i = 0; i < string_table.size(); i++) { -// String s = string_table[i]; -// encode_uint16(s.length(), chars); -// chars += 2; -// for (int j = 0; j < s.length(); j++) { -// encode_uint16(s[j], chars); -// chars += 2; -// } -// encode_uint16(0, chars); -// chars += 2; -// } - -// //pad -// while (ret.size() % 4) { -// ret.push_back(0); -// } - -// //change flags to not use utf8 -// encode_uint32(string_flags & ~0x100, &ret.write[28]); -// //change length -// encode_uint32(ret.size() - 12, &ret.write[16]); -// //append the rest... -// int rest_from = 12 + string_block_len; -// int rest_to = ret.size(); -// int rest_len = (r_manifest.size() - rest_from); -// ret.resize(ret.size() + (r_manifest.size() - rest_from)); -// for (int i = 0; i < rest_len; i++) { -// ret.write[rest_to + i] = r_manifest[rest_from + i]; -// } -// //finally update the size -// encode_uint32(ret.size(), &ret.write[4]); - -// r_manifest = ret; -// //printf("end\n"); -// } - -// void _load_image_data(const Ref &p_splash_image, Vector &p_data) { -// Vector png_buffer; -// Error err = PNGDriverCommon::image_to_png(p_splash_image, png_buffer); -// if (err == OK) { -// p_data.resize(png_buffer.size()); -// memcpy(p_data.ptrw(), png_buffer.ptr(), p_data.size()); -// } else { -// String err_str = String("Failed to convert splash image to png."); -// WARN_PRINT(err_str.utf8().get_data()); -// } -// } - -// void _process_launcher_icons(const String &p_file_name, const Ref &p_source_image, int dimension, Vector &p_data) { -// Ref working_image = p_source_image; - -// if (p_source_image->get_width() != dimension || p_source_image->get_height() != dimension) { -// working_image = p_source_image->duplicate(); -// working_image->resize(dimension, dimension, Image::Interpolation::INTERPOLATE_LANCZOS); -// } - -// Vector png_buffer; -// Error err = PNGDriverCommon::image_to_png(working_image, png_buffer); -// if (err == OK) { -// p_data.resize(png_buffer.size()); -// memcpy(p_data.ptrw(), png_buffer.ptr(), p_data.size()); -// } else { -// String err_str = String("Failed to convert resized icon (") + p_file_name + ") to png."; -// WARN_PRINT(err_str.utf8().get_data()); -// } -// } - -// void load_splash_refs(Ref &splash_image, Ref &splash_bg_color_image) { -// // TODO: Figure out how to handle remaining boot splash parameters (e.g: fullsize, filter) -// String project_splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image"); - -// if (!project_splash_path.is_empty()) { -// splash_image.instance(); -// const Error err = ImageLoader::load_image(project_splash_path, splash_image); -// if (err) { -// splash_image.unref(); -// } -// } - -// if (splash_image.is_null()) { -// // Use the default -// splash_image = Ref(memnew(Image(boot_splash_png))); -// } - -// // Setup the splash bg color -// bool bg_color_valid; -// Color bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color", &bg_color_valid); -// if (!bg_color_valid) { -// bg_color = boot_splash_bg_color; -// } - -// splash_bg_color_image.instance(); -// splash_bg_color_image->create(splash_image->get_width(), splash_image->get_height(), false, splash_image->get_format()); -// splash_bg_color_image->fill(bg_color); -// } - -// void load_icon_refs(const Ref &p_preset, Ref &icon, Ref &foreground, Ref &background) { -// String project_icon_path = ProjectSettings::get_singleton()->get("application/config/icon"); - -// icon.instance(); -// foreground.instance(); -// background.instance(); - -// // Regular icon: user selection -> project icon -> default. -// String path = static_cast(p_preset->get(launcher_icon_option)).strip_edges(); -// if (path.is_empty() || ImageLoader::load_image(path, icon) != OK) { -// ImageLoader::load_image(project_icon_path, icon); -// } - -// // Adaptive foreground: user selection -> regular icon (user selection -> project icon -> default). -// path = static_cast(p_preset->get(launcher_adaptive_icon_foreground_option)).strip_edges(); -// if (path.is_empty() || ImageLoader::load_image(path, foreground) != OK) { -// foreground = icon; -// } - -// // Adaptive background: user selection -> default. -// path = static_cast(p_preset->get(launcher_adaptive_icon_background_option)).strip_edges(); -// if (!path.is_empty()) { -// ImageLoader::load_image(path, background); -// } -// } - -// void store_image(const LauncherIcon launcher_icon, const Vector &data) { -// store_image(launcher_icon.export_path, data); -// } - -// void store_image(const String &export_path, const Vector &data) { -// String img_path = export_path.insert(0, "res://android/build/"); -// store_file_at_path(img_path, data); -// } - -// void _copy_icons_to_gradle_project(const Ref &p_preset, -// const Ref &splash_image, -// const Ref &splash_bg_color_image, -// const Ref &main_image, -// const Ref &foreground, -// const Ref &background) { -// // Store the splash image -// if (splash_image.is_valid() && !splash_image->is_empty()) { -// Vector data; -// _load_image_data(splash_image, data); -// store_image(SPLASH_IMAGE_EXPORT_PATH, data); -// } - -// // Store the splash bg color image -// if (splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) { -// Vector data; -// _load_image_data(splash_bg_color_image, data); -// store_image(SPLASH_BG_COLOR_PATH, data); -// } - -// // Prepare images to be resized for the icons. If some image ends up being uninitialized, -// // the default image from the export template will be used. - -// for (int i = 0; i < icon_densities_count; ++i) { -// if (main_image.is_valid() && !main_image->is_empty()) { -// Vector data; -// _process_launcher_icons(launcher_icons[i].export_path, main_image, launcher_icons[i].dimensions, data); -// store_image(launcher_icons[i], data); -// } - -// if (foreground.is_valid() && !foreground->is_empty()) { -// Vector data; -// _process_launcher_icons(launcher_adaptive_icon_foregrounds[i].export_path, foreground, -// launcher_adaptive_icon_foregrounds[i].dimensions, data); -// store_image(launcher_adaptive_icon_foregrounds[i], data); -// } - -// if (background.is_valid() && !background->is_empty()) { -// Vector data; -// _process_launcher_icons(launcher_adaptive_icon_backgrounds[i].export_path, background, -// launcher_adaptive_icon_backgrounds[i].dimensions, data); -// store_image(launcher_adaptive_icon_backgrounds[i], data); -// } -// } -// } - -// static Vector get_enabled_abis(const Ref &p_preset) { -// Vector abis = get_abis(); -// Vector enabled_abis; -// for (int i = 0; i < abis.size(); ++i) { -// bool is_enabled = p_preset->get("architectures/" + abis[i]); -// if (is_enabled) { -// enabled_abis.push_back(abis[i]); -// } -// } -// return enabled_abis; -// } - -//public: -// typedef Error (*EditorExportSaveFunction)(void *p_userdata, const String &p_path, const Vector &p_data, int p_file, int p_total, const Vector &p_enc_in_filters, const Vector &p_enc_ex_filters, const Vector &p_key); - -//public: -// virtual void get_preset_features(const Ref &p_preset, List *r_features) override { -// String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); -// if (driver == "OpenGL") { -// r_features->push_back("etc"); -// } -// // FIXME: Review what texture formats are used for Vulkan. -// if (driver == "Vulkan") { -// r_features->push_back("etc2"); -// } - -// Vector abis = get_enabled_abis(p_preset); -// for (int i = 0; i < abis.size(); ++i) { -// r_features->push_back(abis[i]); -// } -// } - -// virtual void get_export_options(List *r_options) override { -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.apk"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "custom_template/use_custom_build"), false)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "custom_template/export_format", PROPERTY_HINT_ENUM, "Export APK,Export AAB"), EXPORT_FORMAT_APK)); - -// Vector plugins_configs = get_plugins(); -// for (int i = 0; i < plugins_configs.size(); i++) { -// print_verbose("Found Android plugin " + plugins_configs[i].name); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + plugins_configs[i].name), false)); -// } -// plugins_changed = false; - -// Vector abis = get_abis(); -// for (int i = 0; i < abis.size(); ++i) { -// String abi = abis[i]; -// bool is_default = (abi == "armeabi-v7a" || abi == "arm64-v8a"); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + abi), is_default)); -// } - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_user"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/debug_password"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release", PROPERTY_HINT_GLOBAL_FILE, "*.keystore,*.jks"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_user"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "keystore/release_password"), "")); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "one_click_deploy/clear_previous_install"), false)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name"), "1.0")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_icon_option, PROPERTY_HINT_FILE, "*.png"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_foreground_option, PROPERTY_HINT_FILE, "*.png"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, launcher_adaptive_icon_background_option, PROPERTY_HINT_FILE, "*.png"), "")); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/32_bits_framebuffer"), true)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "graphics/opengl_debug"), false)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/xr_mode", PROPERTY_HINT_ENUM, "Regular,Oculus Mobile VR"), 0)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/degrees_of_freedom", PROPERTY_HINT_ENUM, "None,3DOF and 6DOF,6DOF"), 0)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "xr_features/hand_tracking", PROPERTY_HINT_ENUM, "None,Optional,Required"), 0)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "xr_features/focus_awareness"), false)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/immersive_mode"), true)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_small"), true)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_normal"), true)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_large"), true)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "screen/support_xlarge"), true)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "command_line/extra_args"), "")); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "apk_expansion/enable"), false)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/SALT"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "apk_expansion/public_key", PROPERTY_HINT_MULTILINE_TEXT), "")); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::PACKED_STRING_ARRAY, "permissions/custom_permissions"), PackedStringArray())); - -// const char **perms = android_perms; -// while (*perms) { -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "permissions/" + String(*perms).to_lower()), false)); -// perms++; -// } -// } - -// virtual String get_name() const override { -// return "Android"; -// } - -// virtual String get_os_name() const override { -// return "Android"; -// } - -// virtual Ref get_logo() const override { -// return logo; -// } - -// virtual bool should_update_export_options() override { -// bool export_options_changed = plugins_changed; -// if (export_options_changed) { -// // don't clear unless we're reporting true, to avoid race -// plugins_changed = false; -// } -// return export_options_changed; -// } - -// virtual bool poll_export() override { -// bool dc = devices_changed; -// if (dc) { -// // don't clear unless we're reporting true, to avoid race -// devices_changed = false; -// } -// return dc; -// } - -// virtual int get_options_count() const override { -// MutexLock lock(device_lock); -// return devices.size(); -// } - -// virtual String get_options_tooltip() const override { -// return TTR("Select device from the list"); -// } - -// virtual String get_option_label(int p_index) const override { -// ERR_FAIL_INDEX_V(p_index, devices.size(), ""); -// MutexLock lock(device_lock); -// return devices[p_index].name; -// } - -// virtual String get_option_tooltip(int p_index) const override { -// ERR_FAIL_INDEX_V(p_index, devices.size(), ""); -// MutexLock lock(device_lock); -// String s = devices[p_index].description; -// if (devices.size() == 1) { -// // Tooltip will be: -// // Name -// // Description -// s = devices[p_index].name + "\n\n" + s; -// } -// return s; -// } - -// virtual Error run(const Ref &p_preset, int p_device, int p_debug_flags) override { -// ERR_FAIL_INDEX_V(p_device, devices.size(), ERR_INVALID_PARAMETER); - -// String can_export_error; -// bool can_export_missing_templates; -// if (!can_export(p_preset, can_export_error, can_export_missing_templates)) { -// EditorNode::add_io_error(can_export_error); -// return ERR_UNCONFIGURED; -// } - -// MutexLock lock(device_lock); - -// EditorProgress ep("run", "Running on " + devices[p_device].name, 3); - -// String adb = get_adb_path(); - -// // Export_temp APK. -// if (ep.step("Exporting APK...", 0)) { -// return ERR_SKIP; -// } - -// const bool use_remote = (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) || (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT); -// const bool use_reverse = devices[p_device].api_level >= 21; - -// if (use_reverse) { -// p_debug_flags |= DEBUG_FLAG_REMOTE_DEBUG_LOCALHOST; -// } - -// String tmp_export_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport.apk"); - -//#define CLEANUP_AND_RETURN(m_err) -// { -// DirAccess::remove_file_or_error(tmp_export_path); -// return m_err; -// } - -// // Export to temporary APK before sending to device. -// Error err = export_project_helper(p_preset, true, tmp_export_path, EXPORT_FORMAT_APK, true, p_debug_flags); - -// if (err != OK) { -// CLEANUP_AND_RETURN(err); -// } - -// List args; -// int rv; - -// bool remove_prev = p_preset->get("one_click_deploy/clear_previous_install"); -// String version_name = p_preset->get("version/name"); -// String package_name = p_preset->get("package/unique_name"); - -// if (remove_prev) { -// if (ep.step("Uninstalling...", 1)) { -// CLEANUP_AND_RETURN(ERR_SKIP); -// } - -// print_line("Uninstalling previous version: " + devices[p_device].name); - -// args.push_back("-s"); -// args.push_back(devices[p_device].id); -// args.push_back("uninstall"); -// args.push_back(get_package_name(package_name)); - -// err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv); -// } - -// print_line("Installing to device (please wait...): " + devices[p_device].name); -// if (ep.step("Installing to device, please wait...", 2)) { -// CLEANUP_AND_RETURN(ERR_SKIP); -// } - -// args.clear(); -// args.push_back("-s"); -// args.push_back(devices[p_device].id); -// args.push_back("install"); -// args.push_back("-r"); -// args.push_back(tmp_export_path); - -// err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv); -// if (err || rv != 0) { -// EditorNode::add_io_error("Could not install to device."); -// CLEANUP_AND_RETURN(ERR_CANT_CREATE); -// } - -// if (use_remote) { -// if (use_reverse) { -// static const char *const msg = "--- Device API >= 21; debugging over USB ---"; -// EditorNode::get_singleton()->get_log()->add_message(msg, EditorLog::MSG_TYPE_EDITOR); -// print_line(String(msg).to_upper()); - -// args.clear(); -// args.push_back("-s"); -// args.push_back(devices[p_device].id); -// args.push_back("reverse"); -// args.push_back("--remove-all"); -// OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv); - -// if (p_debug_flags & DEBUG_FLAG_REMOTE_DEBUG) { -// int dbg_port = EditorSettings::get_singleton()->get("network/debug/remote_port"); -// args.clear(); -// args.push_back("-s"); -// args.push_back(devices[p_device].id); -// args.push_back("reverse"); -// args.push_back("tcp:" + itos(dbg_port)); -// args.push_back("tcp:" + itos(dbg_port)); - -// OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv); -// print_line("Reverse result: " + itos(rv)); -// } - -// if (p_debug_flags & DEBUG_FLAG_DUMB_CLIENT) { -// int fs_port = EditorSettings::get_singleton()->get("filesystem/file_server/port"); - -// args.clear(); -// args.push_back("-s"); -// args.push_back(devices[p_device].id); -// args.push_back("reverse"); -// args.push_back("tcp:" + itos(fs_port)); -// args.push_back("tcp:" + itos(fs_port)); - -// err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv); -// print_line("Reverse result2: " + itos(rv)); -// } -// } else { -// static const char *const msg = "--- Device API < 21; debugging over Wi-Fi ---"; -// EditorNode::get_singleton()->get_log()->add_message(msg, EditorLog::MSG_TYPE_EDITOR); -// print_line(String(msg).to_upper()); -// } -// } - -// if (ep.step("Running on device...", 3)) { -// CLEANUP_AND_RETURN(ERR_SKIP); -// } -// args.clear(); -// args.push_back("-s"); -// args.push_back(devices[p_device].id); -// args.push_back("shell"); -// args.push_back("am"); -// args.push_back("start"); -// if ((bool)EditorSettings::get_singleton()->get("export/android/force_system_user") && devices[p_device].api_level >= 17) { // Multi-user introduced in Android 17 -// args.push_back("--user"); -// args.push_back("0"); -// } -// args.push_back("-a"); -// args.push_back("android.intent.action.MAIN"); -// args.push_back("-n"); -// args.push_back(get_package_name(package_name) + "/com.godot.game.GodotApp"); - -// err = OS::get_singleton()->execute(adb, args, true, nullptr, nullptr, &rv); -// if (err || rv != 0) { -// EditorNode::add_io_error("Could not execute on device."); -// CLEANUP_AND_RETURN(ERR_CANT_CREATE); -// } - -// CLEANUP_AND_RETURN(OK); -//#undef CLEANUP_AND_RETURN -// } - -// virtual Ref get_run_icon() const override { -// return run_icon; -// } - -// static String get_adb_path() { -// String exe_ext = ""; -// if (OS::get_singleton()->get_name() == "Windows") { -// exe_ext = ".exe"; -// } -// String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path"); -// return sdk_path.plus_file("platform-tools/adb" + exe_ext); -// } - -// static String get_apksigner_path() { -// String exe_ext = ""; -// if (OS::get_singleton()->get_name() == "Windows") { -// exe_ext = ".bat"; -// } -// String apksigner_command_name = "apksigner" + exe_ext; -// String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path"); -// String apksigner_path = ""; - -// Error errn; -// String build_tools_dir = sdk_path.plus_file("build-tools"); -// DirAccessRef da = DirAccess::open(build_tools_dir, &errn); -// if (errn != OK) { -// print_error("Unable to open Android 'build-tools' directory."); -// return apksigner_path; -// } - -// // There are additional versions directories we need to go through. -// da->list_dir_begin(); -// String sub_dir = da->get_next(); -// while (!sub_dir.is_empty()) { -// if (!sub_dir.begins_with(".") && da->current_is_dir()) { -// // Check if the tool is here. -// String tool_path = build_tools_dir.plus_file(sub_dir).plus_file(apksigner_command_name); -// if (FileAccess::exists(tool_path)) { -// apksigner_path = tool_path; -// break; -// } -// } -// sub_dir = da->get_next(); -// } -// da->list_dir_end(); - -// if (apksigner_path.is_empty()) { -// EditorNode::get_singleton()->show_warning(TTR("Unable to find the 'apksigner' tool.")); -// } - -// return apksigner_path; -// } - -// virtual bool can_export(const Ref &p_preset, String &r_error, bool &r_missing_templates) const override { -// String err; -// bool valid = false; - -// // Look for export templates (first official, and if defined custom templates). - -// if (!bool(p_preset->get("custom_template/use_custom_build"))) { -// String template_err; -// bool dvalid = false; -// bool rvalid = false; - -// if (p_preset->get("custom_template/debug") != "") { -// dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); -// if (!dvalid) { -// template_err += TTR("Custom debug template not found.") + "\n"; -// } -// } else { -// dvalid = exists_export_template("android_debug.apk", &template_err); -// } - -// if (p_preset->get("custom_template/release") != "") { -// rvalid = FileAccess::exists(p_preset->get("custom_template/release")); -// if (!rvalid) { -// template_err += TTR("Custom release template not found.") + "\n"; -// } -// } else { -// rvalid = exists_export_template("android_release.apk", &template_err); -// } - -// valid = dvalid || rvalid; -// if (!valid) { -// err += template_err; -// } -// } else { -// valid = exists_export_template("android_source.zip", &err); - -// if (!FileAccess::exists("res://android/build/build.gradle")) { -// err += TTR("Android build template not installed in the project. Install it from the Project menu.") + "\n"; -// valid = false; -// } -// } -// r_missing_templates = !valid; - -// // Validate the rest of the configuration. - -// String dk = p_preset->get("keystore/debug"); - -// if (!FileAccess::exists(dk)) { -// dk = EditorSettings::get_singleton()->get("export/android/debug_keystore"); -// if (!FileAccess::exists(dk)) { -// valid = false; -// err += TTR("Debug keystore not configured in the Editor Settings nor in the preset.") + "\n"; -// } -// } - -// String rk = p_preset->get("keystore/release"); - -// if (!rk.is_empty() && !FileAccess::exists(rk)) { -// valid = false; -// err += TTR("Release keystore incorrectly configured in the export preset.") + "\n"; -// } - -// String sdk_path = EditorSettings::get_singleton()->get("export/android/android_sdk_path"); -// if (sdk_path == "") { -// err += TTR("A valid Android SDK path is required in Editor Settings.") + "\n"; -// valid = false; -// } else { -// Error errn; -// // Check for the platform-tools directory. -// DirAccessRef da = DirAccess::open(sdk_path.plus_file("platform-tools"), &errn); -// if (errn != OK) { -// err += TTR("Invalid Android SDK path in Editor Settings."); -// err += TTR("Missing 'platform-tools' directory!"); -// err += "\n"; -// valid = false; -// } - -// // Validate that adb is available -// String adb_path = get_adb_path(); -// if (!FileAccess::exists(adb_path)) { -// err += TTR("Unable to find Android SDK platform-tools' adb command."); -// err += TTR("Please check in the Android SDK directory specified in Editor Settings."); -// err += "\n"; -// valid = false; -// } - -// // Check for the build-tools directory. -// DirAccessRef build_tools_da = DirAccess::open(sdk_path.plus_file("build-tools"), &errn); -// if (errn != OK) { -// err += TTR("Invalid Android SDK path in Editor Settings."); -// err += TTR("Missing 'build-tools' directory!"); -// err += "\n"; -// valid = false; -// } - -// // Validate that apksigner is available -// String apksigner_path = get_apksigner_path(); -// if (!FileAccess::exists(apksigner_path)) { -// err += TTR("Unable to find Android SDK build-tools' apksigner command."); -// err += TTR("Please check in the Android SDK directory specified in Editor Settings."); -// err += "\n"; -// valid = false; -// } -// } - -// bool apk_expansion = p_preset->get("apk_expansion/enable"); - -// if (apk_expansion) { -// String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); - -// if (apk_expansion_pkey == "") { -// valid = false; - -// err += TTR("Invalid public key for APK expansion.") + "\n"; -// } -// } - -// String pn = p_preset->get("package/unique_name"); -// String pn_err; - -// if (!is_package_name_valid(get_package_name(pn), &pn_err)) { -// valid = false; -// err += TTR("Invalid package name:") + " " + pn_err + "\n"; -// } - -// String etc_error = test_etc2(); -// if (etc_error != String()) { -// valid = false; -// err += etc_error; -// } - -// // Ensure that `Use Custom Build` is enabled if a plugin is selected. -// String enabled_plugins_names = get_plugins_names(get_enabled_plugins(p_preset)); -// bool custom_build_enabled = p_preset->get("custom_template/use_custom_build"); -// if (!enabled_plugins_names.is_empty() && !custom_build_enabled) { -// valid = false; -// err += TTR("\"Use Custom Build\" must be enabled to use the plugins."); -// err += "\n"; -// } - -// // Validate the Xr features are properly populated -// int xr_mode_index = p_preset->get("xr_features/xr_mode"); -// int degrees_of_freedom = p_preset->get("xr_features/degrees_of_freedom"); -// int hand_tracking = p_preset->get("xr_features/hand_tracking"); -// bool focus_awareness = p_preset->get("xr_features/focus_awareness"); -// if (xr_mode_index != /* XRMode.OVR*/ 1) { -// if (degrees_of_freedom > 0) { -// valid = false; -// err += TTR("\"Degrees Of Freedom\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."); -// err += "\n"; -// } - -// if (hand_tracking > 0) { -// valid = false; -// err += TTR("\"Hand Tracking\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."); -// err += "\n"; -// } - -// if (focus_awareness) { -// valid = false; -// err += TTR("\"Focus Awareness\" is only valid when \"Xr Mode\" is \"Oculus Mobile VR\"."); -// err += "\n"; -// } -// } - -// if (int(p_preset->get("custom_template/export_format")) == EXPORT_FORMAT_AAB && -// !bool(p_preset->get("custom_template/use_custom_build"))) { -// valid = false; -// err += TTR("\"Export AAB\" is only valid when \"Use Custom Build\" is enabled."); -// err += "\n"; -// } - -// r_error = err; -// return valid; -// } - -// virtual List get_binary_extensions(const Ref &p_preset) const override { -// List list; -// list.push_back("apk"); -// list.push_back("aab"); -// return list; -// } - -// inline bool is_clean_build_required(Vector enabled_plugins) { -// String plugin_names = get_plugins_names(enabled_plugins); -// bool first_build = last_custom_build_time == 0; -// bool have_plugins_changed = false; - -// if (!first_build) { -// have_plugins_changed = plugin_names != last_plugin_names; -// if (!have_plugins_changed) { -// for (int i = 0; i < enabled_plugins.size(); i++) { -// if (enabled_plugins.get(i).last_updated > last_custom_build_time) { -// have_plugins_changed = true; -// break; -// } -// } -// } -// } - -// last_custom_build_time = OS::get_singleton()->get_unix_time(); -// last_plugin_names = plugin_names; - -// return have_plugins_changed || first_build; -// } - -// String get_apk_expansion_fullpath(const Ref &p_preset, const String &p_path) { -// int version_code = p_preset->get("version/code"); -// String package_name = p_preset->get("package/unique_name"); -// String apk_file_name = "main." + itos(version_code) + "." + get_package_name(package_name) + ".obb"; -// String fullpath = p_path.get_base_dir().plus_file(apk_file_name); -// return fullpath; -// } - -// Error save_apk_expansion_file(const Ref &p_preset, const String &p_path) { -// String fullpath = get_apk_expansion_fullpath(p_preset, p_path); -// Error err = save_pack(p_preset, fullpath); -// return err; -// } - -// void get_command_line_flags(const Ref &p_preset, const String &p_path, int p_flags, Vector &r_command_line_flags) { -// String cmdline = p_preset->get("command_line/extra_args"); -// Vector command_line_strings = cmdline.strip_edges().split(" "); -// for (int i = 0; i < command_line_strings.size(); i++) { -// if (command_line_strings[i].strip_edges().length() == 0) { -// command_line_strings.remove(i); -// i--; -// } -// } - -// gen_export_flags(command_line_strings, p_flags); - -// bool apk_expansion = p_preset->get("apk_expansion/enable"); -// if (apk_expansion) { -// String fullpath = get_apk_expansion_fullpath(p_preset, p_path); -// String apk_expansion_public_key = p_preset->get("apk_expansion/public_key"); - -// command_line_strings.push_back("--use_apk_expansion"); -// command_line_strings.push_back("--apk_expansion_md5"); -// command_line_strings.push_back(FileAccess::get_md5(fullpath)); -// command_line_strings.push_back("--apk_expansion_key"); -// command_line_strings.push_back(apk_expansion_public_key.strip_edges()); -// } - -// int xr_mode_index = p_preset->get("xr_features/xr_mode"); -// if (xr_mode_index == 1) { -// command_line_strings.push_back("--xr_mode_ovr"); -// } else { // XRMode.REGULAR is the default. -// command_line_strings.push_back("--xr_mode_regular"); -// } - -// bool use_32_bit_framebuffer = p_preset->get("graphics/32_bits_framebuffer"); -// if (use_32_bit_framebuffer) { -// command_line_strings.push_back("--use_depth_32"); -// } - -// bool immersive = p_preset->get("screen/immersive_mode"); -// if (immersive) { -// command_line_strings.push_back("--use_immersive"); -// } - -// bool debug_opengl = p_preset->get("graphics/opengl_debug"); -// if (debug_opengl) { -// command_line_strings.push_back("--debug_opengl"); -// } - -// if (command_line_strings.size()) { -// r_command_line_flags.resize(4); -// encode_uint32(command_line_strings.size(), &r_command_line_flags.write[0]); -// for (int i = 0; i < command_line_strings.size(); i++) { -// print_line(itos(i) + " param: " + command_line_strings[i]); -// CharString command_line_argument = command_line_strings[i].utf8(); -// int base = r_command_line_flags.size(); -// int length = command_line_argument.length(); -// if (length == 0) -// continue; -// r_command_line_flags.resize(base + 4 + length); -// encode_uint32(length, &r_command_line_flags.write[base]); -// copymem(&r_command_line_flags.write[base + 4], command_line_argument.ptr(), length); -// } -// } -// } - -// Error sign_apk(const Ref &p_preset, bool p_debug, const String &export_path, EditorProgress &ep) { -// int export_format = int(p_preset->get("custom_template/export_format")); -// String export_label = export_format == EXPORT_FORMAT_AAB ? "AAB" : "APK"; -// String release_keystore = p_preset->get("keystore/release"); -// String release_username = p_preset->get("keystore/release_user"); -// String release_password = p_preset->get("keystore/release_password"); - -// String apksigner = get_apksigner_path(); -// if (!FileAccess::exists(apksigner)) { -// EditorNode::add_io_error("'apksigner' could not be found.\nPlease check the command is available in the Android SDK build-tools directory.\nThe resulting " + export_label + " is unsigned."); -// return OK; -// } - -// String keystore; -// String password; -// String user; -// if (p_debug) { -// keystore = p_preset->get("keystore/debug"); -// password = p_preset->get("keystore/debug_password"); -// user = p_preset->get("keystore/debug_user"); - -// if (keystore.is_empty()) { -// keystore = EditorSettings::get_singleton()->get("export/android/debug_keystore"); -// password = EditorSettings::get_singleton()->get("export/android/debug_keystore_pass"); -// user = EditorSettings::get_singleton()->get("export/android/debug_keystore_user"); -// } - -// if (ep.step("Signing debug " + export_label + "...", 104)) { -// return ERR_SKIP; -// } - -// } else { -// keystore = release_keystore; -// password = release_password; -// user = release_username; - -// if (ep.step("Signing release " + export_label + "...", 104)) { -// return ERR_SKIP; -// } -// } - -// if (!FileAccess::exists(keystore)) { -// EditorNode::add_io_error("Could not find keystore, unable to export."); -// return ERR_FILE_CANT_OPEN; -// } - -// List args; -// args.push_back("sign"); -// args.push_back("--verbose"); -// args.push_back("--ks"); -// args.push_back(keystore); -// args.push_back("--ks-pass"); -// args.push_back("pass:" + password); -// args.push_back("--ks-key-alias"); -// args.push_back(user); -// args.push_back(export_path); -// int retval; -// OS::get_singleton()->execute(apksigner, args, true, NULL, NULL, &retval); -// if (retval) { -// EditorNode::add_io_error("'apksigner' returned with error #" + itos(retval)); -// return ERR_CANT_CREATE; -// } - -// if (ep.step("Verifying " + export_label + "...", 105)) { -// return ERR_SKIP; -// } - -// args.clear(); -// args.push_back("verify"); -// args.push_back("--verbose"); -// args.push_back(export_path); - -// OS::get_singleton()->execute(apksigner, args, true, NULL, NULL, &retval); -// if (retval) { -// EditorNode::add_io_error("'apksigner' verification of " + export_label + " failed."); -// return ERR_CANT_CREATE; -// } -// return OK; -// } - -// void _clear_assets_directory() { -// DirAccessRef da_res = DirAccess::create(DirAccess::ACCESS_RESOURCES); -// if (da_res->dir_exists("res://android/build/assets")) { -// DirAccessRef da_assets = DirAccess::open("res://android/build/assets"); -// da_assets->erase_contents_recursive(); -// da_res->remove("res://android/build/assets"); -// } -// } - -// virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override { -// int export_format = int(p_preset->get("custom_template/export_format")); -// bool should_sign = p_preset->get("package/signed"); -// return export_project_helper(p_preset, p_debug, p_path, export_format, should_sign, p_flags); -// } - -// Error export_project_helper(const Ref &p_preset, bool p_debug, const String &p_path, int export_format, bool should_sign, int p_flags) { -// ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); - -// String src_apk; -// Error err; - -// EditorProgress ep("export", "Exporting for Android", 105, true); - -// bool use_custom_build = bool(p_preset->get("custom_template/use_custom_build")); -// bool p_give_internet = p_flags & (DEBUG_FLAG_DUMB_CLIENT | DEBUG_FLAG_REMOTE_DEBUG); -// bool apk_expansion = p_preset->get("apk_expansion/enable"); -// Vector enabled_abis = get_enabled_abis(p_preset); - -// Ref splash_image; -// Ref splash_bg_color_image; -// load_splash_refs(splash_image, splash_bg_color_image); - -// Ref main_image; -// Ref foreground; -// Ref background; - -// load_icon_refs(p_preset, main_image, foreground, background); - -// Vector command_line_flags; -// // Write command line flags into the command_line_flags variable. -// get_command_line_flags(p_preset, p_path, p_flags, command_line_flags); - -// if (export_format == EXPORT_FORMAT_AAB) { -// if (!p_path.ends_with(".aab")) { -// EditorNode::get_singleton()->show_warning(TTR("Invalid filename! Android App Bundle requires the *.aab extension.")); -// return ERR_UNCONFIGURED; -// } -// if (apk_expansion) { -// EditorNode::get_singleton()->show_warning(TTR("APK Expansion not compatible with Android App Bundle.")); -// return ERR_UNCONFIGURED; -// } -// } -// if (export_format == EXPORT_FORMAT_APK && !p_path.ends_with(".apk")) { -// EditorNode::get_singleton()->show_warning( -// TTR("Invalid filename! Android APK requires the *.apk extension.")); -// return ERR_UNCONFIGURED; -// } -// if (export_format > EXPORT_FORMAT_AAB || export_format < EXPORT_FORMAT_APK) { -// EditorNode::add_io_error("Unsupported export format!\n"); -// return ERR_UNCONFIGURED; //TODO: is this the right error? -// } - -// if (use_custom_build) { -// //test that installed build version is alright -// { -// FileAccessRef f = FileAccess::open("res://android/.build_version", FileAccess::READ); -// if (!f) { -// EditorNode::get_singleton()->show_warning(TTR("Trying to build from a custom built template, but no version info for it exists. Please reinstall from the 'Project' menu.")); -// return ERR_UNCONFIGURED; -// } -// String version = f->get_line().strip_edges(); -// f->close(); -// if (version != VERSION_FULL_CONFIG) { -// EditorNode::get_singleton()->show_warning(vformat(TTR("Android build version mismatch:\n Template installed: %s\n Godot Version: %s\nPlease reinstall Android build template from 'Project' menu."), version, VERSION_FULL_CONFIG)); -// return ERR_UNCONFIGURED; -// } -// } -// String sdk_path = EDITOR_GET("export/android/android_sdk_path"); -// ERR_FAIL_COND_V_MSG(sdk_path == "", ERR_UNCONFIGURED, "Android SDK path must be configured in Editor Settings at 'export/android/android_sdk_path'."); - -// // TODO: should we use "package/name" or "application/config/name"? -// String project_name = get_project_name(p_preset->get("package/name")); -// err = _create_project_name_strings_files(p_preset, project_name); //project name localization. -// if (err != OK) { -// EditorNode::add_io_error("Unable to overwrite res://android/build/res/*.xml files with project name"); -// } -// // Copies the project icon files into the appropriate Gradle project directory. -// _copy_icons_to_gradle_project(p_preset, splash_image, splash_bg_color_image, main_image, foreground, background); -// // Write an AndroidManifest.xml file into the Gradle project directory. -// _write_tmp_manifest(p_preset, p_give_internet, p_debug); - -// //stores all the project files inside the Gradle project directory. Also includes all ABIs -// _clear_assets_directory(); -// if (!apk_expansion) { -// err = export_project_files(p_preset, rename_and_store_file_in_gradle_project, NULL, ignore_so_file); -// if (err != OK) { -// EditorNode::add_io_error("Could not export project files to gradle project\n"); -// return err; -// } -// } else { -// err = save_apk_expansion_file(p_preset, p_path); -// if (err != OK) { -// EditorNode::add_io_error("Could not write expansion package file!"); -// return err; -// } -// } -// store_file_at_path("res://android/build/assets/_cl_", command_line_flags); - -// OS::get_singleton()->set_environment("ANDROID_HOME", sdk_path); //set and overwrite if required -// String build_command; - -//#ifdef WINDOWS_ENABLED -// build_command = "gradlew.bat"; -//#else -// build_command = "gradlew"; -//#endif - -// String build_path = ProjectSettings::get_singleton()->get_resource_path().plus_file("android/build"); -// build_command = build_path.plus_file(build_command); - -// String package_name = get_package_name(p_preset->get("package/unique_name")); -// String version_code = itos(p_preset->get("version/code")); -// String version_name = p_preset->get("version/name"); -// String enabled_abi_string = String("|").join(enabled_abis); -// String sign_flag = should_sign ? "true" : "false"; -// String zipalign_flag = "true"; - -// Vector enabled_plugins = get_enabled_plugins(p_preset); -// String local_plugins_binaries = get_plugins_binaries(BINARY_TYPE_LOCAL, enabled_plugins); -// String remote_plugins_binaries = get_plugins_binaries(BINARY_TYPE_REMOTE, enabled_plugins); -// String custom_maven_repos = get_plugins_custom_maven_repos(enabled_plugins); -// bool clean_build_required = is_clean_build_required(enabled_plugins); - -// List cmdline; -// if (clean_build_required) { -// cmdline.push_back("clean"); -// } - -// String build_type = p_debug ? "Debug" : "Release"; -// if (export_format == EXPORT_FORMAT_AAB) { -// String bundle_build_command = vformat("bundle%s", build_type); -// cmdline.push_back(bundle_build_command); -// } else if (export_format == EXPORT_FORMAT_APK) { -// String apk_build_command = vformat("assemble%s", build_type); -// cmdline.push_back(apk_build_command); -// } - -// cmdline.push_back("-Pexport_package_name=" + package_name); // argument to specify the package name. -// cmdline.push_back("-Pexport_version_code=" + version_code); // argument to specify the version code. -// cmdline.push_back("-Pexport_version_name=" + version_name); // argument to specify the version name. -// cmdline.push_back("-Pexport_enabled_abis=" + enabled_abi_string); // argument to specify enabled ABIs. -// cmdline.push_back("-Pplugins_local_binaries=" + local_plugins_binaries); // argument to specify the list of plugins local dependencies. -// cmdline.push_back("-Pplugins_remote_binaries=" + remote_plugins_binaries); // argument to specify the list of plugins remote dependencies. -// cmdline.push_back("-Pplugins_maven_repos=" + custom_maven_repos); // argument to specify the list of custom maven repos for the plugins dependencies. -// cmdline.push_back("-Pperform_zipalign=" + zipalign_flag); // argument to specify whether the build should be zipaligned. -// cmdline.push_back("-Pperform_signing=" + sign_flag); // argument to specify whether the build should be signed. -// if (should_sign && !p_debug) { -// // Pass the release keystore info as well -// String release_keystore = p_preset->get("keystore/release"); -// String release_username = p_preset->get("keystore/release_user"); -// String release_password = p_preset->get("keystore/release_password"); -// if (!FileAccess::exists(release_keystore)) { -// EditorNode::add_io_error("Could not find keystore, unable to export."); -// return ERR_FILE_CANT_OPEN; -// } - -// cmdline.push_back("-Prelease_keystore_file=" + release_keystore); // argument to specify the release keystore file. -// cmdline.push_back("-Prelease_keystore_alias=" + release_username); // argument to specify the release keystore alias. -// cmdline.push_back("-Prelease_keystore_password=" + release_password); // argument to specity the release keystore password. -// } -// cmdline.push_back("-p"); // argument to specify the start directory. -// cmdline.push_back(build_path); // start directory. - -// int result = EditorNode::get_singleton()->execute_and_show_output(TTR("Building Android Project (gradle)"), build_command, cmdline); -// if (result != 0) { -// EditorNode::get_singleton()->show_warning(TTR("Building of Android project failed, check output for the error.\nAlternatively visit docs.godotengine.org for Android build documentation.")); -// return ERR_CANT_CREATE; -// } - -// List copy_args; -// String copy_command; -// if (export_format == EXPORT_FORMAT_AAB) { -// copy_command = vformat("copyAndRename%sAab", build_type); -// } else if (export_format == EXPORT_FORMAT_APK) { -// copy_command = vformat("copyAndRename%sApk", build_type); -// } - -// copy_args.push_back(copy_command); - -// copy_args.push_back("-p"); // argument to specify the start directory. -// copy_args.push_back(build_path); // start directory. - -// String export_filename = p_path.get_file(); -// String export_path = p_path.get_base_dir(); -// if (export_path.is_rel_path()) { -// export_path = OS::get_singleton()->get_resource_dir().plus_file(export_path); -// } -// export_path = ProjectSettings::get_singleton()->globalize_path(export_path).simplify_path(); - -// copy_args.push_back("-Pexport_path=file:" + export_path); -// copy_args.push_back("-Pexport_filename=" + export_filename); - -// int copy_result = EditorNode::get_singleton()->execute_and_show_output(TTR("Moving output"), build_command, copy_args); -// if (copy_result != 0) { -// EditorNode::get_singleton()->show_warning(TTR("Unable to copy and rename export file, check gradle project directory for outputs.")); -// return ERR_CANT_CREATE; -// } - -// return OK; -// } -// // This is the start of the Legacy build system -// if (p_debug) -// src_apk = p_preset->get("custom_template/debug"); -// else -// src_apk = p_preset->get("custom_template/release"); -// src_apk = src_apk.strip_edges(); -// if (src_apk == "") { -// if (p_debug) { -// src_apk = find_export_template("android_debug.apk"); -// } else { -// src_apk = find_export_template("android_release.apk"); -// } -// if (src_apk == "") { -// EditorNode::add_io_error("Package not found: " + src_apk); -// return ERR_FILE_NOT_FOUND; -// } -// } - -// if (!DirAccess::exists(p_path.get_base_dir())) { -// return ERR_FILE_BAD_PATH; -// } - -// FileAccess *src_f = nullptr; -// zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - -// if (ep.step("Creating APK...", 0)) { -// return ERR_SKIP; -// } - -// unzFile pkg = unzOpen2(src_apk.utf8().get_data(), &io); -// if (!pkg) { -// EditorNode::add_io_error("Could not find template APK to export:\n" + src_apk); -// return ERR_FILE_NOT_FOUND; -// } - -// int ret = unzGoToFirstFile(pkg); - -// zlib_filefunc_def io2 = io; -// FileAccess *dst_f = nullptr; -// io2.opaque = &dst_f; - -// String tmp_unaligned_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpexport-unaligned.apk"); - -//#define CLEANUP_AND_RETURN(m_err) -// { -// DirAccess::remove_file_or_error(tmp_unaligned_path); -// return m_err; -// } - -// zipFile unaligned_apk = zipOpen2(tmp_unaligned_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2); - -// String cmdline = p_preset->get("command_line/extra_args"); - -// String version_name = p_preset->get("version/name"); -// String package_name = p_preset->get("package/unique_name"); - -// String apk_expansion_pkey = p_preset->get("apk_expansion/public_key"); - -// Vector invalid_abis(enabled_abis); -// while (ret == UNZ_OK) { -// //get filename -// unz_file_info info; -// char fname[16384]; -// ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - -// bool skip = false; - -// String file = fname; - -// Vector data; -// data.resize(info.uncompressed_size); - -// //read -// unzOpenCurrentFile(pkg); -// unzReadCurrentFile(pkg, data.ptrw(), data.size()); -// unzCloseCurrentFile(pkg); - -// //write -// if (file == "AndroidManifest.xml") { -// _fix_manifest(p_preset, data, p_give_internet); -// } -// if (file == "resources.arsc") { -// _fix_resources(p_preset, data); -// } - -// // Process the splash image -// if (file == SPLASH_IMAGE_EXPORT_PATH && splash_image.is_valid() && !splash_image->is_empty()) { -// _load_image_data(splash_image, data); -// } - -// // Process the splash bg color image -// if (file == SPLASH_BG_COLOR_PATH && splash_bg_color_image.is_valid() && !splash_bg_color_image->is_empty()) { -// _load_image_data(splash_bg_color_image, data); -// } - -// for (int i = 0; i < icon_densities_count; ++i) { -// if (main_image.is_valid() && !main_image->is_empty()) { -// if (file == launcher_icons[i].export_path) { -// _process_launcher_icons(file, main_image, launcher_icons[i].dimensions, data); -// } -// } -// if (foreground.is_valid() && !foreground->is_empty()) { -// if (file == launcher_adaptive_icon_foregrounds[i].export_path) { -// _process_launcher_icons(file, foreground, launcher_adaptive_icon_foregrounds[i].dimensions, data); -// } -// } -// if (background.is_valid() && !background->is_empty()) { -// if (file == launcher_adaptive_icon_backgrounds[i].export_path) { -// _process_launcher_icons(file, background, launcher_adaptive_icon_backgrounds[i].dimensions, data); -// } -// } -// } - -// if (file.ends_with(".so")) { -// bool enabled = false; -// for (int i = 0; i < enabled_abis.size(); ++i) { -// if (file.begins_with("lib/" + enabled_abis[i] + "/")) { -// invalid_abis.erase(enabled_abis[i]); -// enabled = true; -// break; -// } -// } -// if (!enabled) { -// skip = true; -// } -// } - -// if (file.begins_with("META-INF") && should_sign) { -// skip = true; -// } - -// if (!skip) { -// print_line("ADDING: " + file); - -// // Respect decision on compression made by AAPT for the export template -// const bool uncompressed = info.compression_method == 0; - -// zip_fileinfo zipfi = get_zip_fileinfo(); - -// zipOpenNewFileInZip(unaligned_apk, -// file.utf8().get_data(), -// &zipfi, -// nullptr, -// 0, -// nullptr, -// 0, -// nullptr, -// uncompressed ? 0 : Z_DEFLATED, -// Z_DEFAULT_COMPRESSION); - -// zipWriteInFileInZip(unaligned_apk, data.ptr(), data.size()); -// zipCloseFileInZip(unaligned_apk); -// } - -// ret = unzGoToNextFile(pkg); -// } - -// if (!invalid_abis.is_empty()) { -// String unsupported_arch = String(", ").join(invalid_abis); -// EditorNode::add_io_error("Missing libraries in the export template for the selected architectures: " + unsupported_arch + ".\n" + -// "Please build a template with all required libraries, or uncheck the missing architectures in the export preset."); -// CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND); -// } - -// if (ep.step("Adding files...", 1)) { -// CLEANUP_AND_RETURN(ERR_SKIP); -// } -// err = OK; - -// if (p_flags & DEBUG_FLAG_DUMB_CLIENT) { -// APKExportData ed; -// ed.ep = &ep; -// ed.apk = unaligned_apk; -// err = export_project_files(p_preset, ignore_apk_file, &ed, save_apk_so); -// } else { -// if (apk_expansion) { -// err = save_apk_expansion_file(p_preset, p_path); -// if (err != OK) { -// EditorNode::add_io_error("Could not write expansion package file!"); -// return err; -// } -// } else { -// APKExportData ed; -// ed.ep = &ep; -// ed.apk = unaligned_apk; -// err = export_project_files(p_preset, save_apk_file, &ed, save_apk_so); -// } -// } - -// if (err != OK) { -// unzClose(pkg); -// EditorNode::add_io_error("Could not export project files"); -// CLEANUP_AND_RETURN(ERR_SKIP); -// } - -// zip_fileinfo zipfi = get_zip_fileinfo(); -// zipOpenNewFileInZip(unaligned_apk, -// "assets/_cl_", -// &zipfi, -// NULL, -// 0, -// NULL, -// 0, -// NULL, -// 0, // No compress (little size gain and potentially slower startup) -// Z_DEFAULT_COMPRESSION); -// zipWriteInFileInZip(unaligned_apk, command_line_flags.ptr(), command_line_flags.size()); -// zipCloseFileInZip(unaligned_apk); -// zipClose(unaligned_apk, nullptr); -// unzClose(pkg); - -// if (err != OK) { -// CLEANUP_AND_RETURN(err); -// } - -// // Let's zip-align (must be done before signing) - -// static const int ZIP_ALIGNMENT = 4; - -// // If we're not signing the apk, then the next step should be the last. -// const int next_step = should_sign ? 103 : 105; -// if (ep.step("Aligning APK...", next_step)) { -// CLEANUP_AND_RETURN(ERR_SKIP); -// } - -// unzFile tmp_unaligned = unzOpen2(tmp_unaligned_path.utf8().get_data(), &io); -// if (!tmp_unaligned) { -// EditorNode::add_io_error("Could not unzip temporary unaligned APK."); -// CLEANUP_AND_RETURN(ERR_FILE_NOT_FOUND); -// } - -// ret = unzGoToFirstFile(tmp_unaligned); - -// io2 = io; -// dst_f = nullptr; -// io2.opaque = &dst_f; -// zipFile final_apk = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, nullptr, &io2); - -// // Take files from the unaligned APK and write them out to the aligned one -// // in raw mode, i.e. not uncompressing and recompressing, aligning them as needed, -// // following what is done in https://github.com/android/platform_build/blob/master/tools/zipalign/ZipAlign.cpp -// int bias = 0; -// while (ret == UNZ_OK) { -// unz_file_info info; -// memset(&info, 0, sizeof(info)); - -// char fname[16384]; -// char extra[16384]; -// ret = unzGetCurrentFileInfo(tmp_unaligned, &info, fname, 16384, extra, 16384 - ZIP_ALIGNMENT, nullptr, 0); - -// String file = fname; - -// Vector data; -// data.resize(info.compressed_size); - -// // read -// int method, level; -// unzOpenCurrentFile2(tmp_unaligned, &method, &level, 1); // raw read -// long file_offset = unzGetCurrentFileZStreamPos64(tmp_unaligned); -// unzReadCurrentFile(tmp_unaligned, data.ptrw(), data.size()); -// unzCloseCurrentFile(tmp_unaligned); - -// // align -// int padding = 0; -// if (!info.compression_method) { -// // Uncompressed file => Align -// long new_offset = file_offset + bias; -// padding = (ZIP_ALIGNMENT - (new_offset % ZIP_ALIGNMENT)) % ZIP_ALIGNMENT; -// } - -// memset(extra + info.size_file_extra, 0, padding); - -// zip_fileinfo fileinfo = get_zip_fileinfo(); -// zipOpenNewFileInZip2(final_apk, -// file.utf8().get_data(), -// &fileinfo, -// extra, -// info.size_file_extra + padding, -// nullptr, -// 0, -// nullptr, -// method, -// level, -// 1); // raw write -// zipWriteInFileInZip(final_apk, data.ptr(), data.size()); -// zipCloseFileInZipRaw(final_apk, info.uncompressed_size, info.crc); - -// bias += padding; - -// ret = unzGoToNextFile(tmp_unaligned); -// } - -// zipClose(final_apk, nullptr); -// unzClose(tmp_unaligned); - -// if (should_sign) { -// // Signing must be done last as any additional modifications to the -// // file will invalidate the signature. -// err = sign_apk(p_preset, p_debug, p_path, ep); -// if (err != OK) { -// CLEANUP_AND_RETURN(err); -// } -// } - -// CLEANUP_AND_RETURN(OK); -// } - -// virtual void get_platform_features(List *r_features) override { -// r_features->push_back("mobile"); -// r_features->push_back("Android"); -// } - -// virtual void resolve_platform_feature_priorities(const Ref &p_preset, Set &p_features) override { -// } - -// EditorExportPlatformAndroid() { -// Ref img = memnew(Image(_android_logo)); -// logo.instance(); -// logo->create_from_image(img); - -// img = Ref(memnew(Image(_android_run_icon))); -// run_icon.instance(); -// run_icon->create_from_image(img); - -// devices_changed = true; -// plugins_changed = true; -// quit_request = false; -// check_for_changes_thread = Thread::create(_check_for_changes_poll_thread, this); -// } - -// ~EditorExportPlatformAndroid() { -// quit_request = true; -// Thread::wait_to_finish(check_for_changes_thread); -// memdelete(check_for_changes_thread); -// } -//}; void register_android_exporter() { String exe_ext; diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 50823884cd..e27274be21 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -1612,7 +1612,7 @@ Vector EditorExportPlatformAndroid::get_enabled_abis(const Ref &p_preset, List *r_features) { String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "OpenGL") { + if (driver == "OpenGL3") { r_features->push_back("etc"); } // FIXME: Review what texture formats are used for Vulkan. diff --git a/platform/android/export/gradle_export_util.h b/platform/android/export/gradle_export_util.h index 7c773309e8..744022f1f9 100644 --- a/platform/android/export/gradle_export_util.h +++ b/platform/android/export/gradle_export_util.h @@ -74,51 +74,6 @@ Error rename_and_store_file_in_gradle_project(void *p_userdata, const String &p_ // Creates strings.xml files inside the gradle project for different locales. Error _create_project_name_strings_files(const Ref &p_preset, const String &project_name); -//Error _create_project_name_strings_files(const Ref &p_preset, const String &project_name) { -// // Stores the string into the default values directory. -// String processed_default_xml_string = vformat(godot_project_name_xml_string, project_name.xml_escape(true)); -// store_string_at_path("res://android/build/res/values/godot_project_name_string.xml", processed_default_xml_string); - -// // Searches the Gradle project res/ directory to find all supported locales -// DirAccessRef da = DirAccess::open("res://android/build/res"); -// if (!da) { -// return ERR_CANT_OPEN; -// } -// da->list_dir_begin(); -// while (true) { -// String file = da->get_next(); -// if (file == "") { -// break; -// } -// if (!file.begins_with("values-")) { -// // NOTE: This assumes all directories that start with "values-" are for localization. -// continue; -// } -// String locale = file.replace("values-", "").replace("-r", "_"); -// String property_name = "application/config/name_" + locale; -// String locale_directory = "res://android/build/res/" + file + "/godot_project_name_string.xml"; -// if (ProjectSettings::get_singleton()->has_setting(property_name)) { -// String locale_project_name = ProjectSettings::get_singleton()->get(property_name); -// String processed_xml_string = vformat(godot_project_name_xml_string, locale_project_name.xml_escape(true)); -// store_string_at_path(locale_directory, processed_xml_string); -// } else { -// // TODO: Once the legacy build system is deprecated we don't need to have xml files for this else branch -// store_string_at_path(locale_directory, processed_default_xml_string); -// } -// } -// da->list_dir_end(); -// return OK; -//} - -//String bool_to_string(bool v) { -// return v ? "true" : "false"; -//} - -//String _get_gles_tag() { -// bool min_gles3 = ProjectSettings::get_singleton()->get("rendering/driver/driver_name") == "GLES3" && -// !ProjectSettings::get_singleton()->get("rendering/quality/driver/fallback_to_gles2"); -// return min_gles3 ? " \n" : ""; -//} String bool_to_string(bool v); diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp index 94ca51f75a..1a4c5ec00f 100644 --- a/platform/android/os_android.cpp +++ b/platform/android/os_android.cpp @@ -262,14 +262,14 @@ Size2i OS_Android::get_display_size() const { } void OS_Android::set_context_is_16_bits(bool p_is_16) { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) //if (rasterizer) // rasterizer->set_force_16_bits_fbo(p_is_16); #endif } void OS_Android::set_opengl_extensions(const char *p_gl_extensions) { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) ERR_FAIL_COND(!p_gl_extensions); gl_extensions = p_gl_extensions; #endif @@ -321,7 +321,7 @@ OS_Android::OS_Android(GodotJavaWrapper *p_godot_java, GodotIOJavaWrapper *p_god main_loop = nullptr; -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) gl_extensions = nullptr; use_gl2 = false; #endif diff --git a/platform/android/os_android.h b/platform/android/os_android.h index 9bb37325cf..d2e0e7d1e9 100644 --- a/platform/android/os_android.h +++ b/platform/android/os_android.h @@ -47,7 +47,7 @@ private: bool use_apk_expansion; -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) const char *gl_extensions; #endif diff --git a/platform/iphone/app_delegate.h b/platform/iphone/app_delegate.h index 68cfde6508..76c28b2272 100644 --- a/platform/iphone/app_delegate.h +++ b/platform/iphone/app_delegate.h @@ -34,7 +34,7 @@ // FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented again, // so it can't be done with compilation time branching. -//#if defined(OPENGL_ENABLED) +//#if defined(GLES3_ENABLED) //@interface AppDelegate : NSObject { //#endif //#if defined(VULKAN_ENABLED) diff --git a/platform/iphone/display_layer.mm b/platform/iphone/display_layer.mm index afa75f53ed..afe612e1a5 100644 --- a/platform/iphone/display_layer.mm +++ b/platform/iphone/display_layer.mm @@ -89,7 +89,7 @@ // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? // Create GL ES 2 context - if (GLOBAL_GET("rendering/driver/driver_name") == "opengl") { + if (GLOBAL_GET("rendering/driver/driver_name") == "opengl3") { context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; NSLog(@"Setting up an OpenGL ES 2.0 context."); if (!context) { diff --git a/platform/iphone/display_server_iphone.mm b/platform/iphone/display_server_iphone.mm index 33601da1c8..7d13a08d39 100644 --- a/platform/iphone/display_server_iphone.mm +++ b/platform/iphone/display_server_iphone.mm @@ -51,7 +51,7 @@ DisplayServerIPhone *DisplayServerIPhone::get_singleton() { DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i &p_resolution, Error &r_error) { rendering_driver = p_rendering_driver; -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) // FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented // again, @@ -60,9 +60,9 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo // FIXME: Add Vulkan support via MoltenVK. Add fallback code back? - if (RasterizerOpenGLis_viable() == OK) { - RasterizerOpenGLregister_config(); - RasterizerOpenGLmake_current(); + if (RasterizerGLES3::is_viable() == OK) { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); } else { gl_initialization_error = true; } @@ -83,7 +83,7 @@ DisplayServerIPhone::DisplayServerIPhone(const String &p_rendering_driver, Windo // reset this to what it should be, it will have been set to 0 after // rendering_server->init() is called - // RasterizerStorageOpenGLsystem_fbo = gl_view_base_fb; + // RasterizerStorageGLES3system_fbo = gl_view_base_fb; } #endif @@ -157,7 +157,7 @@ Vector DisplayServerIPhone::get_rendering_drivers_func() { #if defined(VULKAN_ENABLED) drivers.push_back("vulkan"); #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) drivers.push_back("opengl_es"); #endif diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 6cec365885..208626ae36 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -31,1929 +31,6 @@ #include "export.h" #include "export_plugin.h" -//#include "core/config/project_settings.h" -//#include "core/io/image_loader.h" -//#include "core/io/marshalls.h" -//#include "core/io/resource_saver.h" -//#include "core/io/zip_io.h" -//#include "core/os/file_access.h" -//#include "core/os/os.h" -//#include "core/version.h" -//#include "editor/editor_export.h" -//#include "editor/editor_node.h" -//#include "editor/editor_settings.h" -//#include "main/splash.gen.h" -//#include "platform/iphone/logo.gen.h" -//#include "platform/iphone/plugin/godot_plugin_config.h" -//#include "string.h" - -//#include - -//class EditorExportPlatformIOS : public EditorExportPlatform { -// GDCLASS(EditorExportPlatformIOS, EditorExportPlatform); - -// int version_code; - -// Ref logo; - -// // Plugins -// volatile bool plugins_changed; -// Thread *check_for_changes_thread; -// volatile bool quit_request; -// Mutex plugins_lock; -// Vector plugins; - -// typedef Error (*FileHandler)(String p_file, void *p_userdata); -// static Error _walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata); -// static Error _codesign(String p_file, void *p_userdata); -// void _blend_and_rotate(Ref &p_dst, Ref &p_src, bool p_rot); - -// struct IOSConfigData { -// String pkg_name; -// String binary_name; -// String plist_content; -// String architectures; -// String linker_flags; -// String cpp_code; -// String modules_buildfile; -// String modules_fileref; -// String modules_buildphase; -// String modules_buildgrp; -// Vector capabilities; -// }; -// struct ExportArchitecture { -// String name; -// bool is_default = false; - -// ExportArchitecture() {} - -// ExportArchitecture(String p_name, bool p_is_default) { -// name = p_name; -// is_default = p_is_default; -// } -// }; - -// struct IOSExportAsset { -// String exported_path; -// bool is_framework = false; // framework is anything linked to the binary, otherwise it's a resource -// bool should_embed = false; -// }; - -// String _get_additional_plist_content(); -// String _get_linker_flags(); -// String _get_cpp_code(); -// void _fix_config_file(const Ref &p_preset, Vector &pfile, const IOSConfigData &p_config, bool p_debug); -// Error _export_loading_screen_images(const Ref &p_preset, const String &p_dest_dir); -// Error _export_loading_screen_file(const Ref &p_preset, const String &p_dest_dir); -// Error _export_icons(const Ref &p_preset, const String &p_iconset_dir); - -// Vector _get_supported_architectures(); -// Vector _get_preset_architectures(const Ref &p_preset); - -// void _add_assets_to_project(const Ref &p_preset, Vector &p_project_data, const Vector &p_additional_assets); -// Error _export_additional_assets(const String &p_out_dir, const Vector &p_assets, bool p_is_framework, bool p_should_embed, Vector &r_exported_assets); -// Error _copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector &r_exported_assets); -// Error _export_additional_assets(const String &p_out_dir, const Vector &p_libraries, Vector &r_exported_assets); -// Error _export_ios_plugins(const Ref &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets, bool p_debug); - -// bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const { -// String pname = p_package; - -// if (pname.length() == 0) { -// if (r_error) { -// *r_error = TTR("Identifier is missing."); -// } -// return false; -// } - -// for (int i = 0; i < pname.length(); i++) { -// char32_t c = pname[i]; -// if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '.')) { -// if (r_error) { -// *r_error = vformat(TTR("The character '%s' is not allowed in Identifier."), String::chr(c)); -// } -// return false; -// } -// } - -// return true; -// } - -// static void _check_for_changes_poll_thread(void *ud) { -// EditorExportPlatformIOS *ea = (EditorExportPlatformIOS *)ud; - -// while (!ea->quit_request) { -// // Nothing to do if we already know the plugins have changed. -// if (!ea->plugins_changed) { -// MutexLock lock(ea->plugins_lock); - -// Vector loaded_plugins = get_plugins(); - -// if (ea->plugins.size() != loaded_plugins.size()) { -// ea->plugins_changed = true; -// } else { -// for (int i = 0; i < ea->plugins.size(); i++) { -// if (ea->plugins[i].name != loaded_plugins[i].name || ea->plugins[i].last_updated != loaded_plugins[i].last_updated) { -// ea->plugins_changed = true; -// break; -// } -// } -// } -// } - -// uint64_t wait = 3000000; -// uint64_t time = OS::get_singleton()->get_ticks_usec(); -// while (OS::get_singleton()->get_ticks_usec() - time < wait) { -// OS::get_singleton()->delay_usec(300000); - -// if (ea->quit_request) { -// break; -// } -// } -// } -// } - -//protected: -// virtual void get_preset_features(const Ref &p_preset, List *r_features) override; -// virtual void get_export_options(List *r_options) override; - -//public: -// virtual String get_name() const override { return "iOS"; } -// virtual String get_os_name() const override { return "iOS"; } -// virtual Ref get_logo() const override { return logo; } - -// virtual bool should_update_export_options() override { -// bool export_options_changed = plugins_changed; -// if (export_options_changed) { -// // don't clear unless we're reporting true, to avoid race -// plugins_changed = false; -// } -// return export_options_changed; -// } - -// virtual List get_binary_extensions(const Ref &p_preset) const override { -// List list; -// list.push_back("ipa"); -// return list; -// } -// virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; - -// virtual bool can_export(const Ref &p_preset, String &r_error, bool &r_missing_templates) const override; - -// virtual void get_platform_features(List *r_features) override { -// r_features->push_back("mobile"); -// r_features->push_back("iOS"); -// } - -// virtual void resolve_platform_feature_priorities(const Ref &p_preset, Set &p_features) override { -// } - -// EditorExportPlatformIOS(); -// ~EditorExportPlatformIOS(); - -// /// List the gdip files in the directory specified by the p_path parameter. -// static Vector list_plugin_config_files(const String &p_path, bool p_check_directories) { -// Vector dir_files; -// DirAccessRef da = DirAccess::open(p_path); -// if (da) { -// da->list_dir_begin(); -// while (true) { -// String file = da->get_next(); -// if (file.is_empty()) { -// break; -// } - -// if (file == "." || file == "..") { -// continue; -// } - -// if (da->current_is_hidden()) { -// continue; -// } - -// if (da->current_is_dir()) { -// if (p_check_directories) { -// Vector directory_files = list_plugin_config_files(p_path.plus_file(file), false); -// for (int i = 0; i < directory_files.size(); ++i) { -// dir_files.push_back(file.plus_file(directory_files[i])); -// } -// } - -// continue; -// } - -// if (file.ends_with(PLUGIN_CONFIG_EXT)) { -// dir_files.push_back(file); -// } -// } -// da->list_dir_end(); -// } - -// return dir_files; -// } - -// static Vector get_plugins() { -// Vector loaded_plugins; - -// String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("ios/plugins"); - -// if (DirAccess::exists(plugins_dir)) { -// Vector plugins_filenames = list_plugin_config_files(plugins_dir, true); - -// if (!plugins_filenames.is_empty()) { -// Ref config_file = memnew(ConfigFile); -// for (int i = 0; i < plugins_filenames.size(); i++) { -// PluginConfig config = load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i])); -// if (config.valid_config) { -// loaded_plugins.push_back(config); -// } else { -// print_error("Invalid plugin config file " + plugins_filenames[i]); -// } -// } -// } -// } - -// return loaded_plugins; -// } - -// static Vector get_enabled_plugins(const Ref &p_presets) { -// Vector enabled_plugins; -// Vector all_plugins = get_plugins(); -// for (int i = 0; i < all_plugins.size(); i++) { -// PluginConfig plugin = all_plugins[i]; -// bool enabled = p_presets->get("plugins/" + plugin.name); -// if (enabled) { -// enabled_plugins.push_back(plugin); -// } -// } - -// return enabled_plugins; -// } -//}; - -//void EditorExportPlatformIOS::get_preset_features(const Ref &p_preset, List *r_features) { -// String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); -// r_features->push_back("pvrtc"); -// if (driver == "Vulkan") { -// // FIXME: Review if this is correct. -// r_features->push_back("etc2"); -// } - -// Vector architectures = _get_preset_architectures(p_preset); -// for (int i = 0; i < architectures.size(); ++i) { -// r_features->push_back(architectures[i]); -// } -//} - -//Vector EditorExportPlatformIOS::_get_supported_architectures() { -// Vector archs; -// archs.push_back(ExportArchitecture("armv7", false)); // Disabled by default, not included in official templates. -// archs.push_back(ExportArchitecture("arm64", true)); -// return archs; -//} - -//struct LoadingScreenInfo { -// const char *preset_key; -// const char *export_name; -// int width = 0; -// int height = 0; -// bool rotate = false; -//}; - -//static const LoadingScreenInfo loading_screen_infos[] = { -// { "landscape_launch_screens/iphone_2436x1125", "Default-Landscape-X.png", 2436, 1125, false }, -// { "landscape_launch_screens/iphone_2208x1242", "Default-Landscape-736h@3x.png", 2208, 1242, false }, -// { "landscape_launch_screens/ipad_1024x768", "Default-Landscape.png", 1024, 768, false }, -// { "landscape_launch_screens/ipad_2048x1536", "Default-Landscape@2x.png", 2048, 1536, false }, - -// { "portrait_launch_screens/iphone_640x960", "Default-480h@2x.png", 640, 960, true }, -// { "portrait_launch_screens/iphone_640x1136", "Default-568h@2x.png", 640, 1136, true }, -// { "portrait_launch_screens/iphone_750x1334", "Default-667h@2x.png", 750, 1334, true }, -// { "portrait_launch_screens/iphone_1125x2436", "Default-Portrait-X.png", 1125, 2436, true }, -// { "portrait_launch_screens/ipad_768x1024", "Default-Portrait.png", 768, 1024, true }, -// { "portrait_launch_screens/ipad_1536x2048", "Default-Portrait@2x.png", 1536, 2048, true }, -// { "portrait_launch_screens/iphone_1242x2208", "Default-Portrait-736h@3x.png", 1242, 2208, true } -//}; - -//void EditorExportPlatformIOS::get_export_options(List *r_options) { -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); - -// Vector architectures = _get_supported_architectures(); -// for (int i = 0; i < architectures.size(); ++i) { -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "architectures/" + architectures[i].name), architectures[i].is_default)); -// } - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/app_store_team_id"), "")); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_debug"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_debug", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Developer"), "iPhone Developer")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_debug", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 1)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/provisioning_profile_uuid_release"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/code_sign_identity_release", PROPERTY_HINT_PLACEHOLDER_TEXT, "iPhone Distribution"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_method_release", PROPERTY_HINT_ENUM, "App Store,Development,Ad-Hoc,Enterprise"), 0)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/info"), "Made with Godot Engine")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/bundle_identifier", PROPERTY_HINT_PLACEHOLDER_TEXT, "com.example.game"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/signature"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version"), "1.0")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); - -// Vector found_plugins = get_plugins(); -// for (int i = 0; i < found_plugins.size(); i++) { -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + found_plugins[i].name), false)); -// } -// plugins_changed = false; -// plugins = found_plugins; - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/push_notifications"), false)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_files_app"), false)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_itunes_sharing"), false)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/camera_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the camera"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/microphone_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need to use the microphone"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "privacy/photolibrary_usage_description", PROPERTY_HINT_PLACEHOLDER_TEXT, "Provide a message if you need access to the photo library"), "")); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait"), true)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_left"), true)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/landscape_right"), true)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "orientation/portrait_upside_down"), true)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "icons/generate_missing"), false)); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/iphone_120x120", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone/iPod Touch with retina display -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/ipad_76x76", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "required_icons/app_store_1024x1024", PROPERTY_HINT_FILE, "*.png"), "")); // App Store - -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/iphone_180x180", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPhone with retina HD display -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/ipad_152x152", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad with retina display -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/ipad_167x167", PROPERTY_HINT_FILE, "*.png"), "")); // Home screen on iPad Pro -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_40x40", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "optional_icons/spotlight_80x80", PROPERTY_HINT_FILE, "*.png"), "")); // Spotlight on devices with retina display - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale To Fit,Scale To Fill,Scale"), 0)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png"), "")); -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false)); -// r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color())); - -// r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "launch_screens/generate_missing"), false)); - -// for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { -// r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png"), "")); -// } -//} - -//void EditorExportPlatformIOS::_fix_config_file(const Ref &p_preset, Vector &pfile, const IOSConfigData &p_config, bool p_debug) { -// static const String export_method_string[] = { -// "app-store", -// "development", -// "ad-hoc", -// "enterprise" -// }; -// static const String storyboard_image_scale_mode[] = { -// "center", -// "scaleAspectFit", -// "scaleAspectFill", -// "scaleToFill" -// }; -// String str; -// String strnew; -// str.parse_utf8((const char *)pfile.ptr(), pfile.size()); -// Vector lines = str.split("\n"); -// for (int i = 0; i < lines.size(); i++) { -// if (lines[i].find("$binary") != -1) { -// strnew += lines[i].replace("$binary", p_config.binary_name) + "\n"; -// } else if (lines[i].find("$modules_buildfile") != -1) { -// strnew += lines[i].replace("$modules_buildfile", p_config.modules_buildfile) + "\n"; -// } else if (lines[i].find("$modules_fileref") != -1) { -// strnew += lines[i].replace("$modules_fileref", p_config.modules_fileref) + "\n"; -// } else if (lines[i].find("$modules_buildphase") != -1) { -// strnew += lines[i].replace("$modules_buildphase", p_config.modules_buildphase) + "\n"; -// } else if (lines[i].find("$modules_buildgrp") != -1) { -// strnew += lines[i].replace("$modules_buildgrp", p_config.modules_buildgrp) + "\n"; -// } else if (lines[i].find("$name") != -1) { -// strnew += lines[i].replace("$name", p_config.pkg_name) + "\n"; -// } else if (lines[i].find("$info") != -1) { -// strnew += lines[i].replace("$info", p_preset->get("application/info")) + "\n"; -// } else if (lines[i].find("$bundle_identifier") != -1) { -// strnew += lines[i].replace("$bundle_identifier", p_preset->get("application/bundle_identifier")) + "\n"; -// } else if (lines[i].find("$short_version") != -1) { -// strnew += lines[i].replace("$short_version", p_preset->get("application/short_version")) + "\n"; -// } else if (lines[i].find("$version") != -1) { -// strnew += lines[i].replace("$version", p_preset->get("application/version")) + "\n"; -// } else if (lines[i].find("$signature") != -1) { -// strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n"; -// } else if (lines[i].find("$copyright") != -1) { -// strnew += lines[i].replace("$copyright", p_preset->get("application/copyright")) + "\n"; -// } else if (lines[i].find("$team_id") != -1) { -// strnew += lines[i].replace("$team_id", p_preset->get("application/app_store_team_id")) + "\n"; -// } else if (lines[i].find("$export_method") != -1) { -// int export_method = p_preset->get(p_debug ? "application/export_method_debug" : "application/export_method_release"); -// strnew += lines[i].replace("$export_method", export_method_string[export_method]) + "\n"; -// } else if (lines[i].find("$provisioning_profile_uuid_release") != -1) { -// strnew += lines[i].replace("$provisioning_profile_uuid_release", p_preset->get("application/provisioning_profile_uuid_release")) + "\n"; -// } else if (lines[i].find("$provisioning_profile_uuid_debug") != -1) { -// strnew += lines[i].replace("$provisioning_profile_uuid_debug", p_preset->get("application/provisioning_profile_uuid_debug")) + "\n"; -// } else if (lines[i].find("$provisioning_profile_uuid") != -1) { -// String uuid = p_debug ? p_preset->get("application/provisioning_profile_uuid_debug") : p_preset->get("application/provisioning_profile_uuid_release"); -// strnew += lines[i].replace("$provisioning_profile_uuid", uuid) + "\n"; -// } else if (lines[i].find("$code_sign_identity_debug") != -1) { -// strnew += lines[i].replace("$code_sign_identity_debug", p_preset->get("application/code_sign_identity_debug")) + "\n"; -// } else if (lines[i].find("$code_sign_identity_release") != -1) { -// strnew += lines[i].replace("$code_sign_identity_release", p_preset->get("application/code_sign_identity_release")) + "\n"; -// } else if (lines[i].find("$additional_plist_content") != -1) { -// strnew += lines[i].replace("$additional_plist_content", p_config.plist_content) + "\n"; -// } else if (lines[i].find("$godot_archs") != -1) { -// strnew += lines[i].replace("$godot_archs", p_config.architectures) + "\n"; -// } else if (lines[i].find("$linker_flags") != -1) { -// strnew += lines[i].replace("$linker_flags", p_config.linker_flags) + "\n"; -// } else if (lines[i].find("$cpp_code") != -1) { -// strnew += lines[i].replace("$cpp_code", p_config.cpp_code) + "\n"; -// } else if (lines[i].find("$docs_in_place") != -1) { -// strnew += lines[i].replace("$docs_in_place", ((bool)p_preset->get("user_data/accessible_from_files_app")) ? "" : "") + "\n"; -// } else if (lines[i].find("$docs_sharing") != -1) { -// strnew += lines[i].replace("$docs_sharing", ((bool)p_preset->get("user_data/accessible_from_itunes_sharing")) ? "" : "") + "\n"; -// } else if (lines[i].find("$entitlements_push_notifications") != -1) { -// bool is_on = p_preset->get("capabilities/push_notifications"); -// strnew += lines[i].replace("$entitlements_push_notifications", is_on ? "aps-environmentdevelopment" : "") + "\n"; -// } else if (lines[i].find("$required_device_capabilities") != -1) { -// String capabilities; - -// // I've removed armv7 as we can run on 64bit only devices -// // Note that capabilities listed here are requirements for the app to be installed. -// // They don't enable anything. -// Vector capabilities_list = p_config.capabilities; - -// if ((bool)p_preset->get("capabilities/access_wifi") && !capabilities_list.has("wifi")) { -// capabilities_list.push_back("wifi"); -// } - -// for (int idx = 0; idx < capabilities_list.size(); idx++) { -// capabilities += "" + capabilities_list[idx] + "\n"; -// } - -// strnew += lines[i].replace("$required_device_capabilities", capabilities); -// } else if (lines[i].find("$interface_orientations") != -1) { -// String orientations; - -// if ((bool)p_preset->get("orientation/portrait")) { -// orientations += "UIInterfaceOrientationPortrait\n"; -// } -// if ((bool)p_preset->get("orientation/landscape_left")) { -// orientations += "UIInterfaceOrientationLandscapeLeft\n"; -// } -// if ((bool)p_preset->get("orientation/landscape_right")) { -// orientations += "UIInterfaceOrientationLandscapeRight\n"; -// } -// if ((bool)p_preset->get("orientation/portrait_upside_down")) { -// orientations += "UIInterfaceOrientationPortraitUpsideDown\n"; -// } - -// strnew += lines[i].replace("$interface_orientations", orientations); -// } else if (lines[i].find("$camera_usage_description") != -1) { -// String description = p_preset->get("privacy/camera_usage_description"); -// strnew += lines[i].replace("$camera_usage_description", description) + "\n"; -// } else if (lines[i].find("$microphone_usage_description") != -1) { -// String description = p_preset->get("privacy/microphone_usage_description"); -// strnew += lines[i].replace("$microphone_usage_description", description) + "\n"; -// } else if (lines[i].find("$photolibrary_usage_description") != -1) { -// String description = p_preset->get("privacy/photolibrary_usage_description"); -// strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n"; -// } else if (lines[i].find("$plist_launch_screen_name") != -1) { -// bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); -// String value = is_on ? "UILaunchStoryboardName\nLaunch Screen" : ""; -// strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n"; -// } else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) { -// bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); -// String value = is_on ? "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"\"; };" : ""; -// strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n"; -// } else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) { -// bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); -// String value = is_on ? "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */," : ""; -// strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n"; -// } else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) { -// bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); -// String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */," : ""; -// strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n"; -// } else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) { -// bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); -// String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };" : ""; -// strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n"; -// } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) { -// bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard"); -// String value = is_on ? "" : "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;"; -// strnew += lines[i].replace("$pbx_launch_image_usage_setting", value) + "\n"; -// } else if (lines[i].find("$launch_screen_image_mode") != -1) { -// int image_scale_mode = p_preset->get("storyboard/image_scale_mode"); -// String value; - -// switch (image_scale_mode) { -// case 0: { -// String logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image"); -// bool is_on = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize"); -// // If custom logo is not specified, Godot does not scale default one, so we should do the same. -// value = (is_on && logo_path.length() > 0) ? "scaleAspectFit" : "center"; -// } break; -// default: { -// value = storyboard_image_scale_mode[image_scale_mode - 1]; -// } -// } - -// strnew += lines[i].replace("$launch_screen_image_mode", value) + "\n"; -// } else if (lines[i].find("$launch_screen_background_color") != -1) { -// bool use_custom = p_preset->get("storyboard/use_custom_bg_color"); -// Color color = use_custom ? p_preset->get("storyboard/custom_bg_color") : ProjectSettings::get_singleton()->get("application/boot_splash/bg_color"); -// const String value_format = "red=\"$red\" green=\"$green\" blue=\"$blue\" alpha=\"$alpha\""; - -// Dictionary value_dictionary; -// value_dictionary["red"] = color.r; -// value_dictionary["green"] = color.g; -// value_dictionary["blue"] = color.b; -// value_dictionary["alpha"] = color.a; -// String value = value_format.format(value_dictionary, "$_"); - -// strnew += lines[i].replace("$launch_screen_background_color", value) + "\n"; -// } else { -// strnew += lines[i] + "\n"; -// } -// } - -// // !BAS! I'm assuming the 9 in the original code was a typo. I've added -1 or else it seems to also be adding our terminating zero... -// // should apply the same fix in our OSX export. -// CharString cs = strnew.utf8(); -// pfile.resize(cs.size() - 1); -// for (int i = 0; i < cs.size() - 1; i++) { -// pfile.write[i] = cs[i]; -// } -//} - -//String EditorExportPlatformIOS::_get_additional_plist_content() { -// Vector> export_plugins = EditorExport::get_singleton()->get_export_plugins(); -// String result; -// for (int i = 0; i < export_plugins.size(); ++i) { -// result += export_plugins[i]->get_ios_plist_content(); -// } -// return result; -//} - -//String EditorExportPlatformIOS::_get_linker_flags() { -// Vector> export_plugins = EditorExport::get_singleton()->get_export_plugins(); -// String result; -// for (int i = 0; i < export_plugins.size(); ++i) { -// String flags = export_plugins[i]->get_ios_linker_flags(); -// if (flags.length() == 0) { -// continue; -// } -// if (result.length() > 0) { -// result += ' '; -// } -// result += flags; -// } -// // the flags will be enclosed in quotes, so need to escape them -// return result.replace("\"", "\\\""); -//} - -//String EditorExportPlatformIOS::_get_cpp_code() { -// Vector> export_plugins = EditorExport::get_singleton()->get_export_plugins(); -// String result; -// for (int i = 0; i < export_plugins.size(); ++i) { -// result += export_plugins[i]->get_ios_cpp_code(); -// } -// return result; -//} - -//void EditorExportPlatformIOS::_blend_and_rotate(Ref &p_dst, Ref &p_src, bool p_rot) { -// ERR_FAIL_COND(p_dst.is_null()); -// ERR_FAIL_COND(p_src.is_null()); - -// int sw = p_rot ? p_src->get_height() : p_src->get_width(); -// int sh = p_rot ? p_src->get_width() : p_src->get_height(); - -// int x_pos = (p_dst->get_width() - sw) / 2; -// int y_pos = (p_dst->get_height() - sh) / 2; - -// int xs = (x_pos >= 0) ? 0 : -x_pos; -// int ys = (y_pos >= 0) ? 0 : -y_pos; - -// if (sw + x_pos > p_dst->get_width()) { -// sw = p_dst->get_width() - x_pos; -// } -// if (sh + y_pos > p_dst->get_height()) { -// sh = p_dst->get_height() - y_pos; -// } - -// for (int y = ys; y < sh; y++) { -// for (int x = xs; x < sw; x++) { -// Color sc = p_rot ? p_src->get_pixel(p_src->get_width() - y - 1, x) : p_src->get_pixel(x, y); -// Color dc = p_dst->get_pixel(x_pos + x, y_pos + y); -// dc.r = (double)(sc.a * sc.r + dc.a * (1.0 - sc.a) * dc.r); -// dc.g = (double)(sc.a * sc.g + dc.a * (1.0 - sc.a) * dc.g); -// dc.b = (double)(sc.a * sc.b + dc.a * (1.0 - sc.a) * dc.b); -// dc.a = (double)(sc.a + dc.a * (1.0 - sc.a)); -// p_dst->set_pixel(x_pos + x, y_pos + y, dc); -// } -// } -//} - -//struct IconInfo { -// const char *preset_key; -// const char *idiom; -// const char *export_name; -// const char *actual_size_side; -// const char *scale; -// const char *unscaled_size; -// bool is_required = false; -//}; - -//static const IconInfo icon_infos[] = { -// { "required_icons/iphone_120x120", "iphone", "Icon-120.png", "120", "2x", "60x60", true }, -// { "required_icons/iphone_120x120", "iphone", "Icon-120.png", "120", "3x", "40x40", true }, - -// { "required_icons/ipad_76x76", "ipad", "Icon-76.png", "76", "1x", "76x76", true }, -// { "required_icons/app_store_1024x1024", "ios-marketing", "Icon-1024.png", "1024", "1x", "1024x1024", true }, - -// { "optional_icons/iphone_180x180", "iphone", "Icon-180.png", "180", "3x", "60x60", false }, - -// { "optional_icons/ipad_152x152", "ipad", "Icon-152.png", "152", "2x", "76x76", false }, - -// { "optional_icons/ipad_167x167", "ipad", "Icon-167.png", "167", "2x", "83.5x83.5", false }, - -// { "optional_icons/spotlight_40x40", "ipad", "Icon-40.png", "40", "1x", "40x40", false }, - -// { "optional_icons/spotlight_80x80", "iphone", "Icon-80.png", "80", "2x", "40x40", false }, -// { "optional_icons/spotlight_80x80", "ipad", "Icon-80.png", "80", "2x", "40x40", false } -//}; - -//Error EditorExportPlatformIOS::_export_icons(const Ref &p_preset, const String &p_iconset_dir) { -// String json_description = "{\"images\":["; -// String sizes; - -// DirAccess *da = DirAccess::open(p_iconset_dir); -// ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_iconset_dir + "'."); - -// for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { -// IconInfo info = icon_infos[i]; -// int side_size = String(info.actual_size_side).to_int(); -// String icon_path = p_preset->get(info.preset_key); -// if (icon_path.length() == 0) { -// if ((bool)p_preset->get("icons/generate_missing")) { -// // Resize main app icon -// icon_path = ProjectSettings::get_singleton()->get("application/config/icon"); -// Ref img = memnew(Image); -// Error err = ImageLoader::load_image(icon_path, img); -// if (err != OK) { -// ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'."); -// return ERR_UNCONFIGURED; -// } -// img->resize(side_size, side_size); -// err = img->save_png(p_iconset_dir + info.export_name); -// if (err) { -// String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'."); -// ERR_PRINT(err_str.utf8().get_data()); -// return err; -// } -// } else { -// if (info.is_required) { -// String err_str = String("Required icon (") + info.preset_key + ") is not specified in the preset."; -// ERR_PRINT(err_str); -// return ERR_UNCONFIGURED; -// } else { -// String err_str = String("Icon (") + info.preset_key + ") is not specified in the preset."; -// WARN_PRINT(err_str); -// } -// continue; -// } -// } else { -// // Load custom icon -// Ref img = memnew(Image); -// Error err = ImageLoader::load_image(icon_path, img); -// if (err != OK) { -// ERR_PRINT("Invalid icon (" + String(info.preset_key) + "): '" + icon_path + "'."); -// return ERR_UNCONFIGURED; -// } -// if (img->get_width() != side_size || img->get_height() != side_size) { -// ERR_PRINT("Invalid icon size (" + String(info.preset_key) + "): '" + icon_path + "'."); -// return ERR_UNCONFIGURED; -// } - -// err = da->copy(icon_path, p_iconset_dir + info.export_name); -// if (err) { -// memdelete(da); -// String err_str = String("Failed to export icon(" + String(info.preset_key) + "): '" + icon_path + "'."); -// ERR_PRINT(err_str.utf8().get_data()); -// return err; -// } -// } -// sizes += String(info.actual_size_side) + "\n"; -// if (i > 0) { -// json_description += ","; -// } -// json_description += String("{"); -// json_description += String("\"idiom\":") + "\"" + info.idiom + "\","; -// json_description += String("\"size\":") + "\"" + info.unscaled_size + "\","; -// json_description += String("\"scale\":") + "\"" + info.scale + "\","; -// json_description += String("\"filename\":") + "\"" + info.export_name + "\""; -// json_description += String("}"); -// } -// json_description += "]}"; -// memdelete(da); - -// FileAccess *json_file = FileAccess::open(p_iconset_dir + "Contents.json", FileAccess::WRITE); -// ERR_FAIL_COND_V(!json_file, ERR_CANT_CREATE); -// CharString json_utf8 = json_description.utf8(); -// json_file->store_buffer((const uint8_t *)json_utf8.get_data(), json_utf8.length()); -// memdelete(json_file); - -// FileAccess *sizes_file = FileAccess::open(p_iconset_dir + "sizes", FileAccess::WRITE); -// ERR_FAIL_COND_V(!sizes_file, ERR_CANT_CREATE); -// CharString sizes_utf8 = sizes.utf8(); -// sizes_file->store_buffer((const uint8_t *)sizes_utf8.get_data(), sizes_utf8.length()); -// memdelete(sizes_file); - -// return OK; -//} - -//Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref &p_preset, const String &p_dest_dir) { -// const String custom_launch_image_2x = p_preset->get("storyboard/custom_image@2x"); -// const String custom_launch_image_3x = p_preset->get("storyboard/custom_image@3x"); - -// if (custom_launch_image_2x.length() > 0 && custom_launch_image_3x.length() > 0) { -// Ref image; -// String image_path = p_dest_dir.plus_file("splash@2x.png"); -// image.instance(); -// Error err = image->load(custom_launch_image_2x); - -// if (err) { -// image.unref(); -// return err; -// } - -// if (image->save_png(image_path) != OK) { -// return ERR_FILE_CANT_WRITE; -// } - -// image.unref(); -// image_path = p_dest_dir.plus_file("splash@3x.png"); -// image.instance(); -// err = image->load(custom_launch_image_3x); - -// if (err) { -// image.unref(); -// return err; -// } - -// if (image->save_png(image_path) != OK) { -// return ERR_FILE_CANT_WRITE; -// } -// } else { -// Ref splash; - -// const String splash_path = ProjectSettings::get_singleton()->get("application/boot_splash/image"); - -// if (!splash_path.is_empty()) { -// splash.instance(); -// const Error err = splash->load(splash_path); -// if (err) { -// splash.unref(); -// } -// } - -// if (splash.is_null()) { -// splash = Ref(memnew(Image(boot_splash_png))); -// } - -// // Using same image for both @2x and @3x -// // because Godot's own boot logo uses single image for all resolutions. -// // Also not using @1x image, because devices using this image variant -// // are not supported by iOS 9, which is minimal target. -// const String splash_png_path_2x = p_dest_dir.plus_file("splash@2x.png"); -// const String splash_png_path_3x = p_dest_dir.plus_file("splash@3x.png"); - -// if (splash->save_png(splash_png_path_2x) != OK) { -// return ERR_FILE_CANT_WRITE; -// } - -// if (splash->save_png(splash_png_path_3x) != OK) { -// return ERR_FILE_CANT_WRITE; -// } -// } - -// return OK; -//} - -//Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref &p_preset, const String &p_dest_dir) { -// DirAccess *da = DirAccess::open(p_dest_dir); -// ERR_FAIL_COND_V_MSG(!da, ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'."); - -// for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) { -// LoadingScreenInfo info = loading_screen_infos[i]; -// String loading_screen_file = p_preset->get(info.preset_key); -// if (loading_screen_file.size() > 0) { -// // Load custom loading screens -// Ref img = memnew(Image); -// Error err = ImageLoader::load_image(loading_screen_file, img); -// if (err != OK) { -// ERR_PRINT("Invalid loading screen (" + String(info.preset_key) + "): '" + loading_screen_file + "'."); -// return ERR_UNCONFIGURED; -// } -// if (img->get_width() != info.width || img->get_height() != info.height) { -// ERR_PRINT("Invalid loading screen size (" + String(info.preset_key) + "): '" + loading_screen_file + "'."); -// return ERR_UNCONFIGURED; -// } -// err = da->copy(loading_screen_file, p_dest_dir + info.export_name); -// if (err) { -// memdelete(da); -// String err_str = String("Failed to export loading screen (") + info.preset_key + ") from path '" + loading_screen_file + "'."; -// ERR_PRINT(err_str.utf8().get_data()); -// return err; -// } -// } else if ((bool)p_preset->get("launch_screens/generate_missing")) { -// // Generate loading screen from the splash screen -// Color boot_bg_color = ProjectSettings::get_singleton()->get("application/boot_splash/bg_color"); -// String boot_logo_path = ProjectSettings::get_singleton()->get("application/boot_splash/image"); -// bool boot_logo_scale = ProjectSettings::get_singleton()->get("application/boot_splash/fullsize"); - -// Ref img = memnew(Image); -// img->create(info.width, info.height, false, Image::FORMAT_RGBA8); -// img->fill(boot_bg_color); - -// Ref img_bs; - -// if (boot_logo_path.length() > 0) { -// img_bs = Ref(memnew(Image)); -// ImageLoader::load_image(boot_logo_path, img_bs); -// } -// if (!img_bs.is_valid()) { -// img_bs = Ref(memnew(Image(boot_splash_png))); -// } -// if (img_bs.is_valid()) { -// float aspect_ratio = (float)img_bs->get_width() / (float)img_bs->get_height(); -// if (info.rotate) { -// if (boot_logo_scale) { -// if (info.width * aspect_ratio <= info.height) { -// img_bs->resize(info.width * aspect_ratio, info.width); -// } else { -// img_bs->resize(info.height, info.height / aspect_ratio); -// } -// } -// } else { -// if (boot_logo_scale) { -// if (info.height * aspect_ratio <= info.width) { -// img_bs->resize(info.height * aspect_ratio, info.height); -// } else { -// img_bs->resize(info.width, info.width / aspect_ratio); -// } -// } -// } -// _blend_and_rotate(img, img_bs, info.rotate); -// } -// Error err = img->save_png(p_dest_dir + info.export_name); -// if (err) { -// String err_str = String("Failed to export loading screen (") + info.preset_key + ") from splash screen."; -// WARN_PRINT(err_str.utf8().get_data()); -// } -// } else { -// String err_str = String("No loading screen (") + info.preset_key + ") specified."; -// WARN_PRINT(err_str.utf8().get_data()); -// } -// } -// memdelete(da); - -// return OK; -//} - -//Error EditorExportPlatformIOS::_walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata) { -// Vector dirs; -// String path; -// String current_dir = p_da->get_current_dir(); -// p_da->list_dir_begin(); -// while ((path = p_da->get_next()).length() != 0) { -// if (p_da->current_is_dir()) { -// if (path != "." && path != "..") { -// dirs.push_back(path); -// } -// } else { -// Error err = p_handler(current_dir.plus_file(path), p_userdata); -// if (err) { -// p_da->list_dir_end(); -// return err; -// } -// } -// } -// p_da->list_dir_end(); - -// for (int i = 0; i < dirs.size(); ++i) { -// String dir = dirs[i]; -// p_da->change_dir(dir); -// Error err = _walk_dir_recursive(p_da, p_handler, p_userdata); -// p_da->change_dir(".."); -// if (err) { -// return err; -// } -// } - -// return OK; -//} - -//struct CodesignData { -// const Ref &preset; -// bool debug = false; - -// CodesignData(const Ref &p_preset, bool p_debug) : -// preset(p_preset), -// debug(p_debug) { -// } -//}; - -//Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) { -// if (p_file.ends_with(".dylib")) { -// CodesignData *data = (CodesignData *)p_userdata; -// print_line(String("Signing ") + p_file); -// List codesign_args; -// codesign_args.push_back("-f"); -// codesign_args.push_back("-s"); -// codesign_args.push_back(data->preset->get(data->debug ? "application/code_sign_identity_debug" : "application/code_sign_identity_release")); -// codesign_args.push_back(p_file); -// return OS::get_singleton()->execute("codesign", codesign_args, true); -// } -// return OK; -//} - -//struct PbxId { -//private: -// static char _hex_char(uint8_t four_bits) { -// if (four_bits < 10) { -// return ('0' + four_bits); -// } -// return 'A' + (four_bits - 10); -// } - -// static String _hex_pad(uint32_t num) { -// Vector ret; -// ret.resize(sizeof(num) * 2); -// for (uint64_t i = 0; i < sizeof(num) * 2; ++i) { -// uint8_t four_bits = (num >> (sizeof(num) * 8 - (i + 1) * 4)) & 0xF; -// ret.write[i] = _hex_char(four_bits); -// } -// return String::utf8(ret.ptr(), ret.size()); -// } - -//public: -// uint32_t high_bits; -// uint32_t mid_bits; -// uint32_t low_bits; - -// String str() const { -// return _hex_pad(high_bits) + _hex_pad(mid_bits) + _hex_pad(low_bits); -// } - -// PbxId &operator++() { -// low_bits++; -// if (!low_bits) { -// mid_bits++; -// if (!mid_bits) { -// high_bits++; -// } -// } - -// return *this; -// } -//}; - -//struct ExportLibsData { -// Vector lib_paths; -// String dest_dir; -//}; - -//void EditorExportPlatformIOS::_add_assets_to_project(const Ref &p_preset, Vector &p_project_data, const Vector &p_additional_assets) { -// // that is just a random number, we just need Godot IDs not to clash with -// // existing IDs in the project. -// PbxId current_id = { 0x58938401, 0, 0 }; -// String pbx_files; -// String pbx_frameworks_build; -// String pbx_frameworks_refs; -// String pbx_resources_build; -// String pbx_resources_refs; -// String pbx_embeded_frameworks; - -// const String file_info_format = String("$build_id = {isa = PBXBuildFile; fileRef = $ref_id; };\n") + -// "$ref_id = {isa = PBXFileReference; lastKnownFileType = $file_type; name = \"$name\"; path = \"$file_path\"; sourceTree = \"\"; };\n"; - -// for (int i = 0; i < p_additional_assets.size(); ++i) { -// String additional_asset_info_format = file_info_format; - -// String build_id = (++current_id).str(); -// String ref_id = (++current_id).str(); -// String framework_id = ""; - -// const IOSExportAsset &asset = p_additional_assets[i]; - -// String type; -// if (asset.exported_path.ends_with(".framework")) { -// if (asset.should_embed) { -// additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n"; -// framework_id = (++current_id).str(); -// pbx_embeded_frameworks += framework_id + ",\n"; -// } - -// type = "wrapper.framework"; -// } else if (asset.exported_path.ends_with(".xcframework")) { -// if (asset.should_embed) { -// additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n"; -// framework_id = (++current_id).str(); -// pbx_embeded_frameworks += framework_id + ",\n"; -// } - -// type = "wrapper.xcframework"; -// } else if (asset.exported_path.ends_with(".dylib")) { -// type = "compiled.mach-o.dylib"; -// } else if (asset.exported_path.ends_with(".a")) { -// type = "archive.ar"; -// } else { -// type = "file"; -// } - -// String &pbx_build = asset.is_framework ? pbx_frameworks_build : pbx_resources_build; -// String &pbx_refs = asset.is_framework ? pbx_frameworks_refs : pbx_resources_refs; - -// if (pbx_build.length() > 0) { -// pbx_build += ",\n"; -// pbx_refs += ",\n"; -// } -// pbx_build += build_id; -// pbx_refs += ref_id; - -// Dictionary format_dict; -// format_dict["build_id"] = build_id; -// format_dict["ref_id"] = ref_id; -// format_dict["name"] = asset.exported_path.get_file(); -// format_dict["file_path"] = asset.exported_path; -// format_dict["file_type"] = type; -// if (framework_id.length() > 0) { -// format_dict["framework_id"] = framework_id; -// } -// pbx_files += additional_asset_info_format.format(format_dict, "$_"); -// } - -// // Note, frameworks like gamekit are always included in our project.pbxprof file -// // even if turned off in capabilities. - -// String str = String::utf8((const char *)p_project_data.ptr(), p_project_data.size()); -// str = str.replace("$additional_pbx_files", pbx_files); -// str = str.replace("$additional_pbx_frameworks_build", pbx_frameworks_build); -// str = str.replace("$additional_pbx_frameworks_refs", pbx_frameworks_refs); -// str = str.replace("$additional_pbx_resources_build", pbx_resources_build); -// str = str.replace("$additional_pbx_resources_refs", pbx_resources_refs); -// str = str.replace("$pbx_embeded_frameworks", pbx_embeded_frameworks); - -// CharString cs = str.utf8(); -// p_project_data.resize(cs.size() - 1); -// for (int i = 0; i < cs.size() - 1; i++) { -// p_project_data.write[i] = cs[i]; -// } -//} - -//Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector &r_exported_assets) { -// DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); -// ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'."); - -// String binary_name = p_out_dir.get_file().get_basename(); - -// DirAccess *da = DirAccess::create_for_path(p_asset); -// if (!da) { -// memdelete(filesystem_da); -// ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + p_asset + "."); -// } -// bool file_exists = da->file_exists(p_asset); -// bool dir_exists = da->dir_exists(p_asset); -// if (!file_exists && !dir_exists) { -// memdelete(da); -// memdelete(filesystem_da); -// return ERR_FILE_NOT_FOUND; -// } - -// String base_dir = p_asset.get_base_dir().replace("res://", ""); -// String destination_dir; -// String destination; -// String asset_path; - -// bool create_framework = false; - -// if (p_is_framework && p_asset.ends_with(".dylib")) { -// // For iOS we need to turn .dylib into .framework -// // to be able to send application to AppStore -// asset_path = String("dylibs").plus_file(base_dir); - -// String file_name; - -// if (!p_custom_file_name) { -// file_name = p_asset.get_basename().get_file(); -// } else { -// file_name = *p_custom_file_name; -// } - -// String framework_name = file_name + ".framework"; - -// asset_path = asset_path.plus_file(framework_name); -// destination_dir = p_out_dir.plus_file(asset_path); -// destination = destination_dir.plus_file(file_name); -// create_framework = true; -// } else if (p_is_framework && (p_asset.ends_with(".framework") || p_asset.ends_with(".xcframework"))) { -// asset_path = String("dylibs").plus_file(base_dir); - -// String file_name; - -// if (!p_custom_file_name) { -// file_name = p_asset.get_file(); -// } else { -// file_name = *p_custom_file_name; -// } - -// asset_path = asset_path.plus_file(file_name); -// destination_dir = p_out_dir.plus_file(asset_path); -// destination = destination_dir; -// } else { -// asset_path = base_dir; - -// String file_name; - -// if (!p_custom_file_name) { -// file_name = p_asset.get_file(); -// } else { -// file_name = *p_custom_file_name; -// } - -// destination_dir = p_out_dir.plus_file(asset_path); -// asset_path = asset_path.plus_file(file_name); -// destination = p_out_dir.plus_file(asset_path); -// } - -// if (!filesystem_da->dir_exists(destination_dir)) { -// Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); -// if (make_dir_err) { -// memdelete(da); -// memdelete(filesystem_da); -// return make_dir_err; -// } -// } - -// Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination); -// memdelete(da); -// if (err) { -// memdelete(filesystem_da); -// return err; -// } -// IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed }; -// r_exported_assets.push_back(exported_asset); - -// if (create_framework) { -// String file_name; - -// if (!p_custom_file_name) { -// file_name = p_asset.get_basename().get_file(); -// } else { -// file_name = *p_custom_file_name; -// } - -// String framework_name = file_name + ".framework"; - -// // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib -// { -// List install_name_args; -// install_name_args.push_back("-id"); -// install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name)); -// install_name_args.push_back(destination); - -// OS::get_singleton()->execute("install_name_tool", install_name_args, true); -// } - -// // Creating Info.plist -// { -// String info_plist_format = "\n" -// "\n" -// "\n" -// "\n" -// "CFBundleShortVersionString\n" -// "1.0\n" -// "CFBundleIdentifier\n" -// "com.gdnative.framework.$name\n" -// "CFBundleName\n" -// "$name\n" -// "CFBundleExecutable\n" -// "$name\n" -// "DTPlatformName\n" -// "iphoneos\n" -// "CFBundleInfoDictionaryVersion\n" -// "6.0\n" -// "CFBundleVersion\n" -// "1\n" -// "CFBundlePackageType\n" -// "FMWK\n" -// "MinimumOSVersion\n" -// "10.0\n" -// "\n" -// ""; - -// String info_plist = info_plist_format.replace("$name", file_name); - -// FileAccess *f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE); -// if (f) { -// f->store_string(info_plist); -// f->close(); -// memdelete(f); -// } -// } -// } - -// memdelete(filesystem_da); - -// return OK; -//} - -//Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector &p_assets, bool p_is_framework, bool p_should_embed, Vector &r_exported_assets) { -// for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) { -// String asset = p_assets[f_idx]; -// if (!asset.begins_with("res://")) { -// // either SDK-builtin or already a part of the export template -// IOSExportAsset exported_asset = { asset, p_is_framework, p_should_embed }; -// r_exported_assets.push_back(exported_asset); -// } else { -// Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets); -// ERR_FAIL_COND_V(err, err); -// } -// } - -// return OK; -//} - -//Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector &p_libraries, Vector &r_exported_assets) { -// Vector> export_plugins = EditorExport::get_singleton()->get_export_plugins(); -// for (int i = 0; i < export_plugins.size(); i++) { -// Vector linked_frameworks = export_plugins[i]->get_ios_frameworks(); -// Error err = _export_additional_assets(p_out_dir, linked_frameworks, true, false, r_exported_assets); -// ERR_FAIL_COND_V(err, err); - -// Vector embedded_frameworks = export_plugins[i]->get_ios_embedded_frameworks(); -// err = _export_additional_assets(p_out_dir, embedded_frameworks, true, true, r_exported_assets); -// ERR_FAIL_COND_V(err, err); - -// Vector project_static_libs = export_plugins[i]->get_ios_project_static_libs(); -// for (int j = 0; j < project_static_libs.size(); j++) { -// project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project -// } -// err = _export_additional_assets(p_out_dir, project_static_libs, true, true, r_exported_assets); -// ERR_FAIL_COND_V(err, err); - -// Vector ios_bundle_files = export_plugins[i]->get_ios_bundle_files(); -// err = _export_additional_assets(p_out_dir, ios_bundle_files, false, false, r_exported_assets); -// ERR_FAIL_COND_V(err, err); -// } - -// Vector library_paths; -// for (int i = 0; i < p_libraries.size(); ++i) { -// library_paths.push_back(p_libraries[i].path); -// } -// Error err = _export_additional_assets(p_out_dir, library_paths, true, true, r_exported_assets); -// ERR_FAIL_COND_V(err, err); - -// return OK; -//} - -//Vector EditorExportPlatformIOS::_get_preset_architectures(const Ref &p_preset) { -// Vector all_archs = _get_supported_architectures(); -// Vector enabled_archs; -// for (int i = 0; i < all_archs.size(); ++i) { -// bool is_enabled = p_preset->get("architectures/" + all_archs[i].name); -// if (is_enabled) { -// enabled_archs.push_back(all_archs[i].name); -// } -// } -// return enabled_archs; -//} - -//Error EditorExportPlatformIOS::_export_ios_plugins(const Ref &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets, bool p_debug) { -// String plugin_definition_cpp_code; -// String plugin_initialization_cpp_code; -// String plugin_deinitialization_cpp_code; - -// Vector plugin_linked_dependencies; -// Vector plugin_embedded_dependencies; -// Vector plugin_files; - -// Vector enabled_plugins = get_enabled_plugins(p_preset); - -// Vector added_linked_dependenciy_names; -// Vector added_embedded_dependenciy_names; -// HashMap plist_values; - -// Error err; - -// for (int i = 0; i < enabled_plugins.size(); i++) { -// PluginConfig plugin = enabled_plugins[i]; - -// // Export plugin binary. -// if (!plugin.supports_targets) { -// err = _copy_asset(dest_dir, plugin.binary, nullptr, true, true, r_exported_assets); -// } else { -// String plugin_binary_dir = plugin.binary.get_base_dir(); -// String plugin_name_prefix = plugin.binary.get_basename().get_file(); -// String plugin_file = plugin_name_prefix + "." + (p_debug ? "debug" : "release") + ".a"; -// String result_file_name = plugin.binary.get_file(); - -// err = _copy_asset(dest_dir, plugin_binary_dir.plus_file(plugin_file), &result_file_name, true, true, r_exported_assets); -// } - -// ERR_FAIL_COND_V(err, err); - -// // Adding dependencies. -// // Use separate container for names to check for duplicates. -// for (int j = 0; j < plugin.linked_dependencies.size(); j++) { -// String dependency = plugin.linked_dependencies[j]; -// String name = dependency.get_file(); - -// if (added_linked_dependenciy_names.has(name)) { -// continue; -// } - -// added_linked_dependenciy_names.push_back(name); -// plugin_linked_dependencies.push_back(dependency); -// } - -// for (int j = 0; j < plugin.system_dependencies.size(); j++) { -// String dependency = plugin.system_dependencies[j]; -// String name = dependency.get_file(); - -// if (added_linked_dependenciy_names.has(name)) { -// continue; -// } - -// added_linked_dependenciy_names.push_back(name); -// plugin_linked_dependencies.push_back(dependency); -// } - -// for (int j = 0; j < plugin.embedded_dependencies.size(); j++) { -// String dependency = plugin.embedded_dependencies[j]; -// String name = dependency.get_file(); - -// if (added_embedded_dependenciy_names.has(name)) { -// continue; -// } - -// added_embedded_dependenciy_names.push_back(name); -// plugin_embedded_dependencies.push_back(dependency); -// } - -// plugin_files.append_array(plugin.files_to_copy); - -// // Capabilities -// // Also checking for duplicates. -// for (int j = 0; j < plugin.capabilities.size(); j++) { -// String capability = plugin.capabilities[j]; - -// if (p_config_data.capabilities.has(capability)) { -// continue; -// } - -// p_config_data.capabilities.push_back(capability); -// } - -// // Plist -// // Using hash map container to remove duplicates -// const String *K = nullptr; - -// while ((K = plugin.plist.next(K))) { -// String key = *K; -// String value = plugin.plist[key]; - -// if (key.is_empty() || value.is_empty()) { -// continue; -// } - -// plist_values[key] = value; -// } - -// // CPP Code -// String definition_comment = "// Plugin: " + plugin.name + "\n"; -// String initialization_method = plugin.initialization_method + "();\n"; -// String deinitialization_method = plugin.deinitialization_method + "();\n"; - -// plugin_definition_cpp_code += definition_comment + -// "extern void " + initialization_method + -// "extern void " + deinitialization_method + "\n"; - -// plugin_initialization_cpp_code += "\t" + initialization_method; -// plugin_deinitialization_cpp_code += "\t" + deinitialization_method; -// } - -// // Updating `Info.plist` -// { -// const String *K = nullptr; -// while ((K = plist_values.next(K))) { -// String key = *K; -// String value = plist_values[key]; - -// if (key.is_empty() || value.is_empty()) { -// continue; -// } - -// p_config_data.plist_content += "" + key + "" + value + "\n"; -// } -// } - -// // Export files -// { -// // Export linked plugin dependency -// err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets); -// ERR_FAIL_COND_V(err, err); - -// // Export embedded plugin dependency -// err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets); -// ERR_FAIL_COND_V(err, err); - -// // Export plugin files -// err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets); -// ERR_FAIL_COND_V(err, err); -// } - -// // Update CPP -// { -// Dictionary plugin_format; -// plugin_format["definition"] = plugin_definition_cpp_code; -// plugin_format["initialization"] = plugin_initialization_cpp_code; -// plugin_format["deinitialization"] = plugin_deinitialization_cpp_code; - -// String plugin_cpp_code = "\n// Godot Plugins\n" -// "void godot_ios_plugins_initialize();\n" -// "void godot_ios_plugins_deinitialize();\n" -// "// Exported Plugins\n\n" -// "$definition" -// "// Use Plugins\n" -// "void godot_ios_plugins_initialize() {\n" -// "$initialization" -// "}\n\n" -// "void godot_ios_plugins_deinitialize() {\n" -// "$deinitialization" -// "}\n"; - -// p_config_data.cpp_code += plugin_cpp_code.format(plugin_format, "$_"); -// } -// return OK; -//} - -//Error EditorExportPlatformIOS::export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags) { -// ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); - -// String src_pkg_name; -// String dest_dir = p_path.get_base_dir() + "/"; -// String binary_name = p_path.get_file().get_basename(); - -// EditorProgress ep("export", "Exporting for iOS", 5, true); - -// String team_id = p_preset->get("application/app_store_team_id"); -// ERR_FAIL_COND_V_MSG(team_id.length() == 0, ERR_CANT_OPEN, "App Store Team ID not specified - cannot configure the project."); - -// if (p_debug) { -// src_pkg_name = p_preset->get("custom_template/debug"); -// } else { -// src_pkg_name = p_preset->get("custom_template/release"); -// } - -// if (src_pkg_name == "") { -// String err; -// src_pkg_name = find_export_template("iphone.zip", &err); -// if (src_pkg_name == "") { -// EditorNode::add_io_error(err); -// return ERR_FILE_NOT_FOUND; -// } -// } - -// if (!DirAccess::exists(dest_dir)) { -// return ERR_FILE_BAD_PATH; -// } - -// DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); -// if (da) { -// String current_dir = da->get_current_dir(); - -// // remove leftovers from last export so they don't interfere -// // in case some files are no longer needed -// if (da->change_dir(dest_dir + binary_name + ".xcodeproj") == OK) { -// da->erase_contents_recursive(); -// } -// if (da->change_dir(dest_dir + binary_name) == OK) { -// da->erase_contents_recursive(); -// } - -// da->change_dir(current_dir); - -// if (!da->dir_exists(dest_dir + binary_name)) { -// Error err = da->make_dir(dest_dir + binary_name); -// if (err) { -// memdelete(da); -// return err; -// } -// } -// memdelete(da); -// } - -// if (ep.step("Making .pck", 0)) { -// return ERR_SKIP; -// } -// String pack_path = dest_dir + binary_name + ".pck"; -// Vector libraries; -// Error err = save_pack(p_preset, pack_path, &libraries); -// if (err) { -// return err; -// } - -// if (ep.step("Extracting and configuring Xcode project", 1)) { -// return ERR_SKIP; -// } - -// String library_to_use = "libgodot.iphone." + String(p_debug ? "debug" : "release") + ".fat.a"; - -// print_line("Static library: " + library_to_use); -// String pkg_name; -// if (p_preset->get("application/name") != "") { -// pkg_name = p_preset->get("application/name"); // app_name -// } else if (String(ProjectSettings::get_singleton()->get("application/config/name")) != "") { -// pkg_name = String(ProjectSettings::get_singleton()->get("application/config/name")); -// } else { -// pkg_name = "Unnamed"; -// } - -// bool found_library = false; -// int total_size = 0; - -// const String project_file = "godot_ios.xcodeproj/project.pbxproj"; -// Set files_to_parse; -// files_to_parse.insert("godot_ios/godot_ios-Info.plist"); -// files_to_parse.insert(project_file); -// files_to_parse.insert("godot_ios/export_options.plist"); -// files_to_parse.insert("godot_ios/dummy.cpp"); -// files_to_parse.insert("godot_ios.xcodeproj/project.xcworkspace/contents.xcworkspacedata"); -// files_to_parse.insert("godot_ios.xcodeproj/xcshareddata/xcschemes/godot_ios.xcscheme"); -// files_to_parse.insert("godot_ios/godot_ios.entitlements"); -// files_to_parse.insert("godot_ios/Launch Screen.storyboard"); - -// IOSConfigData config_data = { -// pkg_name, -// binary_name, -// _get_additional_plist_content(), -// String(" ").join(_get_preset_architectures(p_preset)), -// _get_linker_flags(), -// _get_cpp_code(), -// "", -// "", -// "", -// "", -// Vector() -// }; - -// Vector assets; - -// DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir); -// ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE); - -// print_line("Unzipping..."); -// FileAccess *src_f = nullptr; -// zlib_filefunc_def io = zipio_create_io_from_file(&src_f); -// unzFile src_pkg_zip = unzOpen2(src_pkg_name.utf8().get_data(), &io); -// if (!src_pkg_zip) { -// EditorNode::add_io_error("Could not open export template (not a zip file?):\n" + src_pkg_name); -// return ERR_CANT_OPEN; -// } - -// err = _export_ios_plugins(p_preset, config_data, dest_dir + binary_name, assets, p_debug); -// ERR_FAIL_COND_V(err, err); - -// //export rest of the files -// int ret = unzGoToFirstFile(src_pkg_zip); -// Vector project_file_data; -// while (ret == UNZ_OK) { -//#if defined(OSX_ENABLED) || defined(X11_ENABLED) -// bool is_execute = false; -//#endif - -// //get filename -// unz_file_info info; -// char fname[16384]; -// ret = unzGetCurrentFileInfo(src_pkg_zip, &info, fname, 16384, nullptr, 0, nullptr, 0); - -// String file = fname; - -// print_line("READ: " + file); -// Vector data; -// data.resize(info.uncompressed_size); - -// //read -// unzOpenCurrentFile(src_pkg_zip); -// unzReadCurrentFile(src_pkg_zip, data.ptrw(), data.size()); -// unzCloseCurrentFile(src_pkg_zip); - -// //write - -// file = file.replace_first("iphone/", ""); - -// if (files_to_parse.has(file)) { -// _fix_config_file(p_preset, data, config_data, p_debug); -// } else if (file.begins_with("libgodot.iphone")) { -// if (file != library_to_use) { -// ret = unzGoToNextFile(src_pkg_zip); -// continue; //ignore! -// } -// found_library = true; -//#if defined(OSX_ENABLED) || defined(X11_ENABLED) -// is_execute = true; -//#endif -// file = "godot_ios.a"; -// } - -// if (file == project_file) { -// project_file_data = data; -// } - -// ///@TODO need to parse logo files - -// if (data.size() > 0) { -// file = file.replace("godot_ios", binary_name); - -// print_line("ADDING: " + file + " size: " + itos(data.size())); -// total_size += data.size(); - -// /* write it into our folder structure */ -// file = dest_dir + file; - -// /* make sure this folder exists */ -// String dir_name = file.get_base_dir(); -// if (!tmp_app_path->dir_exists(dir_name)) { -// print_line("Creating " + dir_name); -// Error dir_err = tmp_app_path->make_dir_recursive(dir_name); -// if (dir_err) { -// ERR_PRINT("Can't create '" + dir_name + "'."); -// unzClose(src_pkg_zip); -// memdelete(tmp_app_path); -// return ERR_CANT_CREATE; -// } -// } - -// /* write the file */ -// FileAccess *f = FileAccess::open(file, FileAccess::WRITE); -// if (!f) { -// ERR_PRINT("Can't write '" + file + "'."); -// unzClose(src_pkg_zip); -// memdelete(tmp_app_path); -// return ERR_CANT_CREATE; -// }; -// f->store_buffer(data.ptr(), data.size()); -// f->close(); -// memdelete(f); - -//#if defined(OSX_ENABLED) || defined(X11_ENABLED) -// if (is_execute) { -// // we need execute rights on this file -// chmod(file.utf8().get_data(), 0755); -// } -//#endif -// } - -// ret = unzGoToNextFile(src_pkg_zip); -// } - -// /* we're done with our source zip */ -// unzClose(src_pkg_zip); - -// if (!found_library) { -// ERR_PRINT("Requested template library '" + library_to_use + "' not found. It might be missing from your template archive."); -// memdelete(tmp_app_path); -// return ERR_FILE_NOT_FOUND; -// } - -// // Copy project static libs to the project -// Vector> export_plugins = EditorExport::get_singleton()->get_export_plugins(); -// for (int i = 0; i < export_plugins.size(); i++) { -// Vector project_static_libs = export_plugins[i]->get_ios_project_static_libs(); -// for (int j = 0; j < project_static_libs.size(); j++) { -// const String &static_lib_path = project_static_libs[j]; -// String dest_lib_file_path = dest_dir + static_lib_path.get_file(); -// Error lib_copy_err = tmp_app_path->copy(static_lib_path, dest_lib_file_path); -// if (lib_copy_err != OK) { -// ERR_PRINT("Can't copy '" + static_lib_path + "'."); -// memdelete(tmp_app_path); -// return lib_copy_err; -// } -// } -// } - -// String iconset_dir = dest_dir + binary_name + "/Images.xcassets/AppIcon.appiconset/"; -// err = OK; -// if (!tmp_app_path->dir_exists(iconset_dir)) { -// err = tmp_app_path->make_dir_recursive(iconset_dir); -// } -// memdelete(tmp_app_path); -// if (err) { -// return err; -// } - -// err = _export_icons(p_preset, iconset_dir); -// if (err) { -// return err; -// } - -// bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard"); - -// String launch_image_path = dest_dir + binary_name + "/Images.xcassets/LaunchImage.launchimage/"; -// String splash_image_path = dest_dir + binary_name + "/Images.xcassets/SplashImage.imageset/"; - -// DirAccess *launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - -// if (!launch_screen_da) { -// return ERR_CANT_CREATE; -// } - -// if (use_storyboard) { -// print_line("Using Launch Storyboard"); - -// if (launch_screen_da->change_dir(launch_image_path) == OK) { -// launch_screen_da->erase_contents_recursive(); -// launch_screen_da->remove(launch_image_path); -// } - -// err = _export_loading_screen_file(p_preset, splash_image_path); -// } else { -// print_line("Using Launch Images"); - -// const String launch_screen_path = dest_dir + binary_name + "/Launch Screen.storyboard"; - -// launch_screen_da->remove(launch_screen_path); - -// if (launch_screen_da->change_dir(splash_image_path) == OK) { -// launch_screen_da->erase_contents_recursive(); -// launch_screen_da->remove(splash_image_path); -// } - -// err = _export_loading_screen_images(p_preset, launch_image_path); -// } - -// memdelete(launch_screen_da); - -// if (err) { -// return err; -// } - -// print_line("Exporting additional assets"); -// _export_additional_assets(dest_dir + binary_name, libraries, assets); -// _add_assets_to_project(p_preset, project_file_data, assets); -// String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj"; -// FileAccess *f = FileAccess::open(project_file_name, FileAccess::WRITE); -// if (!f) { -// ERR_PRINT("Can't write '" + project_file_name + "'."); -// return ERR_CANT_CREATE; -// }; -// f->store_buffer(project_file_data.ptr(), project_file_data.size()); -// f->close(); -// memdelete(f); - -//#ifdef OSX_ENABLED -// if (ep.step("Code-signing dylibs", 2)) { -// return ERR_SKIP; -// } -// DirAccess *dylibs_dir = DirAccess::open(dest_dir + binary_name + "/dylibs"); -// ERR_FAIL_COND_V(!dylibs_dir, ERR_CANT_OPEN); -// CodesignData codesign_data(p_preset, p_debug); -// err = _walk_dir_recursive(dylibs_dir, _codesign, &codesign_data); -// memdelete(dylibs_dir); -// ERR_FAIL_COND_V(err, err); - -// if (ep.step("Making .xcarchive", 3)) { -// return ERR_SKIP; -// } -// String archive_path = p_path.get_basename() + ".xcarchive"; -// List archive_args; -// archive_args.push_back("-project"); -// archive_args.push_back(dest_dir + binary_name + ".xcodeproj"); -// archive_args.push_back("-scheme"); -// archive_args.push_back(binary_name); -// archive_args.push_back("-sdk"); -// archive_args.push_back("iphoneos"); -// archive_args.push_back("-configuration"); -// archive_args.push_back(p_debug ? "Debug" : "Release"); -// archive_args.push_back("-destination"); -// archive_args.push_back("generic/platform=iOS"); -// archive_args.push_back("archive"); -// archive_args.push_back("-archivePath"); -// archive_args.push_back(archive_path); -// err = OS::get_singleton()->execute("xcodebuild", archive_args, true); -// ERR_FAIL_COND_V(err, err); - -// if (ep.step("Making .ipa", 4)) { -// return ERR_SKIP; -// } -// List export_args; -// export_args.push_back("-exportArchive"); -// export_args.push_back("-archivePath"); -// export_args.push_back(archive_path); -// export_args.push_back("-exportOptionsPlist"); -// export_args.push_back(dest_dir + binary_name + "/export_options.plist"); -// export_args.push_back("-allowProvisioningUpdates"); -// export_args.push_back("-exportPath"); -// export_args.push_back(dest_dir); -// err = OS::get_singleton()->execute("xcodebuild", export_args, true); -// ERR_FAIL_COND_V(err, err); -//#else -// print_line(".ipa can only be built on macOS. Leaving Xcode project without building the package."); -//#endif - -// return OK; -//} - -//bool EditorExportPlatformIOS::can_export(const Ref &p_preset, String &r_error, bool &r_missing_templates) const { -// String err; -// bool valid = false; - -// // Look for export templates (first official, and if defined custom templates). - -// bool dvalid = exists_export_template("iphone.zip", &err); -// bool rvalid = dvalid; // Both in the same ZIP. - -// if (p_preset->get("custom_template/debug") != "") { -// dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); -// if (!dvalid) { -// err += TTR("Custom debug template not found.") + "\n"; -// } -// } -// if (p_preset->get("custom_template/release") != "") { -// rvalid = FileAccess::exists(p_preset->get("custom_template/release")); -// if (!rvalid) { -// err += TTR("Custom release template not found.") + "\n"; -// } -// } - -// valid = dvalid || rvalid; -// r_missing_templates = !valid; - -// // Validate the rest of the configuration. - -// String team_id = p_preset->get("application/app_store_team_id"); -// if (team_id.length() == 0) { -// err += TTR("App Store Team ID not specified - cannot configure the project.") + "\n"; -// valid = false; -// } - -// String identifier = p_preset->get("application/bundle_identifier"); -// String pn_err; -// if (!is_package_name_valid(identifier, &pn_err)) { -// err += TTR("Invalid Identifier:") + " " + pn_err + "\n"; -// valid = false; -// } - -// for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { -// IconInfo info = icon_infos[i]; -// String icon_path = p_preset->get(info.preset_key); -// if (icon_path.length() == 0) { -// if (info.is_required) { -// err += TTR("Required icon is not specified in the preset.") + "\n"; -// valid = false; -// } -// break; -// } -// } - -// String etc_error = test_etc2_or_pvrtc(); -// if (etc_error != String()) { -// valid = false; -// err += etc_error; -// } - -// if (!err.is_empty()) { -// r_error = err; -// } - -// return valid; -//} - -//EditorExportPlatformIOS::EditorExportPlatformIOS() { -// Ref img = memnew(Image(_iphone_logo)); -// logo.instance(); -// logo->create_from_image(img); - -// plugins_changed = true; -// quit_request = false; - -// check_for_changes_thread = Thread::create(_check_for_changes_poll_thread, this); -//} - -//EditorExportPlatformIOS::~EditorExportPlatformIOS() { -// quit_request = true; -// Thread::wait_to_finish(check_for_changes_thread); -// memdelete(check_for_changes_thread); -//} void register_iphone_exporter() { Ref platform; diff --git a/platform/javascript/display_server_javascript.cpp b/platform/javascript/display_server_javascript.cpp index dacae912b5..c7d68019a1 100644 --- a/platform/javascript/display_server_javascript.cpp +++ b/platform/javascript/display_server_javascript.cpp @@ -691,10 +691,10 @@ DisplayServerJavaScript::DisplayServerJavaScript(const String &p_rendering_drive bool gl_initialization_error = false; - if (RasterizerOpenGLis_viable() == OK) { + if (RasterizerGLES3::is_viable() == OK) { attributes.majorVersion = 1; - RasterizerOpenGLregister_config(); - RasterizerOpenGLmake_current(); + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); } else { gl_initialization_error = true; } diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp index 5130630c18..889b0bbd02 100644 --- a/platform/javascript/export/export.cpp +++ b/platform/javascript/export/export.cpp @@ -32,678 +32,6 @@ #include "export_plugin.h" -/* - -class EditorHTTPServer : public Reference { -private: - Ref server; - Ref connection; - uint64_t time = 0; - uint8_t req_buf[4096]; - int req_pos = 0; - - void _clear_client() { - connection = Ref(); - memset(req_buf, 0, sizeof(req_buf)); - time = 0; - req_pos = 0; - } - -public: - EditorHTTPServer() { - server.instance(); - stop(); - } - - void stop() { - server->stop(); - _clear_client(); - } - - Error listen(int p_port, IP_Address p_address) { - return server->listen(p_port, p_address); - } - - bool is_listening() const { - return server->is_listening(); - } - - void _send_response() { - Vector psa = String((char *)req_buf).split("\r\n"); - int len = psa.size(); - ERR_FAIL_COND_MSG(len < 4, "Not enough response headers, got: " + itos(len) + ", expected >= 4."); - - Vector req = psa[0].split(" ", false); - ERR_FAIL_COND_MSG(req.size() < 2, "Invalid protocol or status code."); - - // Wrong protocol - ERR_FAIL_COND_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", "Invalid method or HTTP version."); - - const String cache_path = EditorSettings::get_singleton()->get_cache_dir(); - const String basereq = "/tmp_js_export"; - String filepath; - String ctype; - if (req[1] == basereq + ".html") { - filepath = cache_path.plus_file(req[1].get_file()); - ctype = "text/html"; - } else if (req[1] == basereq + ".js") { - filepath = cache_path.plus_file(req[1].get_file()); - ctype = "application/javascript"; - } else if (req[1] == basereq + ".audio.worklet.js") { - filepath = cache_path.plus_file(req[1].get_file()); - ctype = "application/javascript"; - } else if (req[1] == basereq + ".worker.js") { - filepath = cache_path.plus_file(req[1].get_file()); - ctype = "application/javascript"; - } else if (req[1] == basereq + ".pck") { - filepath = cache_path.plus_file(req[1].get_file()); - ctype = "application/octet-stream"; - } else if (req[1] == basereq + ".png" || req[1] == "/favicon.png") { - // Also allow serving the generated favicon for a smoother loading experience. - if (req[1] == "/favicon.png") { - filepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png"); - } else { - filepath = basereq + ".png"; - } - ctype = "image/png"; - } else if (req[1] == basereq + ".side.wasm") { - filepath = cache_path.plus_file(req[1].get_file()); - ctype = "application/wasm"; - } else if (req[1] == basereq + ".wasm") { - filepath = cache_path.plus_file(req[1].get_file()); - ctype = "application/wasm"; - } else if (req[1].ends_with(".wasm")) { - filepath = cache_path.plus_file(req[1].get_file()); // TODO dangerous? - ctype = "application/wasm"; - } - if (filepath.is_empty() || !FileAccess::exists(filepath)) { - String s = "HTTP/1.1 404 Not Found\r\n"; - s += "Connection: Close\r\n"; - s += "\r\n"; - CharString cs = s.utf8(); - connection->put_data((const uint8_t *)cs.get_data(), cs.size() - 1); - return; - } - FileAccess *f = FileAccess::open(filepath, FileAccess::READ); - ERR_FAIL_COND(!f); - String s = "HTTP/1.1 200 OK\r\n"; - s += "Connection: Close\r\n"; - s += "Content-Type: " + ctype + "\r\n"; - s += "Access-Control-Allow-Origin: *\r\n"; - s += "Cross-Origin-Opener-Policy: same-origin\r\n"; - s += "Cross-Origin-Embedder-Policy: require-corp\r\n"; - s += "\r\n"; - CharString cs = s.utf8(); - Error err = connection->put_data((const uint8_t *)cs.get_data(), cs.size() - 1); - if (err != OK) { - memdelete(f); - ERR_FAIL(); - } - - while (true) { - uint8_t bytes[4096]; - int read = f->get_buffer(bytes, 4096); - if (read < 1) { - break; - } - err = connection->put_data(bytes, read); - if (err != OK) { - memdelete(f); - ERR_FAIL(); - } - } - memdelete(f); - } - - void poll() { - if (!server->is_listening()) { - return; - } - if (connection.is_null()) { - if (!server->is_connection_available()) { - return; - } - connection = server->take_connection(); - time = OS::get_singleton()->get_ticks_usec(); - } - if (OS::get_singleton()->get_ticks_usec() - time > 1000000) { - _clear_client(); - return; - } - if (connection->get_status() != StreamPeerTCP::STATUS_CONNECTED) { - return; - } - - while (true) { - char *r = (char *)req_buf; - int l = req_pos - 1; - if (l > 3 && r[l] == '\n' && r[l - 1] == '\r' && r[l - 2] == '\n' && r[l - 3] == '\r') { - _send_response(); - _clear_client(); - return; - } - - int read = 0; - ERR_FAIL_COND(req_pos >= 4096); - Error err = connection->get_partial_data(&req_buf[req_pos], 1, read); - if (err != OK) { - // Got an error - _clear_client(); - return; - } else if (read != 1) { - // Busy, wait next poll - return; - } - req_pos += read; - } - } -}; - -class EditorExportPlatformJavaScript : public EditorExportPlatform { - GDCLASS(EditorExportPlatformJavaScript, EditorExportPlatform); - - Ref logo; - Ref run_icon; - Ref stop_icon; - int menu_options = 0; - - Ref server; - bool server_quit = false; - Mutex server_lock; - Thread *server_thread = nullptr; - - enum ExportMode { - EXPORT_MODE_NORMAL = 0, - EXPORT_MODE_THREADS = 1, - EXPORT_MODE_GDNATIVE = 2, - }; - - String _get_template_name(ExportMode p_mode, bool p_debug) const { - String name = "webassembly"; - switch (p_mode) { - case EXPORT_MODE_THREADS: - name += "_threads"; - break; - case EXPORT_MODE_GDNATIVE: - name += "_gdnative"; - break; - default: - break; - } - if (p_debug) { - name += "_debug.zip"; - } else { - name += "_release.zip"; - } - return name; - } - - void _fix_html(Vector &p_html, const Ref &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector p_shared_objects); - - static void _server_thread_poll(void *data); - -public: - virtual void get_preset_features(const Ref &p_preset, List *r_features) override; - - virtual void get_export_options(List *r_options) override; - - virtual String get_name() const override; - virtual String get_os_name() const override; - virtual Ref get_logo() const override; - - virtual bool can_export(const Ref &p_preset, String &r_error, bool &r_missing_templates) const override; - virtual List get_binary_extensions(const Ref &p_preset) const override; - virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; - - virtual bool poll_export() override; - virtual int get_options_count() const override; - virtual String get_option_label(int p_index) const override { return p_index ? TTR("Stop HTTP Server") : TTR("Run in Browser"); } - virtual String get_option_tooltip(int p_index) const override { return p_index ? TTR("Stop HTTP Server") : TTR("Run exported HTML in the system's default browser."); } - virtual Ref get_option_icon(int p_index) const override; - virtual Error run(const Ref &p_preset, int p_option, int p_debug_flags) override; - virtual Ref get_run_icon() const override; - - virtual void get_platform_features(List *r_features) override { - r_features->push_back("web"); - r_features->push_back(get_os_name()); - } - - virtual void resolve_platform_feature_priorities(const Ref &p_preset, Set &p_features) override { - } - - String get_debug_protocol() const override { return "ws://"; } - - EditorExportPlatformJavaScript(); - ~EditorExportPlatformJavaScript(); -}; - -void EditorExportPlatformJavaScript::_fix_html(Vector &p_html, const Ref &p_preset, const String &p_name, bool p_debug, int p_flags, const Vector p_shared_objects) { - String str_template = String::utf8(reinterpret_cast(p_html.ptr()), p_html.size()); - String str_export; - Vector lines = str_template.split("\n"); - Vector flags; - String flags_json; - gen_export_flags(flags, p_flags); - flags_json = JSON::print(flags); - String libs; - for (int i = 0; i < p_shared_objects.size(); i++) { - libs += "\"" + p_shared_objects[i].path.get_file() + "\","; - } - - for (int i = 0; i < lines.size(); i++) { - String current_line = lines[i]; - current_line = current_line.replace("$GODOT_BASENAME", p_name); - current_line = current_line.replace("$GODOT_PROJECT_NAME", ProjectSettings::get_singleton()->get_setting("application/config/name")); - current_line = current_line.replace("$GODOT_HEAD_INCLUDE", p_preset->get("html/head_include")); - current_line = current_line.replace("$GODOT_FULL_WINDOW", p_preset->get("html/full_window_size") ? "true" : "false"); - current_line = current_line.replace("$GODOT_GDNATIVE_LIBS", libs); - current_line = current_line.replace("$GODOT_DEBUG_ENABLED", p_debug ? "true" : "false"); - current_line = current_line.replace("$GODOT_ARGS", flags_json); - str_export += current_line + "\n"; - } - - CharString cs = str_export.utf8(); - p_html.resize(cs.length()); - for (int i = 0; i < cs.length(); i++) { - p_html.write[i] = cs[i]; - } -} - -void EditorExportPlatformJavaScript::get_preset_features(const Ref &p_preset, List *r_features) { - if (p_preset->get("vram_texture_compression/for_desktop")) { - r_features->push_back("s3tc"); - } - - if (p_preset->get("vram_texture_compression/for_mobile")) { - String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "OpenGL") { - r_features->push_back("etc"); - } else if (driver == "Vulkan") { - // FIXME: Review if this is correct. - r_features->push_back("etc2"); - } - } - ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); - if (mode == EXPORT_MODE_THREADS) { - r_features->push_back("threads"); - } else if (mode == EXPORT_MODE_GDNATIVE) { - r_features->push_back("wasm32"); - } -} - -void EditorExportPlatformJavaScript::get_export_options(List *r_options) { - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/debug", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "custom_template/release", PROPERTY_HINT_GLOBAL_FILE, "*.zip"), "")); - - r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "variant/export_type", PROPERTY_HINT_ENUM, "Regular,Threads,GDNative"), 0)); // Export type. - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_desktop"), true)); // S3TC - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "vram_texture_compression/for_mobile"), false)); // ETC or ETC2, depending on renderer - - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/custom_html_shell", PROPERTY_HINT_FILE, "*.html"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "html/head_include", PROPERTY_HINT_MULTILINE_TEXT), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "html/full_window_size"), true)); -} - -String EditorExportPlatformJavaScript::get_name() const { - return "HTML5"; -} - -String EditorExportPlatformJavaScript::get_os_name() const { - return "HTML5"; -} - -Ref EditorExportPlatformJavaScript::get_logo() const { - return logo; -} - -bool EditorExportPlatformJavaScript::can_export(const Ref &p_preset, String &r_error, bool &r_missing_templates) const { - String err; - bool valid = false; - ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); - - // Look for export templates (first official, and if defined custom templates). - bool dvalid = exists_export_template(_get_template_name(mode, true), &err); - bool rvalid = exists_export_template(_get_template_name(mode, false), &err); - - if (p_preset->get("custom_template/debug") != "") { - dvalid = FileAccess::exists(p_preset->get("custom_template/debug")); - if (!dvalid) { - err += TTR("Custom debug template not found.") + "\n"; - } - } - if (p_preset->get("custom_template/release") != "") { - rvalid = FileAccess::exists(p_preset->get("custom_template/release")); - if (!rvalid) { - err += TTR("Custom release template not found.") + "\n"; - } - } - - valid = dvalid || rvalid; - r_missing_templates = !valid; - - // Validate the rest of the configuration. - - if (p_preset->get("vram_texture_compression/for_mobile")) { - String etc_error = test_etc2(); - if (etc_error != String()) { - valid = false; - err += etc_error; - } - } - - if (!err.is_empty()) { - r_error = err; - } - - return valid; -} - -List EditorExportPlatformJavaScript::get_binary_extensions(const Ref &p_preset) const { - List list; - list.push_back("html"); - return list; -} - -Error EditorExportPlatformJavaScript::export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags) { - ExportNotifier notifier(*this, p_preset, p_debug, p_path, p_flags); - - String custom_debug = p_preset->get("custom_template/debug"); - String custom_release = p_preset->get("custom_template/release"); - String custom_html = p_preset->get("html/custom_html_shell"); - - String template_path = p_debug ? custom_debug : custom_release; - - template_path = template_path.strip_edges(); - - if (template_path == String()) { - ExportMode mode = (ExportMode)(int)p_preset->get("variant/export_type"); - template_path = find_export_template(_get_template_name(mode, p_debug)); - } - - if (!DirAccess::exists(p_path.get_base_dir())) { - return ERR_FILE_BAD_PATH; - } - - if (template_path != String() && !FileAccess::exists(template_path)) { - EditorNode::get_singleton()->show_warning(TTR("Template file not found:") + "\n" + template_path); - return ERR_FILE_NOT_FOUND; - } - - Vector shared_objects; - String pck_path = p_path.get_basename() + ".pck"; - Error error = save_pack(p_preset, pck_path, &shared_objects); - if (error != OK) { - EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + pck_path); - return error; - } - DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - for (int i = 0; i < shared_objects.size(); i++) { - String dst = p_path.get_base_dir().plus_file(shared_objects[i].path.get_file()); - error = da->copy(shared_objects[i].path, dst); - if (error != OK) { - EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + shared_objects[i].path.get_file()); - memdelete(da); - return error; - } - } - memdelete(da); - - FileAccess *src_f = nullptr; - zlib_filefunc_def io = zipio_create_io_from_file(&src_f); - unzFile pkg = unzOpen2(template_path.utf8().get_data(), &io); - - if (!pkg) { - EditorNode::get_singleton()->show_warning(TTR("Could not open template for export:") + "\n" + template_path); - return ERR_FILE_NOT_FOUND; - } - - if (unzGoToFirstFile(pkg) != UNZ_OK) { - EditorNode::get_singleton()->show_warning(TTR("Invalid export template:") + "\n" + template_path); - unzClose(pkg); - return ERR_FILE_CORRUPT; - } - - do { - //get filename - unz_file_info info; - char fname[16384]; - unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0); - - String file = fname; - - Vector data; - data.resize(info.uncompressed_size); - - //read - unzOpenCurrentFile(pkg); - unzReadCurrentFile(pkg, data.ptrw(), data.size()); - unzCloseCurrentFile(pkg); - - //write - - if (file == "godot.html") { - if (!custom_html.is_empty()) { - continue; - } - _fix_html(data, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects); - file = p_path.get_file(); - - } else if (file == "godot.js") { - file = p_path.get_file().get_basename() + ".js"; - - } else if (file == "godot.worker.js") { - file = p_path.get_file().get_basename() + ".worker.js"; - - } else if (file == "godot.side.wasm") { - file = p_path.get_file().get_basename() + ".side.wasm"; - - } else if (file == "godot.audio.worklet.js") { - file = p_path.get_file().get_basename() + ".audio.worklet.js"; - - } else if (file == "godot.wasm") { - file = p_path.get_file().get_basename() + ".wasm"; - } - - String dst = p_path.get_base_dir().plus_file(file); - FileAccess *f = FileAccess::open(dst, FileAccess::WRITE); - if (!f) { - EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + dst); - unzClose(pkg); - return ERR_FILE_CANT_WRITE; - } - f->store_buffer(data.ptr(), data.size()); - memdelete(f); - - } while (unzGoToNextFile(pkg) == UNZ_OK); - unzClose(pkg); - - if (!custom_html.is_empty()) { - FileAccess *f = FileAccess::open(custom_html, FileAccess::READ); - if (!f) { - EditorNode::get_singleton()->show_warning(TTR("Could not read custom HTML shell:") + "\n" + custom_html); - return ERR_FILE_CANT_READ; - } - Vector buf; - buf.resize(f->get_len()); - f->get_buffer(buf.ptrw(), buf.size()); - memdelete(f); - _fix_html(buf, p_preset, p_path.get_file().get_basename(), p_debug, p_flags, shared_objects); - - f = FileAccess::open(p_path, FileAccess::WRITE); - if (!f) { - EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + p_path); - return ERR_FILE_CANT_WRITE; - } - f->store_buffer(buf.ptr(), buf.size()); - memdelete(f); - } - - Ref splash; - const String splash_path = String(GLOBAL_GET("application/boot_splash/image")).strip_edges(); - if (!splash_path.is_empty()) { - splash.instance(); - const Error err = splash->load(splash_path); - if (err) { - EditorNode::get_singleton()->show_warning(TTR("Could not read boot splash image file:") + "\n" + splash_path + "\n" + TTR("Using default boot splash image.")); - splash.unref(); - } - } - if (splash.is_null()) { - splash = Ref(memnew(Image(boot_splash_png))); - } - const String splash_png_path = p_path.get_base_dir().plus_file(p_path.get_file().get_basename() + ".png"); - if (splash->save_png(splash_png_path) != OK) { - EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + splash_png_path); - return ERR_FILE_CANT_WRITE; - } - - // Save a favicon that can be accessed without waiting for the project to finish loading. - // This way, the favicon can be displayed immediately when loading the page. - Ref favicon; - const String favicon_path = String(GLOBAL_GET("application/config/icon")).strip_edges(); - if (!favicon_path.is_empty()) { - favicon.instance(); - const Error err = favicon->load(favicon_path); - if (err) { - favicon.unref(); - } - } - - if (favicon.is_valid()) { - const String favicon_png_path = p_path.get_base_dir().plus_file("favicon.png"); - if (favicon->save_png(favicon_png_path) != OK) { - EditorNode::get_singleton()->show_warning(TTR("Could not write file:") + "\n" + favicon_png_path); - return ERR_FILE_CANT_WRITE; - } - } - - return OK; -} - -bool EditorExportPlatformJavaScript::poll_export() { - Ref preset; - - for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) { - Ref ep = EditorExport::get_singleton()->get_export_preset(i); - if (ep->is_runnable() && ep->get_platform() == this) { - preset = ep; - break; - } - } - - int prev = menu_options; - menu_options = preset.is_valid(); - if (server->is_listening()) { - if (menu_options == 0) { - MutexLock lock(server_lock); - server->stop(); - } else { - menu_options += 1; - } - } - return menu_options != prev; -} - -Ref EditorExportPlatformJavaScript::get_option_icon(int p_index) const { - return p_index == 1 ? stop_icon : EditorExportPlatform::get_option_icon(p_index); -} - -int EditorExportPlatformJavaScript::get_options_count() const { - return menu_options; -} - -Error EditorExportPlatformJavaScript::run(const Ref &p_preset, int p_option, int p_debug_flags) { - if (p_option == 1) { - MutexLock lock(server_lock); - server->stop(); - return OK; - } - - const String basepath = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp_js_export"); - Error err = export_project(p_preset, true, basepath + ".html", p_debug_flags); - if (err != OK) { - // Export generates several files, clean them up on failure. - DirAccess::remove_file_or_error(basepath + ".html"); - DirAccess::remove_file_or_error(basepath + ".js"); - DirAccess::remove_file_or_error(basepath + ".worker.js"); - DirAccess::remove_file_or_error(basepath + ".audio.worklet.js"); - DirAccess::remove_file_or_error(basepath + ".pck"); - DirAccess::remove_file_or_error(basepath + ".png"); - DirAccess::remove_file_or_error(basepath + ".side.wasm"); - DirAccess::remove_file_or_error(basepath + ".wasm"); - DirAccess::remove_file_or_error(EditorSettings::get_singleton()->get_cache_dir().plus_file("favicon.png")); - return err; - } - - const uint16_t bind_port = EDITOR_GET("export/web/http_port"); - // Resolve host if needed. - const String bind_host = EDITOR_GET("export/web/http_host"); - IP_Address bind_ip; - if (bind_host.is_valid_ip_address()) { - bind_ip = bind_host; - } else { - bind_ip = IP::get_singleton()->resolve_hostname(bind_host); - } - ERR_FAIL_COND_V_MSG(!bind_ip.is_valid(), ERR_INVALID_PARAMETER, "Invalid editor setting 'export/web/http_host': '" + bind_host + "'. Try using '127.0.0.1'."); - - // Restart server. - { - MutexLock lock(server_lock); - - server->stop(); - err = server->listen(bind_port, bind_ip); - } - ERR_FAIL_COND_V_MSG(err != OK, err, "Unable to start HTTP server."); - - OS::get_singleton()->shell_open(String("http://" + bind_host + ":" + itos(bind_port) + "/tmp_js_export.html")); - // FIXME: Find out how to clean up export files after running the successfully - // exported game. Might not be trivial. - return OK; -} - -Ref EditorExportPlatformJavaScript::get_run_icon() const { - return run_icon; -} - -void EditorExportPlatformJavaScript::_server_thread_poll(void *data) { - EditorExportPlatformJavaScript *ej = (EditorExportPlatformJavaScript *)data; - while (!ej->server_quit) { - OS::get_singleton()->delay_usec(1000); - { - MutexLock lock(ej->server_lock); - ej->server->poll(); - } - } -} - -EditorExportPlatformJavaScript::EditorExportPlatformJavaScript() { - server.instance(); - server_thread = Thread::create(_server_thread_poll, this); - - Ref img = memnew(Image(_javascript_logo)); - logo.instance(); - logo->create_from_image(img); - - img = Ref(memnew(Image(_javascript_run_icon))); - run_icon.instance(); - run_icon->create_from_image(img); - - Ref theme = EditorNode::get_singleton()->get_editor_theme(); - if (theme.is_valid()) { - stop_icon = theme->get_icon("Stop", "EditorIcons"); - } else { - stop_icon.instance(); - } -} - -EditorExportPlatformJavaScript::~EditorExportPlatformJavaScript() { - server->stop(); - server_quit = true; - Thread::wait_to_finish(server_thread); - memdelete(server_thread); -} - -*/ void register_javascript_exporter() { EDITOR_DEF("export/web/http_host", "localhost"); EDITOR_DEF("export/web/http_port", 8060); diff --git a/platform/javascript/export/export_plugin.cpp b/platform/javascript/export/export_plugin.cpp index b98e87e789..b4f93b9b44 100644 --- a/platform/javascript/export/export_plugin.cpp +++ b/platform/javascript/export/export_plugin.cpp @@ -300,7 +300,7 @@ void EditorExportPlatformJavaScript::get_preset_features(const Refget("vram_texture_compression/for_mobile")) { String driver = ProjectSettings::get_singleton()->get("rendering/driver/driver_name"); - if (driver == "OpenGL") { + if (driver == "OpenGL3") { r_features->push_back("etc"); } else if (driver == "Vulkan") { // FIXME: Review if this is correct. diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index 04da082b16..a9e8fb64c3 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -381,7 +381,7 @@ def configure(env): # No pkgconfig file for glslang so far env.Append(LIBS=["glslang", "SPIRV"]) - env.Append(CPPDEFINES=["OPENGL_ENABLED"]) + env.Append(CPPDEFINES=["GLES3_ENABLED"]) env.Append(LIBS=["GL"]) env.Append(LIBS=["pthread"]) diff --git a/platform/linuxbsd/detect_prime_x11.cpp b/platform/linuxbsd/detect_prime_x11.cpp index f074c9e9d8..c775546f15 100644 --- a/platform/linuxbsd/detect_prime_x11.cpp +++ b/platform/linuxbsd/detect_prime_x11.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #ifdef X11_ENABLED -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) #include "detect_prime_x11.h" diff --git a/platform/linuxbsd/detect_prime_x11.h b/platform/linuxbsd/detect_prime_x11.h index 0b548b849e..88d00b3acd 100644 --- a/platform/linuxbsd/detect_prime_x11.h +++ b/platform/linuxbsd/detect_prime_x11.h @@ -29,7 +29,7 @@ /*************************************************************************/ #ifdef X11_ENABLED -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) int detect_prime(); diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp index 4421c868d8..d00a5794ca 100644 --- a/platform/linuxbsd/display_server_x11.cpp +++ b/platform/linuxbsd/display_server_x11.cpp @@ -44,8 +44,8 @@ #include "servers/rendering/renderer_rd/renderer_compositor_rd.h" #endif -#if defined(OPENGL_ENABLED) -#include "drivers/opengl/rasterizer_opengl.h" +#if defined(GLES3_ENABLED) +#include "drivers/gles3/rasterizer_gles3.h" #endif #include @@ -889,7 +889,7 @@ void DisplayServerX11::delete_sub_window(WindowID p_id) { context_vulkan->window_destroy(p_id); } #endif -#ifdef OPENGL_ENABLED +#ifdef GLES3_ENABLED if (gl_manager) { gl_manager->window_destroy(p_id); } @@ -1064,7 +1064,7 @@ int DisplayServerX11::window_get_current_screen(WindowID p_window) const { } void DisplayServerX11::gl_window_make_current(DisplayServer::WindowID p_window_id) { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (gl_manager) gl_manager->window_make_current(p_window_id); #endif @@ -2666,7 +2666,7 @@ void DisplayServerX11::_window_changed(XEvent *event) { context_vulkan->window_resize(window_id, wd.size.width, wd.size.height); } #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->window_resize(window_id, wd.size.width, wd.size.height); } @@ -3547,19 +3547,19 @@ void DisplayServerX11::process_events() { } void DisplayServerX11::release_rendering_thread() { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) // gl_manager->release_current(); #endif } void DisplayServerX11::make_rendering_thread() { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) // gl_manager->make_current(); #endif } void DisplayServerX11::swap_buffers() { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->swap_buffers(); } @@ -3710,7 +3710,7 @@ void DisplayServerX11::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo } #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (gl_manager) { gl_manager->set_use_vsync(p_vsync_mode == DisplayServer::VSYNC_ENABLED); } @@ -3724,7 +3724,7 @@ DisplayServer::VSyncMode DisplayServerX11::window_get_vsync_mode(WindowID p_wind return context_vulkan->get_vsync_mode(p_window); } #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (gl_manager) { return gl_manager->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED; } @@ -3738,8 +3738,8 @@ Vector DisplayServerX11::get_rendering_drivers_func() { #ifdef VULKAN_ENABLED drivers.push_back("vulkan"); #endif -#ifdef OPENGL_ENABLED - drivers.push_back("opengl"); +#ifdef GLES3_ENABLED + drivers.push_back("opengl3"); #endif return drivers; @@ -3924,8 +3924,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create a Vulkan window"); } #endif -#ifdef OPENGL_ENABLED - print_line("rendering_driver " + rendering_driver); +#ifdef GLES3_ENABLED if (gl_manager) { Error err = gl_manager->window_create(id, wd.x11_window, x11_display, p_rect.size.width, p_rect.size.height); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL window"); @@ -4115,11 +4114,6 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode //TODO - do Vulkan and OpenGL support checks, driver selection and fallback rendering_driver = p_rendering_driver; -#ifndef _MSC_VER -//#warning Forcing vulkan rendering driver because OpenGL not implemented yet -//#warning Forcing opengl rendering driver because selecting properly is too much effort -#endif - bool driver_found = false; #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { @@ -4133,10 +4127,9 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode driver_found = true; } #endif - // Init context and rendering device -#if defined(OPENGL_ENABLED) - print_line("rendering_driver " + rendering_driver); - if (rendering_driver == "opengl") { + // Initialize context and rendering device. +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { if (getenv("DRI_PRIME") == nullptr) { int use_prime = -1; @@ -4193,9 +4186,9 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode // gl_manager->set_use_vsync(current_videomode.use_vsync); if (true) { - // if (RasterizerOpenGL::is_viable() == OK) { - // RasterizerOpenGL::register_config(); - RasterizerOpenGL::make_current(); + // if (RasterizerGLES3::is_viable() == OK) { + // RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); } else { memdelete(gl_manager); gl_manager = nullptr; @@ -4411,8 +4404,8 @@ DisplayServerX11::~DisplayServerX11() { context_vulkan->window_destroy(E.key); } #endif -#ifdef OPENGL_ENABLED - if (rendering_driver == "opengl") { +#ifdef GLES3_ENABLED + if (rendering_driver == "opengl3") { gl_manager->window_destroy(E.key); } #endif @@ -4440,7 +4433,7 @@ DisplayServerX11::~DisplayServerX11() { } #endif -#ifdef OPENGL_ENABLED +#ifdef GLES3_ENABLED if (gl_manager) { memdelete(gl_manager); gl_manager = nullptr; diff --git a/platform/linuxbsd/display_server_x11.h b/platform/linuxbsd/display_server_x11.h index ba25829974..869ff386c5 100644 --- a/platform/linuxbsd/display_server_x11.h +++ b/platform/linuxbsd/display_server_x11.h @@ -31,7 +31,7 @@ #ifndef DISPLAY_SERVER_X11_H #define DISPLAY_SERVER_X11_H -#include "drivers/opengl/rasterizer_platforms.h" +#include "drivers/gles3/rasterizer_platforms.h" #ifdef X11_ENABLED @@ -48,7 +48,7 @@ #include "servers/rendering/renderer_compositor.h" #include "servers/rendering_server.h" -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) #include "gl_manager_x11.h" #endif @@ -101,7 +101,7 @@ class DisplayServerX11 : public DisplayServer { Atom requested; int xdnd_version; -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) GLManager_X11 *gl_manager = nullptr; #endif #if defined(VULKAN_ENABLED) diff --git a/platform/linuxbsd/gl_manager_x11.cpp b/platform/linuxbsd/gl_manager_x11.cpp index 5928ff3147..e069e92ee6 100644 --- a/platform/linuxbsd/gl_manager_x11.cpp +++ b/platform/linuxbsd/gl_manager_x11.cpp @@ -31,7 +31,7 @@ #include "gl_manager_x11.h" #ifdef X11_ENABLED -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) #include #include @@ -175,12 +175,10 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { switch (context_type) { case GLES_3_0_COMPATIBLE: { - // FIXME: Use `GLX_CONTEXT_CORE_PROFILE_BIT_ARB` instead of compatibility profile - // once deprecated API usages are fixed. static int context_attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*|GLX_CONTEXT_DEBUG_BIT_ARB*/, None }; @@ -207,8 +205,6 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) { } Error GLManager_X11::window_create(DisplayServer::WindowID p_window_id, ::Window p_window, Display *p_display, int p_width, int p_height) { - print_line("window_create window id " + itos(p_window_id)); - // make sure vector is big enough... // we can mirror the external vector, it is simpler // to keep the IDs identical for fast lookup diff --git a/platform/linuxbsd/gl_manager_x11.h b/platform/linuxbsd/gl_manager_x11.h index e2e2545f3e..fa2c8a9c84 100644 --- a/platform/linuxbsd/gl_manager_x11.h +++ b/platform/linuxbsd/gl_manager_x11.h @@ -33,9 +33,9 @@ #ifdef X11_ENABLED -#include "drivers/opengl/rasterizer_platforms.h" +#include "drivers/gles3/rasterizer_platforms.h" -#ifdef OPENGL_ENABLED +#ifdef GLES3_ENABLED #include "core/os/os.h" #include "core/templates/local_vector.h" @@ -124,7 +124,7 @@ public: ~GLManager_X11(); }; -#endif // OPENGL_ENABLED +#endif // GLES3_ENABLED #endif // X11_ENABLED #endif // GL_MANAGER_X11_H diff --git a/platform/osx/context_gl_osx.h b/platform/osx/context_gl_osx.h index ac45559217..77bae3247d 100644 --- a/platform/osx/context_gl_osx.h +++ b/platform/osx/context_gl_osx.h @@ -31,7 +31,7 @@ #ifndef CONTEXT_GL_OSX_H #define CONTEXT_GL_OSX_H -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) +#if defined(GLES3_ENABLED) || defined(GLES_ENABLED) #include "core/error/error_list.h" #include "core/os/os.h" @@ -41,7 +41,7 @@ #include class ContextGL_OSX { - bool opengl_3_context; + bool gles3_context; bool use_vsync; void *framework; @@ -66,7 +66,7 @@ public: void set_use_vsync(bool p_use); bool is_using_vsync() const; - ContextGL_OSX(id p_view, bool p_opengl_3_context); + ContextGL_OSX(id p_view, bool p_gles3_context); ~ContextGL_OSX(); }; diff --git a/platform/osx/context_gl_osx.mm b/platform/osx/context_gl_osx.mm index 88db1a296e..eab9d8dc0c 100644 --- a/platform/osx/context_gl_osx.mm +++ b/platform/osx/context_gl_osx.mm @@ -30,7 +30,7 @@ #include "context_gl_osx.h" -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) +#if defined(GLES3_ENABLED) || defined(GLES_ENABLED) void ContextGL_OSX::release_current() { [NSOpenGLContext clearCurrentContext]; @@ -98,7 +98,7 @@ Error ContextGL_OSX::initialize() { ADD_ATTR(NSOpenGLPFADoubleBuffer); ADD_ATTR(NSOpenGLPFAClosestPolicy); - if (!opengl_3_context) { + if (!gles3_context) { ADD_ATTR2(NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersionLegacy); } else { //we now need OpenGL 3 or better, maybe even change this to 3_3Core ? @@ -150,8 +150,8 @@ Error ContextGL_OSX::initialize() { return OK; } -ContextGL_OSX::ContextGL_OSX(id p_view, bool p_opengl_3_context) { - opengl_3_context = p_opengl_3_context; +ContextGL_OSX::ContextGL_OSX(id p_view, bool p_gles3_context) { + gles3_context = p_gles3_context; window_view = p_view; use_vsync = false; } diff --git a/platform/osx/detect.py b/platform/osx/detect.py index 6c07c2416e..d9b55631cd 100644 --- a/platform/osx/detect.py +++ b/platform/osx/detect.py @@ -189,4 +189,4 @@ def configure(env): if not env["use_volk"]: env.Append(LINKFLAGS=["-L$VULKAN_SDK_PATH/MoltenVK/MoltenVK.xcframework/macos-arm64_x86_64/", "-lMoltenVK"]) - # env.Append(CPPDEFINES=['GLES_ENABLED', 'OPENGL_ENABLED']) + # env.Append(CPPDEFINES=['GLES_ENABLED', 'GLES3_ENABLED']) diff --git a/platform/osx/display_server_osx.h b/platform/osx/display_server_osx.h index e8f2858489..96baeb4dec 100644 --- a/platform/osx/display_server_osx.h +++ b/platform/osx/display_server_osx.h @@ -36,7 +36,7 @@ #include "core/input/input.h" #include "servers/display_server.h" -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) #include "context_gl_osx.h" //TODO - reimplement OpenGLES #endif @@ -64,7 +64,7 @@ public: NSMenu *_get_dock_menu() const; void _menu_callback(id p_sender); -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) ContextGL_OSX *context_gles2; #endif #if defined(VULKAN_ENABLED) @@ -109,7 +109,7 @@ public: Vector mpath; -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) ContextGL_OSX *context_gles2 = nullptr; #endif Point2i mouse_pos; diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index b9d47a757c..d89e64cd7d 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -45,7 +45,7 @@ #include #include -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) //TODO - reimplement OpenGLES #import @@ -166,7 +166,7 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { [pwd.window_object makeKeyAndOrderFront:nil]; // Move focus back to main window if there is no parent or other windows left. } -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (DS_OSX->rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } @@ -271,7 +271,7 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { layer.contentsScale = scale; } -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (DS_OSX->rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } @@ -405,7 +405,7 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (CALayer *)makeBackingLayer { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (DS_OSX->rendering_driver == "opengl_es") { CALayer *layer = [[NSOpenGLLayer class] layer]; return layer; @@ -421,7 +421,7 @@ static NSCursor *_cursorFromSelector(SEL selector, SEL fallback = nil) { } - (void)updateLayer { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (DS_OSX->rendering_driver == "opengl_es") { [super updateLayer]; //TODO - reimplement OpenGLES @@ -2586,7 +2586,7 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled //TODO - implement transparency for Vulkan } #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } @@ -2605,14 +2605,14 @@ void DisplayServerOSX::_set_window_per_pixel_transparency_enabled(bool p_enabled //TODO - implement transparency for Vulkan } #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } #endif wd.layered_window = false; } -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } @@ -3475,7 +3475,7 @@ Vector DisplayServerOSX::get_rendering_drivers_func() { #if defined(VULKAN_ENABLED) drivers.push_back("vulkan"); #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) drivers.push_back("opengl_es"); #endif @@ -3579,7 +3579,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V } } #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } @@ -3600,7 +3600,7 @@ DisplayServerOSX::WindowID DisplayServerOSX::_create_window(WindowMode p_mode, V layer.contentsScale = scale; } -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } @@ -3758,7 +3758,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode #endif rendering_driver = "vulkan"; -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } @@ -3787,7 +3787,7 @@ DisplayServerOSX::DisplayServerOSX(const String &p_rendering_driver, WindowMode } show_window(MAIN_WINDOW_ID); -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } @@ -3820,7 +3820,7 @@ DisplayServerOSX::~DisplayServerOSX() { } //destroy drivers -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) if (rendering_driver == "opengl_es") { //TODO - reimplement OpenGLES } diff --git a/platform/uwp/os_uwp.cpp b/platform/uwp/os_uwp.cpp index 2d355f5f42..1114f5359a 100644 --- a/platform/uwp/os_uwp.cpp +++ b/platform/uwp/os_uwp.cpp @@ -175,9 +175,9 @@ Error OS_UWP::initialize(const VideoMode &p_desired, int p_video_driver, int p_a } if (opengl_api_type == ContextEGL_UWP::GLES_2_0) { - if (RasterizerOpenGLis_viable() == OK) { - RasterizerOpenGLregister_config(); - RasterizerOpenGLmake_current(); + if (RasterizerGLES3::is_viable() == OK) { + RasterizerGLES3::register_config(); + RasterizerGLES3::make_current(); } else { gl_initialization_error = true; } @@ -319,7 +319,7 @@ void OS_UWP::finalize() { rendering_server->finish(); memdelete(rendering_server); -#ifdef OPENGL_ENABLED +#ifdef GLES3_ENABLED if (gl_context) memdelete(gl_context); #endif diff --git a/platform/windows/context_gl_windows.cpp b/platform/windows/context_gl_windows.cpp deleted file mode 100644 index 74b12cbb3b..0000000000 --- a/platform/windows/context_gl_windows.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/*************************************************************************/ -/* context_gl_windows.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 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. */ -/*************************************************************************/ - -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) - -// Author: Juan Linietsky , (C) 2008 - -#include "context_gl_windows.h" - -#include - -#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 -#define WGL_CONTEXT_FLAGS_ARB 0x2094 -#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002 -#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 -#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 - -#if defined(__GNUC__) -// Workaround GCC warning from -Wcast-function-type. -#define wglGetProcAddress (void *)wglGetProcAddress -#endif - -typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *); - -void ContextGL_Windows::release_current() { - wglMakeCurrent(hDC, nullptr); -} - -void ContextGL_Windows::make_current() { - wglMakeCurrent(hDC, hRC); -} - -int ContextGL_Windows::get_window_width() { - return OS::get_singleton()->get_video_mode().width; -} - -int ContextGL_Windows::get_window_height() { - return OS::get_singleton()->get_video_mode().height; -} - -void ContextGL_Windows::swap_buffers() { - SwapBuffers(hDC); -} - -void ContextGL_Windows::set_use_vsync(bool p_use) { - if (wglSwapIntervalEXT) { - int swap_interval = p_use ? 1 : 0; - wglSwapIntervalEXT(swap_interval); - } - - use_vsync = p_use; -} - -bool ContextGL_Windows::is_using_vsync() const { - return use_vsync; -} - -#define _WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 - -Error ContextGL_Windows::initialize() { - static PIXELFORMATDESCRIPTOR pfd = { - sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor - 1, - PFD_DRAW_TO_WINDOW | // Format Must Support Window - PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, - (BYTE)PFD_TYPE_RGBA, - (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24), - (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored - (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer - (BYTE)0, // Shift Bit Ignored - (BYTE)0, // No Accumulation Buffer - (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored - (BYTE)24, // 24Bit Z-Buffer (Depth Buffer) - (BYTE)0, // No Stencil Buffer - (BYTE)0, // No Auxiliary Buffer - (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer - (BYTE)0, // Reserved - 0, 0, 0 // Layer Masks Ignored - }; - - hDC = GetDC(hWnd); - if (!hDC) { - return ERR_CANT_CREATE; // Return FALSE - } - - pixel_format = ChoosePixelFormat(hDC, &pfd); - if (!pixel_format) // Did Windows Find A Matching Pixel Format? - { - return ERR_CANT_CREATE; // Return FALSE - } - - BOOL ret = SetPixelFormat(hDC, pixel_format, &pfd); - if (!ret) // Are We Able To Set The Pixel Format? - { - return ERR_CANT_CREATE; // Return FALSE - } - - hRC = wglCreateContext(hDC); - if (!hRC) // Are We Able To Get A Rendering Context? - { - return ERR_CANT_CREATE; // Return FALSE - } - - wglMakeCurrent(hDC, hRC); - - if (opengl_3_context) { - int attribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context - WGL_CONTEXT_MINOR_VERSION_ARB, 3, - //and it shall be forward compatible so that we can only use up to date functionality - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/, - 0 - }; //zero indicates the end of the array - - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method - wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); - - if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported - { - wglDeleteContext(hRC); - return ERR_CANT_CREATE; - } - - HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs); - if (!new_hRC) { - wglDeleteContext(hRC); - return ERR_CANT_CREATE; // Return false - } - wglMakeCurrent(hDC, nullptr); - wglDeleteContext(hRC); - hRC = new_hRC; - - if (!wglMakeCurrent(hDC, hRC)) // Try To Activate The Rendering Context - { - return ERR_CANT_CREATE; // Return FALSE - } - } - - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT"); - //glWrapperInit(wrapper_get_proc_address); - - return OK; -} - -ContextGL_Windows::ContextGL_Windows(HWND hwnd, bool p_opengl_3_context) { - opengl_3_context = p_opengl_3_context; - hWnd = hwnd; - use_vsync = false; - pixel_format = 0; -} - -ContextGL_Windows::~ContextGL_Windows() { -} - -#endif diff --git a/platform/windows/detect.py b/platform/windows/detect.py index 4740181df0..22fbbeb74f 100644 --- a/platform/windows/detect.py +++ b/platform/windows/detect.py @@ -279,7 +279,7 @@ def configure_msvc(env, manual_msvc_config): if not env["use_volk"]: LIBS += ["vulkan"] - env.AppendUnique(CPPDEFINES=["OPENGL_ENABLED"]) + env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"]) LIBS += ["opengl32"] env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS]) @@ -453,7 +453,7 @@ def configure_mingw(env): if not env["use_volk"]: env.Append(LIBS=["vulkan"]) - env.Append(CPPDEFINES=["OPENGL_ENABLED"]) + env.Append(CPPDEFINES=["GLES3_ENABLED"]) env.Append(LIBS=["opengl32"]) env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)]) diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index fda0bb1627..e2c9951692 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -38,8 +38,8 @@ #include -#if defined(OPENGL_ENABLED) -#include "drivers/opengl/rasterizer_opengl.h" +#if defined(GLES3_ENABLED) +#include "drivers/gles3/rasterizer_gles3.h" #endif static String format_error_message(DWORD id) { @@ -537,8 +537,8 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { context_vulkan->window_destroy(p_window); } #endif -#ifdef OPENGL_ENABLED - if (rendering_driver == "opengl") { +#ifdef GLES3_ENABLED + if (rendering_driver == "opengl3") { gl_manager->window_destroy(p_window); } #endif @@ -552,7 +552,7 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) { } void DisplayServerWindows::gl_window_make_current(DisplayServer::WindowID p_window_id) { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) gl_manager->window_make_current(p_window_id); #endif } @@ -827,8 +827,8 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo context_vulkan->window_resize(p_window, w, h); } #endif -#if defined(OPENGL_ENABLED) - if (rendering_driver == "opengl") { +#if defined(GLES3_ENABLED) + if (rendering_driver == "opengl3") { gl_manager->window_resize(p_window, w, h); } #endif @@ -1611,7 +1611,7 @@ void DisplayServerWindows::make_rendering_thread() { } void DisplayServerWindows::swap_buffers() { -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) gl_manager->swap_buffers(); #endif } @@ -3110,9 +3110,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, } #endif -#ifdef OPENGL_ENABLED - print_line("rendering_driver " + rendering_driver); - if (rendering_driver == "opengl") { +#ifdef GLES3_ENABLED + if (rendering_driver == "opengl3") { Error err = gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top); ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Failed to create an OpenGL window."); } @@ -3326,8 +3325,6 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win use_raw_input = false; } - print_line("rendering_driver " + rendering_driver); - #if defined(VULKAN_ENABLED) if (rendering_driver == "vulkan") { context_vulkan = memnew(VulkanContextWindows); @@ -3340,9 +3337,9 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } #endif // Init context and rendering device -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) - if (rendering_driver == "opengl") { + if (rendering_driver == "opengl3") { GLManager_Windows::ContextType opengl_api_type = GLManager_Windows::GLES_3_0_COMPATIBLE; gl_manager = memnew(GLManager_Windows(opengl_api_type)); @@ -3355,42 +3352,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win } // gl_manager->set_use_vsync(current_videomode.use_vsync); - - if (true) { - RasterizerOpenGL::make_current(); - } else { - memdelete(gl_manager); - gl_manager = nullptr; - r_error = ERR_UNAVAILABLE; - return; - } + RasterizerGLES3::make_current(); } #endif - /* -#if defined(OPENGL_ENABLED) - if (rendering_driver_index == VIDEO_DRIVER_GLES2) { - context_gles2 = memnew(ContextGL_Windows(hWnd, false)); - - if (context_gles2->initialize() != OK) { - memdelete(context_gles2); - context_gles2 = nullptr; - ERR_FAIL_V(ERR_UNAVAILABLE); - } - - context_gles2->set_use_vsync(video_mode.use_vsync); - - if (RasterizerOpenGL::is_viable() == OK) { - RasterizerOpenGL::register_config(); - RasterizerOpenGL::make_current(); - } else { - memdelete(context_gles2); - context_gles2 = nullptr; - ERR_FAIL_V(ERR_UNAVAILABLE); - } - } -#endif - */ Point2i window_position( (screen_get_size(0).width - p_resolution.width) / 2, (screen_get_size(0).height - p_resolution.height) / 2); @@ -3448,8 +3413,8 @@ Vector DisplayServerWindows::get_rendering_drivers_func() { #ifdef VULKAN_ENABLED drivers.push_back("vulkan"); #endif -#ifdef OPENGL_ENABLED - drivers.push_back("opengl"); +#ifdef GLES3_ENABLED + drivers.push_back("opengl3"); #endif return drivers; @@ -3479,7 +3444,7 @@ DisplayServerWindows::~DisplayServerWindows() { SetWindowLongPtr(windows[MAIN_WINDOW_ID].hWnd, GWLP_WNDPROC, (LONG_PTR)user_proc); }; -#ifdef OPENGL_ENABLED +#ifdef GLES3_ENABLED // destroy windows .. NYI? #endif @@ -3511,7 +3476,7 @@ DisplayServerWindows::~DisplayServerWindows() { if (restore_mouse_trails > 1) { SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0); } -#ifdef OPENGL_ENABLED +#ifdef GLES3_ENABLED if (gl_manager) { memdelete(gl_manager); gl_manager = nullptr; diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 86f47eabc8..8e2c346d5b 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -56,7 +56,7 @@ #include "platform/windows/vulkan_context_win.h" #endif -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) #include "gl_manager_windows.h" #endif @@ -304,7 +304,7 @@ class DisplayServerWindows : public DisplayServer { int old_x, old_y; Point2i center; -#if defined(OPENGL_ENABLED) +#if defined(GLES3_ENABLED) GLManager_Windows *gl_manager; #endif diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp index 8a79da987b..98205d6282 100644 --- a/platform/windows/gl_manager_windows.cpp +++ b/platform/windows/gl_manager_windows.cpp @@ -31,7 +31,7 @@ #include "gl_manager_windows.h" #ifdef WINDOWS_ENABLED -#ifdef OPENGL_ENABLED +#ifdef GLES3_ENABLED #include #include @@ -129,50 +129,46 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) { wglMakeCurrent(hDC, gl_display.hRC); - if (opengl_3_context) { - int attribs[] = { - WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context - WGL_CONTEXT_MINOR_VERSION_ARB, 3, - //and it shall be forward compatible so that we can only use up to date functionality - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/, - 0 - }; //zero indicates the end of the array - - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method - wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); - - if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported - { - wglDeleteContext(gl_display.hRC); - gl_display.hRC = 0; - return ERR_CANT_CREATE; - } - - HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs); - if (!new_hRC) { - wglDeleteContext(gl_display.hRC); - gl_display.hRC = 0; - return ERR_CANT_CREATE; // Return false - } - wglMakeCurrent(hDC, nullptr); + int attribs[] = { + WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context + WGL_CONTEXT_MINOR_VERSION_ARB, 3, + //and it shall be forward compatible so that we can only use up to date functionality + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB /*| _WGL_CONTEXT_DEBUG_BIT_ARB*/, + 0 + }; //zero indicates the end of the array + + PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + + if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported + { + wglDeleteContext(gl_display.hRC); + gl_display.hRC = 0; + return ERR_CANT_CREATE; + } + + HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs); + if (!new_hRC) { wglDeleteContext(gl_display.hRC); - gl_display.hRC = new_hRC; - - if (!wglMakeCurrent(hDC, gl_display.hRC)) // Try To Activate The Rendering Context - { - wglDeleteContext(gl_display.hRC); - gl_display.hRC = 0; - return ERR_CANT_CREATE; // Return FALSE - } + gl_display.hRC = 0; + return ERR_CANT_CREATE; // Return false + } + wglMakeCurrent(hDC, nullptr); + wglDeleteContext(gl_display.hRC); + gl_display.hRC = new_hRC; + + if (!wglMakeCurrent(hDC, gl_display.hRC)) // Try To Activate The Rendering Context + { + wglDeleteContext(gl_display.hRC); + gl_display.hRC = 0; + return ERR_CANT_CREATE; // Return FALSE } return OK; } Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) { - print_line("window_create window id " + itos(p_window_id)); - HDC hdc = GetDC(p_hwnd); if (!hdc) { return ERR_CANT_CREATE; // Return FALSE @@ -349,5 +345,5 @@ GLManager_Windows::~GLManager_Windows() { release_current(); } -#endif // OPENGL_ENABLED +#endif // GLES3_ENABLED #endif // WINDOWS diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows.h index 53557cf68e..9733a57420 100644 --- a/platform/windows/gl_manager_windows.h +++ b/platform/windows/gl_manager_windows.h @@ -31,7 +31,7 @@ #ifndef GL_MANAGER_WINDOWS_H #define GL_MANAGER_WINDOWS_H -#if defined(WINDOWS_ENABLED) && defined(OPENGL_ENABLED) +#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) #include "core/error/error_list.h" #include "core/os/os.h" @@ -76,7 +76,6 @@ private: LocalVector _displays; GLWindow *_current_window; - bool opengl_3_context = false; PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT; @@ -123,6 +122,6 @@ public: ~GLManager_Windows(); }; -#endif // defined(WINDOWS_ENABLED) && defined(OPENGL_ENABLED) +#endif // defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED) #endif // GL_MANAGER_WINDOWS_H diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index ce3620b2d0..0f5af96417 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -2722,7 +2722,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome } break; #if 0 case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageOpenGL::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base); + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base); ERR_CONTINUE(!immediate); _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 7716705666..95f5b46831 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -2440,7 +2440,7 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry } break; #if 0 case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageOpenGL::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base); + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base); ERR_CONTINUE(!immediate); _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 723c5ada3f..c3d57a13ad 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -129,7 +129,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { timestamp_vp_map[rt_id] = p_viewport->self; } - if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl") { + if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") { // This is currently needed for GLES to keep the current window being rendered to up to date DisplayServer::get_singleton()->gl_window_make_current(p_viewport->viewport_to_screen); } diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index f43b9352b4..1b16949768 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2957,6 +2957,43 @@ RenderingServer::RenderingServer() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1")); GLOBAL_DEF_RST("rendering/xr/enabled", false); + + GLOBAL_DEF_RST("rendering/2d/options/use_software_skinning", true); + GLOBAL_DEF_RST("rendering/2d/options/ninepatch_mode", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/options/ninepatch_mode", PropertyInfo(Variant::INT, "rendering/2d/options/ninepatch_mode", PROPERTY_HINT_ENUM, "Fixed,Scaling")); + + GLOBAL_DEF_RST("rendering/2d/opengl/batching_send_null", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/opengl/batching_send_null", PropertyInfo(Variant::INT, "rendering/2d/opengl/batching_send_null", PROPERTY_HINT_ENUM, "Default (On),Off,On")); + GLOBAL_DEF_RST("rendering/2d/opengl/batching_stream", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/opengl/batching_stream", PropertyInfo(Variant::INT, "rendering/2d/opengl/batching_stream", PROPERTY_HINT_ENUM, "Default (Off),Off,On")); + GLOBAL_DEF_RST("rendering/2d/opengl/legacy_orphan_buffers", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/opengl/legacy_orphan_buffers", PropertyInfo(Variant::INT, "rendering/2d/opengl/legacy_orphan_buffers", PROPERTY_HINT_ENUM, "Default (On),Off,On")); + GLOBAL_DEF_RST("rendering/2d/opengl/legacy_stream", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/opengl/legacy_stream", PropertyInfo(Variant::INT, "rendering/2d/opengl/legacy_stream", PROPERTY_HINT_ENUM, "Default (On),Off,On")); + + GLOBAL_DEF("rendering/batching/options/use_batching", false); + GLOBAL_DEF_RST("rendering/batching/options/use_batching_in_editor", false); + GLOBAL_DEF("rendering/batching/options/single_rect_fallback", false); + GLOBAL_DEF("rendering/batching/parameters/max_join_item_commands", 16); + GLOBAL_DEF("rendering/batching/parameters/colored_vertex_format_threshold", 0.25f); + GLOBAL_DEF("rendering/batching/lights/scissor_area_threshold", 1.0f); + GLOBAL_DEF("rendering/batching/lights/max_join_items", 32); + GLOBAL_DEF("rendering/batching/parameters/batch_buffer_size", 16384); + GLOBAL_DEF("rendering/batching/parameters/item_reordering_lookahead", 4); + GLOBAL_DEF("rendering/batching/debug/flash_batching", false); + GLOBAL_DEF("rendering/batching/debug/diagnose_frame", false); + GLOBAL_DEF("rendering/gles2/compatibility/disable_half_float", false); + GLOBAL_DEF("rendering/gles2/compatibility/enable_high_float.Android", false); + GLOBAL_DEF("rendering/batching/precision/uv_contract", false); + GLOBAL_DEF("rendering/batching/precision/uv_contract_amount", 100); + + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/parameters/max_join_item_commands", PropertyInfo(Variant::INT, "rendering/batching/parameters/max_join_item_commands", PROPERTY_HINT_RANGE, "0,65535")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/parameters/colored_vertex_format_threshold", PropertyInfo(Variant::FLOAT, "rendering/batching/parameters/colored_vertex_format_threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/parameters/batch_buffer_size", PropertyInfo(Variant::INT, "rendering/batching/parameters/batch_buffer_size", PROPERTY_HINT_RANGE, "1024,65535,1024")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/lights/scissor_area_threshold", PropertyInfo(Variant::FLOAT, "rendering/batching/lights/scissor_area_threshold", PROPERTY_HINT_RANGE, "0.0,1.0")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/lights/max_join_items", PropertyInfo(Variant::INT, "rendering/batching/lights/max_join_items", PROPERTY_HINT_RANGE, "0,512")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/parameters/item_reordering_lookahead", PropertyInfo(Variant::INT, "rendering/batching/parameters/item_reordering_lookahead", PROPERTY_HINT_RANGE, "0,256")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/precision/uv_contract_amount", PropertyInfo(Variant::INT, "rendering/batching/precision/uv_contract_amount", PROPERTY_HINT_RANGE, "0,10000")); } RenderingServer::~RenderingServer() { -- cgit v1.2.3