summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/config/project_settings.cpp16
-rw-r--r--core/object/script_language.h1
-rw-r--r--core/object/script_language_extension.cpp1
-rw-r--r--core/os/os.h8
-rw-r--r--core/string/ustring.cpp63
-rw-r--r--doc/classes/AnimatedSprite2D.xml8
-rw-r--r--doc/classes/GPUParticlesCollisionHeightField3D.xml4
-rw-r--r--doc/classes/ProjectSettings.xml58
-rw-r--r--doc/classes/ScriptLanguageExtension.xml8
-rw-r--r--doc/classes/Shape2D.xml8
-rwxr-xr-xdoc/tools/make_rst.py24
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp8
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h11
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp11
-rw-r--r--drivers/gles3/rasterizer_gles3.h2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp1194
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h373
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp113
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h43
-rw-r--r--drivers/gles3/shader_gles3.cpp9
-rw-r--r--drivers/gles3/shader_gles3.h8
-rw-r--r--drivers/gles3/shaders/SCsub1
-rw-r--r--drivers/gles3/shaders/canvas.glsl28
-rw-r--r--drivers/gles3/shaders/scene.glsl2332
-rw-r--r--drivers/gles3/shaders/sky.glsl88
-rw-r--r--drivers/gles3/shaders/stdlib_inc.glsl4
-rw-r--r--drivers/gles3/shaders/tonemap_inc.glsl119
-rw-r--r--drivers/gles3/storage/config.cpp33
-rw-r--r--drivers/gles3/storage/config.h6
-rw-r--r--drivers/gles3/storage/material_storage.cpp686
-rw-r--r--drivers/gles3/storage/material_storage.h179
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp104
-rw-r--r--drivers/gles3/storage/mesh_storage.h19
-rw-r--r--drivers/gles3/storage/texture_storage.cpp109
-rw-r--r--drivers/gles3/storage/texture_storage.h6
-rw-r--r--editor/create_dialog.cpp2
-rw-r--r--editor/editor_help.cpp95
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/editor_resource_preview.cpp23
-rw-r--r--editor/editor_resource_preview.h8
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp69
-rw-r--r--editor/plugins/script_text_editor.cpp15
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp63
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp2
-rw-r--r--editor/scene_tree_editor.cpp21
-rw-r--r--main/main.cpp55
-rw-r--r--modules/gdscript/gdscript_editor.cpp15
-rw-r--r--modules/gdscript/gdscript_parser.cpp1
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs1
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs3
-rw-r--r--modules/text_server_adv/text_server_adv.cpp8
-rw-r--r--modules/text_server_adv/text_server_adv.h16
-rw-r--r--modules/text_server_fb/text_server_fb.cpp6
-rw-r--r--modules/text_server_fb/text_server_fb.h16
-rw-r--r--platform/android/detect.py7
-rw-r--r--platform/iphone/detect.py7
-rw-r--r--platform/linuxbsd/display_server_x11.cpp4
-rw-r--r--platform/windows/detect.py14
-rw-r--r--platform/windows/display_server_windows.cpp88
-rw-r--r--platform/windows/display_server_windows.h2
-rw-r--r--platform/windows/gl_manager_windows.cpp122
-rw-r--r--platform/windows/gl_manager_windows.h6
-rw-r--r--platform/windows/os_windows.cpp29
-rw-r--r--platform/windows/os_windows.h9
-rw-r--r--platform/windows/vulkan_context_win.cpp4
-rw-r--r--scene/3d/gpu_particles_collision_3d.cpp27
-rw-r--r--scene/3d/gpu_particles_collision_3d.h8
-rw-r--r--scene/gui/code_edit.cpp5
-rw-r--r--scene/gui/line_edit.cpp36
-rw-r--r--scene/gui/line_edit.h3
-rw-r--r--scene/gui/text_edit.cpp45
-rw-r--r--scene/gui/text_edit.h4
-rw-r--r--scene/resources/curve.cpp153
-rw-r--r--scene/resources/environment.cpp1
-rw-r--r--scene/resources/font.cpp3
-rw-r--r--scene/resources/tile_set.cpp8
-rw-r--r--scene/resources/visual_shader.cpp116
-rw-r--r--servers/rendering/dummy/rasterizer_dummy.h2
-rw-r--r--servers/rendering/renderer_compositor.cpp1
-rw-r--r--servers/rendering/renderer_compositor.h3
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp2
-rw-r--r--servers/rendering/renderer_scene_cull.cpp7
-rw-r--r--servers/rendering/rendering_server_default.cpp6
-rw-r--r--servers/rendering/rendering_server_default.h4
-rw-r--r--servers/rendering/shader_compiler.cpp24
-rw-r--r--servers/rendering_server.cpp48
-rw-r--r--thirdparty/README.md2
-rw-r--r--thirdparty/etcpak/ProcessRGB.cpp1084
90 files changed, 5229 insertions, 2766 deletions
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 2aedbdf45f..ba108d75da 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1175,6 +1175,22 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF("application/config/use_custom_user_dir", false);
GLOBAL_DEF("application/config/custom_user_dir_name", "");
GLOBAL_DEF("application/config/project_settings_override", "");
+
+ GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1024);
+ custom_prop_info["display/window/size/viewport_width"] = PropertyInfo(Variant::INT, "display/window/size/viewport_width", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
+
+ GLOBAL_DEF_BASIC("display/window/size/viewport_height", 600);
+ custom_prop_info["display/window/size/viewport_height"] = PropertyInfo(Variant::INT, "display/window/size/viewport_height", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+
+ GLOBAL_DEF_BASIC("display/window/size/resizable", true);
+ GLOBAL_DEF_BASIC("display/window/size/borderless", false);
+ GLOBAL_DEF_BASIC("display/window/size/fullscreen", false);
+ GLOBAL_DEF("display/window/size/always_on_top", false);
+ GLOBAL_DEF("display/window/size/window_width_override", 0);
+ custom_prop_info["display/window/size/window_width_override"] = PropertyInfo(Variant::INT, "display/window/size/window_width_override", PROPERTY_HINT_RANGE, "0,7680,1,or_greater"); // 8K resolution
+ GLOBAL_DEF("display/window/size/window_height_override", 0);
+ custom_prop_info["display/window/size/window_height_override"] = PropertyInfo(Variant::INT, "display/window/size/window_height_override", PROPERTY_HINT_RANGE, "0,4320,1,or_greater"); // 8K resolution
+
GLOBAL_DEF_BASIC("audio/buses/default_bus_layout", "res://default_bus_layout.tres");
custom_prop_info["audio/buses/default_bus_layout"] = PropertyInfo(Variant::STRING, "audio/buses/default_bus_layout", PROPERTY_HINT_FILE, "*.tres");
diff --git a/core/object/script_language.h b/core/object/script_language.h
index f58ef45743..bd87427eaf 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -346,6 +346,7 @@ public:
LOOKUP_RESULT_CLASS_CONSTANT,
LOOKUP_RESULT_CLASS_PROPERTY,
LOOKUP_RESULT_CLASS_METHOD,
+ LOOKUP_RESULT_CLASS_SIGNAL,
LOOKUP_RESULT_CLASS_ENUM,
LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE,
LOOKUP_RESULT_MAX
diff --git a/core/object/script_language_extension.cpp b/core/object/script_language_extension.cpp
index 21d7685674..5af79bbea3 100644
--- a/core/object/script_language_extension.cpp
+++ b/core/object/script_language_extension.cpp
@@ -157,6 +157,7 @@ void ScriptLanguageExtension::_bind_methods() {
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_CONSTANT);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_PROPERTY);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_METHOD);
+ BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_SIGNAL);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_ENUM);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE);
BIND_ENUM_CONSTANT(LOOKUP_RESULT_MAX);
diff --git a/core/os/os.h b/core/os/os.h
index 5eac77d634..157b8ab992 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -82,11 +82,6 @@ public:
RENDER_SEPARATE_THREAD
};
- enum RenderMainThreadMode {
- RENDER_MAIN_THREAD_ONLY,
- RENDER_ANY_THREAD,
- };
-
protected:
friend class Main;
// Needed by tests to setup command-line args.
@@ -94,7 +89,6 @@ protected:
HasServerFeatureCallback has_server_feature_callback = nullptr;
RenderThreadMode _render_thread_mode = RENDER_THREAD_SAFE;
- RenderMainThreadMode _render_main_thread_mode = RENDER_ANY_THREAD;
// Functions used by Main to initialize/deinitialize the OS.
void add_logger(Logger *p_logger);
@@ -258,8 +252,6 @@ public:
virtual uint64_t get_free_static_memory() const;
RenderThreadMode get_render_thread_mode() const { return _render_thread_mode; }
- RenderMainThreadMode get_render_main_thread_mode() const { return _render_main_thread_mode; }
- void set_render_main_thread_mode(RenderMainThreadMode p_thread_mode) { _render_main_thread_mode = p_thread_mode; }
virtual String get_locale() const;
String get_locale_language() const;
diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp
index 5d998d22d4..015dfbc651 100644
--- a/core/string/ustring.cpp
+++ b/core/string/ustring.cpp
@@ -4779,6 +4779,17 @@ Vector<uint8_t> String::to_utf32_buffer() const {
}
#ifdef TOOLS_ENABLED
+/**
+ * "Tools TRanslate". Performs string replacement for internationalization
+ * within the editor. A translation context can optionally be specified to
+ * disambiguate between identical source strings in translations. When
+ * placeholders are desired, use `vformat(TTR("Example: %s"), some_string)`.
+ * If a string mentions a quantity (and may therefore need a dynamic plural form),
+ * use `TTRN()` instead of `TTR()`.
+ *
+ * NOTE: Only use `TTR()` in editor-only code (typically within the `editor/` folder).
+ * For translations that can be supplied by exported projects, use `RTR()` instead.
+ */
String TTR(const String &p_text, const String &p_context) {
if (TranslationServer::get_singleton()) {
return TranslationServer::get_singleton()->tool_translate(p_text, p_context);
@@ -4787,6 +4798,18 @@ String TTR(const String &p_text, const String &p_context) {
return p_text;
}
+/**
+ * "Tools TRanslate for N items". Performs string replacement for
+ * internationalization within the editor. A translation context can optionally
+ * be specified to disambiguate between identical source strings in
+ * translations. Use `TTR()` if the string doesn't need dynamic plural form.
+ * When placeholders are desired, use
+ * `vformat(TTRN("%d item", "%d items", some_integer), some_integer)`.
+ * The placeholder must be present in both strings to avoid run-time warnings in `vformat()`.
+ *
+ * NOTE: Only use `TTRN()` in editor-only code (typically within the `editor/` folder).
+ * For translations that can be supplied by exported projects, use `RTRN()` instead.
+ */
String TTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
if (TranslationServer::get_singleton()) {
return TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context);
@@ -4799,9 +4822,10 @@ String TTRN(const String &p_text, const String &p_text_plural, int p_n, const St
return p_text_plural;
}
-/* DTR and DTRN are used for the documentation, handling descriptions extracted
- * from the XML.
- * They also replace `$DOCS_URL` with the actual URL to the documentation's branch,
+/**
+ * "Docs TRanslate". Used for the editor class reference documentation,
+ * handling descriptions extracted from the XML.
+ * It also replaces `$DOCS_URL` with the actual URL to the documentation's branch,
* to allow dehardcoding it in the XML and doing proper substitutions everywhere.
*/
String DTR(const String &p_text, const String &p_context) {
@@ -4815,6 +4839,12 @@ String DTR(const String &p_text, const String &p_context) {
return text.replace("$DOCS_URL", VERSION_DOCS_URL);
}
+/**
+ * "Docs TRanslate for N items". Used for the editor class reference documentation
+ * (with support for plurals), handling descriptions extracted from the XML.
+ * It also replaces `$DOCS_URL` with the actual URL to the documentation's branch,
+ * to allow dehardcoding it in the XML and doing proper substitutions everywhere.
+ */
String DTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
const String text = p_text.dedent().strip_edges();
const String text_plural = p_text_plural.dedent().strip_edges();
@@ -4831,6 +4861,19 @@ String DTRN(const String &p_text, const String &p_text_plural, int p_n, const St
}
#endif
+/**
+ * "Run-time TRanslate". Performs string replacement for internationalization
+ * within a running project. The translation string must be supplied by the
+ * project, as Godot does not provide built-in translations for `RTR()` strings
+ * to keep binary size low. A translation context can optionally be specified to
+ * disambiguate between identical source strings in translations. When
+ * placeholders are desired, use `vformat(RTR("Example: %s"), some_string)`.
+ * If a string mentions a quantity (and may therefore need a dynamic plural form),
+ * use `RTRN()` instead of `RTR()`.
+ *
+ * NOTE: Do not use `RTR()` in editor-only code (typically within the `editor/`
+ * folder). For editor translations, use `TTR()` instead.
+ */
String RTR(const String &p_text, const String &p_context) {
if (TranslationServer::get_singleton()) {
String rtr = TranslationServer::get_singleton()->tool_translate(p_text, p_context);
@@ -4844,6 +4887,20 @@ String RTR(const String &p_text, const String &p_context) {
return p_text;
}
+/**
+ * "Run-time TRanslate for N items". Performs string replacement for
+ * internationalization within a running project. The translation string must be
+ * supplied by the project, as Godot does not provide built-in translations for
+ * `RTRN()` strings to keep binary size low. A translation context can
+ * optionally be specified to disambiguate between identical source strings in
+ * translations. Use `RTR()` if the string doesn't need dynamic plural form.
+ * When placeholders are desired, use
+ * `vformat(RTRN("%d item", "%d items", some_integer), some_integer)`.
+ * The placeholder must be present in both strings to avoid run-time warnings in `vformat()`.
+ *
+ * NOTE: Do not use `RTRN()` in editor-only code (typically within the `editor/`
+ * folder). For editor translations, use `TTRN()` instead.
+ */
String RTRN(const String &p_text, const String &p_text_plural, int p_n, const String &p_context) {
if (TranslationServer::get_singleton()) {
String rtr = TranslationServer::get_singleton()->tool_translate_plural(p_text, p_text_plural, p_n, p_context);
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index e89134d1ac..638d142791 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AnimatedSprite2D" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Sprite node that can use multiple textures for animation.
+ Sprite node that contains multiple textures as frames to play for animation.
</brief_description>
<description>
- Animations are created using a [SpriteFrames] resource, which can be configured in the editor via the SpriteFrames panel.
+ [AnimatedSprite2D] is similar to the [Sprite2D] node, except it carries multiple textures as animation frames. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel.
[b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
@@ -29,7 +29,7 @@
</methods>
<members>
<member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&amp;&quot;default&quot;">
- The current animation from the [code]frames[/code] resource. If this value changes, the [code]frame[/code] counter is reset.
+ The current animation from the [member frames] resource. If this value changes, the [code]frame[/code] counter is reset.
</member>
<member name="centered" type="bool" setter="set_centered" getter="is_centered" default="true">
If [code]true[/code], texture will be centered.
@@ -44,7 +44,7 @@
The displayed animation frame's index.
</member>
<member name="frames" type="SpriteFrames" setter="set_sprite_frames" getter="get_sprite_frames">
- The [SpriteFrames] resource containing the animation(s).
+ The [SpriteFrames] resource containing the animation(s). Allows you the option to load, edit, clear, make unique and save the states of the [SpriteFrames] resource.
</member>
<member name="offset" type="Vector2" setter="set_offset" getter="get_offset" default="Vector2(0, 0)">
The texture's drawing offset.
diff --git a/doc/classes/GPUParticlesCollisionHeightField3D.xml b/doc/classes/GPUParticlesCollisionHeightField3D.xml
index e7e14375d9..a7b59ea684 100644
--- a/doc/classes/GPUParticlesCollisionHeightField3D.xml
+++ b/doc/classes/GPUParticlesCollisionHeightField3D.xml
@@ -9,9 +9,7 @@
<members>
<member name="extents" type="Vector3" setter="set_extents" getter="get_extents" default="Vector3(1, 1, 1)">
</member>
- <member name="follow_camera_enabled" type="bool" setter="set_follow_camera_mode" getter="is_follow_camera_mode_enabled" default="false">
- </member>
- <member name="follow_camera_push_ratio" type="float" setter="set_follow_camera_push_ratio" getter="get_follow_camera_push_ratio" default="0.1">
+ <member name="follow_camera_enabled" type="bool" setter="set_follow_camera_enabled" getter="is_follow_camera_enabled" default="false">
</member>
<member name="resolution" type="int" setter="set_resolution" getter="get_resolution" enum="GPUParticlesCollisionHeightField3D.Resolution" default="2">
</member>
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 7c6d6d1c10..b54c129369 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -1557,18 +1557,6 @@
[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.
[b]Note:[/b] Only 8 physics ticks may be simulated per rendered frame at most. If more than 8 physics ticks have to be simulated per rendered frame to keep up with rendering, the game will appear to slow down (even if [code]delta[/code] is used consistently in physics calculations). Therefore, it is recommended not to increase [member physics/common/physics_ticks_per_second] above 240. Otherwise, the game will slow down when the rendering framerate goes below 30 FPS.
</member>
- <member name="rendering/2d/opengl/batching_send_null" type="int" setter="" getter="" default="0">
- </member>
- <member name="rendering/2d/opengl/batching_stream" type="int" setter="" getter="" default="0">
- </member>
- <member name="rendering/2d/opengl/legacy_orphan_buffers" type="int" setter="" getter="" default="0">
- </member>
- <member name="rendering/2d/opengl/legacy_stream" type="int" setter="" getter="" default="0">
- </member>
- <member name="rendering/2d/options/ninepatch_mode" type="int" setter="" getter="" default="1">
- </member>
- <member name="rendering/2d/options/use_software_skinning" type="bool" setter="" getter="" default="true">
- </member>
<member name="rendering/2d/sdf/oversize" type="int" setter="" getter="" default="1">
</member>
<member name="rendering/2d/sdf/scale" type="int" setter="" getter="" default="1">
@@ -1594,32 +1582,6 @@
</member>
<member name="rendering/anti_aliasing/screen_space_roughness_limiter/limit" type="float" setter="" getter="" default="0.18">
</member>
- <member name="rendering/batching/debug/diagnose_frame" type="bool" setter="" getter="" default="false">
- </member>
- <member name="rendering/batching/debug/flash_batching" type="bool" setter="" getter="" default="false">
- </member>
- <member name="rendering/batching/lights/max_join_items" type="int" setter="" getter="" default="32">
- </member>
- <member name="rendering/batching/lights/scissor_area_threshold" type="float" setter="" getter="" default="1.0">
- </member>
- <member name="rendering/batching/options/single_rect_fallback" type="bool" setter="" getter="" default="false">
- </member>
- <member name="rendering/batching/options/use_batching" type="bool" setter="" getter="" default="false">
- </member>
- <member name="rendering/batching/options/use_batching_in_editor" type="bool" setter="" getter="" default="false">
- </member>
- <member name="rendering/batching/parameters/batch_buffer_size" type="int" setter="" getter="" default="16384">
- </member>
- <member name="rendering/batching/parameters/colored_vertex_format_threshold" type="float" setter="" getter="" default="0.25">
- </member>
- <member name="rendering/batching/parameters/item_reordering_lookahead" type="int" setter="" getter="" default="4">
- </member>
- <member name="rendering/batching/parameters/max_join_item_commands" type="int" setter="" getter="" default="16">
- </member>
- <member name="rendering/batching/precision/uv_contract" type="bool" setter="" getter="" default="false">
- </member>
- <member name="rendering/batching/precision/uv_contract_amount" type="int" setter="" getter="" default="100">
- </member>
<member name="rendering/camera/depth_of_field/depth_of_field_bokeh_quality" type="int" setter="" getter="" default="1">
Sets the quality of the depth of field effect. Higher quality takes more samples, which is slower but looks smoother.
</member>
@@ -1629,13 +1591,16 @@
<member name="rendering/camera/depth_of_field/depth_of_field_use_jitter" type="bool" setter="" getter="" default="false">
If [code]true[/code], jitters DOF samples to make effect slightly blurrier and hide lines created from low sample rates. This can result in a slightly grainy appearance when used with a low number of samples.
</member>
+ <member name="rendering/driver/depth_prepass/disable_for_vendors" type="String" setter="" getter="" default="&quot;PowerVR,Mali,Adreno,Apple&quot;">
+ Disables [member rendering/driver/depth_prepass/enable] conditionally for certain venders. By default, disables the depth prepass for mobile devices as mobile devices do not benefit from the depth prepass due to their unique architecture.
+ </member>
<member name="rendering/driver/depth_prepass/enable" type="bool" setter="" getter="" default="true">
If [code]true[/code], performs a previous depth pass before rendering 3D materials. This increases performance significantly in scenes with high overdraw, when complex materials and lighting are used. However, in scenes with few occluded surfaces, the depth prepass may reduce performance. If your game is viewed from a fixed angle that makes it easy to avoid overdraw (such as top-down or side-scrolling perspective), consider disabling the depth prepass to improve performance. This setting can be changed at run-time to optimize performance depending on the scene currently being viewed.
- [b]Note:[/b] Only supported when using the Vulkan Clustered backend (not Vulkan Mobile or OpenGL). When using Vulkan Mobile or OpenGL, there is no depth prepass performed.
+ [b]Note:[/b] Only supported when using the Vulkan Clustered backend or the OpenGL backend. When using Vulkan Mobile there is no depth prepass performed.
</member>
<member name="rendering/driver/driver_name" type="String" setter="" getter="" default="&quot;vulkan&quot;">
The video driver to use.
- [b]Note:[/b] OpenGL support is currently incomplete. Only basic 2D rendering is supported, and single-window mode is required for correct operation.
+ [b]Note:[/b] OpenGL support is currently incomplete. Only basic rendering is supported.
[b]Note:[/b] The backend in use can be overridden at runtime via the [code]--rendering-driver[/code] command line argument.
[b]FIXME:[/b] No longer valid after DisplayServer split:
In such cases, this property is not updated, so use [code]OS.get_current_video_driver[/code] to query it at run-time.
@@ -1715,10 +1680,6 @@
<member name="rendering/environment/volumetric_fog/volume_size" type="int" setter="" getter="" default="64">
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.
</member>
- <member name="rendering/gles2/compatibility/disable_half_float" type="bool" setter="" getter="" default="false">
- </member>
- <member name="rendering/gles2/compatibility/enable_high_float.Android" type="bool" setter="" getter="" default="false">
- </member>
<member name="rendering/global_illumination/gi/use_half_resolution" type="bool" setter="" getter="" default="false">
If [code]true[/code], renders [VoxelGI] and SDFGI ([member Environment.sdfgi_enabled]) buffers at halved resolution (e.g. 960×540 when the viewport size is 1920×1080). This improves performance significantly when VoxelGI or SDFGI is enabled, at the cost of artifacts that may be visible on polygon edges. The loss in quality becomes less noticeable as the viewport resolution increases. [LightmapGI] rendering is not affected by this setting.
[b]Note:[/b] This property is only read when the project starts. To set half-resolution GI at run-time, call [method RenderingServer.gi_set_use_half_resolution] instead.
@@ -1761,6 +1722,15 @@
</member>
<member name="rendering/limits/global_shader_variables/buffer_size" type="int" setter="" getter="" default="65536">
</member>
+ <member name="rendering/limits/opengl/max_lights_per_object" type="int" setter="" getter="" default="8">
+ Max number of lights renderable per object. This is further limited by hardware support. Setting this low will slightly reduce memory usage, may decrease shader compile times, and may result in faster rendering on low-end, mobile, or web devices.
+ </member>
+ <member name="rendering/limits/opengl/max_renderable_elements" type="int" setter="" getter="" default="65536">
+ Max amount of elements renderable in a frame. If more elements than this are visible per frame, they will not be drawn. Keep in mind elements refer to mesh surfaces and not meshes themselves. Setting this low will slightly reduce memory usage and may decrease shader compile times, particularly on web. For most uses, the default value is suitable, but consider lowering as much as possible on web export.
+ </member>
+ <member name="rendering/limits/opengl/max_renderable_lights" type="int" setter="" getter="" default="256">
+ Max number of lights renderable in a frame. If more lights than this number are used, they will be ignored. Setting this low will slightly reduce memory usage and may decrease shader compile times, particularly on web. For most uses, the default value is suitable, but consider lowering as much as possible on web export.
+ </member>
<member name="rendering/limits/spatial_indexer/threaded_cull_minimum_instances" type="int" setter="" getter="" default="1000">
</member>
<member name="rendering/limits/spatial_indexer/update_iterations_per_frame" type="int" setter="" getter="" default="10">
diff --git a/doc/classes/ScriptLanguageExtension.xml b/doc/classes/ScriptLanguageExtension.xml
index d66bb6a7c7..0f757cf806 100644
--- a/doc/classes/ScriptLanguageExtension.xml
+++ b/doc/classes/ScriptLanguageExtension.xml
@@ -372,11 +372,13 @@
</constant>
<constant name="LOOKUP_RESULT_CLASS_METHOD" value="4" enum="LookupResultType">
</constant>
- <constant name="LOOKUP_RESULT_CLASS_ENUM" value="5" enum="LookupResultType">
+ <constant name="LOOKUP_RESULT_CLASS_SIGNAL" value="5" enum="LookupResultType">
</constant>
- <constant name="LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE" value="6" enum="LookupResultType">
+ <constant name="LOOKUP_RESULT_CLASS_ENUM" value="6" enum="LookupResultType">
</constant>
- <constant name="LOOKUP_RESULT_MAX" value="7" enum="LookupResultType">
+ <constant name="LOOKUP_RESULT_CLASS_TBD_GLOBALSCOPE" value="7" enum="LookupResultType">
+ </constant>
+ <constant name="LOOKUP_RESULT_MAX" value="8" enum="LookupResultType">
</constant>
<constant name="LOCATION_LOCAL" value="0" enum="CodeCompletionLocation">
The option is local to the location of the code completion query - e.g. a local variable.
diff --git a/doc/classes/Shape2D.xml b/doc/classes/Shape2D.xml
index 03ff3cc188..94fb2d7dc7 100644
--- a/doc/classes/Shape2D.xml
+++ b/doc/classes/Shape2D.xml
@@ -26,7 +26,9 @@
<argument index="1" name="with_shape" type="Shape2D" />
<argument index="2" name="shape_xform" type="Transform2D" />
<description>
- Returns a list of the points where this shape touches another. If there are no collisions the list is empty.
+ Returns a list of contact point pairs where this shape touches another.
+ If there are no collisions, the returned list is empty. Otherwise, the returned list contains contact points arranged in pairs, with entries alternating between points on the boundary of this shape and points on the boundary of [code]with_shape[/code].
+ A collision pair A, B can be used to calculate the collision normal with [code](B - A).normalized()[/code], and the collision depth with [code](B - A).length()[/code]. This information is typically used to separate shapes, particularly in collision solvers.
This method needs the transformation matrix for this shape ([code]local_xform[/code]), the shape to check collisions with ([code]with_shape[/code]), and the transformation matrix of that shape ([code]shape_xform[/code]).
</description>
</method>
@@ -50,7 +52,9 @@
<argument index="3" name="shape_xform" type="Transform2D" />
<argument index="4" name="shape_motion" type="Vector2" />
<description>
- Returns a list of the points where this shape would touch another, if a given movement was applied. If there are no collisions the list is empty.
+ Returns a list of contact point pairs where this shape would touch another, if a given movement was applied.
+ If there would be no collisions, the returned list is empty. Otherwise, the returned list contains contact points arranged in pairs, with entries alternating between points on the boundary of this shape and points on the boundary of [code]with_shape[/code].
+ A collision pair A, B can be used to calculate the collision normal with [code](B - A).normalized()[/code], and the collision depth with [code](B - A).length()[/code]. This information is typically used to separate shapes, particularly in collision solvers.
This method needs the transformation matrix for this shape ([code]local_xform[/code]), the movement to test on this shape ([code]local_motion[/code]), the shape to check collisions with ([code]with_shape[/code]), the transformation matrix of that shape ([code]shape_xform[/code]), and the movement to test onto the other object ([code]shape_motion[/code]).
</description>
</method>
diff --git a/doc/tools/make_rst.py b/doc/tools/make_rst.py
index 1b98699c44..2e227ce578 100755
--- a/doc/tools/make_rst.py
+++ b/doc/tools/make_rst.py
@@ -677,7 +677,8 @@ def make_rst_class(class_def, state, dry_run, output_dir): # type: (ClassDef, S
for value in e.values.values():
f.write("- **{}** = **{}**".format(value.name, value.value))
if value.text is not None and value.text.strip() != "":
- f.write(" --- " + rstize_text(value.text.strip(), state))
+ # If value.text contains a bullet point list, each entry needs additional indentation
+ f.write(" --- " + indent_bullets(rstize_text(value.text.strip(), state)))
f.write("\n\n")
@@ -904,7 +905,7 @@ def rstize_text(text, state): # type: (str, State) -> str
pre_text = text[:pos]
indent_level = 0
- while text[pos + 1] == "\t":
+ while pos + 1 < len(text) and text[pos + 1] == "\t":
pos += 1
indent_level += 1
post_text = text[pos + 1 :]
@@ -1440,5 +1441,24 @@ def sanitize_operator_name(dirty_name, state): # type: (str, State) -> str
return clear_name
+def indent_bullets(text): # type: (str) -> str
+ # Take the text and check each line for a bullet point represented by "-".
+ # Where found, indent the given line by a further "\t".
+ # Used to properly indent bullet points contained in the description for enum values.
+ # Ignore the first line - text will be prepended to it so bullet points wouldn't work anyway.
+ bullet_points = "-"
+
+ lines = text.splitlines(keepends=True)
+ for line_index, line in enumerate(lines[1:], start=1):
+ pos = 0
+ while pos < len(line) and line[pos] == "\t":
+ pos += 1
+
+ if pos < len(line) and line[pos] in bullet_points:
+ lines[line_index] = line[:pos] + "\t" + line[pos:]
+
+ return "".join(lines)
+
+
if __name__ == "__main__":
main()
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 1197f4aac1..df54686574 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -179,12 +179,12 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
//print_line("w: " + itos(ssize.width) + " s: " + rtos(canvas_scale));
state_buffer.tex_to_sdf = 1.0 / ((canvas_scale.x + canvas_scale.y) * 0.5);
- glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_BUFFER_OBJECT, state.canvas_state_buffer);
+ glBindBufferBase(GL_UNIFORM_BUFFER, BASE_UNIFORM_LOCATION, state.canvas_state_buffer);
glBufferData(GL_UNIFORM_BUFFER, sizeof(StateBuffer), &state_buffer, GL_STREAM_DRAW);
GLuint global_buffer = material_storage->global_variables_get_uniform_buffer();
- glBindBufferBase(GL_UNIFORM_BUFFER, GLOBAL_UNIFORM_BUFFER_OBJECT, global_buffer);
+ glBindBufferBase(GL_UNIFORM_BUFFER, GLOBAL_UNIFORM_LOCATION, global_buffer);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
}
@@ -522,7 +522,7 @@ void RasterizerCanvasGLES3::_render_item(RID p_render_target, const Item *p_item
}
}
- glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_BUFFER_OBJECT, state.canvas_instance_data_buffers[state.current_buffer]);
+ glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
#ifdef JAVASCRIPT_ENABLED
//WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData), &state.instance_data_array[0], GL_DYNAMIC_DRAW);
@@ -728,7 +728,7 @@ void RasterizerCanvasGLES3::_render_batch(uint32_t &r_index) {
}
}
- glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_BUFFER_OBJECT, state.canvas_instance_data_buffers[state.current_buffer]);
+ glBindBufferBase(GL_UNIFORM_BUFFER, INSTANCE_UNIFORM_LOCATION, state.canvas_instance_data_buffers[state.current_buffer]);
#ifdef JAVASCRIPT_ENABLED
//WebGL 2.0 does not support mapping buffers, so use slow glBufferData instead
glBufferData(GL_UNIFORM_BUFFER, sizeof(InstanceData) * r_index, state.instance_data_array, GL_DYNAMIC_DRAW);
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index b77b295de9..aedde7c265 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -97,13 +97,12 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
};
public:
- //TODO move to Material storage
enum {
- BASE_UNIFORM_BUFFER_OBJECT = 0,
- GLOBAL_UNIFORM_BUFFER_OBJECT = 1,
- LIGHT_UNIFORM_BUFFER_OBJECT = 2,
- INSTANCE_UNIFORM_BUFFER_OBJECT = 3,
- MATERIAL_UNIFORM_BUFFER_OBJECT = 4,
+ BASE_UNIFORM_LOCATION = 0,
+ GLOBAL_UNIFORM_LOCATION = 1,
+ LIGHT_UNIFORM_LOCATION = 2,
+ INSTANCE_UNIFORM_LOCATION = 3,
+ MATERIAL_UNIFORM_LOCATION = 4,
};
struct StateBuffer {
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index e09355e433..69f69099c7 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -210,6 +210,9 @@ RasterizerGLES3::RasterizerGLES3() {
#ifdef GLAD_ENABLED
if (!gladLoadGL()) {
ERR_PRINT("Error initializing GLAD");
+ // FIXME this is an early return from a constructor. Any other code using this instance will crash or the finalizer will crash, because none of
+ // the members of this instance are initialized, so this just makes debugging harder. It should either crash here intentionally,
+ // or we need to actually test for this situation before constructing this.
return;
}
#endif
@@ -268,10 +271,6 @@ RasterizerGLES3::RasterizerGLES3() {
storage = memnew(RasterizerStorageGLES3);
canvas = memnew(RasterizerCanvasGLES3(storage));
scene = memnew(RasterizerSceneGLES3(storage));
-
- texture_storage->set_main_thread_id(Thread::get_caller_id());
- // 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() {
@@ -289,6 +288,9 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
// TODO: do we need a keep 3d linear option?
+ // Make sure we are drawing to the right context.
+ DisplayServer::get_singleton()->gl_window_make_current(p_screen);
+
if (rt->external.fbo != 0) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo);
} else {
@@ -296,6 +298,7 @@ void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, Display
}
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, GLES3::TextureStorage::system_fbo);
+ // Flip content upside down to correct for coordinates.
glBlitFramebuffer(0, 0, rt->size.x, rt->size.y, 0, p_screen_rect.size.y, p_screen_rect.size.x, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST);
}
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index 33bb97d105..ad3d3d7325 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -92,9 +92,9 @@ public:
static void make_current() {
_create_func = _create_current;
+ low_end = true;
}
- virtual bool is_low_end() const { return true; }
uint64_t get_frame_number() const { return frame; }
double get_frame_delta_time() const { return delta; }
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index e0373ab8e8..68657b9152 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -31,6 +31,7 @@
#include "rasterizer_scene_gles3.h"
#include "core/config/project_settings.h"
#include "servers/rendering/rendering_server_default.h"
+#include "storage/config.h"
#ifdef GLES3_ENABLED
@@ -42,66 +43,169 @@ RasterizerSceneGLES3 *RasterizerSceneGLES3::get_singleton() {
return singleton;
}
-RasterizerSceneGLES3::GeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_base) {
- return nullptr;
+RendererSceneRender::GeometryInstance *RasterizerSceneGLES3::geometry_instance_create(RID p_base) {
+ RS::InstanceType type = storage->get_base_type(p_base);
+ ERR_FAIL_COND_V(!((1 << type) & RS::INSTANCE_GEOMETRY_MASK), nullptr);
+
+ GeometryInstanceGLES3 *ginstance = geometry_instance_alloc.alloc();
+ ginstance->data = memnew(GeometryInstanceGLES3::Data);
+
+ ginstance->data->base = p_base;
+ ginstance->data->base_type = type;
+
+ _geometry_instance_mark_dirty(ginstance);
+
+ return ginstance;
}
void RasterizerSceneGLES3::geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->skeleton = p_skeleton;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
}
void RasterizerSceneGLES3::geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->material_override = p_override;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
}
void RasterizerSceneGLES3::geometry_instance_set_material_overlay(GeometryInstance *p_geometry_instance, RID p_overlay) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->material_overlay = p_overlay;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
}
-void RasterizerSceneGLES3::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_material) {
+void RasterizerSceneGLES3::geometry_instance_set_surface_materials(GeometryInstance *p_geometry_instance, const Vector<RID> &p_materials) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->surface_materials = p_materials;
+
+ _geometry_instance_mark_dirty(ginstance);
+ ginstance->data->dirty_dependencies = true;
}
void RasterizerSceneGLES3::geometry_instance_set_mesh_instance(GeometryInstance *p_geometry_instance, RID p_mesh_instance) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->mesh_instance = p_mesh_instance;
+
+ _geometry_instance_mark_dirty(ginstance);
}
-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_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->transform = p_transform;
+ ginstance->mirror = p_transform.basis.determinant() < 0;
+ ginstance->data->aabb = p_aabb;
+ ginstance->transformed_aabb = p_transformed_aabb;
+
+ Vector3 model_scale_vec = p_transform.basis.get_scale_abs();
+ // handle non uniform scale here
+
+ float max_scale = MAX(model_scale_vec.x, MAX(model_scale_vec.y, model_scale_vec.z));
+ float min_scale = MIN(model_scale_vec.x, MIN(model_scale_vec.y, model_scale_vec.z));
+ ginstance->non_uniform_scale = max_scale >= 0.0 && (min_scale / max_scale) < 0.9;
+
+ ginstance->lod_model_scale = max_scale;
}
void RasterizerSceneGLES3::geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->layer_mask = p_layer_mask;
}
void RasterizerSceneGLES3::geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->lod_bias = p_lod_bias;
}
void RasterizerSceneGLES3::geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->force_alpha = CLAMP(1.0 - p_transparency, 0, 1);
}
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) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->fade_near = p_enable_near;
+ ginstance->fade_near_begin = p_near_begin;
+ ginstance->fade_near_end = p_near_end;
+ ginstance->fade_far = p_enable_far;
+ ginstance->fade_far_begin = p_far_begin;
+ ginstance->fade_far_end = p_far_end;
}
void RasterizerSceneGLES3::geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->parent_fade_alpha = p_alpha;
}
void RasterizerSceneGLES3::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->use_baked_light = p_enable;
+
+ _geometry_instance_mark_dirty(ginstance);
}
void RasterizerSceneGLES3::geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->use_dynamic_gi = p_enable;
+ _geometry_instance_mark_dirty(ginstance);
}
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) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
}
void RasterizerSceneGLES3::geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
}
void RasterizerSceneGLES3::geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->shader_parameters_offset = p_offset;
+ _geometry_instance_mark_dirty(ginstance);
}
void RasterizerSceneGLES3::geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ ginstance->data->cast_double_sided_shadows = p_enable;
+ _geometry_instance_mark_dirty(ginstance);
}
uint32_t RasterizerSceneGLES3::geometry_instance_get_pair_mask() {
- return 0;
+ return 0; //(1 << RS::INSTANCE_LIGHT);
+ // For now, nothing is paired
}
void RasterizerSceneGLES3::geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+
+ ginstance->omni_light_count = 0;
+ ginstance->spot_light_count = 0;
}
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) {
@@ -114,9 +218,314 @@ void RasterizerSceneGLES3::geometry_instance_pair_voxel_gi_instances(GeometryIns
}
void RasterizerSceneGLES3::geometry_instance_set_softshadow_projector_pairing(GeometryInstance *p_geometry_instance, bool p_softshadow, bool p_projector) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
}
void RasterizerSceneGLES3::geometry_instance_free(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ ERR_FAIL_COND(!ginstance);
+ GeometryInstanceSurface *surf = ginstance->surface_caches;
+ while (surf) {
+ GeometryInstanceSurface *next = surf->next;
+ geometry_instance_surface_alloc.free(surf);
+ surf = next;
+ }
+ memdelete(ginstance->data);
+ geometry_instance_alloc.free(ginstance);
+}
+
+void RasterizerSceneGLES3::_geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance) {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+ if (ginstance->dirty_list_element.in_list()) {
+ return;
+ }
+
+ //clear surface caches
+ GeometryInstanceSurface *surf = ginstance->surface_caches;
+
+ while (surf) {
+ GeometryInstanceSurface *next = surf->next;
+ geometry_instance_surface_alloc.free(surf);
+ surf = next;
+ }
+
+ ginstance->surface_caches = nullptr;
+
+ geometry_instance_dirty_list.add(&ginstance->dirty_list_element);
+}
+
+void RasterizerSceneGLES3::_update_dirty_geometry_instances() {
+ while (geometry_instance_dirty_list.first()) {
+ _geometry_instance_update(geometry_instance_dirty_list.first()->self());
+ }
+}
+
+void RasterizerSceneGLES3::_geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker) {
+ switch (p_notification) {
+ case RendererStorage::DEPENDENCY_CHANGED_MATERIAL:
+ case RendererStorage::DEPENDENCY_CHANGED_MESH:
+ case RendererStorage::DEPENDENCY_CHANGED_PARTICLES:
+ case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH:
+ case RendererStorage::DEPENDENCY_CHANGED_SKELETON_DATA: {
+ static_cast<RasterizerSceneGLES3 *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+ } break;
+ case RendererStorage::DEPENDENCY_CHANGED_MULTIMESH_VISIBLE_INSTANCES: {
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_tracker->userdata);
+ if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
+ ginstance->instance_count = GLES3::MeshStorage::get_singleton()->multimesh_get_instances_to_draw(ginstance->data->base);
+ }
+ } break;
+ default: {
+ //rest of notifications of no interest
+ } break;
+ }
+}
+
+void RasterizerSceneGLES3::_geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker) {
+ static_cast<RasterizerSceneGLES3 *>(singleton)->_geometry_instance_mark_dirty(static_cast<GeometryInstance *>(p_tracker->userdata));
+}
+
+void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, GLES3::SceneMaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh) {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+
+ bool has_read_screen_alpha = p_material->shader_data->uses_screen_texture || p_material->shader_data->uses_depth_texture || p_material->shader_data->uses_normal_texture;
+ bool has_base_alpha = ((p_material->shader_data->uses_alpha && !p_material->shader_data->uses_alpha_clip) || has_read_screen_alpha);
+ bool has_blend_alpha = p_material->shader_data->uses_blend_alpha;
+ bool has_alpha = has_base_alpha || has_blend_alpha;
+
+ uint32_t flags = 0;
+
+ if (p_material->shader_data->uses_screen_texture) {
+ flags |= GeometryInstanceSurface::FLAG_USES_SCREEN_TEXTURE;
+ }
+
+ if (p_material->shader_data->uses_depth_texture) {
+ flags |= GeometryInstanceSurface::FLAG_USES_DEPTH_TEXTURE;
+ }
+
+ if (p_material->shader_data->uses_normal_texture) {
+ flags |= GeometryInstanceSurface::FLAG_USES_NORMAL_TEXTURE;
+ }
+
+ if (ginstance->data->cast_double_sided_shadows) {
+ flags |= GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS;
+ }
+
+ if (has_alpha || has_read_screen_alpha || p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) {
+ //material is only meant for alpha pass
+ flags |= GeometryInstanceSurface::FLAG_PASS_ALPHA;
+ if (p_material->shader_data->uses_depth_pre_pass && !(p_material->shader_data->depth_draw == GLES3::SceneShaderData::DEPTH_DRAW_DISABLED || p_material->shader_data->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED)) {
+ flags |= GeometryInstanceSurface::FLAG_PASS_DEPTH;
+ flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW;
+ }
+ } else {
+ flags |= GeometryInstanceSurface::FLAG_PASS_OPAQUE;
+ flags |= GeometryInstanceSurface::FLAG_PASS_DEPTH;
+ flags |= GeometryInstanceSurface::FLAG_PASS_SHADOW;
+ }
+
+ GLES3::SceneMaterialData *material_shadow = nullptr;
+ void *surface_shadow = nullptr;
+ if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass && !p_material->shader_data->uses_alpha_clip) {
+ flags |= GeometryInstanceSurface::FLAG_USES_SHARED_SHADOW_MATERIAL;
+ material_shadow = static_cast<GLES3::SceneMaterialData *>(GLES3::MaterialStorage::get_singleton()->material_get_data(scene_globals.default_material, RS::SHADER_SPATIAL));
+
+ RID shadow_mesh = mesh_storage->mesh_get_shadow_mesh(p_mesh);
+
+ if (shadow_mesh.is_valid()) {
+ surface_shadow = mesh_storage->mesh_get_surface(shadow_mesh, p_surface);
+ }
+
+ } else {
+ material_shadow = p_material;
+ }
+
+ GeometryInstanceSurface *sdcache = geometry_instance_surface_alloc.alloc();
+
+ sdcache->flags = flags;
+
+ sdcache->shader = p_material->shader_data;
+ sdcache->material = p_material;
+ sdcache->surface = mesh_storage->mesh_get_surface(p_mesh, p_surface);
+ sdcache->primitive = mesh_storage->mesh_surface_get_primitive(sdcache->surface);
+ sdcache->surface_index = p_surface;
+
+ if (ginstance->data->dirty_dependencies) {
+ storage->base_update_dependency(p_mesh, &ginstance->data->dependency_tracker);
+ }
+
+ //shadow
+ sdcache->shader_shadow = material_shadow->shader_data;
+ sdcache->material_shadow = material_shadow;
+
+ sdcache->surface_shadow = surface_shadow ? surface_shadow : sdcache->surface;
+
+ sdcache->owner = ginstance;
+
+ sdcache->next = ginstance->surface_caches;
+ ginstance->surface_caches = sdcache;
+
+ //sortkey
+
+ sdcache->sort.sort_key1 = 0;
+ sdcache->sort.sort_key2 = 0;
+
+ sdcache->sort.surface_index = p_surface;
+ sdcache->sort.material_id_low = p_material_id & 0x0000FFFF;
+ sdcache->sort.material_id_hi = p_material_id >> 16;
+ sdcache->sort.shader_id = p_shader_id;
+ sdcache->sort.geometry_id = p_mesh.get_local_index();
+ sdcache->sort.priority = p_material->priority;
+}
+
+void RasterizerSceneGLES3::_geometry_instance_add_surface_with_material_chain(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, GLES3::SceneMaterialData *p_material_data, RID p_mat_src, RID p_mesh) {
+ GLES3::SceneMaterialData *material_data = p_material_data;
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+
+ _geometry_instance_add_surface_with_material(ginstance, p_surface, material_data, p_mat_src.get_local_index(), material_storage->material_get_shader_id(p_mat_src), p_mesh);
+
+ while (material_data->next_pass.is_valid()) {
+ RID next_pass = material_data->next_pass;
+ material_data = static_cast<GLES3::SceneMaterialData *>(material_storage->material_get_data(next_pass, RS::SHADER_SPATIAL));
+ if (!material_data || !material_data->shader_data->valid) {
+ break;
+ }
+ if (ginstance->data->dirty_dependencies) {
+ material_storage->material_update_dependency(next_pass, &ginstance->data->dependency_tracker);
+ }
+ _geometry_instance_add_surface_with_material(ginstance, p_surface, material_data, next_pass.get_local_index(), material_storage->material_get_shader_id(next_pass), p_mesh);
+ }
+}
+
+void RasterizerSceneGLES3::_geometry_instance_add_surface(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, RID p_material, RID p_mesh) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ RID m_src;
+
+ m_src = ginstance->data->material_override.is_valid() ? ginstance->data->material_override : p_material;
+
+ GLES3::SceneMaterialData *material_data = nullptr;
+
+ if (m_src.is_valid()) {
+ material_data = static_cast<GLES3::SceneMaterialData *>(material_storage->material_get_data(m_src, RS::SHADER_SPATIAL));
+ if (!material_data || !material_data->shader_data->valid) {
+ material_data = nullptr;
+ }
+ }
+
+ if (material_data) {
+ if (ginstance->data->dirty_dependencies) {
+ material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
+ }
+ } else {
+ material_data = static_cast<GLES3::SceneMaterialData *>(material_storage->material_get_data(scene_globals.default_material, RS::SHADER_SPATIAL));
+ m_src = scene_globals.default_material;
+ }
+
+ ERR_FAIL_COND(!material_data);
+
+ _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material_data, m_src, p_mesh);
+
+ if (ginstance->data->material_overlay.is_valid()) {
+ m_src = ginstance->data->material_overlay;
+
+ material_data = static_cast<GLES3::SceneMaterialData *>(material_storage->material_get_data(m_src, RS::SHADER_SPATIAL));
+ if (material_data && material_data->shader_data->valid) {
+ if (ginstance->data->dirty_dependencies) {
+ material_storage->material_update_dependency(m_src, &ginstance->data->dependency_tracker);
+ }
+
+ _geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material_data, m_src, p_mesh);
+ }
+ }
+}
+
+void RasterizerSceneGLES3::_geometry_instance_update(GeometryInstance *p_geometry_instance) {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+ GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
+
+ if (ginstance->data->dirty_dependencies) {
+ ginstance->data->dependency_tracker.update_begin();
+ }
+
+ //add geometry for drawing
+ switch (ginstance->data->base_type) {
+ case RS::INSTANCE_MESH: {
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+ RID mesh = ginstance->data->base;
+
+ materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ //if no materials, no surfaces.
+ const RID *inst_materials = ginstance->data->surface_materials.ptr();
+ uint32_t surf_mat_count = ginstance->data->surface_materials.size();
+
+ for (uint32_t j = 0; j < surface_count; j++) {
+ RID material = (j < surf_mat_count && inst_materials[j].is_valid()) ? inst_materials[j] : materials[j];
+ _geometry_instance_add_surface(ginstance, j, material, mesh);
+ }
+ }
+
+ ginstance->instance_count = 1;
+
+ } break;
+
+ case RS::INSTANCE_MULTIMESH: {
+ RID mesh = mesh_storage->multimesh_get_mesh(ginstance->data->base);
+ if (mesh.is_valid()) {
+ const RID *materials = nullptr;
+ uint32_t surface_count;
+
+ materials = mesh_storage->mesh_get_surface_count_and_materials(mesh, surface_count);
+ if (materials) {
+ for (uint32_t j = 0; j < surface_count; j++) {
+ _geometry_instance_add_surface(ginstance, j, materials[j], mesh);
+ }
+ }
+
+ ginstance->instance_count = mesh_storage->multimesh_get_instances_to_draw(ginstance->data->base);
+ }
+
+ } break;
+ case RS::INSTANCE_PARTICLES: {
+ } break;
+
+ default: {
+ }
+ }
+
+ //Fill push constant
+
+ bool store_transform = true;
+ ginstance->base_flags = 0;
+
+ if (ginstance->data->base_type == RS::INSTANCE_MULTIMESH) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH;
+ if (mesh_storage->multimesh_get_transform_format(ginstance->data->base) == RS::MULTIMESH_TRANSFORM_2D) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D;
+ }
+ if (mesh_storage->multimesh_uses_colors(ginstance->data->base)) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR;
+ }
+ if (mesh_storage->multimesh_uses_custom_data(ginstance->data->base)) {
+ ginstance->base_flags |= INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA;
+ }
+
+ //ginstance->transforms_uniform_set = mesh_storage->multimesh_get_3d_uniform_set(ginstance->data->base, scene_globals.default_shader_rd, TRANSFORMS_UNIFORM_SET);
+
+ } else if (ginstance->data->base_type == RS::INSTANCE_PARTICLES) {
+ } else if (ginstance->data->base_type == RS::INSTANCE_MESH) {
+ }
+
+ ginstance->store_transform_cache = store_transform;
+
+ if (ginstance->data->dirty_dependencies) {
+ ginstance->data->dependency_tracker.update_end();
+ ginstance->data->dirty_dependencies = false;
+ }
+
+ ginstance->dirty_list_element.remove_from_list();
}
/* SHADOW ATLAS API */
@@ -238,36 +647,70 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
dirty_sky_list = nullptr;
}
-void RasterizerSceneGLES3::_draw_sky(Sky *p_sky, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_custom_fov, float p_energy, const Basis &p_sky_orientation) {
- ERR_FAIL_COND(!p_sky);
+void RasterizerSceneGLES3::_draw_sky(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform) {
+ GLES3::MaterialStorage *material_storage = GLES3::MaterialStorage::get_singleton();
+ ERR_FAIL_COND(!p_env);
- glDepthMask(GL_TRUE);
- glEnable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
- glDisable(GL_BLEND);
- glDepthFunc(GL_LEQUAL);
- glColorMask(1, 1, 1, 1);
+ Sky *sky = sky_owner.get_or_null(p_env->sky);
+ ERR_FAIL_COND(!sky);
+
+ GLES3::SkyMaterialData *material_data = nullptr;
+ RID sky_material;
+
+ RS::EnvironmentBG background = p_env->background;
+
+ if (sky) {
+ ERR_FAIL_COND(!sky);
+ sky_material = sky->material;
+
+ if (sky_material.is_valid()) {
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ if (!material_data || !material_data->shader_data->valid) {
+ material_data = nullptr;
+ }
+ }
+
+ if (!material_data) {
+ sky_material = sky_globals.default_material;
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+ } else if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) {
+ sky_material = sky_globals.fog_material;
+ material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
+ }
+
+ ERR_FAIL_COND(!material_data);
+ material_data->bind_uniforms();
+
+ GLES3::SkyShaderData *shader_data = material_data->shader_data;
- //state.sky_shader.version_bind_shader(sky_globals.default_shader, SkyShaderGLES3::MODE_BACKGROUND);
- //glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_instance_data_buffers[state.current_buffer]); // Canvas data updated here
- //glBindBufferBase(GL_UNIFORM_BUFFER, 1, state.canvas_instance_data_buffers[state.current_buffer]); // Global data
- //glBindBufferBase(GL_UNIFORM_BUFFER, 2, state.canvas_instance_data_buffers[state.current_buffer]); // Directional light data
- //glBindBufferBase(GL_UNIFORM_BUFFER, 3, state.canvas_instance_data_buffers[state.current_buffer]); // Material uniforms
+ ERR_FAIL_COND(!shader_data);
+
+ //glBindBufferBase(GL_UNIFORM_BUFFER, 2, p_sky.directional light data); // Directional light data
// Camera
CameraMatrix camera;
- if (p_custom_fov) {
+ if (p_env->sky_custom_fov) {
float near_plane = p_projection.get_z_near();
float far_plane = p_projection.get_z_far();
float aspect = p_projection.get_aspect();
- camera.set_perspective(p_custom_fov, aspect, near_plane, far_plane);
-
+ camera.set_perspective(p_env->sky_custom_fov, aspect, near_plane, far_plane);
} else {
camera = p_projection;
}
-
+ Basis sky_transform = p_env->sky_orientation;
+ sky_transform.invert();
+ sky_transform = p_transform.basis * sky_transform;
+
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::ORIENTATION, sky_transform, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::PROJECTION, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1], shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::POSITION, p_transform.origin, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_set_uniform(SkyShaderGLES3::TIME, time, shader_data->version, SkyShaderGLES3::MODE_BACKGROUND);
+ // Bind a vertex array or else OpenGL complains. We won't actually use it
+ glBindVertexArray(sky_globals.quad_array);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
@@ -599,20 +1042,267 @@ void RasterizerSceneGLES3::voxel_gi_update(RID p_probe, bool p_update_light_inst
void RasterizerSceneGLES3::voxel_gi_set_quality(RS::VoxelGIQuality) {
}
+void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append) {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ scene_state.used_screen_texture = false;
+ scene_state.used_normal_texture = false;
+ scene_state.used_depth_texture = false;
+ }
+
+ Plane near_plane;
+ if (p_render_data->cam_orthogonal) {
+ near_plane = Plane(-p_render_data->cam_transform.basis.get_column(Vector3::AXIS_Z), p_render_data->cam_transform.origin);
+ near_plane.d += p_render_data->cam_projection.get_z_near();
+ }
+ float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near();
+
+ RenderList *rl = &render_list[p_render_list];
+
+ // Parse any updates on our geometry, updates surface caches and such
+ _update_dirty_geometry_instances();
+
+ if (!p_append) {
+ rl->clear();
+ if (p_render_list == RENDER_LIST_OPAQUE) {
+ render_list[RENDER_LIST_ALPHA].clear(); //opaque fills alpha too
+ }
+ }
+
+ //fill list
+
+ for (int i = 0; i < (int)p_render_data->instances->size(); i++) {
+ GeometryInstanceGLES3 *inst = static_cast<GeometryInstanceGLES3 *>((*p_render_data->instances)[i]);
+
+ if (p_render_data->cam_orthogonal) {
+ Vector3 support_min = inst->transformed_aabb.get_support(-near_plane.normal);
+ inst->depth = near_plane.distance_to(support_min);
+ } else {
+ Vector3 aabb_center = inst->transformed_aabb.position + (inst->transformed_aabb.size * 0.5);
+ inst->depth = p_render_data->cam_transform.origin.distance_to(aabb_center);
+ }
+ uint32_t depth_layer = CLAMP(int(inst->depth * 16 / z_max), 0, 15);
+
+ uint32_t flags = inst->base_flags; //fill flags if appropriate
+
+ if (inst->non_uniform_scale) {
+ flags |= INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE;
+ }
+
+ //Process lights here, determine if they need extra passes
+ if (p_pass_mode == PASS_MODE_COLOR) {
+ }
+
+ inst->flags_cache = flags;
+
+ GeometryInstanceSurface *surf = inst->surface_caches;
+
+ while (surf) {
+ // LOD
+
+ if (p_render_data->screen_mesh_lod_threshold > 0.0 && mesh_storage->mesh_surface_has_lod(surf->surface)) {
+ //lod
+ Vector3 lod_support_min = inst->transformed_aabb.get_support(-p_render_data->lod_camera_plane.normal);
+ Vector3 lod_support_max = inst->transformed_aabb.get_support(p_render_data->lod_camera_plane.normal);
+
+ float distance_min = p_render_data->lod_camera_plane.distance_to(lod_support_min);
+ float distance_max = p_render_data->lod_camera_plane.distance_to(lod_support_max);
+
+ float distance = 0.0;
+
+ if (distance_min * distance_max < 0.0) {
+ //crossing plane
+ distance = 0.0;
+ } else if (distance_min >= 0.0) {
+ distance = distance_min;
+ } else if (distance_max <= 0.0) {
+ distance = -distance_max;
+ }
+
+ if (p_render_data->cam_orthogonal) {
+ distance = 1.0;
+ }
+
+ uint32_t indices;
+ surf->lod_index = mesh_storage->mesh_surface_get_lod(surf->surface, inst->lod_model_scale * inst->lod_bias, distance * p_render_data->lod_distance_multiplier, p_render_data->screen_mesh_lod_threshold, &indices);
+ /*
+ if (p_render_data->render_info) {
+ indices = _indices_to_primitives(surf->primitive, indices);
+ if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
+ } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += indices;
+ }
+ }
+ */
+ } else {
+ surf->lod_index = 0;
+ /*
+ if (p_render_data->render_info) {
+ uint32_t to_draw = mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ to_draw = _indices_to_primitives(surf->primitive, to_draw);
+ to_draw *= inst->instance_count;
+ if (p_render_list == RENDER_LIST_OPAQUE) { //opaque
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_VISIBLE][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ } else if (p_render_list == RENDER_LIST_SECONDARY) { //shadow
+ p_render_data->render_info->info[RS::VIEWPORT_RENDER_INFO_TYPE_SHADOW][RS::VIEWPORT_RENDER_INFO_PRIMITIVES_IN_FRAME] += mesh_storage->mesh_surface_get_vertices_drawn_count(surf->surface);
+ }
+ }
+ */
+ }
+
+ // ADD Element
+ if (p_pass_mode == PASS_MODE_COLOR) {
+#ifdef DEBUG_ENABLED
+ bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW);
+#else
+ bool force_alpha = false;
+#endif
+ if (!force_alpha && (surf->flags & GeometryInstanceSurface::FLAG_PASS_OPAQUE)) {
+ rl->add_element(surf);
+ }
+ if (force_alpha || (surf->flags & GeometryInstanceSurface::FLAG_PASS_ALPHA)) {
+ render_list[RENDER_LIST_ALPHA].add_element(surf);
+ }
+
+ if (surf->flags & GeometryInstanceSurface::FLAG_USES_SCREEN_TEXTURE) {
+ scene_state.used_screen_texture = true;
+ }
+ if (surf->flags & GeometryInstanceSurface::FLAG_USES_NORMAL_TEXTURE) {
+ scene_state.used_normal_texture = true;
+ }
+ if (surf->flags & GeometryInstanceSurface::FLAG_USES_DEPTH_TEXTURE) {
+ scene_state.used_depth_texture = true;
+ }
+
+ /*
+ Add elements here if there are shadows
+ */
+
+ } else if (p_pass_mode == PASS_MODE_SHADOW) {
+ if (surf->flags & GeometryInstanceSurface::FLAG_PASS_SHADOW) {
+ rl->add_element(surf);
+ }
+ } else {
+ if (surf->flags & (GeometryInstanceSurface::FLAG_PASS_DEPTH | GeometryInstanceSurface::FLAG_PASS_OPAQUE)) {
+ rl->add_element(surf);
+ }
+ }
+
+ surf->sort.depth_layer = depth_layer;
+
+ surf = surf->next;
+ }
+ }
+}
+
+void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows) {
+ CameraMatrix correction;
+ correction.set_depth_correction(p_flip_y);
+ CameraMatrix projection = correction * p_render_data->cam_projection;
+ //store camera into ubo
+ RasterizerStorageGLES3::store_camera(projection, scene_state.ubo.projection_matrix);
+ RasterizerStorageGLES3::store_camera(projection.inverse(), scene_state.ubo.inv_projection_matrix);
+ RasterizerStorageGLES3::store_transform(p_render_data->cam_transform, scene_state.ubo.inv_view_matrix);
+ RasterizerStorageGLES3::store_transform(p_render_data->cam_transform.affine_inverse(), scene_state.ubo.view_matrix);
+
+ scene_state.ubo.directional_light_count = 1;
+
+ scene_state.ubo.z_far = p_render_data->z_far;
+ scene_state.ubo.z_near = p_render_data->z_near;
+
+ scene_state.ubo.pancake_shadows = p_pancake_shadows;
+
+ scene_state.ubo.viewport_size[0] = p_screen_size.x;
+ scene_state.ubo.viewport_size[1] = p_screen_size.y;
+
+ Size2 screen_pixel_size = Vector2(1.0, 1.0) / Size2(p_screen_size);
+ scene_state.ubo.screen_pixel_size[0] = screen_pixel_size.x;
+ scene_state.ubo.screen_pixel_size[1] = screen_pixel_size.y;
+
+ //time global variables
+ scene_state.ubo.time = time;
+
+ if (is_environment(p_render_data->environment)) {
+ Environment *env = environment_owner.get_or_null(p_render_data->environment);
+ RS::EnvironmentBG env_bg = env->background;
+ RS::EnvironmentAmbientSource ambient_src = env->ambient_source;
+
+ float bg_energy = env->bg_energy;
+ scene_state.ubo.ambient_light_color_energy[3] = bg_energy;
+
+ scene_state.ubo.ambient_color_sky_mix = env->ambient_sky_contribution;
+
+ //ambient
+ if (ambient_src == RS::ENV_AMBIENT_SOURCE_BG && (env_bg == RS::ENV_BG_CLEAR_COLOR || env_bg == RS::ENV_BG_COLOR)) {
+ Color color = env_bg == RS::ENV_BG_CLEAR_COLOR ? p_default_bg_color : env->bg_color;
+ color = color.srgb_to_linear();
+
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * bg_energy;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * bg_energy;
+ } else {
+ float energy = env->ambient_light_energy;
+ Color color = env->ambient_light;
+ color = color.srgb_to_linear();
+ scene_state.ubo.ambient_light_color_energy[0] = color.r * energy;
+ scene_state.ubo.ambient_light_color_energy[1] = color.g * energy;
+ scene_state.ubo.ambient_light_color_energy[2] = color.b * energy;
+
+ Basis sky_transform = env->sky_orientation;
+ sky_transform = sky_transform.inverse() * p_render_data->cam_transform.basis;
+ RasterizerStorageGLES3::store_transform_3x3(sky_transform, scene_state.ubo.radiance_inverse_xform);
+ }
+
+ scene_state.ubo.fog_enabled = env->fog_enabled;
+ scene_state.ubo.fog_density = env->fog_density;
+ scene_state.ubo.fog_height = env->fog_height;
+ scene_state.ubo.fog_height_density = env->fog_height_density;
+ scene_state.ubo.fog_aerial_perspective = env->fog_aerial_perspective;
+
+ Color fog_color = env->fog_light_color.srgb_to_linear();
+ float fog_energy = env->fog_light_energy;
+
+ scene_state.ubo.fog_light_color[0] = fog_color.r * fog_energy;
+ scene_state.ubo.fog_light_color[1] = fog_color.g * fog_energy;
+ scene_state.ubo.fog_light_color[2] = fog_color.b * fog_energy;
+
+ scene_state.ubo.fog_sun_scatter = env->fog_sun_scatter;
+
+ } else {
+ }
+
+ if (scene_state.ubo_buffer == 0) {
+ glGenBuffers(1, &scene_state.ubo_buffer);
+ }
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_DATA_UNIFORM_LOCATION, scene_state.ubo_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::UBO), &scene_state.ubo, GL_STREAM_DRAW);
+ glBindBuffer(GL_UNIFORM_BUFFER, 0);
+}
+
void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &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_mesh_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) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
+ GLES3::Config *config = GLES3::Config::get_singleton();
RENDER_TIMESTAMP("Setup 3D Scene");
- // assign render data
+
+ RenderBuffers *rb = nullptr;
+ if (p_render_buffers.is_valid()) {
+ rb = render_buffers_owner.get_or_null(p_render_buffers);
+ ERR_FAIL_COND(!rb);
+ }
+
+ // Assign render data
// Use the format from rendererRD
RenderDataGLES3 render_data;
{
render_data.render_buffers = p_render_buffers;
-
+ render_data.transparent_bg = rb->is_transparent;
// Our first camera is used by default
render_data.cam_transform = p_camera_data->main_transform;
render_data.cam_projection = p_camera_data->main_projection;
render_data.view_projection[0] = p_camera_data->main_projection;
- render_data.cam_ortogonal = p_camera_data->is_orthogonal;
+ render_data.cam_orthogonal = p_camera_data->is_orthogonal;
render_data.view_count = p_camera_data->view_count;
for (uint32_t v = 0; v < p_camera_data->view_count; v++) {
@@ -625,10 +1315,6 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
render_data.instances = &p_instances;
render_data.lights = &p_lights;
render_data.reflection_probes = &p_reflection_probes;
- //render_data.voxel_gi_instances = &p_voxel_gi_instances;
- //render_data.decals = &p_decals;
- //render_data.lightmaps = &p_lightmaps;
- //render_data.fog_volumes = &p_fog_volumes;
render_data.environment = p_environment;
render_data.camera_effects = p_camera_effects;
render_data.shadow_atlas = p_shadow_atlas;
@@ -655,14 +1341,14 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
render_data.reflection_probes = &empty;
}
- RenderBuffers *rb = nullptr;
- //RasterizerStorageGLES3::RenderTarget *rt = nullptr;
- if (p_render_buffers.is_valid()) {
- rb = render_buffers_owner.get_or_null(p_render_buffers);
- ERR_FAIL_COND(!rb);
- //rt = texture_storage->render_target_owner.get_or_null(rb->render_target);
- //ERR_FAIL_COND(!rt);
- }
+ bool reverse_cull = false;
+
+ ///////////
+ // Fill Light lists here
+ //////////
+
+ GLuint global_buffer = GLES3::MaterialStorage::get_singleton()->global_variables_get_uniform_buffer();
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_GLOBALS_UNIFORM_LOCATION, global_buffer);
Color clear_color;
if (p_render_buffers.is_valid()) {
@@ -675,11 +1361,84 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
bool fb_cleared = false;
- glDepthFunc(GL_LEQUAL);
+ Size2i screen_size;
+ screen_size.x = rb->width;
+ screen_size.y = rb->height;
- /* Depth Prepass */
+ SceneState::TonemapUBO tonemap_ubo;
+ if (is_environment(p_environment)) {
+ tonemap_ubo.exposure = env->exposure;
+ tonemap_ubo.white = env->white;
+ tonemap_ubo.tonemapper = int32_t(env->tone_mapper);
+ }
+
+ if (scene_state.tonemap_buffer == 0) {
+ // Only create if using 3D
+ glGenBuffers(1, &scene_state.tonemap_buffer);
+ }
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_TONEMAP_UNIFORM_LOCATION, scene_state.tonemap_buffer);
+ glBufferData(GL_UNIFORM_BUFFER, sizeof(SceneState::TonemapUBO), &tonemap_ubo, GL_STREAM_DRAW);
+
+ _setup_environment(&render_data, render_data.reflection_probe.is_valid(), screen_size, !render_data.reflection_probe.is_valid(), clear_color, false);
+
+ _fill_render_list(RENDER_LIST_OPAQUE, &render_data, PASS_MODE_COLOR);
+ render_list[RENDER_LIST_OPAQUE].sort_by_key();
+ render_list[RENDER_LIST_ALPHA].sort_by_reverse_depth_and_priority();
glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
+ glViewport(0, 0, rb->width, rb->height);
+
+ // Do depth prepass if it's explicitly enabled
+ bool use_depth_prepass = config->use_depth_prepass;
+
+ // Don't do depth prepass we are rendering overdraw
+ use_depth_prepass = use_depth_prepass && get_debug_draw_mode() != RS::VIEWPORT_DEBUG_DRAW_OVERDRAW;
+
+ if (use_depth_prepass) {
+ //pre z pass
+
+ glDisable(GL_BLEND);
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glDisable(GL_SCISSOR_TEST);
+ glCullFace(GL_BACK);
+ glEnable(GL_CULL_FACE);
+ scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
+
+ glColorMask(0, 0, 0, 0);
+ glClearDepth(1.0f);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ uint32_t spec_constant_base_flags = 0;
+
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, render_data.lod_camera_plane, render_data.lod_distance_multiplier, render_data.screen_mesh_lod_threshold);
+ _render_list_template<PASS_MODE_DEPTH>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
+
+ glColorMask(1, 1, 1, 1);
+
+ fb_cleared = true;
+ scene_state.used_depth_prepass = true;
+ } else {
+ scene_state.used_depth_prepass = false;
+ }
+
+ glBlendEquation(GL_FUNC_ADD);
+
+ if (render_data.transparent_bg) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ glEnable(GL_BLEND);
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glDisable(GL_BLEND);
+ }
+ scene_state.current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
+
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_LEQUAL);
+ glDepthMask(GL_TRUE);
+ scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
+ scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE;
if (!fb_cleared) {
glClearDepth(1.0f);
@@ -690,9 +1449,6 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
bool keep_color = false;
if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
- clear_color = Color(0, 0, 0, 1);
- }
- if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) {
clear_color = Color(0, 0, 0, 1); //in overdraw mode, BG should always be black
} else if (is_environment(p_environment)) {
RS::EnvironmentBG bg_mode = environment_get_background(p_environment);
@@ -723,16 +1479,43 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
default: {
}
}
+ // Draw sky cubemap
}
if (!keep_color) {
glClearBufferfv(GL_COLOR, 0, clear_color.components);
}
+ uint32_t spec_constant_base_flags = 0;
+ //Render Opaque Objects
+ RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, render_data.lod_camera_plane, render_data.lod_distance_multiplier, render_data.screen_mesh_lod_threshold);
+
+ _render_list_template<PASS_MODE_COLOR>(&render_list_params, &render_data, 0, render_list[RENDER_LIST_OPAQUE].elements.size());
+
if (draw_sky) {
- //_draw_sky(sky, render_data.cam_projection, render_data.cam_transform, env->sky_custom_fov, env->bg_energy, env->sky_orientation);
+ if (scene_state.current_depth_test != GLES3::SceneShaderData::DEPTH_TEST_ENABLED) {
+ glEnable(GL_DEPTH_TEST);
+ scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
+ }
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_BLEND);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ scene_state.current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_ENABLED;
+ scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_DISABLED;
+ scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
+
+ _draw_sky(env, render_data.cam_projection, render_data.cam_transform);
}
+ glEnable(GL_BLEND);
+
+ //Render transparent pass
+ RenderListParameters render_list_params_alpha(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, render_data.lod_camera_plane, render_data.lod_distance_multiplier, render_data.screen_mesh_lod_threshold);
+
+ _render_list_template<PASS_MODE_COLOR_TRANSPARENT>(&render_list_params_alpha, &render_data, 0, render_list[RENDER_LIST_ALPHA].elements.size(), true);
+
if (p_render_buffers.is_valid()) {
/*
RENDER_TIMESTAMP("Tonemap");
@@ -741,9 +1524,225 @@ void RasterizerSceneGLES3::render_scene(RID p_render_buffers, const CameraData *
_render_buffers_debug_draw(p_render_buffers, p_shadow_atlas, p_occluder_debug_tex);
}
+ glDisable(GL_BLEND);
texture_storage->render_target_disable_clear_request(rb->render_target);
}
+template <PassMode p_pass_mode>
+void RasterizerSceneGLES3::_render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass) {
+ GLES3::MeshStorage *mesh_storage = GLES3::MeshStorage::get_singleton();
+
+ GLuint prev_vertex_array_gl = 0;
+ GLuint prev_index_array_gl = 0;
+
+ GLES3::SceneMaterialData *prev_material_data = nullptr;
+ GLES3::SceneShaderData *prev_shader = nullptr;
+
+ SceneShaderGLES3::ShaderVariant shader_variant = SceneShaderGLES3::MODE_COLOR; // Assigned to silence wrong -Wmaybe-initialized.
+
+ switch (p_pass_mode) {
+ case PASS_MODE_COLOR:
+ case PASS_MODE_COLOR_TRANSPARENT: {
+ } break;
+ case PASS_MODE_COLOR_ADDITIVE: {
+ shader_variant = SceneShaderGLES3::MODE_ADDITIVE;
+ } break;
+ case PASS_MODE_SHADOW:
+ case PASS_MODE_DEPTH: {
+ shader_variant = SceneShaderGLES3::MODE_DEPTH;
+ } break;
+ }
+
+ for (uint32_t i = p_from_element; i < p_to_element; i++) {
+ const GeometryInstanceSurface *surf = p_params->elements[i];
+ const GeometryInstanceGLES3 *inst = surf->owner;
+
+ if (p_pass_mode == PASS_MODE_COLOR && !(surf->flags & GeometryInstanceSurface::FLAG_PASS_OPAQUE)) {
+ continue; // Objects with "Depth-prepass" transparency are included in both render lists, but should only be rendered in the transparent pass
+ }
+
+ if (inst->instance_count == 0) {
+ continue;
+ }
+
+ //uint32_t base_spec_constants = p_params->spec_constant_base_flags;
+
+ GLES3::SceneShaderData *shader;
+ GLES3::SceneMaterialData *material_data;
+ void *mesh_surface;
+
+ if (p_pass_mode == PASS_MODE_SHADOW) {
+ shader = surf->shader_shadow;
+ material_data = surf->material_shadow;
+ mesh_surface = surf->surface_shadow;
+ } else {
+ shader = surf->shader;
+ material_data = surf->material;
+ mesh_surface = surf->surface;
+ }
+
+ if (!mesh_surface) {
+ continue;
+ }
+
+ if (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) {
+ if (scene_state.current_depth_test != shader->depth_test) {
+ if (shader->depth_test == GLES3::SceneShaderData::DEPTH_TEST_DISABLED) {
+ glDisable(GL_DEPTH_TEST);
+ } else {
+ glEnable(GL_DEPTH_TEST);
+ }
+ scene_state.current_depth_test = shader->depth_test;
+ }
+ }
+
+ if (scene_state.current_depth_draw != shader->depth_draw) {
+ switch (shader->depth_draw) {
+ case GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE: {
+ glDepthMask(p_pass_mode == PASS_MODE_COLOR);
+ } break;
+ case GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS: {
+ glDepthMask(GL_TRUE);
+ } break;
+ case GLES3::SceneShaderData::DEPTH_DRAW_DISABLED: {
+ glDepthMask(GL_FALSE);
+ } break;
+ }
+
+ scene_state.current_depth_draw = shader->depth_draw;
+ }
+
+ if (p_pass_mode == PASS_MODE_COLOR_TRANSPARENT || p_pass_mode == PASS_MODE_COLOR_ADDITIVE) {
+ GLES3::SceneShaderData::BlendMode desired_blend_mode;
+ if (p_pass_mode == PASS_MODE_COLOR_ADDITIVE) {
+ desired_blend_mode = GLES3::SceneShaderData::BLEND_MODE_ADD;
+ } else {
+ desired_blend_mode = shader->blend_mode;
+ }
+
+ if (desired_blend_mode != scene_state.current_blend_mode) {
+ switch (desired_blend_mode) {
+ case GLES3::SceneShaderData::BLEND_MODE_MIX: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (p_render_data->transparent_bg) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ } break;
+ case GLES3::SceneShaderData::BLEND_MODE_ADD: {
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(p_pass_mode == PASS_MODE_COLOR_TRANSPARENT ? GL_SRC_ALPHA : GL_ONE, GL_ONE);
+
+ } break;
+ case GLES3::SceneShaderData::BLEND_MODE_SUB: {
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ } break;
+ case GLES3::SceneShaderData::BLEND_MODE_MUL: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (p_render_data->transparent_bg) {
+ glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO);
+ } else {
+ glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
+ }
+
+ } break;
+ case GLES3::SceneShaderData::BLEND_MODE_ALPHA_TO_COVERAGE: {
+ // Do nothing for now.
+ } break;
+ }
+ scene_state.current_blend_mode = desired_blend_mode;
+ }
+ }
+
+ //find cull variant
+ GLES3::SceneShaderData::Cull cull_mode = shader->cull_mode;
+
+ if ((surf->flags & GeometryInstanceSurface::FLAG_USES_DOUBLE_SIDED_SHADOWS)) {
+ cull_mode = GLES3::SceneShaderData::CULL_DISABLED;
+ } else {
+ bool mirror = inst->mirror;
+ if (p_params->reverse_cull) {
+ mirror = !mirror;
+ }
+ if (cull_mode == GLES3::SceneShaderData::CULL_FRONT && mirror) {
+ cull_mode = GLES3::SceneShaderData::CULL_BACK;
+ } else if (cull_mode == GLES3::SceneShaderData::CULL_BACK && mirror) {
+ cull_mode = GLES3::SceneShaderData::CULL_FRONT;
+ }
+ }
+
+ if (scene_state.cull_mode != cull_mode) {
+ if (cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
+ glDisable(GL_CULL_FACE);
+ } else {
+ if (scene_state.cull_mode == GLES3::SceneShaderData::CULL_DISABLED) {
+ // Last time was disabled, so enable and set proper face.
+ glEnable(GL_CULL_FACE);
+ }
+ glCullFace(cull_mode == GLES3::SceneShaderData::CULL_FRONT ? GL_FRONT : GL_BACK);
+ }
+ scene_state.cull_mode = cull_mode;
+ }
+
+ RS::PrimitiveType primitive = surf->primitive;
+ static const GLenum prim[5] = { GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_TRIANGLES, GL_TRIANGLE_STRIP };
+ GLenum primitive_gl = prim[int(primitive)];
+
+ GLuint vertex_array_gl = 0;
+ GLuint index_array_gl = 0;
+
+ //skeleton and blend shape
+ if (surf->owner->mesh_instance.is_valid()) {
+ mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, shader->vertex_input_mask, vertex_array_gl);
+ } else {
+ mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, shader->vertex_input_mask, vertex_array_gl);
+ }
+
+ index_array_gl = mesh_storage->mesh_surface_get_index_buffer(mesh_surface, surf->lod_index);
+
+ if (prev_vertex_array_gl != vertex_array_gl) {
+ glBindVertexArray(vertex_array_gl);
+ prev_vertex_array_gl = vertex_array_gl;
+ }
+
+ bool use_index_buffer = false;
+ if (prev_index_array_gl != index_array_gl) {
+ if (index_array_gl != 0) {
+ // Bind index each time so we can use LODs
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_array_gl);
+ use_index_buffer = true;
+ }
+ prev_index_array_gl = index_array_gl;
+ }
+
+ // Update pipeline information here
+
+ Transform3D world_transform;
+ if (inst->store_transform_cache) {
+ world_transform = inst->transform;
+ }
+
+ if (prev_material_data != material_data) {
+ material_data->bind_uniforms();
+ }
+
+ if (prev_shader != shader) {
+ GLES3::MaterialStorage::get_singleton()->shaders.scene_shader.version_bind_shader(shader->version, shader_variant);
+ }
+
+ GLES3::MaterialStorage::get_singleton()->shaders.scene_shader.version_set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, world_transform, shader->version, shader_variant);
+
+ if (use_index_buffer) {
+ glDrawElements(primitive_gl, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface), mesh_storage->mesh_surface_get_index_type(mesh_surface), 0);
+ } else {
+ glDrawArrays(primitive_gl, 0, mesh_storage->mesh_surface_get_vertices_drawn_count(mesh_surface));
+ }
+ }
+}
+
void RasterizerSceneGLES3::render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) {
}
@@ -879,6 +1878,8 @@ void RasterizerSceneGLES3::render_buffers_configure(RID p_render_buffers, RID p_
GLES3::RenderTarget *rt = texture_storage->get_render_target(p_render_target);
+ rb->is_transparent = rt->flags[RendererTextureStorage::RENDER_TARGET_TRANSPARENT];
+
// framebuffer
glGenFramebuffers(1, &rb->framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, rb->framebuffer);
@@ -1007,6 +2008,38 @@ RasterizerSceneGLES3::RasterizerSceneGLES3(RasterizerStorageGLES3 *p_storage) {
storage = p_storage;
{
+ String global_defines;
+ global_defines += "#define MAX_GLOBAL_VARIABLES 256\n"; // TODO: this is arbitrary for now
+ material_storage->shaders.scene_shader.initialize(global_defines);
+ scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create();
+ material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR);
+ }
+
+ {
+ //default material and shader
+ scene_globals.default_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(scene_globals.default_shader);
+ material_storage->shader_set_code(scene_globals.default_shader, R"(
+// Default 3D material shader (clustered).
+
+shader_type spatial;
+
+void vertex() {
+ ROUGHNESS = 0.8;
+}
+
+void fragment() {
+ ALBEDO = vec3(0.6);
+ ROUGHNESS = 0.8;
+ METALLIC = 0.2;
+}
+)");
+ scene_globals.default_material = material_storage->material_allocate();
+ material_storage->material_initialize(scene_globals.default_material);
+ material_storage->material_set_shader(scene_globals.default_material, scene_globals.default_shader);
+ }
+
+ {
// Initialize Sky stuff
sky_globals.roughness_layers = GLOBAL_GET("rendering/reflections/sky_reflections/roughness_layers");
sky_globals.ggx_samples = GLOBAL_GET("rendering/reflections/sky_reflections/ggx_samples");
@@ -1014,9 +2047,9 @@ RasterizerSceneGLES3::RasterizerSceneGLES3(RasterizerStorageGLES3 *p_storage) {
String global_defines;
global_defines += "#define MAX_GLOBAL_VARIABLES 256\n"; // TODO: this is arbitrary for now
global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(sky_globals.max_directional_lights) + "\n";
- state.sky_shader.initialize(global_defines);
- sky_globals.shader_default_version = state.sky_shader.version_create();
- state.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
+ material_storage->shaders.sky_shader.initialize(global_defines);
+ sky_globals.shader_default_version = material_storage->shaders.sky_shader.version_create();
+ material_storage->shaders.sky_shader.version_bind_shader(sky_globals.shader_default_version, SkyShaderGLES3::MODE_BACKGROUND);
}
{
@@ -1038,12 +2071,79 @@ void sky() {
material_storage->material_set_shader(sky_globals.default_material, sky_globals.default_shader);
}
+ {
+ sky_globals.fog_shader = material_storage->shader_allocate();
+ material_storage->shader_initialize(sky_globals.fog_shader);
+
+ material_storage->shader_set_code(sky_globals.fog_shader, R"(
+// Default clear color sky shader.
+
+shader_type sky;
+
+uniform vec4 clear_color;
+
+void sky() {
+ COLOR = clear_color.rgb;
+}
+)");
+ sky_globals.fog_material = material_storage->material_allocate();
+ material_storage->material_initialize(sky_globals.fog_material);
+
+ material_storage->material_set_shader(sky_globals.fog_material, sky_globals.fog_shader);
+ }
+ {
+ {
+ //quad buffers
+
+ glGenBuffers(1, &sky_globals.quad);
+ glBindBuffer(GL_ARRAY_BUFFER, sky_globals.quad);
+ {
+ 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); //unbind
+
+ glGenVertexArrays(1, &sky_globals.quad_array);
+ glBindVertexArray(sky_globals.quad_array);
+ glBindBuffer(GL_ARRAY_BUFFER, sky_globals.quad);
+ glVertexAttribPointer(RS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, nullptr);
+ glEnableVertexAttribArray(RS::ARRAY_VERTEX);
+ glVertexAttribPointer(RS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8));
+ glEnableVertexAttribArray(RS::ARRAY_TEX_UV);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ }
+ }
}
RasterizerSceneGLES3::~RasterizerSceneGLES3() {
- state.sky_shader.version_free(sky_globals.shader_default_version);
+ GLES3::MaterialStorage::get_singleton()->shaders.scene_shader.version_free(scene_globals.shader_default_version);
+ storage->free(scene_globals.default_material);
+ storage->free(scene_globals.default_shader);
+ GLES3::MaterialStorage::get_singleton()->shaders.sky_shader.version_free(sky_globals.shader_default_version);
storage->free(sky_globals.default_material);
storage->free(sky_globals.default_shader);
+ storage->free(sky_globals.fog_material);
+ storage->free(sky_globals.fog_shader);
}
#endif // GLES3_ENABLED
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index ed529beb25..ac2f3c932a 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -34,6 +34,7 @@
#ifdef GLES3_ENABLED
#include "core/math/camera_matrix.h"
+#include "core/templates/paged_allocator.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
#include "rasterizer_storage_gles3.h"
@@ -44,13 +45,47 @@
#include "shader_gles3.h"
#include "shaders/sky.glsl.gen.h"
-// Copied from renderer_scene_render_rd
+enum RenderListType {
+ RENDER_LIST_OPAQUE, //used for opaque objects
+ RENDER_LIST_ALPHA, //used for transparent objects
+ RENDER_LIST_SECONDARY, //used for shadows and other objects
+ RENDER_LIST_MAX
+};
+
+enum PassMode {
+ PASS_MODE_COLOR,
+ PASS_MODE_COLOR_TRANSPARENT,
+ PASS_MODE_COLOR_ADDITIVE,
+ PASS_MODE_SHADOW,
+ PASS_MODE_DEPTH,
+};
+
+// These should share as much as possible with SkyUniform Location
+enum SceneUniformLocation {
+ SCENE_TONEMAP_UNIFORM_LOCATION,
+ SCENE_GLOBALS_UNIFORM_LOCATION,
+ SCENE_DATA_UNIFORM_LOCATION,
+ SCENE_MATERIAL_UNIFORM_LOCATION,
+ SCENE_RADIANCE_UNIFORM_LOCATION,
+ SCENE_OMNILIGHT_UNIFORM_LOCATION,
+ SCENE_SPOTLIGHT_UNIFORM_LOCATION,
+};
+
+enum SkyUniformLocation {
+ SKY_TONEMAP_UNIFORM_LOCATION,
+ SKY_GLOBALS_UNIFORM_LOCATION,
+ SKY_SCENE_DATA_UNIFORM_LOCATION,
+ SKY_DIRECTIONAL_LIGHT_UNIFORM_LOCATION,
+ SKY_MATERIAL_UNIFORM_LOCATION,
+};
+
struct RenderDataGLES3 {
RID render_buffers = RID();
+ bool transparent_bg = false;
Transform3D cam_transform = Transform3D();
CameraMatrix cam_projection = CameraMatrix();
- bool cam_ortogonal = false;
+ bool cam_orthogonal = false;
// For stereo rendering
uint32_t view_count = 1;
@@ -91,17 +126,324 @@ private:
RS::ViewportDebugDraw debug_draw = RS::VIEWPORT_DEBUG_DRAW_DISABLED;
uint64_t scene_pass = 0;
- /* Sky */
struct SkyGlobals {
- RID shader_current_version;
RID shader_default_version;
RID default_material;
RID default_shader;
+ RID fog_material;
+ RID fog_shader;
+ GLuint quad = 0;
+ GLuint quad_array = 0;
uint32_t max_directional_lights = 4;
uint32_t roughness_layers = 8;
uint32_t ggx_samples = 128;
} sky_globals;
+ struct SceneGlobals {
+ RID shader_default_version;
+ RID default_material;
+ RID default_shader;
+ } scene_globals;
+
+ struct SceneState {
+ struct UBO {
+ float projection_matrix[16];
+ float inv_projection_matrix[16];
+ float inv_view_matrix[16];
+ float view_matrix[16];
+
+ float viewport_size[2];
+ float screen_pixel_size[2];
+
+ float ambient_light_color_energy[4];
+
+ float ambient_color_sky_mix;
+ uint32_t ambient_flags;
+ uint32_t material_uv2_mode;
+ float opaque_prepass_threshold;
+ //bool use_ambient_light;
+ //bool use_ambient_cubemap;
+ //bool use_reflection_cubemap;
+
+ float radiance_inverse_xform[12];
+
+ uint32_t directional_light_count;
+ float z_far;
+ float z_near;
+ uint32_t pancake_shadows;
+
+ uint32_t fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
+
+ float fog_light_color[3];
+ float fog_sun_scatter;
+
+ float fog_aerial_perspective;
+ float time;
+ uint32_t pad[2];
+ };
+ static_assert(sizeof(UBO) % 16 == 0, "Scene UBO size must be a multiple of 16 bytes");
+
+ struct TonemapUBO {
+ float exposure = 1.0;
+ float white = 1.0;
+ int32_t tonemapper = 0;
+ int32_t pad = 0;
+ };
+ static_assert(sizeof(TonemapUBO) % 16 == 0, "Tonemap UBO size must be a multiple of 16 bytes");
+
+ UBO ubo;
+ GLuint ubo_buffer = 0;
+ GLuint tonemap_buffer = 0;
+
+ bool used_depth_prepass = false;
+
+ GLES3::SceneShaderData::BlendMode current_blend_mode = GLES3::SceneShaderData::BLEND_MODE_MIX;
+ GLES3::SceneShaderData::DepthDraw current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_OPAQUE;
+ GLES3::SceneShaderData::DepthTest current_depth_test = GLES3::SceneShaderData::DEPTH_TEST_DISABLED;
+ GLES3::SceneShaderData::Cull cull_mode = GLES3::SceneShaderData::CULL_BACK;
+
+ bool texscreen_copied = false;
+ bool used_screen_texture = false;
+ bool used_normal_texture = false;
+ bool used_depth_texture = false;
+ } scene_state;
+
+ struct GeometryInstanceGLES3;
+
+ // Cached data for drawing surfaces
+ struct GeometryInstanceSurface {
+ enum {
+ FLAG_PASS_DEPTH = 1,
+ FLAG_PASS_OPAQUE = 2,
+ FLAG_PASS_ALPHA = 4,
+ FLAG_PASS_SHADOW = 8,
+ FLAG_USES_SHARED_SHADOW_MATERIAL = 128,
+ FLAG_USES_SCREEN_TEXTURE = 2048,
+ FLAG_USES_DEPTH_TEXTURE = 4096,
+ FLAG_USES_NORMAL_TEXTURE = 8192,
+ FLAG_USES_DOUBLE_SIDED_SHADOWS = 16384,
+ };
+
+ union {
+ struct {
+ uint64_t lod_index : 8;
+ uint64_t surface_index : 8;
+ uint64_t geometry_id : 32;
+ uint64_t material_id_low : 16;
+
+ uint64_t material_id_hi : 16;
+ uint64_t shader_id : 32;
+ uint64_t uses_softshadow : 1;
+ uint64_t uses_projector : 1;
+ uint64_t uses_forward_gi : 1;
+ uint64_t uses_lightmap : 1;
+ uint64_t depth_layer : 4;
+ uint64_t priority : 8;
+ };
+ struct {
+ uint64_t sort_key1;
+ uint64_t sort_key2;
+ };
+ } sort;
+
+ RS::PrimitiveType primitive = RS::PRIMITIVE_MAX;
+ uint32_t flags = 0;
+ uint32_t surface_index = 0;
+ uint32_t lod_index = 0;
+
+ void *surface = nullptr;
+ GLES3::SceneShaderData *shader = nullptr;
+ GLES3::SceneMaterialData *material = nullptr;
+
+ void *surface_shadow = nullptr;
+ GLES3::SceneShaderData *shader_shadow = nullptr;
+ GLES3::SceneMaterialData *material_shadow = nullptr;
+
+ GeometryInstanceSurface *next = nullptr;
+ GeometryInstanceGLES3 *owner = nullptr;
+ };
+
+ struct GeometryInstanceGLES3 : public GeometryInstance {
+ //used during rendering
+ bool mirror = false;
+ bool non_uniform_scale = false;
+ float lod_bias = 0.0;
+ float lod_model_scale = 1.0;
+ AABB transformed_aabb; //needed for LOD
+ float depth = 0;
+ uint32_t flags_cache = 0;
+ bool store_transform_cache = true;
+ int32_t shader_parameters_offset = -1;
+
+ uint32_t layer_mask = 1;
+ uint32_t instance_count = 0;
+
+ RID mesh_instance;
+ bool can_sdfgi = false;
+ bool using_projectors = false;
+ bool using_softshadows = false;
+ bool fade_near = false;
+ float fade_near_begin = 0;
+ float fade_near_end = 0;
+ bool fade_far = false;
+ float fade_far_begin = 0;
+ float fade_far_end = 0;
+ float force_alpha = 1.0;
+ float parent_fade_alpha = 1.0;
+
+ uint32_t omni_light_count = 0;
+ uint32_t omni_lights[8];
+ uint32_t spot_light_count = 0;
+ uint32_t spot_lights[8];
+
+ //used during setup
+ uint32_t base_flags = 0;
+ Transform3D transform;
+ GeometryInstanceSurface *surface_caches = nullptr;
+ SelfList<GeometryInstanceGLES3> dirty_list_element;
+
+ struct Data {
+ //data used less often goes into regular heap
+ RID base;
+ RS::InstanceType base_type;
+
+ RID skeleton;
+ Vector<RID> surface_materials;
+ RID material_override;
+ RID material_overlay;
+ AABB aabb;
+
+ bool use_dynamic_gi = false;
+ bool use_baked_light = false;
+ bool cast_double_sided_shadows = false;
+ bool mirror = false;
+ bool dirty_dependencies = false;
+
+ RendererStorage::DependencyTracker dependency_tracker;
+ };
+
+ Data *data = nullptr;
+
+ GeometryInstanceGLES3() :
+ dirty_list_element(this) {}
+ };
+
+ enum {
+ INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 5,
+ INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 6,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 8,
+ INSTANCE_DATA_FLAG_USE_LIGHTMAP = 1 << 9,
+ INSTANCE_DATA_FLAG_USE_SH_LIGHTMAP = 1 << 10,
+ INSTANCE_DATA_FLAG_USE_VOXEL_GI = 1 << 11,
+ INSTANCE_DATA_FLAG_MULTIMESH = 1 << 12,
+ INSTANCE_DATA_FLAG_MULTIMESH_FORMAT_2D = 1 << 13,
+ INSTANCE_DATA_FLAG_MULTIMESH_HAS_COLOR = 1 << 14,
+ INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15,
+ };
+
+ static void _geometry_instance_dependency_changed(RendererStorage::DependencyChangedNotification p_notification, RendererStorage::DependencyTracker *p_tracker);
+ static void _geometry_instance_dependency_deleted(const RID &p_dependency, RendererStorage::DependencyTracker *p_tracker);
+
+ SelfList<GeometryInstanceGLES3>::List geometry_instance_dirty_list;
+
+ // Use PagedAllocator instead of RID to maximize performance
+ PagedAllocator<GeometryInstanceGLES3> geometry_instance_alloc;
+ PagedAllocator<GeometryInstanceSurface> geometry_instance_surface_alloc;
+
+ void _geometry_instance_add_surface_with_material(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, GLES3::SceneMaterialData *p_material, uint32_t p_material_id, uint32_t p_shader_id, RID p_mesh);
+ void _geometry_instance_add_surface_with_material_chain(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, GLES3::SceneMaterialData *p_material, RID p_mat_src, RID p_mesh);
+ void _geometry_instance_add_surface(GeometryInstanceGLES3 *ginstance, uint32_t p_surface, RID p_material, RID p_mesh);
+ void _geometry_instance_mark_dirty(GeometryInstance *p_geometry_instance);
+ void _geometry_instance_update(GeometryInstance *p_geometry_instance);
+ void _update_dirty_geometry_instances();
+
+ struct RenderListParameters {
+ GeometryInstanceSurface **elements = nullptr;
+ int element_count = 0;
+ bool reverse_cull = false;
+ uint32_t spec_constant_base_flags = 0;
+ bool force_wireframe = false;
+ Plane lod_plane;
+ float lod_distance_multiplier = 0.0;
+ float screen_mesh_lod_threshold = 0.0;
+
+ RenderListParameters(GeometryInstanceSurface **p_elements, int p_element_count, bool p_reverse_cull, uint32_t p_spec_constant_base_flags, bool p_force_wireframe = false, const Plane &p_lod_plane = Plane(), float p_lod_distance_multiplier = 0.0, float p_screen_mesh_lod_threshold = 0.0) {
+ elements = p_elements;
+ element_count = p_element_count;
+ reverse_cull = p_reverse_cull;
+ spec_constant_base_flags = p_spec_constant_base_flags;
+ force_wireframe = p_force_wireframe;
+ lod_plane = p_lod_plane;
+ lod_distance_multiplier = p_lod_distance_multiplier;
+ screen_mesh_lod_threshold = p_screen_mesh_lod_threshold;
+ }
+ };
+
+ struct RenderList {
+ LocalVector<GeometryInstanceSurface *> elements;
+
+ void clear() {
+ elements.clear();
+ }
+
+ //should eventually be replaced by radix
+
+ struct SortByKey {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurface *A, const GeometryInstanceSurface *B) const {
+ return (A->sort.sort_key2 == B->sort.sort_key2) ? (A->sort.sort_key1 < B->sort.sort_key1) : (A->sort.sort_key2 < B->sort.sort_key2);
+ }
+ };
+
+ void sort_by_key() {
+ SortArray<GeometryInstanceSurface *, SortByKey> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ void sort_by_key_range(uint32_t p_from, uint32_t p_size) {
+ SortArray<GeometryInstanceSurface *, SortByKey> sorter;
+ sorter.sort(elements.ptr() + p_from, p_size);
+ }
+
+ struct SortByDepth {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurface *A, const GeometryInstanceSurface *B) const {
+ return (A->owner->depth < B->owner->depth);
+ }
+ };
+
+ void sort_by_depth() { //used for shadows
+
+ SortArray<GeometryInstanceSurface *, SortByDepth> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ struct SortByReverseDepthAndPriority {
+ _FORCE_INLINE_ bool operator()(const GeometryInstanceSurface *A, const GeometryInstanceSurface *B) const {
+ return (A->sort.priority == B->sort.priority) ? (A->owner->depth > B->owner->depth) : (A->sort.priority < B->sort.priority);
+ }
+ };
+
+ void sort_by_reverse_depth_and_priority() { //used for alpha
+
+ SortArray<GeometryInstanceSurface *, SortByReverseDepthAndPriority> sorter;
+ sorter.sort(elements.ptr(), elements.size());
+ }
+
+ _FORCE_INLINE_ void add_element(GeometryInstanceSurface *p_element) {
+ elements.push_back(p_element);
+ }
+ };
+
+ RenderList render_list[RENDER_LIST_MAX];
+
+ void _setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows);
+ void _fill_render_list(RenderListType p_render_list, const RenderDataGLES3 *p_render_data, PassMode p_pass_mode, bool p_append = false);
+
+ template <PassMode p_pass_mode>
+ _FORCE_INLINE_ void _render_list_template(RenderListParameters *p_params, const RenderDataGLES3 *p_render_data, uint32_t p_from_element, uint32_t p_to_element, bool p_alpha_pass = false);
+
protected:
double time;
double time_step = 0;
@@ -117,6 +459,8 @@ protected:
//bool use_debanding = false;
//uint32_t view_count = 1;
+ bool is_transparent = false;
+
RID render_target;
GLuint internal_texture = 0; // Used for rendering when post effects are enabled
GLuint depth_texture = 0; // Main depth texture
@@ -319,7 +663,7 @@ protected:
Sky *dirty_list = nullptr;
//State to track when radiance cubemap needs updating
- //SkyMaterialData *prev_material;
+ GLES3::SkyMaterialData *prev_material;
Vector3 prev_position = Vector3(0.0, 0.0, 0.0);
float prev_time = 0.0f;
@@ -335,17 +679,12 @@ protected:
void _invalidate_sky(Sky *p_sky);
void _update_dirty_skys();
- void _draw_sky(Sky *p_sky, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_custom_fov, float p_energy, const Basis &p_sky_orientation);
+ void _draw_sky(Environment *p_env, const CameraMatrix &p_projection, const Transform3D &p_transform);
public:
RasterizerStorageGLES3 *storage;
RasterizerCanvasGLES3 *canvas;
- // References to shaders are needed in public space so they can be accessed in RasterizerStorageGLES3
- struct State {
- SkyShaderGLES3 sky_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;
@@ -388,9 +727,15 @@ public:
/* 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 { return 0; }
- AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override { return AABB(); }
- uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override { return 0; }
+ int sdfgi_get_pending_region_count(RID p_render_buffers) const override {
+ return 0;
+ }
+ AABB sdfgi_get_pending_region_bounds(RID p_render_buffers, int p_region) const override {
+ return AABB();
+ }
+ uint32_t sdfgi_get_pending_region_cascade(RID p_render_buffers, int p_region) const override {
+ return 0;
+ }
/* SKY API */
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index cca445bf00..3c28289bd0 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -342,25 +342,14 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder,
*/
RS::InstanceType RasterizerStorageGLES3::get_base_type(RID p_rid) const {
- return RS::INSTANCE_NONE;
-
- /*
- if (mesh_owner.owns(p_rid)) {
+ if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
return RS::INSTANCE_MESH;
- } else if (light_owner.owns(p_rid)) {
- return RS::INSTANCE_LIGHT;
- } else if (multimesh_owner.owns(p_rid)) {
+ } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(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;
+ } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) {
+ return RS::INSTANCE_LIGHT;
}
-*/
+ return RS::INSTANCE_NONE;
}
bool RasterizerStorageGLES3::free(RID p_rid) {
@@ -379,89 +368,23 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
} else if (GLES3::MaterialStorage::get_singleton()->owns_material(p_rid)) {
GLES3::MaterialStorage::get_singleton()->material_free(p_rid);
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<InstanceBaseDependency *>::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);
-
+ } else if (GLES3::MeshStorage::get_singleton()->owns_mesh(p_rid)) {
+ GLES3::MeshStorage::get_singleton()->mesh_free(p_rid);
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);
-
+ } else if (GLES3::MeshStorage::get_singleton()->owns_multimesh(p_rid)) {
+ GLES3::MeshStorage::get_singleton()->multimesh_free(p_rid);
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);
-
+ } else if (GLES3::MeshStorage::get_singleton()->owns_mesh_instance(p_rid)) {
+ GLES3::MeshStorage::get_singleton()->mesh_instance_free(p_rid);
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);
-
+ } else if (GLES3::LightStorage::get_singleton()->owns_light(p_rid)) {
+ GLES3::LightStorage::get_singleton()->light_free(p_rid);
return true;
- } else if (reflection_probe_owner.owns(p_rid)) {
+ } else {
+ return false;
+ }
+ /*
+ 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();
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index d22db198c8..fa74fbd5f6 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -41,6 +41,7 @@
#include "servers/rendering/shader_compiler.h"
#include "servers/rendering/shader_language.h"
#include "storage/config.h"
+#include "storage/light_storage.h"
#include "storage/material_storage.h"
#include "storage/mesh_storage.h"
#include "storage/texture_storage.h"
@@ -55,6 +56,48 @@ public:
GLES3::Config *config = nullptr;
+ static _FORCE_INLINE_ void store_transform(const Transform3D &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.basis.rows[0][0];
+ p_array[1] = p_mtx.basis.rows[1][0];
+ p_array[2] = p_mtx.basis.rows[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.basis.rows[0][1];
+ p_array[5] = p_mtx.basis.rows[1][1];
+ p_array[6] = p_mtx.basis.rows[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.basis.rows[0][2];
+ p_array[9] = p_mtx.basis.rows[1][2];
+ p_array[10] = p_mtx.basis.rows[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;
+ }
+
+ static _FORCE_INLINE_ void store_transform_3x3(const Basis &p_mtx, float *p_array) {
+ p_array[0] = p_mtx.rows[0][0];
+ p_array[1] = p_mtx.rows[1][0];
+ p_array[2] = p_mtx.rows[2][0];
+ p_array[3] = 0;
+ p_array[4] = p_mtx.rows[0][1];
+ p_array[5] = p_mtx.rows[1][1];
+ p_array[6] = p_mtx.rows[2][1];
+ p_array[7] = 0;
+ p_array[8] = p_mtx.rows[0][2];
+ p_array[9] = p_mtx.rows[1][2];
+ p_array[10] = p_mtx.rows[2][2];
+ p_array[11] = 0;
+ }
+
+ static _FORCE_INLINE_ void store_camera(const CameraMatrix &p_mtx, float *p_array) {
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ p_array[i * 4 + j] = p_mtx.matrix[i][j];
+ }
+ }
+ }
+
struct Resources {
GLuint mipmap_blur_fbo;
GLuint mipmap_blur_color;
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index e356fa8c1f..b3f37207da 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -171,6 +171,15 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
}
builder.append("\n"); //make sure defines begin at newline
+ // Default to highp precision unless specified otherwise.
+ builder.append("precision highp float;\n");
+ builder.append("precision highp int;\n");
+#ifndef GLES_OVER_GL
+ builder.append("precision highp sampler2D;\n");
+ builder.append("precision highp samplerCube;\n");
+ builder.append("precision highp sampler2DArray;\n");
+#endif
+
for (uint32_t i = 0; i < p_template.chunks.size(); i++) {
const StageTemplate::Chunk &chunk = p_template.chunks[i];
switch (chunk.type) {
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 15281064af..763d3bfa8b 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -73,10 +73,11 @@ private:
//versions
CharString general_defines;
- // A version is a high-level construct which is a combination of built-in and user-defined shader code
- // Variants use #idefs to toggle behaviour on and off to change behaviour of the shader
+ // A version is a high-level construct which is a combination of built-in and user-defined shader code, Each user-created Shader makes one version
+ // Variants use #ifdefs to toggle behaviour on and off to change behaviour of the shader
+ // All variants are compiled each time a new version is created
// Specializations use #ifdefs to toggle behaviour on and off for performance, on supporting hardware, they will compile a version with everything enabled, and then compile more copies to improve performance
- // Use specializations to enable and disabled advanced features, use variants to toggle behaviour when different data may be used (e.g. using a samplerArray vs a sampler)
+ // Use specializations to enable and disabled advanced features, use variants to toggle behaviour when different data may be used (e.g. using a samplerArray vs a sampler, or doing a depth prepass vs a color pass)
struct Version {
Vector<StringName> texture_uniforms;
CharString uniforms;
@@ -217,6 +218,7 @@ protected:
ERR_FAIL_INDEX_V(p_which, uniform_count, -1);
Version *version = version_owner.get_or_null(p_version);
ERR_FAIL_COND_V(!version, -1);
+ ERR_FAIL_INDEX_V(p_variant, int(version->variants.size()), -1);
return version->variants[p_variant].lookup_ptr(p_specialization)->uniform_location[p_which];
}
diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub
index 79247f38d4..ec32badc19 100644
--- a/drivers/gles3/shaders/SCsub
+++ b/drivers/gles3/shaders/SCsub
@@ -8,4 +8,5 @@ env.Depends("#drivers/gles3/shaders/copy.glsl.gen.h", "#core/math/transform_2d.h
if "GLES3_GLSL" in env["BUILDERS"]:
env.GLES3_GLSL("canvas.glsl")
env.GLES3_GLSL("copy.glsl")
+ env.GLES3_GLSL("scene.glsl")
env.GLES3_GLSL("sky.glsl")
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 41d308b776..381a0e8a73 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -21,6 +21,15 @@ layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
#endif
+
+// This needs to be outside clang-format so the ubo comment is in the right place
+#ifdef MATERIAL_UNIFORMS_USED
+layout(std140) uniform MaterialUniforms{ //ubo:4
+
+#MATERIAL_UNIFORMS
+
+};
+#endif
/* clang-format on */
#include "canvas_uniforms_inc.glsl"
#include "stdlib_inc.glsl"
@@ -38,15 +47,6 @@ out vec2 pixel_size_interp;
#endif
-#ifdef MATERIAL_UNIFORMS_USED
-layout(std140) uniform MaterialUniforms{
-//ubo:4
-
-#MATERIAL_UNIFORMS
-
-};
-#endif
-
#GLOBALS
void main() {
@@ -518,8 +518,8 @@ void main() {
float px_size = max(0.5 * dot((vec2(px_range) / msdf_size), dest_size), 1.0);
float d = msdf_median(msdf_sample.r, msdf_sample.g, msdf_sample.b, msdf_sample.a) - 0.5;
- if (outline_thickness > 0) {
- float cr = clamp(outline_thickness, 0.0, px_range / 2) / px_range;
+ if (outline_thickness > 0.0) {
+ float cr = clamp(outline_thickness, 0.0, px_range / 2.0) / px_range;
float a = clamp((d + cr) * px_size, 0.0, 1.0);
color.a = a * color.a;
} else {
@@ -710,8 +710,8 @@ void main() {
vec2 pos_rot = pos_norm * mat2(vec2(0.7071067811865476, -0.7071067811865476), vec2(0.7071067811865476, 0.7071067811865476)); //is there a faster way to 45 degrees rot?
float tex_ofs;
float distance;
- if (pos_rot.y > 0) {
- if (pos_rot.x > 0) {
+ if (pos_rot.y > 0.0) {
+ if (pos_rot.x > 0.0) {
tex_ofs = pos_box.y * 0.125 + 0.125;
distance = shadow_pos.x;
} else {
@@ -719,7 +719,7 @@ void main() {
distance = shadow_pos.y;
}
} else {
- if (pos_rot.x < 0) {
+ if (pos_rot.x < 0.0) {
tex_ofs = pos_box.y * -0.125 + (0.5 + 0.125);
distance = -shadow_pos.x;
} else {
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index ebb00e81d0..ea28685be7 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1,983 +1,553 @@
/* clang-format off */
-[vertex]
+#[modes]
-#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) in highp vec4 vertex_attrib;
-/* clang-format on */
-layout(location = 1) in vec3 normal_attrib;
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
-layout(location = 2) in vec4 tangent_attrib;
-#endif
+mode_color = #define BASE_PASS
+mode_additive = #define USE_ADDITIVE_LIGHTING
+mode_depth = #define MODE_RENDER_DEPTH
-#if defined(ENABLE_COLOR_INTERP)
-layout(location = 3) in vec4 color_attrib;
-#endif
+#[specializations]
-#if defined(ENABLE_UV_INTERP)
-layout(location = 4) in vec2 uv_attrib;
-#endif
+USE_LIGHTMAP = false
+USE_LIGHT_DIRECTIONAL = false
+USE_LIGHT_POSITIONAL = false
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
-layout(location = 5) in vec2 uv2_attrib;
-#endif
-
-#ifdef USE_SKELETON
-
-#ifdef USE_SKELETON_SOFTWARE
-layout(location = 13) in highp vec4 bone_transform_row_0;
-layout(location = 14) in highp vec4 bone_transform_row_1;
-layout(location = 15) in highp vec4 bone_transform_row_2;
+#[vertex]
-#else
+#define M_PI 3.14159265359
-layout(location = 6) in vec4 bone_ids;
-layout(location = 7) in highp vec4 bone_weights;
+#define SHADER_IS_SRGB true
-uniform highp sampler2D bone_transforms; // texunit:-1
-uniform ivec2 skeleton_texture_size;
+#include "stdlib_inc.glsl"
+#if !defined(MODE_RENDER_DEPTH) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) ||defined(LIGHT_CLEARCOAT_USED)
+#ifndef NORMAL_USED
+#define NORMAL_USED
#endif
-
#endif
-#ifdef USE_INSTANCING
+/*
+from RenderingServer:
+ARRAY_VERTEX = 0, // RG32F or RGB32F (depending on 2D bit)
+ARRAY_NORMAL = 1, // A2B10G10R10, A is ignored.
+ARRAY_TANGENT = 2, // A2B10G10R10, A flips sign of binormal.
+ARRAY_COLOR = 3, // RGBA8
+ARRAY_TEX_UV = 4, // RG32F
+ARRAY_TEX_UV2 = 5, // RG32F
+ARRAY_CUSTOM0 = 6, // Depends on ArrayCustomFormat.
+ARRAY_CUSTOM1 = 7,
+ARRAY_CUSTOM2 = 8,
+ARRAY_CUSTOM3 = 9,
+ARRAY_BONES = 10, // RGBA16UI (x2 if 8 weights)
+ARRAY_WEIGHTS = 11, // RGBA16UNORM (x2 if 8 weights)
+ARRAY_INDEX = 12, // 16 or 32 bits depending on length > 0xFFFF.
+ARRAY_MAX = 13
+*/
-layout(location = 8) in highp vec4 instance_xform_row_0;
-layout(location = 9) in highp vec4 instance_xform_row_1;
-layout(location = 10) in highp vec4 instance_xform_row_2;
+/* INPUT ATTRIBS */
-layout(location = 11) in highp vec4 instance_color;
-layout(location = 12) in highp vec4 instance_custom_data;
+layout(location = 0) in highp vec3 vertex_attrib;
+/* clang-format on */
+#ifdef NORMAL_USED
+layout(location = 1) in vec3 normal_attrib;
#endif
-//
-// uniforms
-//
-
-uniform highp mat4 inv_view_matrix;
-uniform highp mat4 view_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;
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+layout(location = 2) in vec4 tangent_attrib;
#endif
-//
-// varyings
-//
-
-#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
-out highp vec4 position_interp;
+#if defined(COLOR_USED)
+layout(location = 3) in vec4 color_attrib;
#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;
+#ifdef UV_USED
+layout(location = 4) in vec2 uv_attrib;
#endif
-#if defined(ENABLE_COLOR_INTERP)
-out vec4 color_interp;
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+layout(location = 5) in vec2 uv2_attrib;
#endif
-#if defined(ENABLE_UV_INTERP)
-out vec2 uv_interp;
+#if defined(CUSTOM0_USED)
+layout(location = 6) in vec4 custom0_attrib;
#endif
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
-out vec2 uv2_interp;
+#if defined(CUSTOM1_USED)
+layout(location = 7) in vec4 custom1_attrib;
#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;
-
+#if defined(CUSTOM2_USED)
+layout(location = 8) in vec4 custom2_attrib;
#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;
+#if defined(CUSTOM3_USED)
+layout(location = 9) in vec4 custom3_attrib;
#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;
-
+#if defined(BONES_USED)
+layout(location = 10) in uvec4 bone_attrib;
#endif
+#if defined(WEIGHTS_USED)
+layout(location = 11) in vec4 weight_attrib;
#endif
-#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING)
+layout(std140) uniform GlobalVariableData { //ubo:1
+ vec4 global_variables[MAX_GLOBAL_VARIABLES];
+};
-out highp vec3 diffuse_interp;
-out highp vec3 specular_interp;
+layout(std140) uniform SceneData { // ubo:2
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 inv_view_matrix;
+ highp mat4 view_matrix;
-// general for all lights
-uniform highp vec4 light_color;
-uniform highp vec4 shadow_color;
-uniform highp float light_specular;
+ vec2 viewport_size;
+ vec2 screen_pixel_size;
-// directional
-uniform highp vec3 light_direction;
+ mediump vec4 ambient_light_color_energy;
-// omni
-uniform highp vec3 light_position;
+ mediump float ambient_color_sky_mix;
+ uint ambient_flags;
+ bool material_uv2_mode;
+ float opaque_prepass_threshold;
+ //bool use_ambient_light;
+ //bool use_ambient_cubemap;
+ //bool use_reflection_cubemap;
-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)
+ mat3 radiance_inverse_xform;
- float NdotL = dot(N, L);
- float cNdotL = max(NdotL, 0.0); // clamped NdotL
- float NdotV = dot(N, V);
- float cNdotV = max(NdotV, 0.0);
+ uint directional_light_count;
+ float z_far;
+ float z_near;
+ float pad;
-#if defined(DIFFUSE_OREN_NAYAR)
- vec3 diffuse_brdf_NL;
-#else
- float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
-#endif
+ bool fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
-#if defined(DIFFUSE_LAMBERT_WRAP)
- // energy conserving lambert wrap shader
- diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
+ vec3 fog_light_color;
+ float fog_sun_scatter;
-#elif defined(DIFFUSE_OREN_NAYAR)
+ float fog_aerial_perspective;
- {
- // see http://mimosa-pudica.net/improved-oren-nayar.html
- float LdotV = dot(L, V);
+ float time;
+ float reflection_multiplier; // one normally, zero when rendering reflections
- float s = LdotV - NdotL * NdotV;
- float t = mix(1.0, max(NdotL, NdotV), step(0.0, s));
+ bool pancake_shadows;
+}
+scene_data;
- 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);
+uniform highp mat4 world_transform;
- 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);
+#ifdef USE_LIGHTMAP
+uniform highp vec4 lightmap_uv_rect;
#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;
+/* Varyings */
-#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;
+out highp vec3 vertex_interp;
+#ifdef NORMAL_USED
+out vec3 normal_interp;
#endif
- SRGB_APPROX(specular_brdf_NL)
- specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI);
- }
-}
-
+#if defined(COLOR_USED)
+out vec4 color_interp;
#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;
+#if defined(UV_USED)
+out vec2 uv_interp;
#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;
+#if defined(UV2_USED)
+out vec2 uv2_interp;
+#else
+#ifdef USE_LIGHTMAP
+out vec2 uv2_interp;
+#endif
+#endif
-#ifndef USE_LIGHTMAP
-out mediump vec3 refprobe2_ambient_normal;
+#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+out vec3 tangent_interp;
+out vec3 binormal_interp;
#endif
-#endif //reflection probe2
+#if defined(MATERIAL_UNIFORMS_USED)
-#endif //vertex lighting for refprobes
+/* clang-format off */
+layout(std140) uniform MaterialUniforms { // ubo:3
-#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED)
+#MATERIAL_UNIFORMS
-out vec4 fog_interp;
+};
+/* clang-format on */
-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;
+/* clang-format off */
-#ifdef FOG_DEPTH_ENABLED
-uniform highp float fog_depth_begin;
-uniform mediump float fog_depth_curve;
-uniform mediump float fog_max_distance;
-#endif
+#GLOBALS
-#ifdef FOG_HEIGHT_ENABLED
-uniform highp float fog_height_min;
-uniform highp float fog_height_max;
-uniform mediump float fog_height_curve;
-#endif
+/* clang-format on */
-#endif //fog
+out highp vec4 position_interp;
-void main() {
- highp vec4 vertex = vertex_attrib;
+invariant gl_Position;
- mat4 model_matrix = world_transform;
+void main() {
+ highp vec3 vertex = vertex_attrib;
-#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));
- model_matrix = model_matrix * transpose(m);
- }
+ highp mat4 model_matrix = world_transform;
+#ifdef NORMAL_USED
+ vec3 normal = normal_attrib * 2.0 - 1.0;
#endif
+ highp mat3 model_normal_matrix = mat3(model_matrix);
- 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);
+#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+ vec3 tangent;
+ float binormalf;
+ tangent = normal_tangent_attrib.xyz;
+ binormalf = normal_tangent_attrib.a;
#endif
-#if defined(ENABLE_COLOR_INTERP)
+#if defined(COLOR_USED)
color_interp = color_attrib;
-#ifdef USE_INSTANCING
- color_interp *= instance_color;
#endif
+
+#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+ vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
-#if defined(ENABLE_UV_INTERP)
+#if defined(UV_USED)
uv_interp = uv_attrib;
#endif
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
+#ifdef USE_LIGHTMAP
+ uv2_interp = lightmap_uv_rect.zw * uv2_attrib + lightmap_uv_rect.xy;
+#else
+#if defined(UV2_USED)
uv2_interp = uv2_attrib;
#endif
+#endif
#if defined(OVERRIDE_POSITION)
highp vec4 position;
#endif
+ highp mat4 projection_matrix = scene_data.projection_matrix;
+ highp mat4 inv_projection_matrix = scene_data.inv_projection_matrix;
-#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
- vertex = model_matrix * vertex;
- normal = normalize((model_matrix * vec4(normal, 0.0)).xyz);
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
-
- tangent = normalize((model_matrix * vec4(tangent, 0.0)).xyz);
- binormal = normalize((model_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);
+ vec4 instance_custom = vec4(0.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));
+ // Using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
- bone_transform += transpose(b) * bone_weights[i];
- }
- }
+ vertex = (model_matrix * vec4(vertex, 1.0)).xyz;
+#ifdef NORMAL_USED
+ normal = model_normal_matrix * normal;
#endif
- model_matrix = model_matrix * bone_transform;
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-#endif
-
-#ifdef USE_INSTANCING
- vec4 instance_custom = instance_custom_data;
-#else
- vec4 instance_custom = vec4(0.0);
+ tangent = model_normal_matrix * tangent;
+ binormal = model_normal_matrix * binormal;
#endif
+#endif
- mat4 local_projection_matrix = projection_matrix;
-
- mat4 modelview = view_matrix * model_matrix;
float roughness = 1.0;
-#define projection_matrix local_projection_matrix
-#define world_transform model_matrix
+ highp mat4 modelview = scene_data.view_matrix * model_matrix;
+ highp mat3 modelview_normal = mat3(scene_data.view_matrix) * model_normal_matrix;
float point_size = 1.0;
{
- /* clang-format off */
-
-VERTEX_SHADER_CODE
-
- /* clang-format on */
+#CODE : VERTEX
}
gl_PointSize = point_size;
- vec4 outvec = vertex;
- // use local coordinates
+ // Using local coordinates (default)
#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
- vertex = modelview * vertex;
- normal = normalize((modelview * vec4(normal, 0.0)).xyz);
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
- tangent = normalize((modelview * vec4(tangent, 0.0)).xyz);
- binormal = normalize((modelview * vec4(binormal, 0.0)).xyz);
-#endif
+ vertex = (modelview * vec4(vertex, 1.0)).xyz;
+#ifdef NORMAL_USED
+ normal = modelview_normal * normal;
#endif
-#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
- vertex = view_matrix * vertex;
- normal = normalize((view_matrix * vec4(normal, 0.0)).xyz);
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
- tangent = normalize((view_matrix * vec4(tangent, 0.0)).xyz);
- binormal = normalize((view_matrix * vec4(binormal, 0.0)).xyz);
-#endif
#endif
- vertex_interp = vertex.xyz;
- normal_interp = normal;
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
- tangent_interp = tangent;
- binormal_interp = binormal;
+ binormal = modelview_normal * binormal;
+ tangent = modelview_normal * tangent;
#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);
+ // Using world coordinates
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
+ vertex = (scene_data.view_matrix * vec4(vertex, 1.0)).xyz;
+#ifdef NORMAL_USED
+ normal = (scene_data.view_matrix * vec4(normal, 0.0)).xyz;
#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);
-
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ binormal = (scene_data.view_matrix * vec4(binormal, 0.0)).xyz;
+ tangent = (scene_data.view_matrix * vec4(tangent, 0.0)).xyz;
#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);
-
+ vertex_interp = vertex;
+#ifdef NORMAL_USED
+ normal_interp = normal;
#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;
+#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+ tangent_interp = tangent;
+ binormal_interp = binormal;
#endif
-#if defined(LIGHT_USE_PSSM4)
- shadow_coord3 = light_shadow_matrix3 * vi4;
- shadow_coord4 = light_shadow_matrix4 * vi4;
-
+#if defined(OVERRIDE_POSITION)
+ gl_Position = position;
+#else
+ gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
#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;
+#ifdef MODE_RENDER_DEPTH
+ if (scene_data.pancake_shadows) {
+ if (gl_Position.z <= 0.00001) {
+ gl_Position.z = 0.00001;
}
-#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)
+ position_interp = gl_Position;
+}
- float fog_amount = 0.0;
+/* clang-format off */
+#[fragment]
-#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;
+// Default to SPECULAR_SCHLICK_GGX.
+#if !defined(SPECULAR_DISABLED) && !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_TOON)
+#define SPECULAR_SCHLICK_GGX
#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 !defined(MODE_RENDER_DEPTH) || defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) ||defined(LIGHT_CLEARCOAT_USED)
+#ifndef NORMAL_USED
+#define NORMAL_USED
#endif
-
-#ifdef FOG_HEIGHT_ENABLED
- {
- float y = (inv_view_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
+#include "tonemap_inc.glsl"
+#include "stdlib_inc.glsl"
-#endif //use vertex lighting
+/* texture unit usage, N is max_texture_unity-N
-#if defined(OVERRIDE_POSITION)
- gl_Position = position;
-#else
- gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
-#endif
+1-color correction // In tonemap_inc.glsl
+2-radiance
+3-directional_shadow
+4-positional_shadow
+5-screen
+6-depth
-#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
+uniform highp mat4 world_transform;
+/* clang-format on */
#define M_PI 3.14159265359
#define SHADER_IS_SRGB true
-//
-// uniforms
-//
-
-uniform highp mat4 inv_view_matrix;
-/* clang-format on */
-uniform highp mat4 view_matrix;
-uniform highp mat4 projection_matrix;
-uniform highp mat4 projection_inverse_matrix;
-
-uniform highp mat4 world_transform;
-
-uniform highp float time;
+/* Varyings */
-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
+#if defined(COLOR_USED)
+in vec4 color_interp;
#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;
+#if defined(UV_USED)
+in vec2 uv_interp;
#endif
+#if defined(UV2_USED)
+in vec2 uv2_interp;
#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;
+#ifdef USE_LIGHTMAP
+in vec2 uv2_interp;
#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;
- }
+#if defined(TANGENT_USED) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+in vec3 tangent_interp;
+in vec3 binormal_interp;
+#endif
- reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb;
+#ifdef NORMAL_USED
+in vec3 normal_interp;
#endif
- if (exterior) {
- reflection.rgb = mix(skybox, reflection.rgb, blend);
- }
- reflection.rgb *= intensity;
- reflection.a = blend;
- reflection.rgb *= blend;
+in highp vec3 vertex_interp;
- reflection_accum += reflection;
+/* PBR CHANNELS */
-#ifndef USE_LIGHTMAP
+#ifdef USE_RADIANCE_MAP
- vec4 ambient_out;
-#ifndef USE_VERTEX_LIGHTING
+layout(std140) uniform Radiance { // ubo:4
- vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz;
-#endif
+ mat4 radiance_inverse_xform;
+ float radiance_ambient_contribution;
+};
- 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);
- }
+#define RADIANCE_MAX_LOD 5.0
- ambient_out.a = blend;
- ambient_out.rgb *= blend;
- ambient_accum += ambient_out;
+uniform sampler2D radiance_map; // texunit:-2
-#endif
+vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec, float p_roughness) {
+ vec3 norm = normalize(p_vec);
+ norm.xy /= 1.0 + abs(norm.z);
+ norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25);
+ if (norm.z > 0.0) {
+ norm.y = 0.5 - norm.y + 0.5;
+ }
+ return textureLod(p_tex, norm.xy, p_roughness * RADIANCE_MAX_LOD).xyz;
}
-#endif //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;
+layout(std140) uniform GlobalVariableData { //ubo:1
+ vec4 global_variables[MAX_GLOBAL_VARIABLES];
+};
-#endif
+ /* Material Uniforms */
-#ifdef USE_RADIANCE_MAP
+#if defined(MATERIAL_UNIFORMS_USED)
-uniform samplerCube radiance_map; // texunit:-2
+/* clang-format off */
+layout(std140) uniform MaterialUniforms { // ubo:3
-uniform mat4 radiance_inverse_xform;
+#MATERIAL_UNIFORMS
-#endif
+};
+/* clang-format on */
-uniform vec4 bg_color;
-uniform float bg_energy;
+#endif
-uniform float ambient_sky_contribution;
-uniform vec4 ambient_color;
-uniform float ambient_energy;
+layout(std140) uniform SceneData { // ubo:2
+ highp mat4 projection_matrix;
+ highp mat4 inv_projection_matrix;
+ highp mat4 inv_view_matrix;
+ highp mat4 view_matrix;
-#ifdef USE_LIGHTING
+ vec2 viewport_size;
+ vec2 screen_pixel_size;
-uniform highp vec4 shadow_color;
+ mediump vec4 ambient_light_color_energy;
-#ifdef USE_VERTEX_LIGHTING
+ mediump float ambient_color_sky_mix;
+ uint ambient_flags;
+ bool material_uv2_mode;
+ float opaque_prepass_threshold;
+ //bool use_ambient_light;
+ //bool use_ambient_cubemap;
+ //bool use_reflection_cubemap;
-//get from vertex
-in highp vec3 diffuse_interp;
-in highp vec3 specular_interp;
+ mat3 radiance_inverse_xform;
-uniform highp vec3 light_direction; //may be used by fog, so leave here
+ uint directional_light_count;
+ float z_far;
+ float z_near;
+ float pad;
-#else
-//done in fragment
-// general for all lights
-uniform highp vec4 light_color;
+ bool fog_enabled;
+ float fog_density;
+ float fog_height;
+ float fog_height_density;
-uniform highp float light_specular;
+ vec3 fog_light_color;
+ float fog_sun_scatter;
-// directional
-uniform highp vec3 light_direction;
-// omni
-uniform highp vec3 light_position;
+ float fog_aerial_perspective;
-uniform highp float light_attenuation;
+ float time;
+ float reflection_multiplier; // one normally, zero when rendering reflections
-// spot
-uniform highp float light_spot_attenuation;
-uniform highp float light_spot_range;
-uniform highp float light_spot_angle;
-#endif
+ bool pancake_shadows;
+}
+scene_data;
-//this is needed outside above if because dual paraboloid wants it
-uniform highp float light_range;
+/* clang-format off */
-#ifdef USE_SHADOW
+#GLOBALS
-uniform highp vec2 shadow_pixel_size;
+/* clang-format on */
-#if defined(LIGHT_MODE_OMNI) || defined(LIGHT_MODE_SPOT)
-uniform highp sampler2D light_shadow_atlas; //texunit:-3
-#endif
+//directional light data
-#ifdef LIGHT_MODE_DIRECTIONAL
-uniform highp sampler2D light_directional_shadow; // texunit:-3
-uniform highp vec4 light_split_offsets;
-#endif
+#ifdef USE_LIGHT_DIRECTIONAL
-in highp vec4 shadow_coord;
+struct DirectionalLightData {
+ mediump vec3 direction;
+ mediump float energy;
+ mediump vec3 color;
+ mediump float size;
+ mediump vec3 pad;
+ mediump float specular;
+};
-#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4)
-in highp vec4 shadow_coord2;
#endif
-#if defined(LIGHT_USE_PSSM4)
+// omni and spot
+#ifdef USE_LIGHT_POSITIONAL
+struct LightData { //this structure needs to be as packed as possible
+ highp vec3 position;
+ highp float inv_radius;
-in highp vec4 shadow_coord3;
-in highp vec4 shadow_coord4;
-
-#endif
+ mediump vec3 direction;
+ highp float size;
-uniform vec4 light_clamp;
+ mediump vec3 color;
+ mediump float attenuation;
-#endif // light shadow
+ mediump float cone_attenuation;
+ mediump float cone_angle;
+ mediump float specular_amount;
+ bool shadow_enabled;
+};
-// directional shadow
+layout(std140) uniform OmniLightData { // ubo:5
-#endif
+ LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
+};
-//
-// varyings
-//
+layout(std140) uniform SpotLightData { // ubo:6
-#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS)
-in highp vec4 position_interp;
-#endif
+ LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
+};
-in highp vec3 vertex_interp;
-in vec3 normal_interp;
+uniform highp samplerCubeShadow positional_shadow; // texunit:-6
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
-in vec3 tangent_interp;
-in vec3 binormal_interp;
-#endif
+uniform int omni_light_indices[MAX_FORWARD_LIGHTS];
+uniform int omni_light_count;
-#if defined(ENABLE_COLOR_INTERP)
-in vec4 color_interp;
-#endif
+uniform int spot_light_indices[MAX_FORWARD_LIGHTS];
+uniform int spot_light_count;
-#if defined(ENABLE_UV_INTERP)
-in vec2 uv_interp;
-#endif
+uniform int reflection_indices[MAX_FORWARD_LIGHTS];
+uniform int reflection_count;
-#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
-in vec2 uv2_interp;
#endif
-in vec3 view_interp;
+uniform highp sampler2D screen_texture; // texunit:-5
+uniform highp sampler2D depth_buffer; // texunit:-6
layout(location = 0) out vec4 frag_color;
+in highp vec4 position_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;
@@ -985,95 +555,31 @@ vec3 F0(float metallic, float specular, vec3 albedo) {
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);
-}
-
+#if defined(USE_LIGHT_DIRECTIONAL) || defined(USE_LIGHT_POSITIONAL)
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 a = cos_theta_m * alpha;
+ float k = alpha / (1.0 - cos_theta_m * cos_theta_m + a * a);
+ return k * k * (1.0 / M_PI);
}
-/*
-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);
+// From Earl Hammon, Jr. "PBR Diffuse Lighting for GGX+Smith Microsurfaces" https://www.gdcvault.com/play/1024478/PBR-Diffuse-Lighting-for-GGX
+float V_GGX(float NdotL, float NdotV, float alpha) {
+ return 0.5 / mix(2.0 * NdotL * NdotV, NdotL + NdotV, alpha);
}
-float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) {
+float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
float alpha2 = alpha_x * alpha_y;
- highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH);
+ highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * cos_theta_m);
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 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 SchlickFresnel(float u) {
@@ -1082,109 +588,64 @@ float SchlickFresnel(float u) {
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, float A, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 B, vec3 T, float anisotropy,
+#endif
+ inout vec3 diffuse_light, inout vec3 specular_light) {
-void light_compute(
- vec3 N,
- vec3 L,
- vec3 V,
- vec3 B,
- vec3 T,
- vec3 light_color,
- vec3 attenuation,
- vec3 diffuse_color,
- vec3 transmission,
- float specular_blob_intensity,
- float roughness,
- float metallic,
- float specular,
- float rim,
- float rim_tint,
- float clearcoat,
- float clearcoat_roughness,
- 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
+ vec4 orms_unpacked = unpackUnorm4x8(orms);
-//#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 roughness = orms_unpacked.y;
+ float metallic = orms_unpacked.z;
#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
+
+#CODE : LIGHT
/* clang-format on */
#else
- float NdotL = dot(N, L);
+ float NdotL = min(A + dot(N, L), 1.0);
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
- float cNdotV = max(abs(NdotV), 1e-6);
+ float cNdotV = max(NdotV, 0.0);
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT)
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
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);
+#if defined(SPECULAR_SCHLICK_GGX)
+ float cNdotH = clamp(A + dot(N, H), 0.0, 1.0);
#endif
-#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT)
- float cLdotH = max(dot(L, H), 0.0);
+#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_CLEARCOAT_USED)
+ float cLdotH = clamp(A + dot(L, H), 0.0, 1.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);
@@ -1196,230 +657,208 @@ LIGHT_SHADER_CODE
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_brdf_NL * attenuation;
- 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;
+#if defined(LIGHT_BACKLIGHT_USED)
+ diffuse_light += light_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * backlight * attenuation;
#endif
-#if defined(LIGHT_USE_RIM)
+#if defined(LIGHT_RIM_USED)
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;
+ diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color;
#endif
}
- if (roughness > 0.0) {
+ if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
-#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);
+ // D
-#elif defined(SPECULAR_TOON)
+#if 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;
+ float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
+ diffuse_light += light_color * intensity * attenuation * specular_amount; // write to diffuse_light, as in toon shading you generally want no reflection
#elif defined(SPECULAR_DISABLED)
// none..
+
#elif defined(SPECULAR_SCHLICK_GGX)
// shlick+ggx as default
-
-#if defined(LIGHT_USE_ANISOTROPY)
float alpha_ggx = roughness * roughness;
+#if defined(LIGHT_ANISOTROPY_USED)
+
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 D = D_GGX_anisotropic(cNdotH, 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;
+#else // LIGHT_ANISOTROPY_USED
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);
+#endif // LIGHT_ANISOTROPY_USED
+ // F
float cLdotH5 = SchlickFresnel(cLdotH);
vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0);
- specular_brdf_NL = cNdotL * D * F * G;
+ vec3 specular_brdf_NL = cNdotL * D * F * G;
+ specular_light += specular_brdf_NL * light_color * attenuation * specular_amount;
#endif
- SRGB_APPROX(specular_brdf_NL)
- specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation;
-
-#if defined(LIGHT_USE_CLEARCOAT)
+#if defined(LIGHT_CLEARCOAT_USED)
+ // Clearcoat ignores normal_map, use vertex normal instead
+ float ccNdotL = max(min(A + dot(vertex_normal, L), 1.0), 0.0);
+ float ccNdotH = clamp(A + dot(vertex_normal, H), 0.0, 1.0);
+ float ccNdotV = max(dot(vertex_normal, V), 1e-4);
#if !defined(SPECULAR_SCHLICK_GGX)
float cLdotH5 = SchlickFresnel(cLdotH);
#endif
- float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_roughness));
+ float Dr = D_GGX(ccNdotH, mix(0.001, 0.1, clearcoat_roughness));
+ float Gr = 0.25 / (cLdotH * cLdotH);
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;
+ float clearcoat_specular_brdf_NL = clearcoat * Gr * Fr * Dr * cNdotL;
- specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation;
-#endif
+ specular_light += clearcoat_specular_brdf_NL * light_color * attenuation * specular_amount;
+ // TODO: Clearcoat adds light to the scene right now (it is non-energy conserving), both diffuse and specular need to be scaled by (1.0 - FR)
+ // but to do so we need to rearrange this entire function
+#endif // LIGHT_CLEARCOAT_USED
}
#ifdef USE_SHADOW_TO_OPACITY
- alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0));
+ alpha = min(alpha, clamp(1.0 - attenuation, 0.0, 1.0));
#endif
-#endif //defined(USE_LIGHT_SHADER_CODE)
+#endif //defined(LIGHT_CODE_USED)
}
-#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
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+ float nd = distance * inv_range;
+ nd *= nd;
+ nd *= nd; // nd^4
+ nd = max(1.0 - nd, 0.0);
+ nd *= nd; // nd^2
+ return nd * pow(max(distance, 0.0001), -decay);
+}
+void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
#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);
+#ifdef LIGHT_TRANSMITTANCE_USED
+ vec4 transmittance_color,
+ float transmittance_depth,
+ float transmittance_boost,
#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);
-
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint,
#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 binormal, vec3 tangent, float anisotropy,
+#endif
+ inout vec3 diffuse_light, inout vec3 specular_light) {
+ vec3 light_rel_vec = omni_lights[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float omni_attenuation = get_omni_attenuation(light_length, omni_lights[idx].inv_radius, omni_lights[idx].attenuation);
+ vec3 light_attenuation = vec3(omni_attenuation);
+ vec3 color = omni_lights[idx].color;
+ float size_A = 0.0;
+
+ if (omni_lights.data[idx].size > 0.0) {
+ float t = omni_lights[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
-#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13)
-
- return SAMPLE_SHADOW_TEXEL_PROJ(shadow, spos);
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, omni_lights[idx].specular_amount, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
+#endif
+#ifdef LIGHT_RIM_USED
+ rim * omni_attenuation, rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, vertex_normal,
#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+ diffuse_light,
+ specular_light);
}
+void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ vec3 backlight,
#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;
+#ifdef LIGHT_RIM_USED
+ float rim, float rim_tint,
+#endif
+#ifdef LIGHT_CLEARCOAT_USED
+ float clearcoat, float clearcoat_roughness, vec3 vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ vec3 binormal, vec3 tangent, float anisotropy,
#endif
+ inout vec3 diffuse_light,
+ inout vec3 specular_light) {
-uniform bool fog_transmit_enabled;
-uniform mediump float fog_transmit_curve;
+ vec3 light_rel_vec = spot_lights[idx].position - vertex;
+ float light_length = length(light_rel_vec);
+ float spot_attenuation = get_omni_attenuation(light_length, spot_lights[idx].inv_radius, spot_lights[idx].attenuation);
+ vec3 spot_dir = spot_lights[idx].direction;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights[idx].cone_angle);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights[idx].cone_angle));
+ spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].cone_attenuation);
+ float light_attenuation = spot_attenuation;
+ vec3 color = spot_lights[idx].color;
+
+ float size_A = 0.0;
+
+ if (spot_lights.data[idx].size > 0.0) {
+ float t = spot_lights.data[idx].size / max(0.001, light_length);
+ size_A = max(0.0, 1.0 - 1 / sqrt(1 + t * t));
+ }
-#ifdef FOG_DEPTH_ENABLED
-uniform highp float fog_depth_begin;
-uniform mediump float fog_depth_curve;
-uniform mediump float fog_max_distance;
+ light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, spot_lights[idx].specular_amount, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
#endif
-
-#ifdef FOG_HEIGHT_ENABLED
-uniform highp float fog_height_min;
-uniform highp float fog_height_max;
-uniform mediump float fog_height_curve;
+#ifdef LIGHT_RIM_USED
+ rim * spot_attenuation, rim_tint,
#endif
-
-#endif //vertex lit
-#endif //fog
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, vertex_normal,
+#endif
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal, tangent, anisotropy,
+#endif
+ diffuse_light, specular_light);
+}
+#endif // defined(USE_LIGHT_DIRECTIONAL) || defined(USE_LIGHT_POSITIONAL)
void main() {
-#ifdef RENDER_DEPTH_DUAL_PARABOLOID
-
- if (dp_clip > 0.0)
- discard;
-#endif
- highp vec3 vertex = vertex_interp;
+ //lay out everything, whatever is unused is optimized away anyway
+ vec3 vertex = vertex_interp;
vec3 view = -normalize(vertex_interp);
vec3 albedo = vec3(1.0);
- vec3 transmission = vec3(0.0);
+ vec3 backlight = vec3(0.0);
+ vec4 transmittance_color = vec4(0.0, 0.0, 0.0, 1.0);
+ float transmittance_depth = 0.0;
+ float transmittance_boost = 0.0;
float metallic = 0.0;
float specular = 0.5;
vec3 emission = vec3(0.0);
@@ -1430,617 +869,235 @@ void main() {
float clearcoat_roughness = 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;
+ vec4 fog = vec4(0.0);
+#if defined(CUSTOM_RADIANCE_USED)
+ vec4 custom_radiance = vec4(0.0);
+#endif
+#if defined(CUSTOM_IRRADIANCE_USED)
+ vec4 custom_irradiance = vec4(0.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;
+ float alpha = 1.0;
+
+#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
+ vec3 binormal = normalize(binormal_interp);
+ vec3 tangent = normalize(tangent_interp);
#else
vec3 binormal = vec3(0.0);
vec3 tangent = vec3(0.0);
#endif
- vec3 normal = normalize(normal_interp) * side;
-#if defined(ENABLE_NORMALMAP)
- vec3 normalmap = vec3(0.5);
+#ifdef NORMAL_USED
+ vec3 normal = normalize(normal_interp);
+
+#if defined(DO_SIDE_CHECK)
+ if (!gl_FrontFacing) {
+ normal = -normal;
+ }
#endif
- float normaldepth = 1.0;
-#if defined(ALPHA_SCISSOR_USED)
- float alpha_scissor = 0.5;
+#endif //NORMAL_USED
+
+#ifdef UV_USED
+ vec2 uv = uv_interp;
#endif
-#if defined(SCREEN_UV_USED)
- vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
+#if defined(UV2_USED) || defined(USE_LIGHTMAP)
+ vec2 uv2 = uv2_interp;
#endif
- {
- /* clang-format off */
+#if defined(COLOR_USED)
+ vec4 color = color_interp;
+#endif
-FRAGMENT_SHADER_CODE
+#if defined(NORMAL_MAP_USED)
- /* clang-format on */
- }
+ vec3 normal_map = vec3(0.5);
+#endif
-#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)));
+ float normal_map_depth = 1.0;
- normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side;
- //normal = normalmap;
-#endif
+ vec2 screen_uv = gl_FragCoord.xy * scene_data.screen_pixel_size + scene_data.screen_pixel_size * 0.5; //account for center
- normal = normalize(normal);
+ float sss_strength = 0.0;
- vec3 N = normal;
+#ifdef ALPHA_SCISSOR_USED
+ float alpha_scissor_threshold = 1.0;
+#endif // ALPHA_SCISSOR_USED
- 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);
+#ifdef ALPHA_HASH_USED
+ float alpha_hash_scale = 1.0;
+#endif // ALPHA_HASH_USED
- vec3 eye_position = view;
+#ifdef ALPHA_ANTIALIASING_EDGE_USED
+ float alpha_antialiasing_edge = 0.0;
+ vec2 alpha_texture_coordinate = vec2(0.0, 0.0);
+#endif // ALPHA_ANTIALIASING_EDGE_USED
+ {
+#CODE : FRAGMENT
+ }
-#if !defined(USE_SHADOW_TO_OPACITY)
+#ifndef USE_SHADOW_TO_OPACITY
#if defined(ALPHA_SCISSOR_USED)
- if (alpha < alpha_scissor) {
+ if (alpha < alpha_scissor_threshold) {
discard;
}
#endif // ALPHA_SCISSOR_USED
-#ifdef USE_DEPTH_PREPASS
- if (alpha < 0.1) {
+#ifdef USE_OPAQUE_PREPASS
+#if !defined(ALPHA_SCISSOR_USED)
+
+ if (alpha < scene_data.opaque_prepass_threshold) {
discard;
}
-#endif // USE_DEPTH_PREPASS
-#endif // !USE_SHADOW_TO_OPACITY
+#endif // not ALPHA_SCISSOR_USED
+#endif // USE_OPAQUE_PREPASS
-#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;
+#endif // !USE_SHADOW_TO_OPACITY
- ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution);
- }
-#endif
+#ifdef NORMAL_MAP_USED
-#else
+ normal_map.xy = normal_map.xy * 2.0 - 1.0;
+ normal_map.z = sqrt(max(0.0, 1.0 - dot(normal_map.xy, normal_map.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
- ambient_light = ambient_color.rgb;
- specular_light = bg_color.rgb * bg_energy;
+ normal = normalize(mix(normal, tangent * normal_map.x + binormal * normal_map.y + normal * normal_map.z, normal_map_depth));
#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 LIGHT_ANISOTROPY_USED
-#ifdef USE_REFLECTION_PROBE1
+ if (anisotropy > 0.01) {
+ //rotation matrix
+ mat3 rot = mat3(tangent, binormal, normal);
+ //make local to space
+ tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0));
+ binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0));
+ }
- 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
+#ifndef MODE_RENDER_DEPTH
+ vec3 f0 = F0(metallic, specular, albedo);
+ // Convert albedo to linear. Approximation from: http://chilliant.blogspot.com/2012/08/srgb-approximations-for-hlsl.html
+ albedo = albedo * (albedo * (albedo * 0.305306011 + 0.682171111) + 0.012522878);
+ 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);
-#ifdef USE_REFLECTION_PROBE2
+#ifdef BASE_PASS
+ /////////////////////// LIGHTING //////////////////////////////
- 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);
+ // IBL precalculations
+ float ndotv = clamp(dot(normal, view), 0.0, 1.0);
+ vec3 F = f0 + (max(vec3(1.0 - roughness), f0) - f0) * pow(1.0 - ndotv, 5.0);
-#endif // USE_REFLECTION_PROBE2
+ // Calculate IBL
+ // Calculate Reflection probes
+ // Caclculate Lightmaps
- if (reflection_accum.a > 0.0) {
- specular_light = reflection_accum.rgb / reflection_accum.a;
- }
+ float specular_blob_intensity = 1.0;
-#ifndef USE_LIGHTMAP
- if (ambient_accum.a > 0.0) {
- ambient_light = ambient_accum.rgb / ambient_accum.a;
- }
+#if defined(SPECULAR_TOON)
+ specular_blob_intensity *= specular * 2.0;
#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 computed before lighting happens,
- // but after environment and reflection probes are added
- //TODO: this curve is not really designed for gammaspace, should be adjusted
+ // scales the specular reflections, needs to be be computed before lighting happens,
+ // but after environment, GI, and reflection probes are added
+ // Environment brdf approximation (Lazarov 2013)
+ // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
vec4 r = roughness * c0 + c1;
+ float ndotv = clamp(dot(normal, view), 0.0, 1.0);
+
float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
vec2 env = vec2(-1.04, 1.04) * a004 + r.zw;
- 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(inv_view_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);
-
+ specular_light *= env.x * f0 + env.y;
#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)
+#endif // BASE_PASS
-#ifdef USE_SHADOW
+ //this saves some VGPRs
+ uint orms = packUnorm4x8(vec4(ao, roughness, metallic, specular));
-#ifdef USE_VERTEX_LIGHTING
- //compute shadows in a mobile friendly way
+#ifdef USE_LIGHT_DIRECTIONAL
-#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);
+ float size_A = directional_lights[i].size;
- 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;
+ light_compute(normal, directional_lights[i].direction, normalize(view), size_A, directional_lights[i].color * directional_lights[i].energy, shadow, f0, orms, 1.0, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
#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);
+#ifdef LIGHT_RIM_USED
+ rim, rim_tint,
#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);
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#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);
- }
+#ifdef LIGHT_ANISOTROPY_USED
+ binormal,
+ tangent, anisotropy,
#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);
+ diffuse_light,
+ specular_light);
- if (depth_z < light_split_offsets.y) {
- float shadow_att = 1.0;
- float pssm_fade = 0.0;
+#endif //#USE_LIGHT_DIRECTIONAL
-#ifdef LIGHT_USE_PSSM_BLEND
- float shadow_att2 = 1.0;
- float pssm_blend = 0.0;
- bool use_blend = true;
+#ifdef USE_LIGHT_POSITIONAL
+ float shadow = 0.0;
+ for (int i = 0; i < omni_light_count; i++) {
+ light_process_omni(omni_light_indices[i], vertex, view, normal, f0, orms, shadow, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
#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);
+#ifdef LIGHT_RIM_USED
+ rim,
+ rim_tint,
#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;
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#endif
- }
-#ifdef LIGHT_USE_PSSM_BLEND
- if (use_blend) {
- shadow_att = mix(shadow_att, shadow_att2, pssm_blend);
- }
+#ifdef LIGHT_ANISOTROPY_USED
+ tangent, binormal, anisotropy,
#endif
- light_att *= mix(shadow_color.rgb, vec3(1.0), shadow_att);
+ diffuse_light, specular_light);
}
-#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);
+ for (int i = 0; i < spot_light_count; i++) {
+ light_process_spot(spot_light_indices[i], vertex, view, normal, f0, orms, shadow, albedo, alpha,
+#ifdef LIGHT_BACKLIGHT_USED
+ backlight,
#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;
+#ifdef LIGHT_RIM_USED
+ rim,
+ rim_tint,
#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);
- }
+#ifdef LIGHT_CLEARCOAT_USED
+ clearcoat, clearcoat_roughness, normalize(normal_interp),
#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);
-
+#ifdef LIGHT_ANISOTROPY_USED
+ tangent,
+ binormal, anisotropy,
#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);
+ diffuse_light, specular_light);
}
-#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_roughness,
- anisotropy,
- diffuse_light,
- specular_light,
- alpha);
-
-#endif //vertex lighting
-#endif //USE_LIGHTING
- //compute and merge
-
-#ifdef USE_SHADOW_TO_OPACITY
+#endif // USE_LIGHT_POSITIONAL
+#endif //!MODE_RENDER_DEPTH
+#if defined(USE_SHADOW_TO_OPACITY)
alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0));
#if defined(ALPHA_SCISSOR_USED)
@@ -2049,105 +1106,50 @@ FRAGMENT_SHADER_CODE
}
#endif // ALPHA_SCISSOR_USED
-#ifdef USE_DEPTH_PREPASS
- if (alpha < 0.1) {
+#ifdef USE_OPAQUE_PREPASS
+#if !defined(ALPHA_SCISSOR_USED)
+
+ if (alpha < opaque_prepass_threshold) {
discard;
}
-#endif // USE_DEPTH_PREPASS
-#endif // !USE_SHADOW_TO_OPACITY
+#endif // not ALPHA_SCISSOR_USED
+#endif // USE_OPAQUE_PREPASS
-#ifndef RENDER_DEPTH
+#endif // USE_SHADOW_TO_OPACITY
-#ifdef SHADELESS
+#ifdef MODE_RENDER_DEPTH
+//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
+#else // !MODE_RENDER_DEPTH
- 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
+ specular_light *= scene_data.reflection_multiplier;
+ ambient_light *= albedo; //ambient must be multiplied by albedo at the end
+ // base color remapping
diffuse_light *= 1.0 - metallic;
ambient_light *= 1.0 - metallic;
+#ifdef MODE_UNSHADED
+ frag_color = vec4(albedo, alpha);
+#else
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
+#endif //MODE_UNSHADED
- {
- float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex));
+ // Tonemap before writing as we are writing to an sRGB framebuffer
+ frag_color.rgb *= exposure;
+ frag_color.rgb = apply_tonemapping(frag_color.rgb, white);
+ frag_color.rgb = linear_to_srgb(frag_color.rgb);
- 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);
- }
- }
+#ifdef USE_BCS
+ frag_color.rgb = apply_bcs(frag_color.rgb, bcs);
#endif
-#ifdef FOG_HEIGHT_ENABLED
- {
- float y = (inv_view_matrix * vec4(vertex, 1.0)).y;
- fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve));
- }
+#ifdef USE_COLOR_CORRECTION
+ frag_color.rgb = apply_color_correction(frag_color.rgb, color_correction);
#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
+#endif //!MODE_RENDER_DEPTH
}
diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl
index 0faa3eb70c..3a1bcd3b28 100644
--- a/drivers/gles3/shaders/sky.glsl
+++ b/drivers/gles3/shaders/sky.glsl
@@ -12,21 +12,12 @@ mode_cubemap_quarter_res = #define USE_CUBEMAP_PASS \n#define USE_QUARTER_RES_PA
#[vertex]
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-precision highp float;
-precision highp int;
-#endif
-
out vec2 uv_interp;
/* clang-format on */
void main() {
// One big triangle to cover the whole screen
- vec2 base_arr[3] = vec2[](vec2(-1.0, -2.0), vec2(-1.0, 2.0), vec2(2.0, 2.0));
+ vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
uv_interp = base_arr[gl_VertexID];
gl_Position = vec4(uv_interp, 1.0, 1.0);
}
@@ -36,19 +27,7 @@ void main() {
#define M_PI 3.14159265359
-#ifdef USE_GLES_OVER_GL
-#define lowp
-#define mediump
-#define highp
-#else
-#if defined(USE_HIGHP_PRECISION)
-precision highp float;
-precision highp int;
-#else
-precision mediump float;
-precision mediump int;
-#endif
-#endif
+#include "tonemap_inc.glsl"
in vec2 uv_interp;
@@ -63,40 +42,36 @@ uniform sampler2D half_res; //texunit:-2
uniform sampler2D quarter_res; //texunit:-3
#endif
-layout(std140) uniform CanvasData { //ubo:0
- mat3 orientation;
- vec4 projection;
- vec4 position_multiplier;
- float time;
- float luminance_multiplier;
- float pad1;
- float pad2;
-};
-
layout(std140) uniform GlobalVariableData { //ubo:1
vec4 global_variables[MAX_GLOBAL_VARIABLES];
};
+layout(std140) uniform SceneData { //ubo:2
+ float pad1;
+ float pad2;
+};
+
struct DirectionalLightData {
vec4 direction_energy;
vec4 color_size;
bool enabled;
};
-layout(std140) uniform DirectionalLights { //ubo:2
+layout(std140) uniform DirectionalLights { //ubo:3
DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS];
}
directional_lights;
+/* clang-format off */
+
#ifdef MATERIAL_UNIFORMS_USED
-layout(std140) uniform MaterialUniforms{
-//ubo:3
+layout(std140) uniform MaterialUniforms{ //ubo:4
#MATERIAL_UNIFORMS
-} material;
+};
#endif
-
+/* clang-format on */
#GLOBALS
#ifdef USE_CUBEMAP_PASS
@@ -117,6 +92,12 @@ layout(std140) uniform MaterialUniforms{
#define AT_QUARTER_RES_PASS false
#endif
+// mat4 is a waste of space, but we don't have an easy way to set a mat3 uniform for now
+uniform mat4 orientation;
+uniform vec4 projection;
+uniform vec3 position;
+uniform float time;
+
layout(location = 0) out vec4 frag_color;
void main() {
@@ -128,7 +109,7 @@ void main() {
cube_normal.z = -cube_normal.z;
cube_normal = normalize(cube_normal);
- vec2 uv = uv_interp * 0.5 + 0.5;
+ vec2 uv = gl_FragCoord.xy; // uv_interp * 0.5 + 0.5;
vec2 panorama_coords = vec2(atan(cube_normal.x, cube_normal.z), acos(cube_normal.y));
@@ -148,17 +129,17 @@ void main() {
vec3 inverted_cube_normal = cube_normal;
inverted_cube_normal.z *= -1.0;
#ifdef USES_HALF_RES_COLOR
- half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * luminance_multiplier;
+ half_res_color = texture(samplerCube(half_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal) * luminance_multiplier;
+ quarter_res_color = texture(samplerCube(quarter_res, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), inverted_cube_normal);
#endif
#else
#ifdef USES_HALF_RES_COLOR
- half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * luminance_multiplier;
+ half_res_color = textureLod(sampler2D(half_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
#endif
#ifdef USES_QUARTER_RES_COLOR
- quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0) * luminance_multiplier;
+ quarter_res_color = textureLod(sampler2D(quarter_res, material_samplers[SAMPLER_LINEAR_CLAMP]), uv, 0.0);
#endif
#endif
@@ -168,12 +149,19 @@ void main() {
}
- frag_color.rgb = color * position_multiplier.w / luminance_multiplier;
- frag_color.a = alpha;
+ // Tonemap before writing as we are writing to an sRGB framebuffer
+ color *= exposure;
+ color = apply_tonemapping(color, white);
+ color = linear_to_srgb(color);
- // Blending is disabled for Sky, so alpha doesn't blend
- // alpha is used for subsurface scattering so make sure it doesn't get applied to Sky
- if (!AT_CUBEMAP_PASS && !AT_HALF_RES_PASS && !AT_QUARTER_RES_PASS) {
- frag_color.a = 0.0;
- }
+#ifdef USE_BCS
+ color = apply_bcs(color, bcs);
+#endif
+
+#ifdef USE_COLOR_CORRECTION
+ color = apply_color_correction(color, color_correction);
+#endif
+
+ frag_color.rgb = color;
+ frag_color.a = alpha;
}
diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl
index 2eddf9d479..6cce6c12bd 100644
--- a/drivers/gles3/shaders/stdlib_inc.glsl
+++ b/drivers/gles3/shaders/stdlib_inc.glsl
@@ -1,5 +1,6 @@
-//TODO: only needed by GLES_OVER_GL
+#ifdef USE_GLES_OVER_GL
+// Floating point pack/unpack functions are part of the GLSL ES 300 specification used by web and mobile.
uint float2half(uint f) {
return ((f >> uint(16)) & uint(0x8000)) |
((((f & uint(0x7f800000)) - uint(0x38000000)) >> uint(13)) & uint(0x7c00)) |
@@ -37,6 +38,7 @@ vec2 unpackSnorm2x16(uint p) {
vec2 v = vec2(float(p & uint(0xffff)), float(p >> uint(16)));
return clamp((v - 32767.0) * vec2(0.00003051851), vec2(-1.0), vec2(1.0));
}
+#endif
uint packUnorm4x8(vec4 v) {
uvec4 uv = uvec4(round(clamp(v, vec4(0.0), vec4(1.0)) * 255.0));
diff --git a/drivers/gles3/shaders/tonemap_inc.glsl b/drivers/gles3/shaders/tonemap_inc.glsl
new file mode 100644
index 0000000000..ea15c05359
--- /dev/null
+++ b/drivers/gles3/shaders/tonemap_inc.glsl
@@ -0,0 +1,119 @@
+#ifdef USE_BCS
+uniform vec3 bcs;
+#endif
+
+#ifdef USE_COLOR_CORRECTION
+#ifdef USE_1D_LUT
+uniform sampler2D source_color_correction; //texunit:-1
+#else
+uniform sampler3D source_color_correction; //texunit:-1
+#endif
+#endif
+
+layout(std140) uniform TonemapData { //ubo:0
+ float exposure;
+ float white;
+ int tonemapper;
+ int pad;
+};
+
+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;
+}
+#ifdef USE_COLOR_CORRECTION
+#ifdef USE_1D_LUT
+vec3 apply_color_correction(vec3 color) {
+ color.r = texture(source_color_correction, vec2(color.r, 0.0f)).r;
+ color.g = texture(source_color_correction, vec2(color.g, 0.0f)).g;
+ color.b = texture(source_color_correction, vec2(color.b, 0.0f)).b;
+ return color;
+}
+#else
+vec3 apply_color_correction(vec3 color) {
+ return textureLod(source_color_correction, color, 0.0).rgb;
+}
+#endif
+#endif
+
+vec3 tonemap_filmic(vec3 color, float p_white) {
+ // exposure bias: input scale (color *= bias, white *= bias) to make the brightness consistent with other tonemappers
+ // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values)
+ // has no effect on the curve's general shape or visual properties
+ const float exposure_bias = 2.0f;
+ const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance
+ const float B = 0.30f * exposure_bias;
+ const float C = 0.10f;
+ const float D = 0.20f;
+ const float E = 0.01f;
+ const float F = 0.30f;
+
+ vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
+ float p_white_tonemapped = ((p_white * (A * p_white + C * B) + D * E) / (p_white * (A * p_white + B) + D * F)) - E / F;
+
+ return color_tonemapped / p_white_tonemapped;
+}
+
+// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl
+// (MIT License).
+vec3 tonemap_aces(vec3 color, float p_white) {
+ const float exposure_bias = 1.8f;
+ const float A = 0.0245786f;
+ const float B = 0.000090537f;
+ const float C = 0.983729f;
+ const float D = 0.432951f;
+ const float E = 0.238081f;
+
+ // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias`
+ const mat3 rgb_to_rrt = mat3(
+ vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias),
+ vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias),
+ vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias));
+
+ const mat3 odt_to_rgb = mat3(
+ vec3(1.60475f, -0.53108f, -0.07367f),
+ vec3(-0.10208f, 1.10813f, -0.00605f),
+ vec3(-0.00327f, -0.07276f, 1.07602f));
+
+ color *= rgb_to_rrt;
+ vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E);
+ color_tonemapped *= odt_to_rgb;
+
+ p_white *= exposure_bias;
+ float p_white_tonemapped = (p_white * (p_white + A) - B) / (p_white * (C * p_white + D) + E);
+
+ return color_tonemapped / p_white_tonemapped;
+}
+
+vec3 tonemap_reinhard(vec3 color, float p_white) {
+ return (p_white * color + color) / (color * p_white + p_white);
+}
+
+vec3 linear_to_srgb(vec3 color) {
+ //if going to srgb, clamp from 0 to 1.
+ color = clamp(color, vec3(0.0), vec3(1.0));
+ const vec3 a = vec3(0.055f);
+ return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
+}
+
+#define TONEMAPPER_LINEAR 0
+#define TONEMAPPER_REINHARD 1
+#define TONEMAPPER_FILMIC 2
+#define TONEMAPPER_ACES 3
+
+vec3 apply_tonemapping(vec3 color, float p_white) { // inputs are LINEAR, always outputs clamped [0;1] color
+ // Ensure color values passed to tonemappers are positive.
+ // They can be negative in the case of negative lights, which leads to undesired behavior.
+ if (tonemapper == TONEMAPPER_LINEAR) {
+ return color;
+ } else if (tonemapper == TONEMAPPER_REINHARD) {
+ return tonemap_reinhard(max(vec3(0.0f), color), p_white);
+ } else if (tonemapper == TONEMAPPER_FILMIC) {
+ return tonemap_filmic(max(vec3(0.0f), color), p_white);
+ } else { // TONEMAPPER_ACES
+ return tonemap_aces(max(vec3(0.0f), color), p_white);
+ }
+}
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 369e523cc4..49a2a79cb2 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -44,7 +44,7 @@ Config::Config() {
singleton = this;
{
- int max_extensions = 0;
+ GLint max_extensions = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &max_extensions);
for (int i = 0; i < max_extensions; i++) {
const GLubyte *s = glGetStringi(GL_EXTENSIONS, i);
@@ -120,16 +120,6 @@ Config::Config() {
support_write_depth = extensions.has("GL_EXT_frag_depth");
#endif
- 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
- support_half_float_vertices = false;
-#endif
- bool disable_half_float = false; //GLOBAL_GET("rendering/opengl/compatibility/disable_half_float");
- if (disable_half_float) {
- support_half_float_vertices = false;
- }
-
//picky requirements for these
support_shadow_cubemaps = support_write_depth && support_depth_cubemaps;
// the use skeleton software path should be used if either float texture is not supported,
@@ -149,6 +139,27 @@ Config::Config() {
force_vertex_shading = false; //GLOBAL_GET("rendering/quality/shading/force_vertex_shading");
use_nearest_mip_filter = GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter");
+
+ use_depth_prepass = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
+ if (use_depth_prepass) {
+ String vendors = GLOBAL_GET("rendering/driver/depth_prepass/disable_for_vendors");
+ Vector<String> vendor_match = vendors.split(",");
+ String renderer = (const char *)glGetString(GL_RENDERER);
+ for (int i = 0; i < vendor_match.size(); i++) {
+ String v = vendor_match[i].strip_edges();
+ if (v == String()) {
+ continue;
+ }
+
+ if (renderer.findn(v) != -1) {
+ use_depth_prepass = false;
+ }
+ }
+ }
+
+ max_renderable_elements = GLOBAL_GET("rendering/limits/opengl/max_renderable_elements");
+ max_renderable_lights = GLOBAL_GET("rendering/limits/opengl/max_renderable_lights");
+ max_lights_per_object = GLOBAL_GET("rendering/limits/opengl/max_lights_per_object");
}
Config::~Config() {
diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h
index 0646881b72..7e143c1c1e 100644
--- a/drivers/gles3/storage/config.h
+++ b/drivers/gles3/storage/config.h
@@ -58,6 +58,9 @@ public:
int max_texture_image_units = 0;
int max_texture_size = 0;
int max_uniform_buffer_size = 0;
+ int max_renderable_elements = 0;
+ int max_renderable_lights = 0;
+ int max_lights_per_object = 0;
// TODO implement wireframe in OpenGL
// bool generate_wireframes;
@@ -82,7 +85,6 @@ public:
bool support_32_bits_indices = false;
bool support_write_depth = false;
- bool support_half_float_vertices = false;
bool support_npot_repeat_mipmap = false;
bool support_depth_cubemaps = false;
bool support_shadow_cubemaps = false;
@@ -97,6 +99,8 @@ public:
// so the user can switch orphaning off for them.
bool should_orphan = true;
+ bool use_depth_prepass = true;
+
static Config *get_singleton() { return singleton; };
Config();
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index d4bb551704..c1122ccc07 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -43,7 +43,7 @@ using namespace GLES3;
///////////////////////////////////////////////////////////////////////////
// UBI helper functions
-_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data, bool p_linear_color) {
+_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data) {
switch (type) {
case ShaderLanguage::TYPE_BOOL: {
uint32_t *gui = (uint32_t *)data;
@@ -399,9 +399,6 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
if (i < s) {
Color color = a[i];
- if (p_linear_color) {
- color = color.srgb_to_linear();
- }
gui[j] = color.r;
gui[j + 1] = color.g;
gui[j + 2] = color.b;
@@ -433,10 +430,6 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
if (value.get_type() == Variant::COLOR) {
Color v = value;
- if (p_linear_color) {
- v = v.srgb_to_linear();
- }
-
gui[0] = v.r;
gui[1] = v.g;
gui[2] = v.b;
@@ -459,9 +452,6 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
for (int i = 0, j = 0; i < p_array_size; i++, j += 4) {
if (i < s) {
Color color = a[i];
- if (p_linear_color) {
- color = color.srgb_to_linear();
- }
gui[j] = color.r;
gui[j + 1] = color.g;
gui[j + 2] = color.b;
@@ -496,10 +486,6 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy
if (value.get_type() == Variant::COLOR) {
Color v = value;
- if (p_linear_color) {
- v = v.srgb_to_linear();
- }
-
gui[0] = v.r;
gui[1] = v.g;
gui[2] = v.b;
@@ -900,6 +886,42 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type,
///////////////////////////////////////////////////////////////////////////
// MaterialData
+// Look up table to translate ShaderLanguage::DataType to GL_TEXTURE_*
+static const GLenum target_from_type[ShaderLanguage::TYPE_MAX] = {
+ GL_TEXTURE_2D, // TYPE_VOID,
+ GL_TEXTURE_2D, // TYPE_BOOL,
+ GL_TEXTURE_2D, // TYPE_BVEC2,
+ GL_TEXTURE_2D, // TYPE_BVEC3,
+ GL_TEXTURE_2D, // TYPE_BVEC4,
+ GL_TEXTURE_2D, // TYPE_INT,
+ GL_TEXTURE_2D, // TYPE_IVEC2,
+ GL_TEXTURE_2D, // TYPE_IVEC3,
+ GL_TEXTURE_2D, // TYPE_IVEC4,
+ GL_TEXTURE_2D, // TYPE_UINT,
+ GL_TEXTURE_2D, // TYPE_UVEC2,
+ GL_TEXTURE_2D, // TYPE_UVEC3,
+ GL_TEXTURE_2D, // TYPE_UVEC4,
+ GL_TEXTURE_2D, // TYPE_FLOAT,
+ GL_TEXTURE_2D, // TYPE_VEC2,
+ GL_TEXTURE_2D, // TYPE_VEC3,
+ GL_TEXTURE_2D, // TYPE_VEC4,
+ GL_TEXTURE_2D, // TYPE_MAT2,
+ GL_TEXTURE_2D, // TYPE_MAT3,
+ GL_TEXTURE_2D, // TYPE_MAT4,
+ GL_TEXTURE_2D, // TYPE_SAMPLER2D,
+ GL_TEXTURE_2D, // TYPE_ISAMPLER2D,
+ GL_TEXTURE_2D, // TYPE_USAMPLER2D,
+ GL_TEXTURE_2D_ARRAY, // TYPE_SAMPLER2DARRAY,
+ GL_TEXTURE_2D_ARRAY, // TYPE_ISAMPLER2DARRAY,
+ GL_TEXTURE_2D_ARRAY, // TYPE_USAMPLER2DARRAY,
+ GL_TEXTURE_3D, // TYPE_SAMPLER3D,
+ GL_TEXTURE_3D, // TYPE_ISAMPLER3D,
+ GL_TEXTURE_3D, // TYPE_USAMPLER3D,
+ GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBE,
+ GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBEARRAY,
+ GL_TEXTURE_2D, // TYPE_STRUCT
+};
+
void MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) {
MaterialStorage *material_storage = MaterialStorage::get_singleton();
bool uses_global_buffer = false;
@@ -951,7 +973,7 @@ void MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::S
if (V) {
//user provided
- _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->get(), data, p_use_linear_color);
+ _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->get(), data);
} else if (E.value.default_value.size()) {
//default value
@@ -961,7 +983,7 @@ void MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::S
//zero because it was not provided
if ((E.value.type == ShaderLanguage::TYPE_VEC3 || E.value.type == ShaderLanguage::TYPE_VEC4) && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) {
//colors must be set as black, with alpha as 1.0
- _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data, p_use_linear_color);
+ _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data);
} else {
//else just zero it out
_fill_std140_ubo_empty(E.value.type, E.value.array_size, data);
@@ -1275,16 +1297,16 @@ MaterialStorage *MaterialStorage::get_singleton() {
MaterialStorage::MaterialStorage() {
singleton = this;
- shader_data_request_func[RS::SHADER_SPATIAL] = nullptr;
+ shader_data_request_func[RS::SHADER_SPATIAL] = _create_scene_shader_func;
shader_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_shader_func;
shader_data_request_func[RS::SHADER_PARTICLES] = nullptr;
- shader_data_request_func[RS::SHADER_SKY] = nullptr;
+ shader_data_request_func[RS::SHADER_SKY] = _create_sky_shader_func;
shader_data_request_func[RS::SHADER_FOG] = nullptr;
- material_data_request_func[RS::SHADER_SPATIAL] = nullptr;
+ material_data_request_func[RS::SHADER_SPATIAL] = _create_scene_material_func;
material_data_request_func[RS::SHADER_CANVAS_ITEM] = _create_canvas_material_func;
material_data_request_func[RS::SHADER_PARTICLES] = nullptr;
- material_data_request_func[RS::SHADER_SKY] = nullptr;
+ material_data_request_func[RS::SHADER_SKY] = _create_sky_material_func;
material_data_request_func[RS::SHADER_FOG] = nullptr;
static_assert(sizeof(GlobalVariables::Value) == 16);
@@ -1365,16 +1387,12 @@ MaterialStorage::MaterialStorage() {
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n";
- actions.base_texture_binding_index = 1;
- actions.base_uniform_string = "";
- actions.global_buffer_array_variable = "";
-
shaders.compiler_canvas.initialize(actions);
}
{
// Setup Scene compiler
- /*
+
//shader compiler
ShaderCompiler::DefaultIdentifierActions actions;
@@ -1529,11 +1547,6 @@ MaterialStorage::MaterialStorage() {
actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n";
actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
-
- actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; // linear filter with mipmaps
- actions.custom_samplers["DEPTH_TEXTURE"] = "material_samplers[3]";
- actions.custom_samplers["NORMAL_ROUGHNESS_TEXTURE"] = "material_samplers[1]"; // linear filter
-
actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
actions.render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
actions.render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
@@ -1541,19 +1554,10 @@ MaterialStorage::MaterialStorage() {
actions.render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
- actions.sampler_array_name = "material_samplers";
- actions.base_texture_binding_index = 1;
- actions.texture_layout_set = RenderForwardClustered::MATERIAL_UNIFORM_SET;
- actions.base_uniform_string = "material.";
- actions.base_varying_index = 10;
-
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
- actions.global_buffer_array_variable = "global_variables.data";
- actions.instance_uniform_index_variable = "instances.data[instance_index].instance_uniforms_ofs";
- compiler.initialize(actions);
- */
+ shaders.compiler_scene.initialize(actions);
}
{
@@ -1626,10 +1630,10 @@ ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["COLOR"] = "color";
actions.renames["ALPHA"] = "alpha";
actions.renames["EYEDIR"] = "cube_normal";
- actions.renames["POSITION"] = "params.position_multiplier.xyz";
+ actions.renames["POSITION"] = "position";
actions.renames["SKY_COORDS"] = "panorama_coords";
actions.renames["SCREEN_UV"] = "uv";
- actions.renames["TIME"] = "params.time";
+ actions.renames["TIME"] = "time";
actions.renames["PI"] = _MKSTR(Math_PI);
actions.renames["TAU"] = _MKSTR(Math_TAU);
actions.renames["E"] = _MKSTR(Math_E);
@@ -1660,20 +1664,12 @@ ShaderCompiler::DefaultIdentifierActions actions;
actions.renames["AT_CUBEMAP_PASS"] = "AT_CUBEMAP_PASS";
actions.renames["AT_HALF_RES_PASS"] = "AT_HALF_RES_PASS";
actions.renames["AT_QUARTER_RES_PASS"] = "AT_QUARTER_RES_PASS";
- actions.custom_samplers["RADIANCE"] = "material_samplers[3]";
actions.usage_defines["HALF_RES_COLOR"] = "\n#define USES_HALF_RES_COLOR\n";
actions.usage_defines["QUARTER_RES_COLOR"] = "\n#define USES_QUARTER_RES_COLOR\n";
actions.render_mode_defines["disable_fog"] = "#define DISABLE_FOG\n";
- actions.sampler_array_name = "material_samplers";
- actions.base_texture_binding_index = 1;
- actions.texture_layout_set = 1;
- actions.base_uniform_string = "material.";
- actions.base_varying_index = 10;
-
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
- actions.global_buffer_array_variable = "global_variables";
shaders.compiler_sky.initialize(actions);
}
@@ -1873,7 +1869,7 @@ void MaterialStorage::_global_variable_store_in_buffer(int32_t p_index, RS::Glob
bv.w = v.a;
GlobalVariables::Value &bv_linear = global_variables.buffer_values[p_index + 1];
- v = v.srgb_to_linear();
+ //v = v.srgb_to_linear();
bv_linear.x = v.r;
bv_linear.y = v.g;
bv_linear.z = v.b;
@@ -2311,7 +2307,7 @@ void MaterialStorage::global_variables_instance_update(RID p_instance, int p_ind
pos += p_index;
- _fill_std140_variant_ubo_value(datatype, 0, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer
+ _fill_std140_variant_ubo_value(datatype, 0, p_value, (uint8_t *)&global_variables.buffer_values[pos]);
_global_variable_mark_buffer_dirty(pos, 1);
}
@@ -2546,7 +2542,7 @@ RS::ShaderNativeSourceCode MaterialStorage::shader_get_native_source_code(RID p_
/* MATERIAL API */
-void MaterialStorage::_material_queue_update(Material *material, bool p_uniform, bool p_texture) {
+void MaterialStorage::_material_queue_update(GLES3::Material *material, bool p_uniform, bool p_texture) {
material->uniform_dirty = material->uniform_dirty || p_uniform;
material->texture_dirty = material->texture_dirty || p_texture;
@@ -2738,7 +2734,8 @@ void MaterialStorage::material_update_dependency(RID p_material, RendererStorage
}
}
-// Canvas Shader Data
+/* Canvas Shader Data */
+
void CanvasShaderData::set_code(const String &p_code) {
// compile the shader
@@ -2915,51 +2912,15 @@ void CanvasMaterialData::update_parameters(const Map<StringName, Variant> &p_par
return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
}
-// Look up table to translate ShaderLanguage::DataType to GL_TEXTURE_*
-static const GLenum target_from_type[ShaderLanguage::TYPE_MAX] = {
- GL_TEXTURE_2D, // TYPE_VOID,
- GL_TEXTURE_2D, // TYPE_BOOL,
- GL_TEXTURE_2D, // TYPE_BVEC2,
- GL_TEXTURE_2D, // TYPE_BVEC3,
- GL_TEXTURE_2D, // TYPE_BVEC4,
- GL_TEXTURE_2D, // TYPE_INT,
- GL_TEXTURE_2D, // TYPE_IVEC2,
- GL_TEXTURE_2D, // TYPE_IVEC3,
- GL_TEXTURE_2D, // TYPE_IVEC4,
- GL_TEXTURE_2D, // TYPE_UINT,
- GL_TEXTURE_2D, // TYPE_UVEC2,
- GL_TEXTURE_2D, // TYPE_UVEC3,
- GL_TEXTURE_2D, // TYPE_UVEC4,
- GL_TEXTURE_2D, // TYPE_FLOAT,
- GL_TEXTURE_2D, // TYPE_VEC2,
- GL_TEXTURE_2D, // TYPE_VEC3,
- GL_TEXTURE_2D, // TYPE_VEC4,
- GL_TEXTURE_2D, // TYPE_MAT2,
- GL_TEXTURE_2D, // TYPE_MAT3,
- GL_TEXTURE_2D, // TYPE_MAT4,
- GL_TEXTURE_2D, // TYPE_SAMPLER2D,
- GL_TEXTURE_2D, // TYPE_ISAMPLER2D,
- GL_TEXTURE_2D, // TYPE_USAMPLER2D,
- GL_TEXTURE_2D_ARRAY, // TYPE_SAMPLER2DARRAY,
- GL_TEXTURE_2D_ARRAY, // TYPE_ISAMPLER2DARRAY,
- GL_TEXTURE_2D_ARRAY, // TYPE_USAMPLER2DARRAY,
- GL_TEXTURE_3D, // TYPE_SAMPLER3D,
- GL_TEXTURE_3D, // TYPE_ISAMPLER3D,
- GL_TEXTURE_3D, // TYPE_USAMPLER3D,
- GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBE,
- GL_TEXTURE_CUBE_MAP, // TYPE_SAMPLERCUBEARRAY,
- GL_TEXTURE_2D, // TYPE_STRUCT
-};
-
void CanvasMaterialData::bind_uniforms() {
// Bind Material Uniforms
- glBindBufferBase(GL_UNIFORM_BUFFER, RasterizerCanvasGLES3::MATERIAL_UNIFORM_BUFFER_OBJECT, uniform_buffer);
+ glBindBufferBase(GL_UNIFORM_BUFFER, RasterizerCanvasGLES3::MATERIAL_UNIFORM_LOCATION, uniform_buffer);
RID *textures = texture_cache.ptrw();
ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
for (int ti = 0; ti < texture_cache.size(); ti++) {
Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
- glActiveTexture(GL_TEXTURE1 + ti);
+ glActiveTexture(GL_TEXTURE1 + ti); // Start at GL_TEXTURE1 because texture slot 0 is used by the base texture
glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
// Set sampler state here as the same texture can be used in multiple places with different flags
@@ -2981,4 +2942,543 @@ GLES3::MaterialData *GLES3::_create_canvas_material_func(ShaderData *p_shader) {
return material_data;
}
+////////////////////////////////////////////////////////////////////////////////
+// SKY SHADER
+
+void SkyShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+
+ if (code.is_empty()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompiler::GeneratedCode gen_code;
+ ShaderCompiler::IdentifierActions actions;
+ actions.entry_point_stages["sky"] = ShaderCompiler::STAGE_FRAGMENT;
+
+ uses_time = false;
+ uses_half_res = false;
+ uses_quarter_res = false;
+ uses_position = false;
+ uses_light = false;
+
+ actions.render_mode_flags["use_half_res_pass"] = &uses_half_res;
+ actions.render_mode_flags["use_quarter_res_pass"] = &uses_quarter_res;
+
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["POSITION"] = &uses_position;
+ actions.usage_flag_pointers["LIGHT0_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT0_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT1_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT2_SIZE"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_ENABLED"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_ENERGY"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_DIRECTION"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_COLOR"] = &uses_light;
+ actions.usage_flag_pointers["LIGHT3_SIZE"] = &uses_light;
+
+ actions.uniforms = &uniforms;
+
+ Error err = MaterialStorage::get_singleton()->shaders.compiler_sky.compile(RS::SHADER_SKY, code, &actions, path, gen_code);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+
+ if (version.is_null()) {
+ version = MaterialStorage::get_singleton()->shaders.sky_shader.version_create();
+ }
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ // print_line("\n**vertex_globals:\n" + gen_code.vertex_global);
+ // print_line("\n**vertex_code:\n" + gen_code.vertex);
+ print_line("\n**fragment_globals:\n" + gen_code.fragment_global);
+ print_line("\n**fragment_code:\n" + gen_code.fragment);
+ print_line("\n**light_code:\n" + gen_code.light);
+#endif
+
+ Vector<StringName> texture_uniform_names;
+ for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
+ texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
+ }
+
+ MaterialStorage::get_singleton()->shaders.sky_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+ ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.sky_shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ valid = true;
+}
+
+void SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+ if (!p_texture.is_valid()) {
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
+ } else {
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = Map<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
+ }
+}
+
+void SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
+ } else {
+ order[E.value.order] = E.key;
+ }
+ }
+
+ for (const KeyValue<int, StringName> &E : order) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
+ p_param_list->push_back(pi);
+ }
+}
+
+void SkyShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererMaterialStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool SkyShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool SkyShaderData::is_animated() const {
+ return false;
+}
+
+bool SkyShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant SkyShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode SkyShaderData::get_native_source_code() const {
+ return MaterialStorage::get_singleton()->shaders.sky_shader.version_get_native_source_code(version);
+}
+
+SkyShaderData::SkyShaderData() {
+ valid = false;
+}
+
+SkyShaderData::~SkyShaderData() {
+ if (version.is_valid()) {
+ MaterialStorage::get_singleton()->shaders.sky_shader.version_free(version);
+ }
+}
+
+GLES3::ShaderData *GLES3::_create_sky_shader_func() {
+ SkyShaderData *shader_data = memnew(SkyShaderData);
+ return shader_data;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Sky material
+
+void SkyMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
+}
+
+SkyMaterialData::~SkyMaterialData() {
+}
+GLES3::MaterialData *GLES3::_create_sky_material_func(ShaderData *p_shader) {
+ SkyMaterialData *material_data = memnew(SkyMaterialData);
+ material_data->shader_data = static_cast<SkyShaderData *>(p_shader);
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+void SkyMaterialData::bind_uniforms() {
+ // Bind Material Uniforms
+ glBindBufferBase(GL_UNIFORM_BUFFER, SKY_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
+
+ RID *textures = texture_cache.ptrw();
+ ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
+ for (int ti = 0; ti < texture_cache.size(); ti++) {
+ Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
+ glActiveTexture(GL_TEXTURE0 + ti);
+ glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+
+ // Set sampler state here as the same texture can be used in multiple places with different flags
+ // Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
+ RS::CanvasItemTextureFilter filter = RS::CanvasItemTextureFilter((int(texture_uniforms[ti].filter) + 1) % RS::CANVAS_ITEM_TEXTURE_FILTER_MAX);
+ RS::CanvasItemTextureRepeat repeat = RS::CanvasItemTextureRepeat((int(texture_uniforms[ti].repeat) + 1) % RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+ texture->gl_set_filter(filter);
+ texture->gl_set_repeat(repeat);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Scene SHADER
+
+void SceneShaderData::set_code(const String &p_code) {
+ //compile
+
+ code = p_code;
+ valid = false;
+ ubo_size = 0;
+ uniforms.clear();
+ uses_screen_texture = false;
+
+ if (code.is_empty()) {
+ return; //just invalid, but no error
+ }
+
+ ShaderCompiler::GeneratedCode gen_code;
+
+ int blend_modei = BLEND_MODE_MIX;
+ int depth_testi = DEPTH_TEST_ENABLED;
+ int alpha_antialiasing_modei = ALPHA_ANTIALIASING_OFF;
+ int cull_modei = CULL_BACK;
+ int depth_drawi = DEPTH_DRAW_OPAQUE;
+
+ uses_point_size = false;
+ uses_alpha = false;
+ uses_alpha_clip = false;
+ uses_blend_alpha = false;
+ uses_depth_pre_pass = false;
+ uses_discard = false;
+ uses_roughness = false;
+ uses_normal = false;
+ wireframe = false;
+
+ unshaded = false;
+ uses_vertex = false;
+ uses_position = false;
+ uses_sss = false;
+ uses_transmittance = false;
+ uses_screen_texture = false;
+ uses_depth_texture = false;
+ uses_normal_texture = false;
+ uses_time = false;
+ writes_modelview_or_projection = false;
+ uses_world_coordinates = false;
+ uses_particle_trails = false;
+
+ ShaderCompiler::IdentifierActions actions;
+ actions.entry_point_stages["vertex"] = ShaderCompiler::STAGE_VERTEX;
+ actions.entry_point_stages["fragment"] = ShaderCompiler::STAGE_FRAGMENT;
+ actions.entry_point_stages["light"] = ShaderCompiler::STAGE_FRAGMENT;
+
+ actions.render_mode_values["blend_add"] = Pair<int *, int>(&blend_modei, BLEND_MODE_ADD);
+ actions.render_mode_values["blend_mix"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MIX);
+ actions.render_mode_values["blend_sub"] = Pair<int *, int>(&blend_modei, BLEND_MODE_SUB);
+ actions.render_mode_values["blend_mul"] = Pair<int *, int>(&blend_modei, BLEND_MODE_MUL);
+
+ actions.render_mode_values["alpha_to_coverage"] = Pair<int *, int>(&alpha_antialiasing_modei, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE);
+ actions.render_mode_values["alpha_to_coverage_and_one"] = Pair<int *, int>(&alpha_antialiasing_modei, ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE);
+
+ actions.render_mode_values["depth_draw_never"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_DISABLED);
+ actions.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_OPAQUE);
+ actions.render_mode_values["depth_draw_always"] = Pair<int *, int>(&depth_drawi, DEPTH_DRAW_ALWAYS);
+
+ actions.render_mode_values["depth_test_disabled"] = Pair<int *, int>(&depth_testi, DEPTH_TEST_DISABLED);
+
+ actions.render_mode_values["cull_disabled"] = Pair<int *, int>(&cull_modei, CULL_DISABLED);
+ actions.render_mode_values["cull_front"] = Pair<int *, int>(&cull_modei, CULL_FRONT);
+ actions.render_mode_values["cull_back"] = Pair<int *, int>(&cull_modei, CULL_BACK);
+
+ actions.render_mode_flags["unshaded"] = &unshaded;
+ actions.render_mode_flags["wireframe"] = &wireframe;
+ actions.render_mode_flags["particle_trails"] = &uses_particle_trails;
+
+ actions.usage_flag_pointers["ALPHA"] = &uses_alpha;
+ actions.usage_flag_pointers["ALPHA_SCISSOR_THRESHOLD"] = &uses_alpha_clip;
+ actions.render_mode_flags["depth_prepass_alpha"] = &uses_depth_pre_pass;
+
+ actions.usage_flag_pointers["SSS_STRENGTH"] = &uses_sss;
+ actions.usage_flag_pointers["SSS_TRANSMITTANCE_DEPTH"] = &uses_transmittance;
+
+ actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
+ actions.usage_flag_pointers["DEPTH_TEXTURE"] = &uses_depth_texture;
+ actions.usage_flag_pointers["NORMAL_TEXTURE"] = &uses_normal_texture;
+ actions.usage_flag_pointers["DISCARD"] = &uses_discard;
+ actions.usage_flag_pointers["TIME"] = &uses_time;
+ actions.usage_flag_pointers["ROUGHNESS"] = &uses_roughness;
+ actions.usage_flag_pointers["NORMAL"] = &uses_normal;
+ actions.usage_flag_pointers["NORMAL_MAP"] = &uses_normal;
+
+ actions.usage_flag_pointers["POINT_SIZE"] = &uses_point_size;
+ actions.usage_flag_pointers["POINT_COORD"] = &uses_point_size;
+
+ actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection;
+ actions.write_flag_pointers["VERTEX"] = &uses_vertex;
+ actions.write_flag_pointers["POSITION"] = &uses_position;
+
+ actions.usage_flag_pointers["TANGENT"] = &uses_tangent;
+ actions.usage_flag_pointers["BINORMAL"] = &uses_tangent;
+ actions.usage_flag_pointers["COLOR"] = &uses_color;
+ actions.usage_flag_pointers["UV"] = &uses_uv;
+ actions.usage_flag_pointers["UV2"] = &uses_uv2;
+ actions.usage_flag_pointers["CUSTOM0"] = &uses_custom0;
+ actions.usage_flag_pointers["CUSTOM1"] = &uses_custom1;
+ actions.usage_flag_pointers["CUSTOM2"] = &uses_custom2;
+ actions.usage_flag_pointers["CUSTOM3"] = &uses_custom3;
+ actions.usage_flag_pointers["BONE_INDICES"] = &uses_bones;
+ actions.usage_flag_pointers["BONE_WEIGHTS"] = &uses_weights;
+
+ actions.uniforms = &uniforms;
+
+ Error err = MaterialStorage::get_singleton()->shaders.compiler_scene.compile(RS::SHADER_SPATIAL, code, &actions, path, gen_code);
+ ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
+
+ if (version.is_null()) {
+ version = MaterialStorage::get_singleton()->shaders.scene_shader.version_create();
+ }
+
+ depth_draw = DepthDraw(depth_drawi);
+ depth_test = DepthTest(depth_testi);
+ cull_mode = Cull(cull_modei);
+ blend_mode = BlendMode(blend_modei);
+ alpha_antialiasing_mode = AlphaAntiAliasing(alpha_antialiasing_modei);
+ vertex_input_mask = uint32_t(uses_normal);
+ vertex_input_mask |= uses_tangent << 1;
+ vertex_input_mask |= uses_color << 2;
+ vertex_input_mask |= uses_uv << 3;
+ vertex_input_mask |= uses_uv2 << 4;
+ vertex_input_mask |= uses_custom0 << 5;
+ vertex_input_mask |= uses_custom1 << 6;
+ vertex_input_mask |= uses_custom2 << 7;
+ vertex_input_mask |= uses_custom3 << 8;
+ vertex_input_mask |= uses_bones << 9;
+ vertex_input_mask |= uses_weights << 10;
+
+#if 0
+ print_line("**compiling shader:");
+ print_line("**defines:\n");
+ for (int i = 0; i < gen_code.defines.size(); i++) {
+ print_line(gen_code.defines[i]);
+ }
+
+ Map<String, String>::Element *el = gen_code.code.front();
+ while (el) {
+ print_line("\n**code " + el->key() + ":\n" + el->value());
+
+ el = el->next();
+ }
+
+ print_line("\n**uniforms:\n" + gen_code.uniforms);
+ print_line("\n**vertex_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX]);
+ print_line("\n**fragment_globals:\n" + gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT]);
+#endif
+
+ Vector<StringName> texture_uniform_names;
+ for (int i = 0; i < gen_code.texture_uniforms.size(); i++) {
+ texture_uniform_names.push_back(gen_code.texture_uniforms[i].name);
+ }
+
+ MaterialStorage::get_singleton()->shaders.scene_shader.version_set_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompiler::STAGE_VERTEX], gen_code.stage_globals[ShaderCompiler::STAGE_FRAGMENT], gen_code.defines, texture_uniform_names);
+ ERR_FAIL_COND(!MaterialStorage::get_singleton()->shaders.scene_shader.version_is_valid(version));
+
+ ubo_size = gen_code.uniform_total_size;
+ ubo_offsets = gen_code.uniform_offsets;
+ texture_uniforms = gen_code.texture_uniforms;
+
+ // if any form of Alpha Antialiasing is enabled, set the blend mode to alpha to coverage
+ if (alpha_antialiasing_mode != ALPHA_ANTIALIASING_OFF) {
+ blend_mode = BLEND_MODE_ALPHA_TO_COVERAGE;
+ }
+
+ valid = true;
+}
+
+void SceneShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) {
+ if (!p_texture.is_valid()) {
+ if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) {
+ default_texture_params[p_name].erase(p_index);
+
+ if (default_texture_params[p_name].is_empty()) {
+ default_texture_params.erase(p_name);
+ }
+ }
+ } else {
+ if (!default_texture_params.has(p_name)) {
+ default_texture_params[p_name] = Map<int, RID>();
+ }
+ default_texture_params[p_name][p_index] = p_texture;
+ }
+}
+
+void SceneShaderData::get_param_list(List<PropertyInfo> *p_param_list) const {
+ Map<int, StringName> order;
+
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) {
+ continue;
+ }
+
+ if (E.value.texture_order >= 0) {
+ order[E.value.texture_order + 100000] = E.key;
+ } else {
+ order[E.value.order] = E.key;
+ }
+ }
+
+ for (const KeyValue<int, StringName> &E : order) {
+ PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]);
+ pi.name = E.value;
+ p_param_list->push_back(pi);
+ }
+}
+
+void SceneShaderData::get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const {
+ for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) {
+ if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) {
+ continue;
+ }
+
+ RendererMaterialStorage::InstanceShaderParam p;
+ p.info = ShaderLanguage::uniform_to_property_info(E.value);
+ p.info.name = E.key; //supply name
+ p.index = E.value.instance_index;
+ p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint);
+ p_param_list->push_back(p);
+ }
+}
+
+bool SceneShaderData::is_param_texture(const StringName &p_param) const {
+ if (!uniforms.has(p_param)) {
+ return false;
+ }
+
+ return uniforms[p_param].texture_order >= 0;
+}
+
+bool SceneShaderData::is_animated() const {
+ return false;
+}
+
+bool SceneShaderData::casts_shadows() const {
+ return false;
+}
+
+Variant SceneShaderData::get_default_parameter(const StringName &p_parameter) const {
+ if (uniforms.has(p_parameter)) {
+ ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter];
+ Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value;
+ return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint);
+ }
+ return Variant();
+}
+
+RS::ShaderNativeSourceCode SceneShaderData::get_native_source_code() const {
+ return MaterialStorage::get_singleton()->shaders.scene_shader.version_get_native_source_code(version);
+}
+
+SceneShaderData::SceneShaderData() {
+ valid = false;
+ uses_screen_texture = false;
+}
+
+SceneShaderData::~SceneShaderData() {
+ if (version.is_valid()) {
+ MaterialStorage::get_singleton()->shaders.scene_shader.version_free(version);
+ }
+}
+
+GLES3::ShaderData *GLES3::_create_scene_shader_func() {
+ SceneShaderData *shader_data = memnew(SceneShaderData);
+ return shader_data;
+}
+
+void SceneMaterialData::set_render_priority(int p_priority) {
+ priority = p_priority - RS::MATERIAL_RENDER_PRIORITY_MIN; //8 bits
+}
+
+void SceneMaterialData::set_next_pass(RID p_pass) {
+ next_pass = p_pass;
+}
+
+void SceneMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) {
+ return update_parameters_internal(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size);
+}
+
+SceneMaterialData::~SceneMaterialData() {
+}
+
+GLES3::MaterialData *GLES3::_create_scene_material_func(ShaderData *p_shader) {
+ SceneMaterialData *material_data = memnew(SceneMaterialData);
+ material_data->shader_data = static_cast<SceneShaderData *>(p_shader);
+ //update will happen later anyway so do nothing.
+ return material_data;
+}
+
+void SceneMaterialData::bind_uniforms() {
+ // Bind Material Uniforms
+ glBindBufferBase(GL_UNIFORM_BUFFER, SCENE_MATERIAL_UNIFORM_LOCATION, uniform_buffer);
+
+ RID *textures = texture_cache.ptrw();
+ ShaderCompiler::GeneratedCode::Texture *texture_uniforms = shader_data->texture_uniforms.ptrw();
+ for (int ti = 0; ti < texture_cache.size(); ti++) {
+ Texture *texture = TextureStorage::get_singleton()->get_texture(textures[ti]);
+ glActiveTexture(GL_TEXTURE0 + ti);
+ glBindTexture(target_from_type[texture_uniforms[ti].type], texture->tex_id);
+
+ // Set sampler state here as the same texture can be used in multiple places with different flags
+ // Need to convert sampler state from ShaderLanguage::Texture* to RS::CanvasItemTexture*
+ RS::CanvasItemTextureFilter filter = RS::CanvasItemTextureFilter((int(texture_uniforms[ti].filter) + 1) % RS::CANVAS_ITEM_TEXTURE_FILTER_MAX);
+ RS::CanvasItemTextureRepeat repeat = RS::CanvasItemTextureRepeat((int(texture_uniforms[ti].repeat) + 1) % RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+ texture->gl_set_filter(filter);
+ texture->gl_set_repeat(repeat);
+ }
+}
+
#endif // !GLES3_ENABLED
diff --git a/drivers/gles3/storage/material_storage.h b/drivers/gles3/storage/material_storage.h
index cc6cbdc152..aa36dda4e6 100644
--- a/drivers/gles3/storage/material_storage.h
+++ b/drivers/gles3/storage/material_storage.h
@@ -45,15 +45,17 @@
#include "drivers/gles3/shaders/copy.glsl.gen.h"
#include "../shaders/canvas.glsl.gen.h"
+#include "../shaders/scene.glsl.gen.h"
#include "../shaders/sky.glsl.gen.h"
namespace GLES3 {
-/* SHADER Structs */
+/* Shader Structs */
struct Shaders {
CanvasShaderGLES3 canvas_shader;
SkyShaderGLES3 sky_shader;
+ SceneShaderGLES3 scene_shader;
ShaderCompiler compiler_canvas;
ShaderCompiler compiler_scene;
@@ -141,7 +143,7 @@ struct Material {
update_element(this) {}
};
-// CanvasItem Materials
+/* CanvasItem Materials */
struct CanvasShaderData : public ShaderData {
enum BlendMode { //used internally
@@ -200,6 +202,179 @@ struct CanvasMaterialData : public MaterialData {
MaterialData *_create_canvas_material_func(ShaderData *p_shader);
+/* Sky Materials */
+
+struct SkyShaderData : public ShaderData {
+ bool valid;
+ RID version;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String path;
+ String code;
+ Map<StringName, Map<int, RID>> default_texture_params;
+
+ bool uses_time;
+ bool uses_position;
+ bool uses_half_res;
+ bool uses_quarter_res;
+ bool uses_light;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+ SkyShaderData();
+ virtual ~SkyShaderData();
+};
+
+ShaderData *_create_sky_shader_func();
+
+struct SkyMaterialData : public MaterialData {
+ SkyShaderData *shader_data = nullptr;
+
+ virtual void set_render_priority(int p_priority) {}
+ virtual void set_next_pass(RID p_pass) {}
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual void bind_uniforms();
+ virtual ~SkyMaterialData();
+};
+
+MaterialData *_create_sky_material_func(ShaderData *p_shader);
+
+/* Scene Materials */
+
+struct SceneShaderData : public ShaderData {
+ enum BlendMode { //used internally
+ BLEND_MODE_MIX,
+ BLEND_MODE_ADD,
+ BLEND_MODE_SUB,
+ BLEND_MODE_MUL,
+ BLEND_MODE_ALPHA_TO_COVERAGE
+ };
+
+ enum DepthDraw {
+ DEPTH_DRAW_DISABLED,
+ DEPTH_DRAW_OPAQUE,
+ DEPTH_DRAW_ALWAYS
+ };
+
+ enum DepthTest {
+ DEPTH_TEST_DISABLED,
+ DEPTH_TEST_ENABLED
+ };
+
+ enum Cull {
+ CULL_DISABLED,
+ CULL_FRONT,
+ CULL_BACK
+ };
+
+ enum AlphaAntiAliasing {
+ ALPHA_ANTIALIASING_OFF,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE,
+ ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE
+ };
+
+ bool valid;
+ RID version;
+
+ String path;
+
+ Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms;
+ Vector<ShaderCompiler::GeneratedCode::Texture> texture_uniforms;
+
+ Vector<uint32_t> ubo_offsets;
+ uint32_t ubo_size;
+
+ String code;
+ Map<StringName, Map<int, RID>> default_texture_params;
+
+ BlendMode blend_mode;
+ AlphaAntiAliasing alpha_antialiasing_mode;
+ DepthDraw depth_draw;
+ DepthTest depth_test;
+ Cull cull_mode;
+
+ bool uses_point_size;
+ bool uses_alpha;
+ bool uses_blend_alpha;
+ bool uses_alpha_clip;
+ bool uses_depth_pre_pass;
+ bool uses_discard;
+ bool uses_roughness;
+ bool uses_normal;
+ bool uses_particle_trails;
+ bool wireframe;
+
+ bool unshaded;
+ bool uses_vertex;
+ bool uses_position;
+ bool uses_sss;
+ bool uses_transmittance;
+ bool uses_screen_texture;
+ bool uses_depth_texture;
+ bool uses_normal_texture;
+ bool uses_time;
+ bool writes_modelview_or_projection;
+ bool uses_world_coordinates;
+ bool uses_tangent;
+ bool uses_color;
+ bool uses_uv;
+ bool uses_uv2;
+ bool uses_custom0;
+ bool uses_custom1;
+ bool uses_custom2;
+ bool uses_custom3;
+ bool uses_bones;
+ bool uses_weights;
+
+ uint32_t vertex_input_mask = 0;
+
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+
+ virtual void set_code(const String &p_Code);
+ virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index);
+ virtual void get_param_list(List<PropertyInfo> *p_param_list) const;
+ virtual void get_instance_param_list(List<RendererMaterialStorage::InstanceShaderParam> *p_param_list) const;
+
+ virtual bool is_param_texture(const StringName &p_param) const;
+ virtual bool is_animated() const;
+ virtual bool casts_shadows() const;
+ virtual Variant get_default_parameter(const StringName &p_parameter) const;
+ virtual RS::ShaderNativeSourceCode get_native_source_code() const;
+
+ SceneShaderData();
+ virtual ~SceneShaderData();
+};
+
+ShaderData *_create_scene_shader_func();
+
+struct SceneMaterialData : public MaterialData {
+ SceneShaderData *shader_data = nullptr;
+ uint64_t last_pass = 0;
+ uint32_t index = 0;
+ RID next_pass;
+ uint8_t priority = 0;
+ virtual void set_render_priority(int p_priority);
+ virtual void set_next_pass(RID p_pass);
+ virtual void update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty);
+ virtual void bind_uniforms();
+ virtual ~SceneMaterialData();
+};
+
+MaterialData *_create_scene_material_func(ShaderData *p_shader);
+
/* Global variable structs */
struct GlobalVariables {
enum {
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index 41b5107b6c..a2b9cb6a62 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -194,6 +194,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
glBindBuffer(GL_ARRAY_BUFFER, s->attribute_buffer);
glBufferData(GL_ARRAY_BUFFER, p_surface.attribute_data.size(), p_surface.attribute_data.ptr(), (s->format & RS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
+ s->attribute_buffer_size = p_surface.attribute_data.size();
}
if (p_surface.skin_data.size()) {
glGenBuffers(1, &s->skin_buffer);
@@ -216,6 +217,7 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
glBufferData(GL_ELEMENT_ARRAY_BUFFER, p_surface.index_data.size(), p_surface.index_data.ptr(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind
s->index_count = p_surface.index_count;
+ s->index_buffer_size = p_surface.index_data.size();
if (p_surface.lods.size()) {
s->lods = memnew_arr(Mesh::Surface::LOD, p_surface.lods.size());
@@ -323,7 +325,97 @@ RID MeshStorage::mesh_surface_get_material(RID p_mesh, int p_surface) const {
}
RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
- return RS::SurfaceData();
+ Mesh *mesh = mesh_owner.get_or_null(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RS::SurfaceData());
+ ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData());
+
+ Mesh::Surface &s = *mesh->surfaces[p_surface];
+
+ RS::SurfaceData sd;
+ sd.format = s.format;
+ {
+ Vector<uint8_t> ret;
+ ret.resize(s.vertex_buffer_size);
+ glBindBuffer(GL_ARRAY_BUFFER, s.vertex_buffer);
+
+#if defined(__EMSCRIPTEN__)
+ {
+ uint8_t *w = ret.ptrw();
+ glGetBufferSubData(GL_ARRAY_BUFFER, 0, s.vertex_buffer_size, w);
+ }
+#else
+ void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, s.vertex_buffer_size, GL_MAP_READ_BIT);
+ ERR_FAIL_NULL_V(data, RS::SurfaceData());
+ {
+ uint8_t *w = ret.ptrw();
+ memcpy(w, data, s.vertex_buffer_size);
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+#endif
+ sd.vertex_data = ret;
+ }
+
+ if (s.attribute_buffer != 0) {
+ Vector<uint8_t> ret;
+ ret.resize(s.attribute_buffer_size);
+ glBindBuffer(GL_ARRAY_BUFFER, s.attribute_buffer);
+
+#if defined(__EMSCRIPTEN__)
+ {
+ uint8_t *w = ret.ptrw();
+ glGetBufferSubData(GL_ARRAY_BUFFER, 0, s.attribute_buffer_size, w);
+ }
+#else
+ void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, s.attribute_buffer_size, GL_MAP_READ_BIT);
+ ERR_FAIL_NULL_V(data, RS::SurfaceData());
+ {
+ uint8_t *w = ret.ptrw();
+ memcpy(w, data, s.attribute_buffer_size);
+ }
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+#endif
+ sd.attribute_data = ret;
+ }
+
+ sd.vertex_count = s.vertex_count;
+ sd.index_count = s.index_count;
+ sd.primitive = s.primitive;
+
+ if (sd.index_count) {
+ Vector<uint8_t> ret;
+ ret.resize(s.index_buffer_size);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s.index_buffer);
+
+#if defined(__EMSCRIPTEN__)
+ {
+ uint8_t *w = ret.ptrw();
+ glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, s.index_buffer_size, w);
+ }
+#else
+ void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, s.index_buffer_size, GL_MAP_READ_BIT);
+ ERR_FAIL_NULL_V(data, RS::SurfaceData());
+ {
+ uint8_t *w = ret.ptrw();
+ memcpy(w, data, s.index_buffer_size);
+ }
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+#endif
+ sd.index_data = ret;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ sd.aabb = s.aabb;
+ for (uint32_t i = 0; i < s.lod_count; i++) {
+ RS::SurfaceData::LOD lod;
+ lod.edge_length = s.lods[i].edge_length;
+ //lod.index_data = RD::get_singleton()->buffer_get_data(s.lods[i].index_buffer);
+ sd.lods.push_back(lod);
+ }
+
+ sd.bone_aabbs = s.bone_aabbs;
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ return sd;
}
int MeshStorage::mesh_get_surface_count(RID p_mesh) const {
@@ -496,7 +588,6 @@ void MeshStorage::mesh_clear(RID p_mesh) {
if (s.index_buffer != 0) {
glDeleteBuffers(1, &s.index_buffer);
- glDeleteVertexArrays(1, &s.index_array);
}
memdelete(mesh->surfaces[i]);
}
@@ -553,14 +644,14 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
case RS::ARRAY_NORMAL: {
attribs[i].offset = vertex_stride;
// Will need to change to accommodate octahedral compression
- attribs[i].size = 1;
+ attribs[i].size = 4;
attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV;
vertex_stride += sizeof(float);
attribs[i].normalized = GL_TRUE;
} break;
case RS::ARRAY_TANGENT: {
attribs[i].offset = vertex_stride;
- attribs[i].size = 1;
+ attribs[i].size = 4;
attribs[i].type = GL_UNSIGNED_INT_2_10_10_10_REV;
vertex_stride += sizeof(float);
attribs[i].normalized = GL_TRUE;
@@ -629,14 +720,17 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
continue;
}
if (i <= RS::ARRAY_TANGENT) {
+ attribs[i].stride = vertex_stride;
if (mis) {
glBindBuffer(GL_ARRAY_BUFFER, mis->vertex_buffer);
} else {
glBindBuffer(GL_ARRAY_BUFFER, s->vertex_buffer);
}
} else if (i <= RS::ARRAY_CUSTOM3) {
+ attribs[i].stride = attributes_stride;
glBindBuffer(GL_ARRAY_BUFFER, s->attribute_buffer);
} else {
+ attribs[i].stride = skin_stride;
glBindBuffer(GL_ARRAY_BUFFER, s->skin_buffer);
}
@@ -645,7 +739,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
} else {
glVertexAttribPointer(i, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset));
}
- glEnableVertexAttribArray(attribs[i].index);
+ glEnableVertexAttribArray(i);
}
// Do not bind index here as we want to switch between index buffers for LOD
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index f51ec6edbe..dfb9046e7b 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -54,7 +54,6 @@ struct Mesh {
struct Attrib {
bool enabled;
bool integer;
- GLuint index;
GLint size;
GLenum type;
GLboolean normalized;
@@ -69,6 +68,7 @@ struct Mesh {
GLuint skin_buffer = 0;
uint32_t vertex_count = 0;
uint32_t vertex_buffer_size = 0;
+ uint32_t attribute_buffer_size = 0;
uint32_t skin_buffer_size = 0;
// Cache vertex arrays so they can be created
@@ -84,8 +84,8 @@ struct Mesh {
uint32_t version_count = 0;
GLuint index_buffer = 0;
- GLuint index_array = 0;
uint32_t index_count = 0;
+ uint32_t index_buffer_size = 0;
struct LOD {
float edge_length = 0.0;
@@ -357,6 +357,12 @@ public:
}
}
+ _FORCE_INLINE_ GLenum mesh_surface_get_index_type(void *p_surface) const {
+ Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
+
+ return s->vertex_count <= 65536 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT;
+ }
+
// Use this to cache Vertex Array Objects so they are only generated once
_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, GLuint &r_vertex_array_gl) {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
@@ -388,6 +394,9 @@ public:
/* MESH INSTANCE API */
+ MeshInstance *get_mesh_instance(RID p_rid) { return mesh_instance_owner.get_or_null(p_rid); };
+ bool owns_mesh_instance(RID p_rid) { return mesh_instance_owner.owns(p_rid); };
+
virtual RID mesh_instance_create(RID p_base) override;
virtual void mesh_instance_free(RID p_rid) override;
virtual void mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) override;
@@ -431,6 +440,9 @@ public:
/* MULTIMESH API */
+ MultiMesh *get_multimesh(RID p_rid) { return multimesh_owner.get_or_null(p_rid); };
+ bool owns_multimesh(RID p_rid) { return multimesh_owner.owns(p_rid); };
+
virtual RID multimesh_allocate() override;
virtual void multimesh_initialize(RID p_rid) override;
virtual void multimesh_free(RID p_rid) override;
@@ -483,6 +495,9 @@ public:
/* SKELETON API */
+ Skeleton *get_skeleton(RID p_rid) { return skeleton_owner.get_or_null(p_rid); };
+ bool owns_skeleton(RID p_rid) { return skeleton_owner.owns(p_rid); };
+
virtual RID skeleton_allocate() override;
virtual void skeleton_initialize(RID p_rid) override;
virtual void skeleton_free(RID p_rid) override;
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 6f2dc391d8..4396ca4f93 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -62,8 +62,9 @@ TextureStorage::TextureStorage() {
Ref<Image> image;
image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(1, 1, 1, 1));
+ image->generate_mipmaps();
default_gl_textures[DEFAULT_GL_TEXTURE_WHITE] = texture_allocate();
texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_WHITE], image);
@@ -92,8 +93,9 @@ TextureStorage::TextureStorage() {
{ // black
Ref<Image> image;
image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(0, 0, 0, 1));
+ image->generate_mipmaps();
default_gl_textures[DEFAULT_GL_TEXTURE_BLACK] = texture_allocate();
texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_BLACK], image);
@@ -117,8 +119,9 @@ TextureStorage::TextureStorage() {
{
Ref<Image> image;
image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(0.5, 0.5, 1, 1));
+ image->generate_mipmaps();
default_gl_textures[DEFAULT_GL_TEXTURE_NORMAL] = texture_allocate();
texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_NORMAL], image);
@@ -127,8 +130,9 @@ TextureStorage::TextureStorage() {
{
Ref<Image> image;
image.instantiate();
- image->create(4, 4, false, Image::FORMAT_RGBA8);
+ image->create(4, 4, true, Image::FORMAT_RGBA8);
image->fill(Color(1.0, 0.5, 1, 1));
+ image->generate_mipmaps();
default_gl_textures[DEFAULT_GL_TEXTURE_ANISO] = texture_allocate();
texture_2d_initialize(default_gl_textures[DEFAULT_GL_TEXTURE_ANISO], image);
@@ -189,18 +193,7 @@ TextureStorage::~TextureStorage() {
}
}
-void TextureStorage::set_main_thread_id(Thread::ID p_id) {
- _main_thread_id = p_id;
-}
-
-bool TextureStorage::_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;
-}
-
+//TODO, move back to storage
bool TextureStorage::can_create_resources_async() const {
return false;
}
@@ -644,10 +637,14 @@ void TextureStorage::texture_2d_initialize(RID p_texture, const Ref<Image> &p_im
Texture texture;
texture.width = p_image->get_width();
texture.height = p_image->get_height();
+ texture.alloc_width = texture.width;
+ texture.alloc_height = texture.height;
+ texture.mipmaps = p_image->get_mipmap_count();
texture.format = p_image->get_format();
texture.type = Texture::TYPE_2D;
texture.target = GL_TEXTURE_2D;
- texture.image_cache_2d = p_image; //TODO, remove this once texture_2d_get is implemented
+ _get_gl_image_and_format(Ref<Image>(), texture.format, 0, texture.real_format, texture.gl_format_cache, texture.gl_internal_format_cache, texture.gl_type_cache, texture.compressed, false);
+ //texture.total_data_size = p_image->get_image_data_size(); // verify that this returns size in bytes
texture.active = true;
glGenTextures(1, &texture.tex_id);
texture_owner.initialize_rid(p_texture, texture);
@@ -740,49 +737,66 @@ void TextureStorage::texture_3d_placeholder_initialize(RID p_texture) {
}
Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
- Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, Ref<Image>());
+ Texture *texture = texture_owner.get_or_null(p_texture);
+ ERR_FAIL_COND_V(!texture, Ref<Image>());
#ifdef TOOLS_ENABLED
- if (tex->image_cache_2d.is_valid() && !tex->is_render_target) {
- return tex->image_cache_2d;
+ if (texture->image_cache_2d.is_valid() && !texture->is_render_target) {
+ return texture->image_cache_2d;
}
#endif
- /*
-#ifdef TOOLS_ENABLED
- if (tex->image_cache_2d.is_valid()) {
- return tex->image_cache_2d;
+#ifdef GLES_OVER_GL
+ // OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
+ Vector<uint8_t> data;
+
+ int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->real_format, texture->mipmaps > 1);
+
+ data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
+ uint8_t *w = data.ptrw();
+
+ 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, texture->real_format, i);
+
+ if (texture->compressed) {
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ glGetCompressedTexImage(texture->target, i, &w[ofs]);
+
+ } else {
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &w[ofs]);
+ }
}
-#endif
- Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, 0);
+
+ data.resize(data_size);
+
ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
Ref<Image> image;
- image.instance();
- image->create(tex->width, tex->height, tex->mipmaps > 1, tex->validated_format, data);
- ERR_FAIL_COND_V(image->empty(), Ref<Image>());
- if (tex->format != tex->validated_format) {
- image->convert(tex->format);
+ image.instantiate();
+ image->create(texture->width, texture->height, texture->mipmaps > 1, texture->real_format, data);
+ ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
+ if (texture->format != texture->real_format) {
+ image->convert(texture->format);
}
+#else
+ // Support for Web and Mobile will come later.
+ Ref<Image> image;
+#endif
#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- tex->image_cache_2d = image;
+ if (Engine::get_singleton()->is_editor_hint() && !texture->is_render_target) {
+ texture->image_cache_2d = image;
}
#endif
-*/
-
- /*
- #ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint() && !tex->is_render_target) {
- tex->image_cache_2d = image;
- }
- #endif
- */
-
- // return image;
- return Ref<Image>();
+ return image;
}
void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
@@ -1357,6 +1371,9 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
}
texture->format = rt->image_format;
+ texture->real_format = rt->image_format;
+ texture->type = Texture::TYPE_2D;
+ texture->target = GL_TEXTURE_2D;
texture->gl_format_cache = rt->color_format;
texture->gl_type_cache = GL_UNSIGNED_BYTE;
texture->gl_internal_format_cache = rt->color_internal_format;
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index a841ff8f46..8281b8c596 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -141,6 +141,7 @@ struct Texture {
int alloc_width = 0;
int alloc_height = 0;
Image::Format format = Image::FORMAT_R8;
+ Image::Format real_format = Image::FORMAT_R8;
enum Type {
TYPE_2D,
@@ -370,9 +371,6 @@ private:
RID default_gl_textures[DEFAULT_GL_TEXTURE_MAX];
- Thread::ID _main_thread_id = 0;
- bool _is_main_thread();
-
/* Canvas Texture API */
RID_Owner<CanvasTexture, true> canvas_texture_owner;
@@ -440,8 +438,6 @@ public:
};
bool owns_texture(RID p_rid) { return texture_owner.owns(p_rid); };
- void set_main_thread_id(Thread::ID p_id);
-
virtual bool can_create_resources_async() const override;
RID texture_create();
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index fbb61a1614..b064f6aec7 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -125,7 +125,7 @@ bool CreateDialog::_should_hide_type(const String &p_type) const {
return true; // Do not show editor nodes.
}
- if (p_type == base_type) {
+ if (p_type == base_type && !EditorNode::get_editor_data().get_custom_types().has(p_type)) {
return true; // Root is already added.
}
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index dfd768d0d0..b24268ade7 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -123,37 +123,34 @@ void EditorHelp::_class_desc_select(const String &p_select) {
return;
}
- if (link.contains(".")) {
- emit_signal(SNAME("go_to_help"), topic + ":" + link.get_slice(".", 0) + ":" + link.get_slice(".", 1));
- } else {
- if (table->has(link)) {
- // Found in the current page
- class_desc->scroll_to_paragraph((*table)[link]);
- } else {
- if (topic == "class_enum") {
- // Try to find the enum in @GlobalScope
- const DocData::ClassDoc &cd = doc->class_list["@GlobalScope"];
-
- for (int i = 0; i < cd.constants.size(); i++) {
- if (cd.constants[i].enumeration == link) {
- // Found in @GlobalScope
- emit_signal(SNAME("go_to_help"), topic + ":@GlobalScope:" + link);
- break;
- }
- }
- } else if (topic == "class_constant") {
- // Try to find the constant in @GlobalScope
- const DocData::ClassDoc &cd = doc->class_list["@GlobalScope"];
-
- for (int i = 0; i < cd.constants.size(); i++) {
- if (cd.constants[i].name == link) {
- // Found in @GlobalScope
- emit_signal(SNAME("go_to_help"), topic + ":@GlobalScope:" + link);
- break;
- }
- }
+ // Case order is important here to correctly handle edge cases like Variant.Type in @GlobalScope.
+ if (table->has(link)) {
+ // Found in the current page.
+ class_desc->scroll_to_paragraph((*table)[link]);
+ } else if (topic == "class_enum") {
+ // Try to find the enum in @GlobalScope.
+ const DocData::ClassDoc &cd = doc->class_list["@GlobalScope"];
+
+ for (int i = 0; i < cd.constants.size(); i++) {
+ if (cd.constants[i].enumeration == link) {
+ // Found in @GlobalScope.
+ emit_signal(SNAME("go_to_help"), topic + ":@GlobalScope:" + link);
+ break;
}
}
+ } else if (topic == "class_constant") {
+ // Try to find the constant in @GlobalScope.
+ const DocData::ClassDoc &cd = doc->class_list["@GlobalScope"];
+
+ for (int i = 0; i < cd.constants.size(); i++) {
+ if (cd.constants[i].name == link) {
+ // Found in @GlobalScope.
+ emit_signal(SNAME("go_to_help"), topic + ":@GlobalScope:" + link);
+ break;
+ }
+ }
+ } else if (link.contains(".")) {
+ emit_signal(SNAME("go_to_help"), topic + ":" + link.get_slice(".", 0) + ":" + link.get_slice(".", 1));
}
} else if (p_select.begins_with("http")) {
OS::get_singleton()->shell_open(p_select);
@@ -339,7 +336,7 @@ Error EditorHelp::_goto_desc(const String &p_class, int p_vscr) {
description_line = 0;
if (p_class == edited_class) {
- return OK; //already there
+ return OK; // Already there.
}
edited_class = p_class;
@@ -885,7 +882,7 @@ void EditorHelp::_update_doc() {
data_type_names["style"] = TTR("Styles");
for (int i = 0; i < cd.theme_properties.size(); i++) {
- theme_property_line[cd.theme_properties[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
+ theme_property_line[cd.theme_properties[i].name] = class_desc->get_line_count() - 2; // Gets overridden if description.
if (theme_data_type != cd.theme_properties[i].data_type) {
theme_data_type = cd.theme_properties[i].data_type;
@@ -970,7 +967,7 @@ void EditorHelp::_update_doc() {
class_desc->push_indent(1);
for (int i = 0; i < cd.signals.size(); i++) {
- signal_line[cd.signals[i].name] = class_desc->get_line_count() - 2; //gets overridden if description
+ signal_line[cd.signals[i].name] = class_desc->get_line_count() - 2; // Gets overridden if description.
class_desc->push_font(doc_code_font); // monofont
class_desc->push_color(headline_color);
@@ -1100,7 +1097,7 @@ void EditorHelp::_update_doc() {
enumValuesContainer[enum_list[i].name] = enumStartingLine;
}
- // Add the enum constant line to the constant_line map so we can locate it as a constant
+ // Add the enum constant line to the constant_line map so we can locate it as a constant.
constant_line[enum_list[i].name] = class_desc->get_line_count() - 2;
class_desc->push_font(doc_code_font);
@@ -1417,7 +1414,7 @@ void EditorHelp::_help_callback(const String &p_topic) {
name = p_topic.get_slice(":", 2);
}
- _request_help(clss); //first go to class
+ _request_help(clss); // First go to class.
int line = 0;
@@ -1486,7 +1483,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
String bbcode = p_bbcode.dedent().replace("\t", "").replace("\r", "").strip_edges();
- // Select the correct code examples
+ // Select the correct code examples.
switch ((int)EDITOR_GET("text_editor/help/class_reference_examples")) {
case 0: // GDScript
bbcode = bbcode.replace("[gdscript]", "[codeblock]");
@@ -1531,13 +1528,13 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
break;
}
- // Remove codeblocks (they would be printed otherwise)
+ // Remove codeblocks (they would be printed otherwise).
bbcode = bbcode.replace("[codeblocks]\n", "");
bbcode = bbcode.replace("\n[/codeblocks]", "");
bbcode = bbcode.replace("[codeblocks]", "");
bbcode = bbcode.replace("[/codeblocks]", "");
- // remove extra new lines around code blocks
+ // Remove extra new lines around code blocks.
bbcode = bbcode.replace("[codeblock]\n", "[codeblock]");
bbcode = bbcode.replace("\n[/codeblock]", "[/codeblock]");
@@ -1561,7 +1558,7 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
}
if (brk_pos == bbcode.length()) {
- break; //nothing else to add
+ break; // Nothing else to add.
}
int brk_end = bbcode.find("]", brk_pos + 1);
@@ -1627,45 +1624,45 @@ static void _add_text_to_rt(const String &p_bbcode, RichTextLabel *p_rt) {
pos = brk_end + 1;
} else if (tag == "b") {
- //use bold font
+ // Use bold font.
p_rt->push_font(doc_bold_font);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "i") {
- //use italics font
+ // Use italics font.
p_rt->push_font(doc_italic_font);
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "code" || tag == "codeblock") {
- //use monospace font
+ // Use monospace font.
p_rt->push_font(doc_code_font);
p_rt->push_color(code_color);
code_tag = true;
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "kbd") {
- //use keyboard font with custom color
+ // Use keyboard font with custom color.
p_rt->push_font(doc_kbd_font);
p_rt->push_color(kbd_color);
- code_tag = true; // though not strictly a code tag, logic is similar
+ code_tag = true; // Though not strictly a code tag, logic is similar.
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "center") {
- //align to center
+ // Align to center.
p_rt->push_paragraph(HORIZONTAL_ALIGNMENT_CENTER, Control::TEXT_DIRECTION_AUTO, "");
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "br") {
- //force a line break
+ // Force a line break.
p_rt->add_newline();
pos = brk_end + 1;
} else if (tag == "u") {
- //use underline
+ // Use underline.
p_rt->push_underline();
pos = brk_end + 1;
tag_stack.push_front(tag);
} else if (tag == "s") {
- //use strikethrough
+ // Use strikethrough.
p_rt->push_strikethrough();
pos = brk_end + 1;
tag_stack.push_front(tag);
@@ -1741,7 +1738,7 @@ void EditorHelp::_wait_for_thread() {
void EditorHelp::_gen_doc_thread(void *p_udata) {
DocTools compdoc;
compdoc.load_compressed(_doc_data_compressed, _doc_data_compressed_size, _doc_data_uncompressed_size);
- doc->merge_from(compdoc); //ensure all is up to date
+ doc->merge_from(compdoc); // Ensure all is up to date.
}
static bool doc_gen_use_threads = true;
@@ -1935,7 +1932,7 @@ void EditorHelpBit::_meta_clicked(String p_select) {
String m = p_select.substr(1, p_select.length());
if (m.contains(".")) {
- _go_to_help("class_method:" + m.get_slice(".", 0) + ":" + m.get_slice(".", 0)); //must go somewhere else
+ _go_to_help("class_method:" + m.get_slice(".", 0) + ":" + m.get_slice(".", 0)); // Must go somewhere else.
}
}
}
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index efbdf91d2f..f31ad3a68d 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -623,8 +623,6 @@ void EditorNode::_notification(int p_what) {
ResourceImporterTexture::get_singleton()->update_imports();
- // if using a main thread only renderer, we need to update the resource previews
- EditorResourcePreview::get_singleton()->update();
} break;
case NOTIFICATION_ENTER_TREE: {
diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp
index 6d5b20e591..dffb378408 100644
--- a/editor/editor_resource_preview.cpp
+++ b/editor/editor_resource_preview.cpp
@@ -430,12 +430,8 @@ void EditorResourcePreview::check_for_invalidation(const String &p_path) {
}
void EditorResourcePreview::start() {
- if (OS::get_singleton()->get_render_main_thread_mode() == OS::RENDER_ANY_THREAD) {
- ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
- thread.start(_thread_func, this);
- } else {
- _mainthread_only = true;
- }
+ ERR_FAIL_COND_MSG(thread.is_started(), "Thread already started.");
+ thread.start(_thread_func, this);
}
void EditorResourcePreview::stop() {
@@ -458,18 +454,3 @@ EditorResourcePreview::EditorResourcePreview() {
EditorResourcePreview::~EditorResourcePreview() {
stop();
}
-
-void EditorResourcePreview::update() {
- if (!_mainthread_only) {
- return;
- }
-
- if (!exit.is_set()) {
- // no need to even lock the mutex if the size is zero
- // there is no problem if queue.size() is wrong, even if
- // there was a race condition.
- if (queue.size()) {
- _iterate();
- }
- }
-}
diff --git a/editor/editor_resource_preview.h b/editor/editor_resource_preview.h
index 769340c36f..4e91df8e08 100644
--- a/editor/editor_resource_preview.h
+++ b/editor/editor_resource_preview.h
@@ -81,11 +81,6 @@ class EditorResourcePreview : public Node {
SafeFlag exit;
SafeFlag exited;
- // when running from GLES, we want to run the previews
- // in the main thread using an update, rather than create
- // a separate thread
- bool _mainthread_only = false;
-
struct Item {
Ref<Texture2D> preview;
Ref<Texture2D> small_preview;
@@ -125,9 +120,6 @@ public:
void start();
void stop();
- // for single threaded mode
- void update();
-
EditorResourcePreview();
~EditorResourcePreview();
};
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index d33803213a..1c75591b34 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -77,12 +77,14 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
StaticBody3D *body = memnew(StaticBody3D);
body->add_child(cshape, true);
- Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
+ Node *owner = get_tree()->get_edited_scene_root();
ur->create_action(TTR("Create Static Trimesh Body"));
ur->add_do_method(node, "add_child", body, true);
ur->add_do_method(body, "set_owner", owner);
ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", body);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape);
ur->add_do_reference(body);
ur->add_undo_method(node, "remove_child", body);
ur->commit_action();
@@ -112,11 +114,13 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
StaticBody3D *body = memnew(StaticBody3D);
body->add_child(cshape, true);
- Node *owner = instance == get_tree()->get_edited_scene_root() ? instance : instance->get_owner();
+ Node *owner = get_tree()->get_edited_scene_root();
ur->add_do_method(instance, "add_child", body, true);
ur->add_do_method(body, "set_owner", owner);
ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", body);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape);
ur->add_do_reference(body);
ur->add_undo_method(instance, "remove_child", body);
}
@@ -141,7 +145,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
cshape->set_shape(shape);
cshape->set_transform(node->get_transform());
- Node *owner = node->get_owner();
+ Node *owner = get_tree()->get_edited_scene_root();
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
@@ -150,6 +154,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
ur->add_do_method(node->get_parent(), "add_child", cshape, true);
ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape);
ur->add_do_reference(cshape);
ur->add_undo_method(node->get_parent(), "remove_child", cshape);
ur->commit_action();
@@ -184,11 +189,12 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
cshape->set_shape(shape);
cshape->set_transform(node->get_transform());
- Node *owner = node->get_owner();
+ Node *owner = get_tree()->get_edited_scene_root();
ur->add_do_method(node->get_parent(), "add_child", cshape, true);
ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape);
ur->add_do_reference(cshape);
ur->add_undo_method(node->get_parent(), "remove_child", cshape);
@@ -217,14 +223,17 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
for (int i = 0; i < shapes.size(); i++) {
CollisionShape3D *cshape = memnew(CollisionShape3D);
+ cshape->set_name("CollisionShape3D");
+
cshape->set_shape(shapes[i]);
cshape->set_transform(node->get_transform());
- Node *owner = node->get_owner();
+ Node *owner = get_tree()->get_edited_scene_root();
ur->add_do_method(node->get_parent(), "add_child", cshape);
ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
ur->add_do_method(cshape, "set_owner", owner);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape);
ur->add_do_reference(cshape);
ur->add_undo_method(node->get_parent(), "remove_child", cshape);
}
@@ -243,13 +252,14 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
NavigationRegion3D *nmi = memnew(NavigationRegion3D);
nmi->set_navigation_mesh(nmesh);
- Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner();
+ Node *owner = get_tree()->get_edited_scene_root();
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Navigation Mesh"));
ur->add_do_method(node, "add_child", nmi, true);
ur->add_do_method(nmi, "set_owner", owner);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", nmi);
ur->add_do_reference(nmi);
ur->add_undo_method(node, "remove_child", nmi);
@@ -267,13 +277,52 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
return;
}
- Error err = mesh2->lightmap_unwrap(node->get_global_transform());
+ String path = mesh2->get_path();
+ int srpos = path.find("::");
+ if (srpos != -1) {
+ String base = path.substr(0, srpos);
+ if (ResourceLoader::get_resource_type(base) == "PackedScene") {
+ if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) {
+ err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it does not belong to the edited scene. Make it unique first."));
+ err_dialog->popup_centered();
+ return;
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it belongs to another resource which was imported from another file type. Make it unique first."));
+ err_dialog->popup_centered();
+ return;
+ }
+ }
+ } else {
+ if (FileAccess::exists(path + ".import")) {
+ err_dialog->set_text(TTR("Mesh cannot unwrap UVs because it was imported from another file type. Make it unique first."));
+ err_dialog->popup_centered();
+ return;
+ }
+ }
+
+ Ref<ArrayMesh> unwrapped_mesh = mesh2->duplicate(false);
+
+ Error err = unwrapped_mesh->lightmap_unwrap(node->get_global_transform());
if (err != OK) {
err_dialog->set_text(TTR("UV Unwrap failed, mesh may not be manifold?"));
err_dialog->popup_centered();
return;
}
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action(TTR("Unwrap UV2"));
+
+ ur->add_do_method(node, "set_mesh", unwrapped_mesh);
+ ur->add_do_reference(node);
+ ur->add_do_reference(mesh2.ptr());
+
+ ur->add_undo_method(node, "set_mesh", mesh2);
+ ur->add_undo_reference(unwrapped_mesh.ptr());
+
+ ur->commit_action();
+
} break;
case MENU_OPTION_DEBUG_UV1: {
Ref<Mesh> mesh2 = node->get_mesh();
@@ -418,10 +467,7 @@ void MeshInstance3DEditor::_create_outline_mesh() {
MeshInstance3D *mi = memnew(MeshInstance3D);
mi->set_mesh(mesho);
- Node *owner = node->get_owner();
- if (get_tree()->get_edited_scene_root() == node) {
- owner = node;
- }
+ Node *owner = get_tree()->get_edited_scene_root();
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
@@ -429,6 +475,7 @@ void MeshInstance3DEditor::_create_outline_mesh() {
ur->add_do_method(node, "add_child", mi, true);
ur->add_do_method(mi, "set_owner", owner);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", mi);
ur->add_do_reference(mi);
ur->add_undo_method(node, "remove_child", mi);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 981881fb9b..bed7739239 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -855,6 +855,21 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
emit_signal(SNAME("go_to_help"), "class_method:" + result.class_name + ":" + result.class_member);
} break;
+ case ScriptLanguage::LOOKUP_RESULT_CLASS_SIGNAL: {
+ StringName cname = result.class_name;
+
+ while (true) {
+ if (ClassDB::has_signal(cname, result.class_member)) {
+ result.class_name = cname;
+ cname = ClassDB::get_parent_class(cname);
+ } else {
+ break;
+ }
+ }
+
+ emit_signal(SNAME("go_to_help"), "class_signal:" + result.class_name + ":" + result.class_member);
+
+ } break;
case ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM: {
StringName cname = result.class_name;
StringName success;
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 1b703a097c..26a982a091 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -357,7 +357,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
void Skeleton3DEditor::create_physical_skeleton() {
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ERR_FAIL_COND(!get_tree());
- Node *owner = skeleton == get_tree()->get_edited_scene_root() ? skeleton : skeleton->get_owner();
+ Node *owner = get_tree()->get_edited_scene_root();
const int bc = skeleton->get_bone_count();
@@ -368,37 +368,47 @@ void Skeleton3DEditor::create_physical_skeleton() {
Vector<BoneInfo> bones_infos;
bones_infos.resize(bc);
- for (int bone_id = 0; bc > bone_id; ++bone_id) {
- const int parent = skeleton->get_bone_parent(bone_id);
+ if (bc > 0) {
+ ur->create_action(TTR("Create physical bones"), UndoRedo::MERGE_ALL);
+ for (int bone_id = 0; bc > bone_id; ++bone_id) {
+ const int parent = skeleton->get_bone_parent(bone_id);
- if (parent < 0) {
- bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);
-
- } else {
- const int parent_parent = skeleton->get_bone_parent(parent);
-
- bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);
-
- // Create physical bone on parent.
- if (!bones_infos[parent].physical_bone) {
- bones_infos.write[parent].physical_bone = create_physical_bone(parent, bone_id, bones_infos);
-
- ur->create_action(TTR("Create physical bones"), UndoRedo::MERGE_ALL);
- ur->add_do_method(skeleton, "add_child", bones_infos[parent].physical_bone);
- ur->add_do_reference(bones_infos[parent].physical_bone);
- ur->add_undo_method(skeleton, "remove_child", bones_infos[parent].physical_bone);
- ur->commit_action();
+ if (parent < 0) {
+ bones_infos.write[bone_id].relative_rest = skeleton->get_bone_rest(bone_id);
+ } else {
+ const int parent_parent = skeleton->get_bone_parent(parent);
+
+ bones_infos.write[bone_id].relative_rest = bones_infos[parent].relative_rest * skeleton->get_bone_rest(bone_id);
+
+ // Create physical bone on parent.
+ if (!bones_infos[parent].physical_bone) {
+ PhysicalBone3D *physical_bone = create_physical_bone(parent, bone_id, bones_infos);
+ if (physical_bone && physical_bone->get_child(0)) {
+ CollisionShape3D *collision_shape = Object::cast_to<CollisionShape3D>(physical_bone->get_child(0));
+ if (collision_shape) {
+ bones_infos.write[parent].physical_bone = physical_bone;
+
+ ur->add_do_method(skeleton, "add_child", physical_bone);
+ ur->add_do_method(physical_bone, "set_owner", owner);
+ ur->add_do_method(collision_shape, "set_owner", owner);
+ ur->add_do_property(physical_bone, "bone_name", skeleton->get_bone_name(parent));
+
+ // Create joint between parent of parent.
+ if (parent_parent != -1) {
+ ur->add_do_method(physical_bone, "set_joint_type", PhysicalBone3D::JOINT_TYPE_PIN);
+ }
- bones_infos[parent].physical_bone->set_bone_name(skeleton->get_bone_name(parent));
- bones_infos[parent].physical_bone->set_owner(owner);
- bones_infos[parent].physical_bone->get_child(0)->set_owner(owner); // set shape owner
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", physical_bone);
+ ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", collision_shape);
- // Create joint between parent of parent.
- if (-1 != parent_parent) {
- bones_infos[parent].physical_bone->set_joint_type(PhysicalBone3D::JOINT_TYPE_PIN);
+ ur->add_do_reference(physical_bone);
+ ur->add_undo_method(skeleton, "remove_child", physical_bone);
+ }
+ }
}
}
}
+ ur->commit_action();
}
}
@@ -414,6 +424,7 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
CollisionShape3D *bone_shape = memnew(CollisionShape3D);
bone_shape->set_shape(bone_shape_capsule);
+ bone_shape->set_name("CollisionShape3D");
Transform3D capsule_transform;
capsule_transform.basis = Basis(Vector3(1, 0, 0), Vector3(0, 0, 1), Vector3(0, -1, 0));
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index b0844828df..ff35e3e6f3 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -4801,7 +4801,7 @@ VisualShaderEditor::VisualShaderEditor() {
///////////////////////////////////////
preview_window = memnew(Window);
- preview_window->set_title(TTR("Generated shader code"));
+ preview_window->set_title(TTR("Generated Shader Code"));
preview_window->set_visible(preview_showed);
preview_window->connect("close_requested", callable_mp(this, &VisualShaderEditor::_preview_close_requested));
preview_window->connect("size_changed", callable_mp(this, &VisualShaderEditor::_preview_size_changed));
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index b588c01bce..4efd22aa1e 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -279,15 +279,26 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent, bool p_scroll
Array arr;
arr.push_back(num_connections);
msg_temp += TTRN("Node has one connection.", "Node has {num} connections.", num_connections).format(arr, "{num}");
- msg_temp += " ";
+ if (num_groups >= 1) {
+ msg_temp += "\n";
+ }
}
if (num_groups >= 1) {
- Array arr;
- arr.push_back(num_groups);
- msg_temp += TTRN("Node is in one group.", "Node is in {num} groups.", num_groups).format(arr, "{num}");
+ msg_temp += TTRN("Node is in this group:", "Node is in the following groups:", num_groups) + "\n";
+
+ List<GroupInfo> groups;
+ p_node->get_groups(&groups);
+ for (const GroupInfo &E : groups) {
+ if (E.persistent) {
+ msg_temp += String::utf8("• ") + String(E.name) + "\n";
+ }
+ }
}
if (num_connections >= 1 || num_groups >= 1) {
- msg_temp += "\n" + TTR("Click to show signals dock.");
+ if (num_groups < 1) {
+ msg_temp += "\n";
+ }
+ msg_temp += TTR("Click to show signals dock.");
}
Ref<Texture2D> icon_temp;
diff --git a/main/main.cpp b/main/main.cpp
index 9747f5aa11..2134e5079d 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -641,6 +641,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
bool found_project = false;
#endif
+ String default_renderer = "";
+ String renderer_hints = "";
+
packed_data = PackedData::get_singleton();
if (!packed_data) {
packed_data = memnew(PackedData);
@@ -1306,14 +1309,33 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// possibly be worth changing the default from vulkan to something lower spec,
// for the project manager, depending on how smooth the fallback is.
- GLOBAL_DEF_RST("rendering/driver/driver_name", "vulkan");
// this list is hard coded, which makes it more difficult to add new backends.
// can potentially be changed to more of a plugin system at a later date.
+
+ // Start with Vulkan, which will be the default if enabled.
+#ifdef VULKAN_ENABLED
+ renderer_hints = "vulkan";
+#endif
+
+ // And OpenGL3 next, or first if Vulkan is disabled.
+#ifdef GLES3_ENABLED
+ if (!renderer_hints.is_empty()) {
+ renderer_hints += ",";
+ }
+ renderer_hints += "opengl3";
+#endif
+ if (renderer_hints.is_empty()) {
+ ERR_PRINT("No rendering driver available.");
+ }
+
+ default_renderer = renderer_hints.get_slice(",", 0);
+ GLOBAL_DEF_RST("rendering/driver/driver_name", default_renderer);
+
ProjectSettings::get_singleton()->set_custom_property_info("rendering/driver/driver_name",
PropertyInfo(Variant::STRING,
"rendering/driver/driver_name",
- PROPERTY_HINT_ENUM, "vulkan,opengl3"));
+ PROPERTY_HINT_ENUM, renderer_hints));
// if not set on the command line
if (rendering_driver.is_empty()) {
@@ -1328,35 +1350,6 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// always convert to lower case for consistency in the code
rendering_driver = rendering_driver.to_lower();
- GLOBAL_DEF_BASIC("display/window/size/viewport_width", 1024);
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/viewport_width",
- PropertyInfo(Variant::INT, "display/window/size/viewport_width",
- PROPERTY_HINT_RANGE,
- "0,7680,1,or_greater")); // 8K resolution
-
- GLOBAL_DEF_BASIC("display/window/size/viewport_height", 600);
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/viewport_height",
- PropertyInfo(Variant::INT, "display/window/size/viewport_height",
- PROPERTY_HINT_RANGE,
- "0,4320,1,or_greater")); // 8K resolution
-
- GLOBAL_DEF_BASIC("display/window/size/resizable", true);
- GLOBAL_DEF_BASIC("display/window/size/borderless", false);
- GLOBAL_DEF_BASIC("display/window/size/fullscreen", false);
- GLOBAL_DEF("display/window/size/always_on_top", false);
- GLOBAL_DEF("display/window/size/window_width_override", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/window_width_override",
- PropertyInfo(Variant::INT,
- "display/window/size/window_width_override",
- PROPERTY_HINT_RANGE,
- "0,7680,1,or_greater")); // 8K resolution
- GLOBAL_DEF("display/window/size/window_height_override", 0);
- ProjectSettings::get_singleton()->set_custom_property_info("display/window/size/window_height_override",
- PropertyInfo(Variant::INT,
- "display/window/size/window_height_override",
- PROPERTY_HINT_RANGE,
- "0,4320,1,or_greater")); // 8K resolution
-
if (use_custom_res) {
if (!force_res) {
window_size.width = GLOBAL_GET("display/window/size/viewport_width");
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 7021f0aa1e..226b4c24b1 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -1057,6 +1057,14 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
r_result.insert(option.display, option);
}
+ List<MethodInfo> signals;
+ ClassDB::get_signal_list(type, &signals);
+ for (const MethodInfo &E : signals) {
+ int location = p_recursion_depth + _get_signal_location(type, StringName(E.name));
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
+ r_result.insert(option.display, option);
+ }
+
if (!_static || Engine::get_singleton()->has_singleton(type)) {
List<PropertyInfo> pinfo;
ClassDB::get_property_list(type, &pinfo);
@@ -3058,6 +3066,13 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
}
+ if (ClassDB::has_signal(class_name, p_symbol, true)) {
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_SIGNAL;
+ r_result.class_name = base_type.native_type;
+ r_result.class_member = p_symbol;
+ return OK;
+ }
+
StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true);
if (enum_name != StringName()) {
r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index b6bf523a67..aa1bfb312c 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -3565,6 +3565,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
for (const KeyValue<StringName, int> &E : export_type.enum_values) {
if (!first) {
enum_hint_string += ",";
+ } else {
first = false;
}
enum_hint_string += E.key.operator String().capitalize().xml_escape();
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index bac7a2e6db..02e9d98647 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -63,6 +63,7 @@ namespace GodotTools.Build
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
+ startInfo.CreateNoWindow = true;
if (UsingMonoMsBuildOnWindows)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index 93a1360cb6..2db549c623 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -184,7 +184,8 @@ namespace GodotTools.Utils
{
RedirectStandardOutput = true,
RedirectStandardError = true,
- UseShellExecute = false
+ UseShellExecute = false,
+ CreateNoWindow = true
};
using (Process process = Process.Start(startInfo))
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index c5fa126d0f..fe3a43dc97 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -2769,7 +2769,7 @@ Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_si
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- const Map<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map;
+ const HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> &kern = fd->cache[size]->kerning_map;
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
@@ -2827,7 +2827,7 @@ bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) co
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false);
}
- FontDataForSizeAdvanced *at_size = fd->cache.front()->get();
+ FontDataForSizeAdvanced *at_size = fd->cache.begin()->value;
#ifdef MODULE_FREETYPE_ENABLED
if (at_size && at_size->face) {
@@ -2845,7 +2845,7 @@ String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String());
}
- FontDataForSizeAdvanced *at_size = fd->cache.front()->get();
+ FontDataForSizeAdvanced *at_size = fd->cache.begin()->value;
String chars;
#ifdef MODULE_FREETYPE_ENABLED
@@ -4575,7 +4575,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape
Glyph *sd_glyphs = sd->glyphs.ptrw();
int sd_size = sd->glyphs.size();
- if (sd->jstops.size() > 0) {
+ if (!sd->jstops.is_empty()) {
for (int i = 0; i < sd_size; i++) {
if (sd_glyphs[i].count > 0) {
char32_t c = sd->text[sd_glyphs[i].start - sd->start];
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 1b4293aa72..c292e2e707 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -67,7 +67,6 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/templates/hash_map.hpp>
-#include <godot_cpp/templates/map.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
#include <godot_cpp/templates/set.hpp>
#include <godot_cpp/templates/thread_work_pool.hpp>
@@ -78,6 +77,7 @@ using namespace godot;
#else
// Headers for building as built-in module.
+#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "core/templates/thread_work_pool.h"
#include "scene/resources/texture.h"
@@ -133,8 +133,8 @@ class TextServerAdvanced : public TextServerExtension {
};
Vector<NumSystemData> num_systems;
- Map<StringName, int32_t> feature_sets;
- Map<int32_t, StringName> feature_sets_inv;
+ HashMap<StringName, int32_t> feature_sets;
+ HashMap<int32_t, StringName> feature_sets_inv;
void _insert_num_systems_lang();
void _insert_feature_sets();
@@ -191,7 +191,7 @@ class TextServerAdvanced : public TextServerExtension {
Vector<FontTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
- Map<Vector2i, Vector2> kerning_map;
+ HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> kerning_map;
hb_font_t *hb_handle = nullptr;
@@ -233,7 +233,7 @@ class TextServerAdvanced : public TextServerExtension {
String font_name;
String style_name;
- Map<Vector2i, FontDataForSizeAdvanced *> cache;
+ HashMap<Vector2i, FontDataForSizeAdvanced *, VariantHasher, VariantComparator> cache;
bool face_init = false;
Set<uint32_t> supported_scripts;
@@ -242,8 +242,8 @@ class TextServerAdvanced : public TextServerExtension {
Dictionary feature_overrides;
// Language/script support override.
- Map<String, bool> language_support_overrides;
- Map<String, bool> script_support_overrides;
+ HashMap<String, bool> language_support_overrides;
+ HashMap<String, bool> script_support_overrides;
PackedByteArray data;
const uint8_t *data_ptr;
@@ -334,7 +334,7 @@ class TextServerAdvanced : public TextServerExtension {
InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
Rect2 rect;
};
- Map<Variant, EmbeddedObject> objects;
+ HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects;
/* Shaped data */
TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 96ebe025f5..4a4b51e5d3 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -1917,7 +1917,7 @@ Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_si
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- const Map<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map;
+ const HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> &kern = fd->cache[size]->kerning_map;
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
@@ -1957,7 +1957,7 @@ bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) co
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false);
}
- FontDataForSizeFallback *at_size = fd->cache.front()->get();
+ FontDataForSizeFallback *at_size = fd->cache.begin()->value;
#ifdef MODULE_FREETYPE_ENABLED
if (at_size && at_size->face) {
@@ -1975,7 +1975,7 @@ String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String());
}
- FontDataForSizeFallback *at_size = fd->cache.front()->get();
+ FontDataForSizeFallback *at_size = fd->cache.begin()->value;
String chars;
#ifdef MODULE_FREETYPE_ENABLED
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index c837029623..0d2fc2628d 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -67,7 +67,6 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/templates/hash_map.hpp>
-#include <godot_cpp/templates/map.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
#include <godot_cpp/templates/set.hpp>
#include <godot_cpp/templates/thread_work_pool.hpp>
@@ -80,6 +79,7 @@ using namespace godot;
#include "servers/text/text_server_extension.h"
+#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "core/templates/thread_work_pool.h"
#include "scene/resources/texture.h"
@@ -106,8 +106,8 @@ class TextServerFallback : public TextServerExtension {
GDCLASS(TextServerFallback, TextServerExtension);
_THREAD_SAFE_CLASS_
- Map<StringName, int32_t> feature_sets;
- Map<int32_t, StringName> feature_sets_inv;
+ HashMap<StringName, int32_t> feature_sets;
+ HashMap<int32_t, StringName> feature_sets_inv;
void _insert_feature_sets();
_FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag);
@@ -159,7 +159,7 @@ class TextServerFallback : public TextServerExtension {
Vector<FontTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
- Map<Vector2i, Vector2> kerning_map;
+ HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> kerning_map;
#ifdef MODULE_FREETYPE_ENABLED
FT_Face face = nullptr;
@@ -196,15 +196,15 @@ class TextServerFallback : public TextServerExtension {
String font_name;
String style_name;
- Map<Vector2i, FontDataForSizeFallback *> cache;
+ HashMap<Vector2i, FontDataForSizeFallback *, VariantHasher, VariantComparator> cache;
bool face_init = false;
Dictionary supported_varaitions;
Dictionary feature_overrides;
// Language/script support override.
- Map<String, bool> language_support_overrides;
- Map<String, bool> script_support_overrides;
+ HashMap<String, bool> language_support_overrides;
+ HashMap<String, bool> script_support_overrides;
PackedByteArray data;
const uint8_t *data_ptr;
@@ -294,7 +294,7 @@ class TextServerFallback : public TextServerExtension {
InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
Rect2 rect;
};
- Map<Variant, EmbeddedObject> objects;
+ HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects;
/* Shaped data */
TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 3319d5890c..0099ac7e0d 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -188,8 +188,11 @@ def configure(env):
if env["target"].startswith("release"):
if env["optimize"] == "speed": # optimize for speed (default)
- env.Append(LINKFLAGS=["-O2"])
- env.Append(CCFLAGS=["-O2", "-fomit-frame-pointer"])
+ # `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
+ # when using `target=release_debug`.
+ opt = "-O3" if env["target"] == "release" else "-O2"
+ env.Append(LINKFLAGS=[opt])
+ env.Append(CCFLAGS=[opt, "-fomit-frame-pointer"])
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os"])
env.Append(LINKFLAGS=["-Os"])
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index f442235e7c..392a0151be 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -47,8 +47,11 @@ def configure(env):
if env["target"].startswith("release"):
env.Append(CPPDEFINES=["NDEBUG", ("NS_BLOCK_ASSERTIONS", 1)])
if env["optimize"] == "speed": # optimize for speed (default)
- env.Append(CCFLAGS=["-O2", "-ftree-vectorize", "-fomit-frame-pointer"])
- env.Append(LINKFLAGS=["-O2"])
+ # `-O2` is more friendly to debuggers than `-O3`, leading to better crash backtraces
+ # when using `target=release_debug`.
+ opt = "-O3" if env["target"] == "release" else "-O2"
+ env.Append(CCFLAGS=[opt, "-ftree-vectorize", "-fomit-frame-pointer"])
+ env.Append(LINKFLAGS=[opt])
elif env["optimize"] == "size": # optimize for size
env.Append(CCFLAGS=["-Os", "-ftree-vectorize"])
env.Append(LINKFLAGS=["-Os"])
diff --git a/platform/linuxbsd/display_server_x11.cpp b/platform/linuxbsd/display_server_x11.cpp
index b35f0daec6..9f53b31567 100644
--- a/platform/linuxbsd/display_server_x11.cpp
+++ b/platform/linuxbsd/display_server_x11.cpp
@@ -4112,13 +4112,13 @@ void DisplayServerX11::process_events() {
void DisplayServerX11::release_rendering_thread() {
#if defined(GLES3_ENABLED)
-// gl_manager->release_current();
+ gl_manager->release_current();
#endif
}
void DisplayServerX11::make_rendering_thread() {
#if defined(GLES3_ENABLED)
-// gl_manager->make_current();
+ gl_manager->make_current();
#endif
}
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 0b18fb74fb..b82fe5e7ad 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -269,12 +269,14 @@ def configure_msvc(env, manual_msvc_config):
"dwmapi",
]
- env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
- if not env["use_volk"]:
- LIBS += ["vulkan"]
-
- env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
- LIBS += ["opengl32"]
+ if env["vulkan"]:
+ env.AppendUnique(CPPDEFINES=["VULKAN_ENABLED"])
+ if not env["use_volk"]:
+ LIBS += ["vulkan"]
+
+ if env["opengl3"]:
+ env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
+ LIBS += ["opengl32"]
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 93cab85441..341eb58f9f 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -607,8 +607,11 @@ void DisplayServerWindows::show_window(WindowID p_id) {
_update_window_style(p_id);
}
- ShowWindow(wd.hWnd, (wd.no_focus || wd.is_popup) ? SW_SHOWNOACTIVATE : SW_SHOW); // Show the window.
- if (!wd.no_focus && !wd.is_popup) {
+ if (wd.no_focus || wd.is_popup) {
+ // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-showwindow
+ ShowWindow(wd.hWnd, SW_SHOWNA);
+ } else {
+ ShowWindow(wd.hWnd, SW_SHOW);
SetForegroundWindow(wd.hWnd); // Slightly higher priority.
SetFocus(wd.hWnd); // Set keyboard focus.
}
@@ -1798,7 +1801,9 @@ void DisplayServerWindows::make_rendering_thread() {
void DisplayServerWindows::swap_buffers() {
#if defined(GLES3_ENABLED)
- gl_manager->swap_buffers();
+ if (gl_manager) {
+ gl_manager->swap_buffers();
+ }
#endif
}
@@ -1952,14 +1957,18 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ if (context_vulkan) {
+ context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
+ }
#endif
}
DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(VULKAN_ENABLED)
- return context_vulkan->get_vsync_mode(p_window);
+ if (context_vulkan) {
+ return context_vulkan->get_vsync_mode(p_window);
+ }
#endif
return DisplayServer::VSYNC_ENABLED;
}
@@ -2193,8 +2202,39 @@ LRESULT DisplayServerWindows::MouseProc(int code, WPARAM wParam, LPARAM lParam)
return ::CallNextHookEx(mouse_monitor, code, wParam, lParam);
}
-// Our default window procedure to handle processing of window-related system messages/events.
-// Also known as DefProc or DefWindowProc.
+// Handle a single window message received while CreateWindowEx is still on the stack and our data
+// structures are not fully initialized.
+LRESULT DisplayServerWindows::_handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
+ switch (uMsg) {
+ case WM_GETMINMAXINFO: {
+ // We receive this during CreateWindowEx and we haven't initialized the window
+ // struct, so let Windows figure out the maximized size.
+ // Silently forward to user/default.
+ } break;
+ case WM_NCCREATE: {
+ // We tunnel an unowned pointer to our window context (WindowData) through the
+ // first possible message (WM_NCCREATE) to fix up our window context collection.
+ CREATESTRUCTW *pCreate = (CREATESTRUCTW *)lParam;
+ WindowData *pWindowData = reinterpret_cast<WindowData *>(pCreate->lpCreateParams);
+
+ // Fix this up so we can recognize the remaining messages.
+ pWindowData->hWnd = hWnd;
+ } break;
+ default: {
+ // Additional messages during window creation should happen after we fixed
+ // up the data structures on WM_NCCREATE, but this might change in the future,
+ // so report an error here and then we can implement them.
+ ERR_PRINT_ONCE(vformat("Unexpected window message 0x%x received for window we cannot recognize in our collection; sequence error.", uMsg));
+ } break;
+ }
+
+ if (user_proc) {
+ return CallWindowProcW(user_proc, hWnd, uMsg, wParam, lParam);
+ }
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+
+// The window procedure for our window class "Engine", used to handle processing of window-related system messages/events.
// See: https://docs.microsoft.com/en-us/windows/win32/winmsg/window-procedures
LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
if (drop_events) {
@@ -2208,7 +2248,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
WindowID window_id = INVALID_WINDOW_ID;
bool window_created = false;
- // Check whether window exists.
+ // Check whether window exists
+ // FIXME this is O(n), where n is the set of currently open windows and subwindows
+ // we should have a secondary map from HWND to WindowID or even WindowData* alias, if we want to eliminate all the map lookups below
for (const KeyValue<WindowID, WindowData> &E : windows) {
if (E.value.hWnd == hWnd) {
window_id = E.key;
@@ -2217,10 +2259,12 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
- // Window doesn't exist or creation in progress, don't handle messages yet.
+ // WARNING: we get called with events before the window is registered in our collection
+ // specifically, even the call to CreateWindowEx already calls here while still on the stack,
+ // so there is no way to store the window handle in our collection before we get here
if (!window_created) {
- window_id = window_id_counter;
- ERR_FAIL_COND_V(!windows.has(window_id), 0);
+ // don't let code below operate on incompletely initialized window objects or missing window_id
+ return _handle_early_window_message(hWnd, uMsg, wParam, lParam);
}
// Process window messages.
@@ -3388,11 +3432,17 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
WindowRect.top,
WindowRect.right - WindowRect.left,
WindowRect.bottom - WindowRect.top,
- nullptr, nullptr, hInstance, nullptr);
+ nullptr,
+ nullptr,
+ hInstance,
+ // tunnel the WindowData we need to handle creation message
+ // lifetime is ensured because we are still on the stack when this is
+ // processed in the window proc
+ reinterpret_cast<void *>(&wd));
if (!wd.hWnd) {
MessageBoxW(nullptr, L"Window Creation Error.", L"ERROR", MB_OK | MB_ICONEXCLAMATION);
windows.erase(id);
- return INVALID_WINDOW_ID;
+ ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create Windows OS window.");
}
if (p_mode != WINDOW_MODE_FULLSCREEN && p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN) {
wd.pre_fs_valid = true;
@@ -3412,7 +3462,14 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
#ifdef GLES3_ENABLED
if (gl_manager) {
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.");
+
+ // shut down OpenGL, to mirror behavior of Vulkan code
+ if (err != OK) {
+ memdelete(gl_manager);
+ gl_manager = nullptr;
+ windows.erase(id);
+ ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
+ }
}
#endif
@@ -3457,6 +3514,8 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
ImmReleaseContext(wd.hWnd, wd.im_himc);
wd.im_position = Vector2();
+
+ // FIXME this is wrong in cases where the window coordinates were changed due to full screen mode; use WindowRect
wd.last_pos = p_rect.position;
wd.width = p_rect.size.width;
wd.height = p_rect.size.height;
@@ -3747,6 +3806,7 @@ DisplayServerWindows::~DisplayServerWindows() {
#ifdef GLES3_ENABLED
// destroy windows .. NYI?
+ // FIXME wglDeleteContext is never called
#endif
if (windows.has(MAIN_WINDOW_ID)) {
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index febc8a2043..e8e207401e 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -448,6 +448,8 @@ class DisplayServerWindows : public DisplayServer {
static void _dispatch_input_events(const Ref<InputEvent> &p_event);
void _dispatch_input_event(const Ref<InputEvent> &p_event);
+ LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
+
public:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows.cpp
index a97fa99d7f..d509ff8c51 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows.cpp
@@ -54,6 +54,18 @@
typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
+static String format_error_message(DWORD id) {
+ LPWSTR messageBuffer = nullptr;
+ size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ nullptr, id, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, nullptr);
+
+ String msg = "Error " + itos(id) + ": " + String::utf16((const char16_t *)messageBuffer, size);
+
+ LocalFree(messageBuffer);
+
+ return msg;
+}
+
int GLManager_Windows::_find_or_create_display(GLWindow &win) {
// find display NYI, only 1 supported so far
if (_displays.size()) {
@@ -79,7 +91,7 @@ int GLManager_Windows::_find_or_create_display(GLWindow &win) {
return new_display_id;
}
-Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
+static Error _configure_pixel_format(HDC hDC) {
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1,
@@ -101,9 +113,6 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
0, 0, 0 // Layer Masks Ignored
};
- // alias
- HDC hDC = win.hDC;
-
int pixel_format = ChoosePixelFormat(hDC, &pfd);
if (!pixel_format) // Did Windows Find A Matching Pixel Format?
{
@@ -116,13 +125,24 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
return ERR_CANT_CREATE; // Return FALSE
}
- gl_display.hRC = wglCreateContext(hDC);
+ return OK;
+}
+
+Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
+ Error err = _configure_pixel_format(win.hDC);
+ if (err != OK) {
+ return err;
+ }
+
+ gl_display.hRC = wglCreateContext(win.hDC);
if (!gl_display.hRC) // Are We Able To Get A Rendering Context?
{
return ERR_CANT_CREATE; // Return FALSE
}
- wglMakeCurrent(hDC, gl_display.hRC);
+ if (!wglMakeCurrent(win.hDC, gl_display.hRC)) {
+ ERR_PRINT("Could not attach OpenGL context to newly created window: " + format_error_message(GetLastError()));
+ }
int attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3, //we want a 3.3 context
@@ -143,57 +163,61 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
return ERR_CANT_CREATE;
}
- HGLRC new_hRC = wglCreateContextAttribsARB(hDC, 0, attribs);
+ HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, 0, attribs);
if (!new_hRC) {
wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
- return ERR_CANT_CREATE; // Return false
+ return ERR_CANT_CREATE;
}
- wglMakeCurrent(hDC, nullptr);
+
+ if (!wglMakeCurrent(win.hDC, nullptr)) {
+ ERR_PRINT("Could not detach OpenGL context from newly created window: " + format_error_message(GetLastError()));
+ }
+
wglDeleteContext(gl_display.hRC);
gl_display.hRC = new_hRC;
- if (!wglMakeCurrent(hDC, gl_display.hRC)) // Try To Activate The Rendering Context
+ if (!wglMakeCurrent(win.hDC, gl_display.hRC)) // Try To Activate The Rendering Context
{
+ ERR_PRINT("Could not attach OpenGL context to newly created window with replaced OpenGL context: " + format_error_message(GetLastError()));
wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
- return ERR_CANT_CREATE; // Return FALSE
+ return ERR_CANT_CREATE;
}
return OK;
}
Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
- HDC hdc = GetDC(p_hwnd);
- if (!hdc) {
- return ERR_CANT_CREATE; // Return FALSE
+ HDC hDC = GetDC(p_hwnd);
+ if (!hDC) {
+ return ERR_CANT_CREATE;
}
- // make sure vector is big enough...
- // we can mirror the external vector, it is simpler
- // to keep the IDs identical for fast lookup
- if (p_window_id >= (int)_windows.size()) {
- _windows.resize(p_window_id + 1);
+ // configure the HDC to use a compatible pixel format
+ Error result = _configure_pixel_format(hDC);
+ if (result != OK) {
+ return result;
}
- GLWindow &win = _windows[p_window_id];
- win.in_use = true;
- win.window_id = p_window_id;
+ GLWindow win;
win.width = p_width;
win.height = p_height;
win.hwnd = p_hwnd;
- win.hDC = hdc;
+ win.hDC = hDC;
win.gldisplay_id = _find_or_create_display(win);
if (win.gldisplay_id == -1) {
- // release DC?
- _windows.remove_at(_windows.size() - 1);
return FAILED;
}
+ // WARNING: p_window_id is an eternally growing integer since popup windows keep coming and going
+ // and each of them has a higher id than the previous, so it must be used in a map not a vector
+ _windows[p_window_id] = win;
+
// make current
- window_make_current(_windows.size() - 1);
+ window_make_current(p_window_id);
return OK;
}
@@ -217,11 +241,10 @@ int GLManager_Windows::window_get_height(DisplayServer::WindowID p_window_id) {
void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
GLWindow &win = get_window(p_window_id);
- win.in_use = false;
-
if (_current_window == &win) {
_current_window = nullptr;
}
+ _windows.erase(p_window_id);
}
void GLManager_Windows::release_current() {
@@ -229,7 +252,9 @@ void GLManager_Windows::release_current() {
return;
}
- wglMakeCurrent(_current_window->hDC, nullptr);
+ if (!wglMakeCurrent(_current_window->hDC, nullptr)) {
+ ERR_PRINT("Could not detach OpenGL context from window marked current: " + format_error_message(GetLastError()));
+ }
}
void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
@@ -237,10 +262,8 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
return;
}
+ // crash if our data structures are out of sync, i.e. not found
GLWindow &win = _windows[p_window_id];
- if (!win.in_use) {
- return;
- }
// noop
if (&win == _current_window) {
@@ -248,7 +271,9 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
}
const GLDisplay &disp = get_display(win.gldisplay_id);
- wglMakeCurrent(win.hDC, disp.hRC);
+ if (!wglMakeCurrent(win.hDC, disp.hRC)) {
+ ERR_PRINT("Could not switch OpenGL context to other window: " + format_error_message(GetLastError()));
+ }
_internal_set_current_window(&win);
}
@@ -257,34 +282,19 @@ void GLManager_Windows::make_current() {
if (!_current_window) {
return;
}
- if (!_current_window->in_use) {
- WARN_PRINT("current window not in use!");
- return;
- }
const GLDisplay &disp = get_current_display();
- wglMakeCurrent(_current_window->hDC, disp.hRC);
+ if (!wglMakeCurrent(_current_window->hDC, disp.hRC)) {
+ ERR_PRINT("Could not switch OpenGL context to window marked current: " + format_error_message(GetLastError()));
+ }
}
void GLManager_Windows::swap_buffers() {
- // NO NEED TO CALL SWAP BUFFERS for each window...
- // see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glXSwapBuffers.xml
-
- if (!_current_window) {
- return;
+ // on other platforms, OpenGL swaps buffers for all windows (on all displays, really?)
+ // Windows swaps buffers on a per-window basis
+ // REVISIT: this could be structurally bad, should we have "dirty" flags then?
+ for (KeyValue<DisplayServer::WindowID, GLWindow> &entry : _windows) {
+ SwapBuffers(entry.value.hDC);
}
- if (!_current_window->in_use) {
- WARN_PRINT("current window not in use!");
- return;
- }
-
- // print_line("\tswap_buffers");
-
- // only for debugging without drawing anything
- // glClearColor(Math::randf(), 0, 1, 1);
- //glClear(GL_COLOR_BUFFER_BIT);
-
- // const GLDisplay &disp = get_current_display();
- SwapBuffers(_current_window->hDC);
}
Error GLManager_Windows::initialize() {
diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows.h
index dc411983e8..0d544a5715 100644
--- a/platform/windows/gl_manager_windows.h
+++ b/platform/windows/gl_manager_windows.h
@@ -52,10 +52,6 @@ public:
private:
// any data specific to the window
struct GLWindow {
- bool in_use = false;
-
- // the external ID .. should match the GL window number .. unused I think
- DisplayServer::WindowID window_id = DisplayServer::INVALID_WINDOW_ID;
int width = 0;
int height = 0;
@@ -71,7 +67,7 @@ private:
HGLRC hRC;
};
- LocalVector<GLWindow> _windows;
+ Map<DisplayServer::WindowID, GLWindow> _windows;
LocalVector<GLDisplay> _displays;
GLWindow *_current_window = nullptr;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index 68e188bbed..55483cfc83 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -129,9 +129,34 @@ void OS_Windows::initialize_debugging() {
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
}
+#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
+static void _error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) {
+ String err_str;
+ if (p_errorexp && p_errorexp[0]) {
+ err_str = String::utf8(p_errorexp);
+ } else {
+ err_str = String::utf8(p_file) + ":" + itos(p_line) + " - " + String::utf8(p_error);
+ }
+
+ if (p_editor_notify) {
+ err_str += " (User)\n";
+ } else {
+ err_str += "\n";
+ }
+
+ OutputDebugStringW((LPCWSTR)err_str.utf16().ptr());
+}
+#endif
+
void OS_Windows::initialize() {
crash_handler.initialize();
+#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
+ error_handlers.errfunc = _error_handler;
+ error_handlers.userdata = this;
+ add_error_handler(&error_handlers);
+#endif
+
#ifndef WINDOWS_SUBSYSTEM_CONSOLE
RedirectIOToConsole();
#endif
@@ -194,6 +219,10 @@ void OS_Windows::finalize_core() {
memdelete(process_map);
NetSocketPosix::cleanup();
+
+#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
+ remove_error_handler(&error_handlers);
+#endif
}
Error OS_Windows::get_entropy(uint8_t *r_buffer, int p_bytes) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 378438a075..d06d30f958 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -57,6 +57,11 @@
#include <windows.h>
#include <windowsx.h>
+#ifdef DEBUG_ENABLED
+// forward error messages to OutputDebugString
+#define WINDOWS_DEBUG_OUTPUT_ENABLED
+#endif
+
class JoypadWindows;
class OS_Windows : public OS {
#ifdef STDOUT_FILE
@@ -81,6 +86,10 @@ class OS_Windows : public OS {
CrashHandler crash_handler;
+#ifdef WINDOWS_DEBUG_OUTPUT_ENABLED
+ ErrorHandlerList error_handlers;
+#endif
+
bool force_quit;
HWND main_window;
diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/vulkan_context_win.cpp
index 07c41395fb..e62c6c1dc8 100644
--- a/platform/windows/vulkan_context_win.cpp
+++ b/platform/windows/vulkan_context_win.cpp
@@ -28,6 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#if defined(WINDOWS_ENABLED) && defined(VULKAN_ENABLED)
+
#include "vulkan_context_win.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -57,3 +59,5 @@ VulkanContextWindows::VulkanContextWindows() {
VulkanContextWindows::~VulkanContextWindows() {
}
+
+#endif
diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp
index bedf0edf38..4552ed9537 100644
--- a/scene/3d/gpu_particles_collision_3d.cpp
+++ b/scene/3d/gpu_particles_collision_3d.cpp
@@ -640,18 +640,13 @@ void GPUParticlesCollisionHeightField3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_update_mode", "update_mode"), &GPUParticlesCollisionHeightField3D::set_update_mode);
ClassDB::bind_method(D_METHOD("get_update_mode"), &GPUParticlesCollisionHeightField3D::get_update_mode);
- ClassDB::bind_method(D_METHOD("set_follow_camera_mode", "enabled"), &GPUParticlesCollisionHeightField3D::set_follow_camera_mode);
- ClassDB::bind_method(D_METHOD("is_follow_camera_mode_enabled"), &GPUParticlesCollisionHeightField3D::is_follow_camera_mode_enabled);
-
- ClassDB::bind_method(D_METHOD("set_follow_camera_push_ratio", "ratio"), &GPUParticlesCollisionHeightField3D::set_follow_camera_push_ratio);
- ClassDB::bind_method(D_METHOD("get_follow_camera_push_ratio"), &GPUParticlesCollisionHeightField3D::get_follow_camera_push_ratio);
+ ClassDB::bind_method(D_METHOD("set_follow_camera_enabled", "enabled"), &GPUParticlesCollisionHeightField3D::set_follow_camera_enabled);
+ ClassDB::bind_method(D_METHOD("is_follow_camera_enabled"), &GPUParticlesCollisionHeightField3D::is_follow_camera_enabled);
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents", PROPERTY_HINT_RANGE, "0.01,1024,0.01,or_greater"), "set_extents", "get_extents");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096,8192"), "set_resolution", "get_resolution");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "WhenMoved,Always"), "set_update_mode", "get_update_mode");
- ADD_GROUP("Follow Camera", "follow_camera_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_camera_enabled"), "set_follow_camera_mode", "is_follow_camera_mode_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "follow_camera_push_ratio", PROPERTY_HINT_RANGE, "0.01,1,0.01"), "set_follow_camera_push_ratio", "get_follow_camera_push_ratio");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "resolution", PROPERTY_HINT_ENUM, "256 (Fastest),512 (Fast),1024 (Average),2048 (Slow),4096 (Slower),8192 (Slowest)"), "set_resolution", "get_resolution");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "When Moved (Fast),Always (Slow)"), "set_update_mode", "get_update_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_camera_enabled"), "set_follow_camera_enabled", "is_follow_camera_enabled");
BIND_ENUM_CONSTANT(RESOLUTION_256);
BIND_ENUM_CONSTANT(RESOLUTION_512);
@@ -665,14 +660,6 @@ void GPUParticlesCollisionHeightField3D::_bind_methods() {
BIND_ENUM_CONSTANT(UPDATE_MODE_ALWAYS);
}
-void GPUParticlesCollisionHeightField3D::set_follow_camera_push_ratio(float p_follow_camera_push_ratio) {
- follow_camera_push_ratio = p_follow_camera_push_ratio;
-}
-
-float GPUParticlesCollisionHeightField3D::get_follow_camera_push_ratio() const {
- return follow_camera_push_ratio;
-}
-
void GPUParticlesCollisionHeightField3D::set_extents(const Vector3 &p_extents) {
extents = p_extents;
RS::get_singleton()->particles_collision_set_box_extents(_get_collision(), extents);
@@ -704,12 +691,12 @@ GPUParticlesCollisionHeightField3D::UpdateMode GPUParticlesCollisionHeightField3
return update_mode;
}
-void GPUParticlesCollisionHeightField3D::set_follow_camera_mode(bool p_enabled) {
+void GPUParticlesCollisionHeightField3D::set_follow_camera_enabled(bool p_enabled) {
follow_camera_mode = p_enabled;
set_process_internal(follow_camera_mode || update_mode == UPDATE_MODE_ALWAYS);
}
-bool GPUParticlesCollisionHeightField3D::is_follow_camera_mode_enabled() const {
+bool GPUParticlesCollisionHeightField3D::is_follow_camera_enabled() const {
return follow_camera_mode;
}
diff --git a/scene/3d/gpu_particles_collision_3d.h b/scene/3d/gpu_particles_collision_3d.h
index fdd2fa4b18..4b2cb930fa 100644
--- a/scene/3d/gpu_particles_collision_3d.h
+++ b/scene/3d/gpu_particles_collision_3d.h
@@ -211,7 +211,6 @@ private:
Vector3 extents = Vector3(1, 1, 1);
Resolution resolution = RESOLUTION_1024;
bool follow_camera_mode = false;
- float follow_camera_push_ratio = 0.1;
UpdateMode update_mode = UPDATE_MODE_WHEN_MOVED;
@@ -229,11 +228,8 @@ public:
void set_update_mode(UpdateMode p_update_mode);
UpdateMode get_update_mode() const;
- void set_follow_camera_mode(bool p_enabled);
- bool is_follow_camera_mode_enabled() const;
-
- void set_follow_camera_push_ratio(float p_ratio);
- float get_follow_camera_push_ratio() const;
+ void set_follow_camera_enabled(bool p_enabled);
+ bool is_follow_camera_enabled() const;
virtual AABB get_aabb() const override;
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index c4fce7ccb8..b2aa4030b7 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -357,6 +357,11 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
Ref<InputEventKey> k = p_gui_input;
+ if (TextEdit::alt_input(p_gui_input)) {
+ accept_event();
+ return;
+ }
+
bool update_code_completion = false;
if (!k.is_valid()) {
TextEdit::gui_input(p_gui_input);
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index e5b58a7cc8..73188d6602 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -406,9 +406,45 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
if (k.is_valid()) {
if (!k->is_pressed()) {
+ if (alt_start && k->get_keycode() == Key::ALT) {
+ alt_start = false;
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ char32_t ucodestr[2] = { (char32_t)alt_code, 0 };
+ insert_text_at_caret(ucodestr);
+ }
+ accept_event();
+ return;
+ }
return;
}
+ // Alt+ Unicode input:
+ if (k->is_alt_pressed()) {
+ if (!alt_start) {
+ if (k->get_keycode() == Key::KP_ADD) {
+ alt_start = true;
+ alt_code = 0;
+ accept_event();
+ return;
+ }
+ } else {
+ if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
+ }
+ if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
+ }
+ if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
+ }
+ accept_event();
+ return;
+ }
+ }
+
if (context_menu_enabled) {
if (k->is_action("ui_menu", true)) {
_ensure_menu();
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 50aa2f4460..0fb178fca4 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -77,6 +77,9 @@ private:
bool pass = false;
bool text_changed_dirty = false;
+ bool alt_start = false;
+ uint32_t alt_code = 0;
+
String undo_text;
String text;
String placeholder;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index d7a07454de..315ffbd419 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1557,6 +1557,47 @@ void TextEdit::unhandled_key_input(const Ref<InputEvent> &p_event) {
}
}
+bool TextEdit::alt_input(const Ref<InputEvent> &p_gui_input) {
+ Ref<InputEventKey> k = p_gui_input;
+ if (k.is_valid()) {
+ if (!k->is_pressed()) {
+ if (alt_start && k->get_keycode() == Key::ALT) {
+ alt_start = false;
+ if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) {
+ handle_unicode_input(alt_code);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ if (k->is_alt_pressed()) {
+ if (!alt_start) {
+ if (k->get_keycode() == Key::KP_ADD) {
+ alt_start = true;
+ alt_code = 0;
+ return true;
+ }
+ } else {
+ if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0);
+ }
+ if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::KP_0);
+ }
+ if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) {
+ alt_code = alt_code << 4;
+ alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
ERR_FAIL_COND(p_gui_input.is_null());
@@ -1865,6 +1906,10 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
Ref<InputEventKey> k = p_gui_input;
if (k.is_valid()) {
+ if (alt_input(p_gui_input)) {
+ accept_event();
+ return;
+ }
if (!k->is_pressed()) {
return;
}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index a0ae9631f9..194cad72d1 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -247,6 +247,9 @@ private:
bool setting_text = false;
+ bool alt_start = false;
+ uint32_t alt_code = 0;
+
// Text properties.
String ime_text = "";
Point2 ime_selection;
@@ -625,6 +628,7 @@ public:
/* General overrides. */
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
+ bool alt_input(const Ref<InputEvent> &p_gui_input);
virtual Size2 get_minimum_size() const override;
virtual bool is_text_field() const override;
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 6485c1ac77..c719455a0a 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -681,7 +681,8 @@ void Curve2D::_bake() const {
List<Vector2> pointlist;
List<real_t> distlist;
- pointlist.push_back(position); //start always from origin
+ // Start always from origin.
+ pointlist.push_back(position);
distlist.push_back(0.0);
for (int i = 0; i < points.size() - 1; i++) {
@@ -728,15 +729,18 @@ void Curve2D::_bake() const {
p = np;
}
}
- }
- Vector2 lastpos = points[points.size() - 1].position;
+ Vector2 npp = points[i + 1].position;
+ real_t d = position.distance_to(npp);
+
+ position = npp;
+ dist += d;
+
+ pointlist.push_back(position);
+ distlist.push_back(dist);
+ }
- real_t rem = position.distance_to(lastpos);
- dist += rem;
baked_max_ofs = dist;
- pointlist.push_back(lastpos);
- distlist.push_back(dist);
baked_point_cache.resize(pointlist.size());
baked_dist_cache.resize(distlist.size());
@@ -763,7 +767,7 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, Vector2(), "No points in Curve2D.");
@@ -771,18 +775,19 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
return baked_point_cache.get(0);
}
- int bpc = baked_point_cache.size();
const Vector2 *r = baked_point_cache.ptr();
if (p_offset < 0) {
return r[0];
}
if (p_offset >= baked_max_ofs) {
- return r[bpc - 1];
+ return r[pc - 1];
}
- int start = 0, end = bpc, idx = (end + start) / 2;
- // binary search to find baked points
+ int start = 0;
+ int end = pc;
+ int idx = (end + start) / 2;
+ // Binary search to find baked points.
while (start < idx) {
real_t offset = baked_dist_cache[idx];
if (p_offset <= offset) {
@@ -803,7 +808,7 @@ Vector2 Curve2D::interpolate_baked(real_t p_offset, bool p_cubic) const {
if (p_cubic) {
Vector2 pre = idx > 0 ? r[idx - 1] : r[idx];
- Vector2 post = (idx < (bpc - 2)) ? r[idx + 2] : r[idx + 1];
+ Vector2 post = (idx < (pc - 2)) ? r[idx + 2] : r[idx + 1];
return r[idx].cubic_interpolate(r[idx + 1], pre, post, frac);
} else {
return r[idx].lerp(r[idx + 1], frac);
@@ -829,13 +834,13 @@ real_t Curve2D::get_bake_interval() const {
}
Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const {
- // Brute force method
+ // Brute force method.
if (baked_cache_dirty) {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, Vector2(), "No points in Curve2D.");
@@ -867,13 +872,13 @@ Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const {
}
real_t Curve2D::get_closest_offset(const Vector2 &p_to_point) const {
- // Brute force method
+ // Brute force method.
if (baked_cache_dirty) {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, 0.0f, "No points in Curve2D.");
@@ -1009,11 +1014,7 @@ void Curve2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
-Curve2D::Curve2D() {
- /* add_point(Vector2(-1,0,0));
- add_point(Vector2(0,2,0));
- add_point(Vector2(0,3,5));*/
-}
+Curve2D::Curve2D() {}
/***********************************************************************************/
/***********************************************************************************/
@@ -1194,6 +1195,7 @@ void Curve3D::_bake() const {
List<Plane> pointlist;
List<real_t> distlist;
+ // Start always from origin.
pointlist.push_back(Plane(position, points[0].tilt));
distlist.push_back(0.0);
@@ -1244,16 +1246,22 @@ void Curve3D::_bake() const {
p = np;
}
}
- }
- Vector3 lastpos = points[points.size() - 1].position;
- real_t lastilt = points[points.size() - 1].tilt;
+ Vector3 npp = points[i + 1].position;
+ real_t d = position.distance_to(npp);
+
+ position = npp;
+ Plane post;
+ post.normal = position;
+ post.d = points[i + 1].tilt;
+
+ dist += d;
+
+ pointlist.push_back(post);
+ distlist.push_back(dist);
+ }
- real_t rem = position.distance_to(lastpos);
- dist += rem;
baked_max_ofs = dist;
- pointlist.push_back(Plane(lastpos, lastilt));
- distlist.push_back(dist);
baked_point_cache.resize(pointlist.size());
Vector3 *w = baked_point_cache.ptrw();
@@ -1328,7 +1336,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, Vector3(), "No points in Curve3D.");
@@ -1336,18 +1344,19 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
return baked_point_cache.get(0);
}
- int bpc = baked_point_cache.size();
const Vector3 *r = baked_point_cache.ptr();
if (p_offset < 0) {
return r[0];
}
if (p_offset >= baked_max_ofs) {
- return r[bpc - 1];
+ return r[pc - 1];
}
- int start = 0, end = bpc, idx = (end + start) / 2;
- // binary search to find baked points
+ int start = 0;
+ int end = pc;
+ int idx = (end + start) / 2;
+ // Binary search to find baked points.
while (start < idx) {
real_t offset = baked_dist_cache[idx];
if (p_offset <= offset) {
@@ -1368,7 +1377,7 @@ Vector3 Curve3D::interpolate_baked(real_t p_offset, bool p_cubic) const {
if (p_cubic) {
Vector3 pre = idx > 0 ? r[idx - 1] : r[idx];
- Vector3 post = (idx < (bpc - 2)) ? r[idx + 2] : r[idx + 1];
+ Vector3 post = (idx < (pc - 2)) ? r[idx + 2] : r[idx + 1];
return r[idx].cubic_interpolate(r[idx + 1], pre, post, frac);
} else {
return r[idx].lerp(r[idx + 1], frac);
@@ -1380,7 +1389,7 @@ real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked tilts.
int pc = baked_tilt_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, 0, "No tilts in Curve3D.");
@@ -1388,29 +1397,37 @@ real_t Curve3D::interpolate_baked_tilt(real_t p_offset) const {
return baked_tilt_cache.get(0);
}
- int bpc = baked_tilt_cache.size();
const real_t *r = baked_tilt_cache.ptr();
if (p_offset < 0) {
return r[0];
}
if (p_offset >= baked_max_ofs) {
- return r[bpc - 1];
+ return r[pc - 1];
}
- int idx = Math::floor((double)p_offset / (double)bake_interval);
- real_t frac = Math::fmod(p_offset, bake_interval);
-
- if (idx >= bpc - 1) {
- return r[bpc - 1];
- } else if (idx == bpc - 2) {
- if (frac > 0) {
- frac /= Math::fmod(baked_max_ofs, bake_interval);
+ int start = 0;
+ int end = pc;
+ int idx = (end + start) / 2;
+ // Binary search to find baked points.
+ while (start < idx) {
+ real_t offset = baked_dist_cache[idx];
+ if (p_offset <= offset) {
+ end = idx;
+ } else {
+ start = idx;
}
- } else {
- frac /= bake_interval;
+ idx = (end + start) / 2;
}
+ real_t offset_begin = baked_dist_cache[idx];
+ real_t offset_end = baked_dist_cache[idx + 1];
+
+ real_t idx_interval = offset_end - offset_begin;
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, 0, "failed to find baked segment");
+
+ real_t frac = (p_offset - offset_begin) / idx_interval;
+
return Math::lerp(r[idx], r[idx + 1], (real_t)frac);
}
@@ -1419,8 +1436,7 @@ Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt)
_bake();
}
- //validate//
- // curve may not have baked up vectors
+ // Validate: Curve may not have baked up vectors.
int count = baked_up_vector_cache.size();
ERR_FAIL_COND_V_MSG(count == 0, Vector3(0, 1, 0), "No up vectors in Curve3D.");
@@ -1432,10 +1448,27 @@ Vector3 Curve3D::interpolate_baked_up_vector(real_t p_offset, bool p_apply_tilt)
const Vector3 *rp = baked_point_cache.ptr();
const real_t *rt = baked_tilt_cache.ptr();
- real_t offset = CLAMP(p_offset, 0.0f, baked_max_ofs);
+ int start = 0;
+ int end = count;
+ int idx = (end + start) / 2;
+ // Binary search to find baked points.
+ while (start < idx) {
+ real_t offset = baked_dist_cache[idx];
+ if (p_offset <= offset) {
+ end = idx;
+ } else {
+ start = idx;
+ }
+ idx = (end + start) / 2;
+ }
+
+ real_t offset_begin = baked_dist_cache[idx];
+ real_t offset_end = baked_dist_cache[idx + 1];
- int idx = Math::floor((double)offset / (double)bake_interval);
- real_t frac = Math::fmod(offset, bake_interval) / bake_interval;
+ real_t idx_interval = offset_end - offset_begin;
+ ERR_FAIL_COND_V_MSG(p_offset < offset_begin || p_offset > offset_end, Vector3(0, 1, 0), "failed to find baked segment");
+
+ real_t frac = (p_offset - offset_begin) / idx_interval;
if (idx == count - 1) {
return p_apply_tilt ? r[idx].rotated((rp[idx] - rp[idx - 1]).normalized(), rt[idx]) : r[idx];
@@ -1486,13 +1519,13 @@ PackedVector3Array Curve3D::get_baked_up_vectors() const {
}
Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const {
- // Brute force method
+ // Brute force method.
if (baked_cache_dirty) {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, Vector3(), "No points in Curve3D.");
@@ -1524,13 +1557,13 @@ Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const {
}
real_t Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
- // Brute force method
+ // Brute force method.
if (baked_cache_dirty) {
_bake();
}
- //validate//
+ // Validate: Curve may not have baked points.
int pc = baked_point_cache.size();
ERR_FAIL_COND_V_MSG(pc == 0, 0.0f, "No points in Curve3D.");
@@ -1705,8 +1738,4 @@ void Curve3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "up_vector_enabled"), "set_up_vector_enabled", "is_up_vector_enabled");
}
-Curve3D::Curve3D() {
- /* add_point(Vector3(-1,0,0));
- add_point(Vector3(0,2,0));
- add_point(Vector3(0,3,5));*/
-}
+Curve3D::Curve3D() {}
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index d92d34437e..5d1e07f6cd 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1096,7 +1096,6 @@ void Environment::_validate_property(PropertyInfo &property) const {
static const char *high_end_prefixes[] = {
"auto_exposure_",
- "tonemap_",
"ssr_",
"ssao_",
nullptr
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index d6b2572628..d586abac14 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -33,6 +33,7 @@
#include "core/io/image_loader.h"
#include "core/io/resource_loader.h"
#include "core/string/translation.h"
+#include "core/templates/hash_map.h"
#include "core/templates/hashfuncs.h"
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
@@ -963,7 +964,7 @@ Error FontData::load_bitmap_font(const String &p_path) {
int delimiter = line.find(" ");
String type = line.substr(0, delimiter);
int pos = delimiter + 1;
- Map<String, String> keys;
+ HashMap<String, String> keys;
while (pos < line.size() && line[pos] == ' ') {
pos++;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index da9e1ef2f6..67b82af617 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -3264,16 +3264,10 @@ void TileSet::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uv_clipping"), "set_uv_clipping", "is_uv_clipping");
ADD_ARRAY("occlusion_layers", "occlusion_layer_");
- ADD_GROUP("Physics", "");
+ ADD_GROUP("", "");
ADD_ARRAY("physics_layers", "physics_layer_");
-
- ADD_GROUP("Terrains", "");
ADD_ARRAY("terrain_sets", "terrain_set_");
-
- ADD_GROUP("Navigation", "");
ADD_ARRAY("navigation_layers", "navigation_layer_");
-
- ADD_GROUP("Custom Data", "");
ADD_ARRAY("custom_data_layers", "custom_data_layer_");
// -- Enum binding --
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 755962b96c..6848011228 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -3479,89 +3479,89 @@ const VisualShaderNodeOutput::Port VisualShaderNodeOutput::ports[] = {
////////////////////////////////////////////////////////////////////////
// Node3D, Vertex.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "vertex", "VERTEX" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "tangent", "TANGENT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "binormal", "BINORMAL" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv2", "UV2" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "model_view_matrix", "MODELVIEW_MATRIX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Vertex", "VERTEX" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Tangent", "TANGENT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Binormal", "BINORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV", "UV" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV2", "UV2" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color", "COLOR" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_TRANSFORM, "Model View Matrix", "MODELVIEW_MATRIX" },
////////////////////////////////////////////////////////////////////////
// Node3D, Fragment.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "metallic", "METALLIC" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "roughness", "ROUGHNESS" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "specular", "SPECULAR" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "emission", "EMISSION" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao", "AO" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "ao_light_affect", "AO_LIGHT_AFFECT" },
-
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal_map", "NORMAL_MAP" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" },
-
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim", "RIM" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "rim_tint", "RIM_TINT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat", "CLEARCOAT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "clearcoat_roughness", "CLEARCOAT_ROUGHNESS" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "anisotropy", "ANISOTROPY" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "anisotropy_flow", "ANISOTROPY_FLOW" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "subsurf_scatter", "SSS_STRENGTH" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "backlight", "BACKLIGHT" },
-
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_scissor_threshold", "ALPHA_SCISSOR_THRESHOLD" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_hash_scale", "ALPHA_HASH_SCALE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha_aa_edge", "ALPHA_ANTIALIASING_EDGE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "alpha_uv", "ALPHA_TEXTURE_COORDINATE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Albedo", "ALBEDO" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Metallic", "METALLIC" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Roughness", "ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Specular", "SPECULAR" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Emission", "EMISSION" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "AO", "AO" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "AO Light Affect", "AO_LIGHT_AFFECT" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal Map", "NORMAL_MAP" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Normal Map Depth", "NORMAL_MAP_DEPTH" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Rim", "RIM" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Rim Tint", "RIM_TINT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Clearcoat", "CLEARCOAT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Clearcoat Roughness", "CLEARCOAT_ROUGHNESS" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Anisotropy", "ANISOTROPY" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Anisotropy Flow", "ANISOTROPY_FLOW" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Subsurf Scatter", "SSS_STRENGTH" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Backlight", "BACKLIGHT" },
+
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha Scissor Threshold", "ALPHA_SCISSOR_THRESHOLD" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha Hash Scale", "ALPHA_HASH_SCALE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha AA Edge", "ALPHA_ANTIALIASING_EDGE" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Alpha UV", "ALPHA_TEXTURE_COORDINATE" },
////////////////////////////////////////////////////////////////////////
// Node3D, Light.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "diffuse", "DIFFUSE_LIGHT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "specular", "SPECULAR_LIGHT" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Diffuse", "DIFFUSE_LIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Specular", "SPECULAR_LIGHT" },
+ { Shader::MODE_SPATIAL, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
////////////////////////////////////////////////////////////////////////
// Canvas Item.
////////////////////////////////////////////////////////////////////////
// Canvas Item, Vertex.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "uv", "UV" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "point_size", "POINT_SIZE" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Vertex", "VERTEX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_2D, "UV", "UV" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color", "COLOR" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_VERTEX, VisualShaderNode::PORT_TYPE_SCALAR, "Point Size", "POINT_SIZE" },
////////////////////////////////////////////////////////////////////////
// Canvas Item, Fragment.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "color", "COLOR" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal", "NORMAL" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "normal_map", "NORMAL_MAP" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "normal_map_depth", "NORMAL_MAP_DEPTH" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "light_vertex", "LIGHT_VERTEX" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "shadow_vertex", "SHADOW_VERTEX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Color", "COLOR" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal", "NORMAL" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Normal Map", "NORMAL_MAP" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR, "Normal Map Depth", "NORMAL_MAP_DEPTH" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Light Vertex", "LIGHT_VERTEX" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "Shadow Vertex", "SHADOW_VERTEX" },
////////////////////////////////////////////////////////////////////////
// Canvas Item, Light.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "light", "LIGHT" },
+ { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Light", "LIGHT" },
////////////////////////////////////////////////////////////////////////
// Sky, Sky.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "color", "COLOR" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "alpha", "ALPHA" },
- { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "fog", "FOG" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Color", "COLOR" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_SCALAR, "Alpha", "ALPHA" },
+ { Shader::MODE_SKY, VisualShader::TYPE_SKY, VisualShaderNode::PORT_TYPE_VECTOR_4D, "Fog", "FOG" },
////////////////////////////////////////////////////////////////////////
// Fog, Fog.
////////////////////////////////////////////////////////////////////////
- { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "density", "DENSITY" },
- { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "albedo", "ALBEDO" },
- { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "emission", "EMISSION" },
+ { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_SCALAR, "Density", "DENSITY" },
+ { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Albedo", "ALBEDO" },
+ { Shader::MODE_FOG, VisualShader::TYPE_FOG, VisualShaderNode::PORT_TYPE_VECTOR_3D, "Emission", "EMISSION" },
////////////////////////////////////////////////////////////////////////
{ Shader::MODE_MAX, VisualShader::TYPE_MAX, VisualShaderNode::PORT_TYPE_TRANSFORM, nullptr, nullptr },
@@ -3605,7 +3605,7 @@ String VisualShaderNodeOutput::get_input_port_name(int p_port) const {
while (ports[idx].mode != Shader::MODE_MAX) {
if (ports[idx].mode == shader_mode && ports[idx].shader_type == shader_type) {
if (count == p_port) {
- return String(ports[idx].name).capitalize();
+ return String(ports[idx].name);
}
count++;
}
@@ -3638,7 +3638,7 @@ bool VisualShaderNodeOutput::is_port_separator(int p_index) const {
}
if (shader_mode == Shader::MODE_SPATIAL && shader_type == VisualShader::TYPE_FRAGMENT) {
String name = get_input_port_name(p_index);
- return bool(name == "Ao" || name == "Normal" || name == "Rim" || name == "Clearcoat" || name == "Anisotropy" || name == "Subsurf Scatter" || name == "Alpha Scissor Threshold");
+ return bool(name == "AO" || name == "Normal" || name == "Rim" || name == "Clearcoat" || name == "Anisotropy" || name == "Subsurf Scatter" || name == "Alpha Scissor Threshold");
}
return false;
}
diff --git a/servers/rendering/dummy/rasterizer_dummy.h b/servers/rendering/dummy/rasterizer_dummy.h
index 6cad45ea6d..5c6fcc8386 100644
--- a/servers/rendering/dummy/rasterizer_dummy.h
+++ b/servers/rendering/dummy/rasterizer_dummy.h
@@ -95,9 +95,9 @@ public:
static void make_current() {
_create_func = _create_current;
+ low_end = true;
}
- bool is_low_end() const override { return true; }
uint64_t get_frame_number() const override { return frame; }
double get_frame_delta_time() const override { return delta; }
diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp
index fa4d9c8b31..b331ec2c1d 100644
--- a/servers/rendering/renderer_compositor.cpp
+++ b/servers/rendering/renderer_compositor.cpp
@@ -35,6 +35,7 @@
#include "core/string/print_string.h"
RendererCompositor *(*RendererCompositor::_create_func)() = nullptr;
+bool RendererCompositor::low_end = false;
RendererCompositor *RendererCompositor::create() {
return _create_func();
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 9466148a31..df3df1077a 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -71,6 +71,7 @@ private:
protected:
static RendererCompositor *(*_create_func)();
bool back_end = false;
+ static bool low_end;
public:
static RendererCompositor *create();
@@ -97,7 +98,7 @@ public:
virtual uint64_t get_frame_number() const = 0;
virtual double get_frame_delta_time() const = 0;
- _FORCE_INLINE_ virtual bool is_low_end() const { return back_end; };
+ static bool is_low_end() { return low_end; };
virtual bool is_xr_enabled() const;
RendererCompositor();
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index fabedc80c1..6b786fdf16 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -306,8 +306,6 @@ void CopyEffects::copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID
}
void CopyEffects::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) {
- ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the copy_to_atlas_fb shader with the mobile renderer.");
-
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -343,8 +341,6 @@ void CopyEffects::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuff
}
void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview) {
- ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the copy_to_fb_rect shader with the mobile renderer.");
-
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 26bd28286b..1fd6550fb8 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -131,6 +131,7 @@ public:
static void make_current() {
_create_func = _create_current;
+ low_end = false;
}
static RendererCompositorRD *singleton;
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 9f780013bd..21b1b45802 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -2593,7 +2593,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
}
if (can_use_effects && can_use_storage && (rb->internal_width != rb->width || rb->internal_height != rb->height)) {
- RD::get_singleton()->draw_command_begin_label("FSR Upscale");
+ RD::get_singleton()->draw_command_begin_label("FSR 1.0 Upscale");
storage->get_effects()->fsr_upscale(rb->internal_texture, rb->upscale_texture, rb->texture, Size2i(rb->internal_width, rb->internal_height), Size2i(rb->width, rb->height), rb->fsr_sharpness);
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 6e1fa59a7a..d85f314c5c 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -609,13 +609,16 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
if (p_base.is_valid()) {
instance->base_type = RSG::storage->get_base_type(p_base);
+ // fix up a specific malfunctioning case before the switch, so it can be handled
if (instance->base_type == RS::INSTANCE_NONE && RendererSceneOcclusionCull::get_singleton()->is_occluder(p_base)) {
instance->base_type = RS::INSTANCE_OCCLUDER;
}
- ERR_FAIL_COND(instance->base_type == RS::INSTANCE_NONE);
-
switch (instance->base_type) {
+ case RS::INSTANCE_NONE: {
+ ERR_PRINT_ONCE("unimplemented base type encountered in renderer scene cull");
+ return;
+ }
case RS::INSTANCE_LIGHT: {
InstanceLightData *light = memnew(InstanceLightData);
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index c8345d8eef..c4538e0776 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -321,11 +321,7 @@ void RenderingServerDefault::set_debug_generate_wireframes(bool p_generate) {
}
bool RenderingServerDefault::is_low_end() const {
- // FIXME: Commented out when rebasing vulkan branch on master,
- // causes a crash, it seems rasterizer is not initialized yet the
- // first time it's called.
- //return RSG::rasterizer->is_low_end();
- return false;
+ return RendererCompositor::is_low_end();
}
void RenderingServerDefault::_thread_exit() {
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index daf2f86a4c..9d4059b9df 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -113,7 +113,9 @@ public:
_changes_changed();
#else
- _FORCE_INLINE_ static void redraw_request() { changes++; }
+ _FORCE_INLINE_ static void redraw_request() {
+ changes++;
+ }
#endif
#define WRITE_ACTION redraw_request();
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 812d636a0b..5669cb2054 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -48,8 +48,8 @@ static String _mktab(int p_level) {
static String _typestr(SL::DataType p_type) {
String type = ShaderLanguage::get_datatype_name(p_type);
- if (ShaderLanguage::is_sampler_type(p_type)) {
- type = type.replace("sampler", "texture"); //we use textures instead of samplers
+ if (!RS::get_singleton()->is_low_end() && ShaderLanguage::is_sampler_type(p_type)) {
+ type = type.replace("sampler", "texture"); //we use textures instead of samplers in Vulkan GLSL
}
return type;
}
@@ -538,7 +538,11 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
continue; // Instances are indexed directly, don't need index uniforms.
}
if (SL::is_sampler_type(uniform.type)) {
- ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") uniform ";
+ // Texture layouts are different for OpenGL GLSL and Vulkan GLSL
+ if (!RS::get_singleton()->is_low_end()) {
+ ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") ";
+ }
+ ucode += "uniform ";
}
bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL;
@@ -681,9 +685,13 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
vcode += ";\n";
-
- r_gen_code.stage_globals[STAGE_VERTEX] += "layout(location=" + itos(index) + ") " + interp_mode + "out " + vcode;
- r_gen_code.stage_globals[STAGE_FRAGMENT] += "layout(location=" + itos(index) + ") " + interp_mode + "in " + vcode;
+ // GLSL ES 3.0 does not allow layout qualifiers for varyings
+ if (!RS::get_singleton()->is_low_end()) {
+ r_gen_code.stage_globals[STAGE_VERTEX] += "layout(location=" + itos(index) + ") ";
+ r_gen_code.stage_globals[STAGE_FRAGMENT] += "layout(location=" + itos(index) + ") ";
+ }
+ r_gen_code.stage_globals[STAGE_VERTEX] += interp_mode + "out " + vcode;
+ r_gen_code.stage_globals[STAGE_FRAGMENT] += interp_mode + "in " + vcode;
index += inc;
}
@@ -1125,8 +1133,8 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
code += ", ";
}
String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
- if (is_texture_func && i == 1) {
- //need to map from texture to sampler in order to sample
+ if (!RS::get_singleton()->is_low_end() && is_texture_func && i == 1) {
+ //need to map from texture to sampler in order to sample when using Vulkan GLSL
StringName texture_uniform;
bool correct_texture_uniform = false;
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 136664e333..fc40f058aa 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2885,6 +2885,7 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/shading/overrides/force_lambert_over_burley.mobile", true);
GLOBAL_DEF("rendering/driver/depth_prepass/enable", true);
+ GLOBAL_DEF("rendering/driver/depth_prepass/disable_for_vendors", "PowerVR,Mali,Adreno,Apple");
GLOBAL_DEF_RST("rendering/textures/default_filters/use_nearest_mipmap_filter", false);
GLOBAL_DEF_RST("rendering/textures/default_filters/anisotropic_filtering_level", 2);
@@ -2933,7 +2934,7 @@ RenderingServer::RenderingServer() {
ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/mode",
PropertyInfo(Variant::INT,
"rendering/scaling_3d/mode",
- PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR (Fast)"));
+ PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast)"));
ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/scale",
PropertyInfo(Variant::FLOAT,
@@ -3002,44 +3003,15 @@ RenderingServer::RenderingServer() {
GLOBAL_DEF("rendering/limits/cluster_builder/max_clustered_elements", 512);
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_BASIC("xr/shaders/enabled", false);
+ // OpenGL limits
+ GLOBAL_DEF_RST("rendering/limits/opengl/max_renderable_elements", 65536);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/opengl/max_renderable_elements", PropertyInfo(Variant::INT, "rendering/limits/opengl/max_renderable_elements", PROPERTY_HINT_RANGE, "1024,65536,1"));
+ GLOBAL_DEF_RST("rendering/limits/opengl/max_renderable_lights", 256);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/opengl/max_renderable_lights", PropertyInfo(Variant::INT, "rendering/limits/opengl/max_renderable_lights", PROPERTY_HINT_RANGE, "16,4096,1"));
+ GLOBAL_DEF_RST("rendering/limits/opengl/max_lights_per_object", 8);
+ ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/opengl/max_lights_per_object", PropertyInfo(Variant::INT, "rendering/limits/opengl/max_lights_per_object", PROPERTY_HINT_RANGE, "2,1024,1"));
- 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"));
+ GLOBAL_DEF_RST_BASIC("xr/shaders/enabled", false);
}
RenderingServer::~RenderingServer() {
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 41cd0230cc..bb30105c56 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -115,7 +115,7 @@ will limit its functionality to IPv4 only.
## etcpak
- Upstream: https://github.com/wolfpld/etcpak
-- Version: git (7c3cb6fe708d4ae330b0ab2af1ad472bae2a37a2, 2021)
+- Version: git (f128369e64a5f4715de8125b325e4fe7debb5194, 2022)
- License: BSD-3-Clause
Files extracted from upstream source:
diff --git a/thirdparty/etcpak/ProcessRGB.cpp b/thirdparty/etcpak/ProcessRGB.cpp
index d60164bcc8..fdb0967ce7 100644
--- a/thirdparty/etcpak/ProcessRGB.cpp
+++ b/thirdparty/etcpak/ProcessRGB.cpp
@@ -28,6 +28,10 @@
# define _bswap64(x) __builtin_bswap64(x)
#endif
+static const uint32_t MaxError = 1065369600; // ((38+76+14) * 255)^2
+// common T-/H-mode table
+static uint8_t tableTH[8] = { 3, 6, 11, 16, 23, 32, 41, 64 };
+
// thresholds for the early compression-mode decision scheme
// default: 0.03, 0.09, and 0.38
float ecmd_threshold[3] = { 0.03f, 0.09f, 0.38f };
@@ -36,13 +40,17 @@ static const uint8_t ModeUndecided = 0;
static const uint8_t ModePlanar = 0x1;
static const uint8_t ModeTH = 0x2;
+const unsigned int R = 2;
+const unsigned int G = 1;
+const unsigned int B = 0;
+
struct Luma
{
#ifdef __AVX2__
float max, min;
uint8_t minIdx = 255, maxIdx = 255;
__m128i luma8;
-#elif defined __ARM_NEON
+#elif defined __ARM_NEON && defined __aarch64__
float max, min;
uint8_t minIdx = 255, maxIdx = 255;
uint8x16_t luma8;
@@ -52,8 +60,206 @@ struct Luma
#endif
};
+#ifdef __AVX2__
+struct Plane
+{
+ uint64_t plane;
+ uint64_t error;
+ __m256i sum4;
+};
+#endif
+
+#if defined __AVX2__ || (defined __ARM_NEON && defined __aarch64__)
+struct Channels
+{
+#ifdef __AVX2__
+ __m128i r8, g8, b8;
+#elif defined __ARM_NEON && defined __aarch64__
+ uint8x16x2_t r, g, b;
+#endif
+};
+#endif
+
namespace
{
+static etcpak_force_inline uint8_t clamp( uint8_t min, int16_t val, uint8_t max )
+{
+ return val < min ? min : ( val > max ? max : val );
+}
+
+static etcpak_force_inline uint8_t clampMin( uint8_t min, int16_t val )
+{
+ return val < min ? min : val;
+}
+
+static etcpak_force_inline uint8_t clampMax( int16_t val, uint8_t max )
+{
+ return val > max ? max : val;
+}
+
+// slightly faster than std::sort
+static void insertionSort( uint8_t* arr1, uint8_t* arr2 )
+{
+ for( uint8_t i = 1; i < 16; ++i )
+ {
+ uint8_t value = arr1[i];
+ uint8_t hole = i;
+
+ for( ; hole > 0 && value < arr1[hole - 1]; --hole )
+ {
+ arr1[hole] = arr1[hole - 1];
+ arr2[hole] = arr2[hole - 1];
+ }
+ arr1[hole] = value;
+ arr2[hole] = i;
+ }
+}
+
+//converts indices from |a0|a1|e0|e1|i0|i1|m0|m1|b0|b1|f0|f1|j0|j1|n0|n1|c0|c1|g0|g1|k0|k1|o0|o1|d0|d1|h0|h1|l0|l1|p0|p1| previously used by T- and H-modes
+// into |p0|o0|n0|m0|l0|k0|j0|i0|h0|g0|f0|e0|d0|c0|b0|a0|p1|o1|n1|m1|l1|k1|j1|i1|h1|g1|f1|e1|d1|c1|b1|a1| which should be used for all modes.
+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved.
+static etcpak_force_inline int indexConversion( int pixelIndices )
+{
+ int correctIndices = 0;
+ int LSB[4][4];
+ int MSB[4][4];
+ int shift = 0;
+ for( int y = 3; y >= 0; y-- )
+ {
+ for( int x = 3; x >= 0; x-- )
+ {
+ LSB[x][y] = ( pixelIndices >> shift ) & 1;
+ shift++;
+ MSB[x][y] = ( pixelIndices >> shift ) & 1;
+ shift++;
+ }
+ }
+ shift = 0;
+ for( int x = 0; x < 4; x++ )
+ {
+ for( int y = 0; y < 4; y++ )
+ {
+ correctIndices |= ( LSB[x][y] << shift );
+ correctIndices |= ( MSB[x][y] << ( 16 + shift ) );
+ shift++;
+ }
+ }
+ return correctIndices;
+}
+
+// Swapping two RGB-colors
+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved.
+static etcpak_force_inline void swapColors( uint8_t( colors )[2][3] )
+{
+ uint8_t temp = colors[0][R];
+ colors[0][R] = colors[1][R];
+ colors[1][R] = temp;
+
+ temp = colors[0][G];
+ colors[0][G] = colors[1][G];
+ colors[1][G] = temp;
+
+ temp = colors[0][B];
+ colors[0][B] = colors[1][B];
+ colors[1][B] = temp;
+}
+
+
+// calculates quantized colors for T or H modes
+void compressColor( uint8_t( currColor )[2][3], uint8_t( quantColor )[2][3], bool t_mode )
+{
+ if( t_mode )
+ {
+ quantColor[0][R] = clampMax( 15 * ( currColor[0][R] + 8 ) / 255, 15 );
+ quantColor[0][G] = clampMax( 15 * ( currColor[0][G] + 8 ) / 255, 15 );
+ quantColor[0][B] = clampMax( 15 * ( currColor[0][B] + 8 ) / 255, 15 );
+ }
+ else // clamped to [1,14] to get a wider range
+ {
+ quantColor[0][R] = clamp( 1, 15 * ( currColor[0][R] + 8 ) / 255, 14 );
+ quantColor[0][G] = clamp( 1, 15 * ( currColor[0][G] + 8 ) / 255, 14 );
+ quantColor[0][B] = clamp( 1, 15 * ( currColor[0][B] + 8 ) / 255, 14 );
+ }
+
+ // clamped to [1,14] to get a wider range
+ quantColor[1][R] = clamp( 1, 15 * ( currColor[1][R] + 8 ) / 255, 14 );
+ quantColor[1][G] = clamp( 1, 15 * ( currColor[1][G] + 8 ) / 255, 14 );
+ quantColor[1][B] = clamp( 1, 15 * ( currColor[1][B] + 8 ) / 255, 14 );
+}
+
+// three decoding functions come from ETCPACK v2.74 and are slightly changed.
+static etcpak_force_inline void decompressColor( uint8_t( colorsRGB444 )[2][3], uint8_t( colors )[2][3] )
+{
+ // The color should be retrieved as:
+ //
+ // c = round(255/(r_bits^2-1))*comp_color
+ //
+ // This is similar to bit replication
+ //
+ // Note -- this code only work for bit replication from 4 bits and up --- 3 bits needs
+ // two copy operations.
+ colors[0][R] = ( colorsRGB444[0][R] << 4 ) | colorsRGB444[0][R];
+ colors[0][G] = ( colorsRGB444[0][G] << 4 ) | colorsRGB444[0][G];
+ colors[0][B] = ( colorsRGB444[0][B] << 4 ) | colorsRGB444[0][B];
+ colors[1][R] = ( colorsRGB444[1][R] << 4 ) | colorsRGB444[1][R];
+ colors[1][G] = ( colorsRGB444[1][G] << 4 ) | colorsRGB444[1][G];
+ colors[1][B] = ( colorsRGB444[1][B] << 4 ) | colorsRGB444[1][B];
+}
+
+// calculates the paint colors from the block colors
+// using a distance d and one of the H- or T-patterns.
+static void calculatePaintColors59T( uint8_t d, uint8_t( colors )[2][3], uint8_t( pColors )[4][3] )
+{
+ //////////////////////////////////////////////
+ //
+ // C3 C1 C4----C1---C2
+ // | | |
+ // | | |
+ // |-------| |
+ // | | |
+ // | | |
+ // C4 C2 C3
+ //
+ //////////////////////////////////////////////
+
+ // C4
+ pColors[3][R] = clampMin( 0, colors[1][R] - tableTH[d] );
+ pColors[3][G] = clampMin( 0, colors[1][G] - tableTH[d] );
+ pColors[3][B] = clampMin( 0, colors[1][B] - tableTH[d] );
+
+ // C3
+ pColors[0][R] = colors[0][R];
+ pColors[0][G] = colors[0][G];
+ pColors[0][B] = colors[0][B];
+ // C2
+ pColors[1][R] = clampMax( colors[1][R] + tableTH[d], 255 );
+ pColors[1][G] = clampMax( colors[1][G] + tableTH[d], 255 );
+ pColors[1][B] = clampMax( colors[1][B] + tableTH[d], 255 );
+ // C1
+ pColors[2][R] = colors[1][R];
+ pColors[2][G] = colors[1][G];
+ pColors[2][B] = colors[1][B];
+}
+
+static void calculatePaintColors58H( uint8_t d, uint8_t( colors )[2][3], uint8_t( pColors )[4][3] )
+{
+ pColors[3][R] = clampMin( 0, colors[1][R] - tableTH[d] );
+ pColors[3][G] = clampMin( 0, colors[1][G] - tableTH[d] );
+ pColors[3][B] = clampMin( 0, colors[1][B] - tableTH[d] );
+
+ // C1
+ pColors[0][R] = clampMax( colors[0][R] + tableTH[d], 255 );
+ pColors[0][G] = clampMax( colors[0][G] + tableTH[d], 255 );
+ pColors[0][B] = clampMax( colors[0][B] + tableTH[d], 255 );
+ // C2
+ pColors[1][R] = clampMin( 0, colors[0][R] - tableTH[d] );
+ pColors[1][G] = clampMin( 0, colors[0][G] - tableTH[d] );
+ pColors[1][B] = clampMin( 0, colors[0][B] - tableTH[d] );
+ // C3
+ pColors[2][R] = clampMax( colors[1][R] + tableTH[d], 255 );
+ pColors[2][G] = clampMax( colors[1][G] + tableTH[d], 255 );
+ pColors[2][B] = clampMax( colors[1][B] + tableTH[d], 255 );
+}
#if defined _MSC_VER && !defined __clang__
static etcpak_force_inline unsigned long _bit_scan_forward( unsigned long mask )
@@ -586,127 +792,107 @@ static etcpak_force_inline __m128i r6g7b6_AVX2(__m128 cof, __m128 chf, __m128 cv
return _mm_shuffle_epi8(cohv5, _mm_setr_epi8(6, 5, 4, -1, 2, 1, 0, -1, 10, 9, 8, -1, -1, -1, -1, -1));
}
-struct Plane
+static etcpak_force_inline Plane Planar_AVX2( const Channels& ch, uint8_t& mode, bool useHeuristics )
{
- uint64_t plane;
- uint64_t error;
- __m256i sum4;
-};
-
-static etcpak_force_inline Plane Planar_AVX2( const uint8_t* src, const uint8_t mode )
-{
- __m128i d0 = _mm_loadu_si128(((__m128i*)src) + 0);
- __m128i d1 = _mm_loadu_si128(((__m128i*)src) + 1);
- __m128i d2 = _mm_loadu_si128(((__m128i*)src) + 2);
- __m128i d3 = _mm_loadu_si128(((__m128i*)src) + 3);
-
- __m128i rgb0 = _mm_shuffle_epi8(d0, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
- __m128i rgb1 = _mm_shuffle_epi8(d1, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
- __m128i rgb2 = _mm_shuffle_epi8(d2, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
- __m128i rgb3 = _mm_shuffle_epi8(d3, _mm_setr_epi8(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, -1, -1, -1, -1));
-
- __m128i rg0 = _mm_unpacklo_epi32(rgb0, rgb1);
- __m128i rg1 = _mm_unpacklo_epi32(rgb2, rgb3);
- __m128i b0 = _mm_unpackhi_epi32(rgb0, rgb1);
- __m128i b1 = _mm_unpackhi_epi32(rgb2, rgb3);
-
- // swap channels
- __m128i b8 = _mm_unpacklo_epi64(rg0, rg1);
- __m128i g8 = _mm_unpackhi_epi64(rg0, rg1);
- __m128i r8 = _mm_unpacklo_epi64(b0, b1);
+ __m128i t0 = _mm_sad_epu8( ch.r8, _mm_setzero_si128() );
+ __m128i t1 = _mm_sad_epu8( ch.g8, _mm_setzero_si128() );
+ __m128i t2 = _mm_sad_epu8( ch.b8, _mm_setzero_si128() );
- __m128i t0 = _mm_sad_epu8(r8, _mm_setzero_si128());
- __m128i t1 = _mm_sad_epu8(g8, _mm_setzero_si128());
- __m128i t2 = _mm_sad_epu8(b8, _mm_setzero_si128());
+ __m128i r8s = _mm_shuffle_epi8( ch.r8, _mm_set_epi8( 0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0 ) );
+ __m128i g8s = _mm_shuffle_epi8( ch.g8, _mm_set_epi8( 0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0 ) );
+ __m128i b8s = _mm_shuffle_epi8( ch.b8, _mm_set_epi8( 0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0 ) );
- __m128i r8s = _mm_shuffle_epi8(r8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
- __m128i g8s = _mm_shuffle_epi8(g8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
- __m128i b8s = _mm_shuffle_epi8(b8, _mm_set_epi8(0xF, 0xE, 0xB, 0xA, 0x7, 0x6, 0x3, 0x2, 0xD, 0xC, 0x9, 0x8, 0x5, 0x4, 0x1, 0x0));
+ __m128i s0 = _mm_sad_epu8( r8s, _mm_setzero_si128() );
+ __m128i s1 = _mm_sad_epu8( g8s, _mm_setzero_si128() );
+ __m128i s2 = _mm_sad_epu8( b8s, _mm_setzero_si128() );
- __m128i s0 = _mm_sad_epu8(r8s, _mm_setzero_si128());
- __m128i s1 = _mm_sad_epu8(g8s, _mm_setzero_si128());
- __m128i s2 = _mm_sad_epu8(b8s, _mm_setzero_si128());
+ __m256i sr0 = _mm256_insertf128_si256( _mm256_castsi128_si256( t0 ), s0, 1 );
+ __m256i sg0 = _mm256_insertf128_si256( _mm256_castsi128_si256( t1 ), s1, 1 );
+ __m256i sb0 = _mm256_insertf128_si256( _mm256_castsi128_si256( t2 ), s2, 1 );
- __m256i sr0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t0), s0, 1);
- __m256i sg0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t1), s1, 1);
- __m256i sb0 = _mm256_insertf128_si256(_mm256_castsi128_si256(t2), s2, 1);
+ __m256i sr1 = _mm256_slli_epi64( sr0, 32 );
+ __m256i sg1 = _mm256_slli_epi64( sg0, 16 );
- __m256i sr1 = _mm256_slli_epi64(sr0, 32);
- __m256i sg1 = _mm256_slli_epi64(sg0, 16);
+ __m256i srb = _mm256_or_si256( sr1, sb0 );
+ __m256i srgb = _mm256_or_si256( srb, sg1 );
- __m256i srb = _mm256_or_si256(sr1, sb0);
- __m256i srgb = _mm256_or_si256(srb, sg1);
+ if( mode != ModePlanar && useHeuristics )
+ {
+ Plane plane;
+ plane.sum4 = _mm256_permute4x64_epi64( srgb, _MM_SHUFFLE( 2, 3, 0, 1 ) );
+ return plane;
+ }
- __m128i t3 = _mm_castps_si128(_mm_shuffle_ps(_mm_castsi128_ps(t0), _mm_castsi128_ps(t1), _MM_SHUFFLE(2, 0, 2, 0)));
- __m128i t4 = _mm_shuffle_epi32(t2, _MM_SHUFFLE(3, 1, 2, 0));
- __m128i t5 = _mm_hadd_epi32(t3, t4);
- __m128i t6 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(1, 1, 1, 1));
- __m128i t7 = _mm_shuffle_epi32(t5, _MM_SHUFFLE(2, 2, 2, 2));
+ __m128i t3 = _mm_castps_si128( _mm_shuffle_ps( _mm_castsi128_ps( t0 ), _mm_castsi128_ps( t1 ), _MM_SHUFFLE( 2, 0, 2, 0 ) ) );
+ __m128i t4 = _mm_shuffle_epi32( t2, _MM_SHUFFLE( 3, 1, 2, 0 ) );
+ __m128i t5 = _mm_hadd_epi32( t3, t4 );
+ __m128i t6 = _mm_shuffle_epi32( t5, _MM_SHUFFLE( 1, 1, 1, 1 ) );
+ __m128i t7 = _mm_shuffle_epi32( t5, _MM_SHUFFLE( 2, 2, 2, 2 ) );
- __m256i sr = _mm256_broadcastw_epi16(t5);
- __m256i sg = _mm256_broadcastw_epi16(t6);
- __m256i sb = _mm256_broadcastw_epi16(t7);
+ __m256i sr = _mm256_broadcastw_epi16( t5 );
+ __m256i sg = _mm256_broadcastw_epi16( t6 );
+ __m256i sb = _mm256_broadcastw_epi16( t7 );
- __m256i r08 = _mm256_cvtepu8_epi16(r8);
- __m256i g08 = _mm256_cvtepu8_epi16(g8);
- __m256i b08 = _mm256_cvtepu8_epi16(b8);
+ __m256i r08 = _mm256_cvtepu8_epi16( ch.r8 );
+ __m256i g08 = _mm256_cvtepu8_epi16( ch.g8 );
+ __m256i b08 = _mm256_cvtepu8_epi16( ch.b8 );
- __m256i r16 = _mm256_slli_epi16(r08, 4);
- __m256i g16 = _mm256_slli_epi16(g08, 4);
- __m256i b16 = _mm256_slli_epi16(b08, 4);
+ __m256i r16 = _mm256_slli_epi16( r08, 4 );
+ __m256i g16 = _mm256_slli_epi16( g08, 4 );
+ __m256i b16 = _mm256_slli_epi16( b08, 4 );
- __m256i difR0 = _mm256_sub_epi16(r16, sr);
- __m256i difG0 = _mm256_sub_epi16(g16, sg);
- __m256i difB0 = _mm256_sub_epi16(b16, sb);
+ __m256i difR0 = _mm256_sub_epi16( r16, sr );
+ __m256i difG0 = _mm256_sub_epi16( g16, sg );
+ __m256i difB0 = _mm256_sub_epi16( b16, sb );
- __m256i difRyz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
- __m256i difGyz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
- __m256i difByz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255));
+ __m256i difRyz = _mm256_madd_epi16( difR0, _mm256_set_epi16( 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255 ) );
+ __m256i difGyz = _mm256_madd_epi16( difG0, _mm256_set_epi16( 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255 ) );
+ __m256i difByz = _mm256_madd_epi16( difB0, _mm256_set_epi16( 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255, 255, 85, -85, -255 ) );
- __m256i difRxz = _mm256_madd_epi16(difR0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
- __m256i difGxz = _mm256_madd_epi16(difG0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
- __m256i difBxz = _mm256_madd_epi16(difB0, _mm256_set_epi16(255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255));
+ __m256i difRxz = _mm256_madd_epi16( difR0, _mm256_set_epi16( 255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255 ) );
+ __m256i difGxz = _mm256_madd_epi16( difG0, _mm256_set_epi16( 255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255 ) );
+ __m256i difBxz = _mm256_madd_epi16( difB0, _mm256_set_epi16( 255, 255, 255, 255, 85, 85, 85, 85, -85, -85, -85, -85, -255, -255, -255, -255 ) );
- __m256i difRGyz = _mm256_hadd_epi32(difRyz, difGyz);
- __m256i difByzxz = _mm256_hadd_epi32(difByz, difBxz);
+ __m256i difRGyz = _mm256_hadd_epi32( difRyz, difGyz );
+ __m256i difByzxz = _mm256_hadd_epi32( difByz, difBxz );
- __m256i difRGxz = _mm256_hadd_epi32(difRxz, difGxz);
+ __m256i difRGxz = _mm256_hadd_epi32( difRxz, difGxz );
- __m128i sumRGyz = _mm_add_epi32(_mm256_castsi256_si128(difRGyz), _mm256_extracti128_si256(difRGyz, 1));
- __m128i sumByzxz = _mm_add_epi32(_mm256_castsi256_si128(difByzxz), _mm256_extracti128_si256(difByzxz, 1));
- __m128i sumRGxz = _mm_add_epi32(_mm256_castsi256_si128(difRGxz), _mm256_extracti128_si256(difRGxz, 1));
+ __m128i sumRGyz = _mm_add_epi32( _mm256_castsi256_si128( difRGyz ), _mm256_extracti128_si256( difRGyz, 1 ) );
+ __m128i sumByzxz = _mm_add_epi32( _mm256_castsi256_si128( difByzxz ), _mm256_extracti128_si256( difByzxz, 1 ) );
+ __m128i sumRGxz = _mm_add_epi32( _mm256_castsi256_si128( difRGxz ), _mm256_extracti128_si256( difRGxz, 1 ) );
- __m128i sumRGByz = _mm_hadd_epi32(sumRGyz, sumByzxz);
- __m128i sumRGByzxz = _mm_hadd_epi32(sumRGxz, sumByzxz);
+ __m128i sumRGByz = _mm_hadd_epi32( sumRGyz, sumByzxz );
+ __m128i sumRGByzxz = _mm_hadd_epi32( sumRGxz, sumByzxz );
- __m128i sumRGBxz = _mm_shuffle_epi32(sumRGByzxz, _MM_SHUFFLE(2, 3, 1, 0));
+ __m128i sumRGBxz = _mm_shuffle_epi32( sumRGByzxz, _MM_SHUFFLE( 2, 3, 1, 0 ) );
- __m128 sumRGByzf = _mm_cvtepi32_ps(sumRGByz);
- __m128 sumRGBxzf = _mm_cvtepi32_ps(sumRGBxz);
+ __m128 sumRGByzf = _mm_cvtepi32_ps( sumRGByz );
+ __m128 sumRGBxzf = _mm_cvtepi32_ps( sumRGBxz );
- const float value = (255 * 255 * 8.0f + 85 * 85 * 8.0f) * 16.0f;
+ const float value = ( 255 * 255 * 8.0f + 85 * 85 * 8.0f ) * 16.0f;
- __m128 scale = _mm_set1_ps(-4.0f / value);
+ __m128 scale = _mm_set1_ps( -4.0f / value );
- __m128 af = _mm_mul_ps(sumRGBxzf, scale);
- __m128 bf = _mm_mul_ps(sumRGByzf, scale);
+ __m128 af = _mm_mul_ps( sumRGBxzf, scale );
+ __m128 bf = _mm_mul_ps( sumRGByzf, scale );
- __m128 df = _mm_mul_ps(_mm_cvtepi32_ps(t5), _mm_set1_ps(4.0f / 16.0f));
+ __m128 df = _mm_mul_ps( _mm_cvtepi32_ps( t5 ), _mm_set1_ps( 4.0f / 16.0f ) );
// calculating the three colors RGBO, RGBH, and RGBV. RGB = df - af * x - bf * y;
- __m128 cof0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df));
- __m128 chf0 = _mm_fnmadd_ps(af, _mm_set1_ps( 425.0f), _mm_fnmadd_ps(bf, _mm_set1_ps(-255.0f), df));
- __m128 cvf0 = _mm_fnmadd_ps(af, _mm_set1_ps(-255.0f), _mm_fnmadd_ps(bf, _mm_set1_ps( 425.0f), df));
+ __m128 cof0 = _mm_fnmadd_ps( af, _mm_set1_ps( -255.0f ), _mm_fnmadd_ps( bf, _mm_set1_ps( -255.0f ), df ) );
+ __m128 chf0 = _mm_fnmadd_ps( af, _mm_set1_ps( 425.0f ), _mm_fnmadd_ps( bf, _mm_set1_ps( -255.0f ), df ) );
+ __m128 cvf0 = _mm_fnmadd_ps( af, _mm_set1_ps( -255.0f ), _mm_fnmadd_ps( bf, _mm_set1_ps( 425.0f ), df ) );
// convert to r6g7b6
- __m128i cohv = r6g7b6_AVX2(cof0, chf0, cvf0);
+ __m128i cohv = r6g7b6_AVX2( cof0, chf0, cvf0 );
- uint64_t rgbho = _mm_extract_epi64(cohv, 0);
- uint32_t rgbv0 = _mm_extract_epi32(cohv, 2);
+ uint64_t rgbho = _mm_extract_epi64( cohv, 0 );
+ uint32_t rgbv0 = _mm_extract_epi32( cohv, 2 );
// Error calculation
uint64_t error = 0;
- if( mode != ModePlanar )
+ if( !useHeuristics )
{
auto ro0 = ( rgbho >> 48 ) & 0x3F;
auto go0 = ( rgbho >> 40 ) & 0x7F;
@@ -820,7 +1006,15 @@ static etcpak_force_inline Plane Planar_AVX2( const uint8_t* src, const uint8_t
Plane plane;
plane.plane = result;
- plane.error = error;
+ if( useHeuristics )
+ {
+ plane.error = 0;
+ mode = ModePlanar;
+ }
+ else
+ {
+ plane.error = error;
+ }
plane.sum4 = _mm256_permute4x64_epi64(srgb, _MM_SHUFFLE(2, 3, 0, 1));
return plane;
@@ -1570,7 +1764,7 @@ static etcpak_force_inline uint8_t convert7(float f)
return (i + 9 - ((i + 9) >> 8) - ((i + 6) >> 8)) >> 2;
}
-static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar( const uint8_t* src, const uint8_t mode )
+static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar( const uint8_t* src, const uint8_t mode, bool useHeuristics )
{
int32_t r = 0;
int32_t g = 0;
@@ -1645,7 +1839,7 @@ static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar( const uint8_t*
// Error calculation
uint64_t error = 0;
- if( ModePlanar != mode )
+ if( ModePlanar != mode && useHeuristics )
{
auto ro0 = coR;
auto go0 = coG;
@@ -1756,7 +1950,7 @@ static etcpak_force_inline int16x8_t Planar_NEON_SumWide( uint8x16_t src )
uint16x4_t accu2 = vpadd_u16( accu4, accu4 );
uint16x4_t accu1 = vpadd_u16( accu2, accu2 );
return vreinterpretq_s16_u16( vcombine_u16( accu1, accu1 ) );
-#else
+#else
return vdupq_n_s16( vaddvq_u16( accu8 ) );
#endif
}
@@ -1783,7 +1977,7 @@ static etcpak_force_inline int16x4_t convert7_NEON( int32x4_t x )
return vshr_n_s16( vsub_s16( vsub_s16( p9, vshr_n_s16( p9, 8 ) ), vshr_n_s16( p6, 8 ) ), 2 );
}
-static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar_NEON( const uint8_t* src, const uint8_t mode )
+static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar_NEON( const uint8_t* src, const uint8_t mode, bool useHeuristics )
{
uint8x16x4_t srcBlock = vld4q_u8( src );
@@ -1828,7 +2022,7 @@ static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar_NEON( const uint
int16x4_t c_hvox_g_8 = vorr_s16( vshr_n_s16( c_hvox_g_7, 6 ), vshl_n_s16( c_hvox_g_7, 1 ) );
uint64_t error = 0;
- if( mode != ModePlanar )
+ if( mode != ModePlanar && useHeuristics )
{
int16x4_t rec_gxbr_o = vext_s16( c_hvox_g_8, vget_high_s16( c_hvoo_br_8 ), 3 );
@@ -1924,6 +2118,376 @@ static etcpak_force_inline std::pair<uint64_t, uint64_t> Planar_NEON( const uint
#endif
+#ifdef __AVX2__
+uint32_t calculateErrorTH( bool tMode, uint8_t( colorsRGB444 )[2][3], uint8_t& dist, uint32_t& pixIndices, uint8_t startDist, __m128i r8, __m128i g8, __m128i b8 )
+#else
+uint32_t calculateErrorTH( bool tMode, uint8_t* src, uint8_t( colorsRGB444 )[2][3], uint8_t& dist, uint32_t& pixIndices, uint8_t startDist )
+#endif
+{
+ uint32_t blockErr = 0, bestBlockErr = MaxError;
+
+ uint32_t pixColors;
+ uint8_t possibleColors[4][3];
+ uint8_t colors[2][3];
+
+ decompressColor( colorsRGB444, colors );
+
+#ifdef __AVX2__
+ __m128i reverseMask = _mm_set_epi8( 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 );
+#endif
+
+ // test distances
+ for( uint8_t d = startDist; d < 8; ++d )
+ {
+ if( d >= 2 && dist == d - 2 ) break;
+
+ blockErr = 0;
+ pixColors = 0;
+
+ if( tMode )
+ {
+ calculatePaintColors59T( d, colors, possibleColors );
+ }
+ else
+ {
+ calculatePaintColors58H( d, colors, possibleColors );
+ }
+
+#ifdef __AVX2__
+ // RGB ordering
+ __m128i b8Rev = _mm_shuffle_epi8( b8, reverseMask );
+ __m128i g8Rev = _mm_shuffle_epi8( g8, reverseMask );
+ __m128i r8Rev = _mm_shuffle_epi8( r8, reverseMask );
+
+ // extends 3x128 bits RGB into 3x256 bits RGB for error comparisions
+ static const __m128i zero = _mm_setzero_si128();
+ __m128i b8Lo = _mm_unpacklo_epi8( b8Rev, zero );
+ __m128i g8Lo = _mm_unpacklo_epi8( g8Rev, zero );
+ __m128i r8Lo = _mm_unpacklo_epi8( r8Rev, zero );
+ __m128i b8Hi = _mm_unpackhi_epi8( b8Rev, zero );
+ __m128i g8Hi = _mm_unpackhi_epi8( g8Rev, zero );
+ __m128i r8Hi = _mm_unpackhi_epi8( r8Rev, zero );
+
+ __m256i b8 = _mm256_set_m128i( b8Hi, b8Lo );
+ __m256i g8 = _mm256_set_m128i( g8Hi, g8Lo );
+ __m256i r8 = _mm256_set_m128i( r8Hi, r8Lo );
+
+ // caculates differences between the pixel colrs and the palette colors
+ __m256i diffb = _mm256_abs_epi16( _mm256_sub_epi16( b8, _mm256_set1_epi16( possibleColors[0][B] ) ) );
+ __m256i diffg = _mm256_abs_epi16( _mm256_sub_epi16( g8, _mm256_set1_epi16( possibleColors[0][G] ) ) );
+ __m256i diffr = _mm256_abs_epi16( _mm256_sub_epi16( r8, _mm256_set1_epi16( possibleColors[0][R] ) ) );
+
+ // luma-based error calculations
+ static const __m256i bWeight = _mm256_set1_epi16( 14 );
+ static const __m256i gWeight = _mm256_set1_epi16( 76 );
+ static const __m256i rWeight = _mm256_set1_epi16( 38 );
+
+ diffb = _mm256_mullo_epi16( diffb, bWeight );
+ diffg = _mm256_mullo_epi16( diffg, gWeight );
+ diffr = _mm256_mullo_epi16( diffr, rWeight );
+
+ // obtains the error with the current palette color
+ __m256i lowestPixErr = _mm256_add_epi16( _mm256_add_epi16( diffb, diffg ), diffr );
+
+ // error calucations with the remaining three palette colors
+ static const uint32_t masks[4] = { 0, 0x55555555, 0xAAAAAAAA, 0xFFFFFFFF };
+ for( uint8_t c = 1; c < 4; c++ )
+ {
+ __m256i diffb = _mm256_abs_epi16( _mm256_sub_epi16( b8, _mm256_set1_epi16( possibleColors[c][B] ) ) );
+ __m256i diffg = _mm256_abs_epi16( _mm256_sub_epi16( g8, _mm256_set1_epi16( possibleColors[c][G] ) ) );
+ __m256i diffr = _mm256_abs_epi16( _mm256_sub_epi16( r8, _mm256_set1_epi16( possibleColors[c][R] ) ) );
+
+ diffb = _mm256_mullo_epi16( diffb, bWeight );
+ diffg = _mm256_mullo_epi16( diffg, gWeight );
+ diffr = _mm256_mullo_epi16( diffr, rWeight );
+
+ // error comparison with the previous best color
+ __m256i pixErrors = _mm256_add_epi16( _mm256_add_epi16( diffb, diffg ), diffr );
+ __m256i minErr = _mm256_min_epu16( lowestPixErr, pixErrors );
+ __m256i cmpRes = _mm256_cmpeq_epi16( pixErrors, minErr );
+ lowestPixErr = minErr;
+
+ // update pixel colors
+ uint32_t updPixColors = _mm256_movemask_epi8( cmpRes );
+ uint32_t prevPixColors = pixColors & ~updPixColors;
+ uint32_t mskPixColors = masks[c] & updPixColors;
+ pixColors = prevPixColors | mskPixColors;
+ }
+
+ // accumulate the block error
+ alignas( 32 ) uint16_t pixErr16[16] = { 0, };
+ _mm256_storeu_si256( (__m256i*)pixErr16, lowestPixErr );
+ for( uint8_t p = 0; p < 16; p++ )
+ {
+ blockErr += (int)( pixErr16[p] ) * pixErr16[p];
+ }
+#else
+ for( size_t y = 0; y < 4; ++y )
+ {
+ for( size_t x = 0; x < 4; ++x )
+ {
+ uint32_t bestPixErr = MaxError;
+ pixColors <<= 2; // Make room for next value
+
+ // Loop possible block colors
+ for( uint8_t c = 0; c < 4; ++c )
+ {
+ int diff[3];
+ diff[R] = src[4 * ( x * 4 + y ) + R] - possibleColors[c][R];
+ diff[G] = src[4 * ( x * 4 + y ) + G] - possibleColors[c][G];
+ diff[B] = src[4 * ( x * 4 + y ) + B] - possibleColors[c][B];
+
+ const uint32_t err = 38 * abs( diff[R] ) + 76 * abs( diff[G] ) + 14 * abs( diff[B] );
+ uint32_t pixErr = err * err;
+
+ // Choose best error
+ if( pixErr < bestPixErr )
+ {
+ bestPixErr = pixErr;
+ pixColors ^= ( pixColors & 3 ); // Reset the two first bits
+ pixColors |= c;
+ }
+ }
+ blockErr += bestPixErr;
+ }
+ }
+#endif
+
+ if( blockErr < bestBlockErr )
+ {
+ bestBlockErr = blockErr;
+ dist = d;
+ pixIndices = pixColors;
+ }
+ }
+
+ return bestBlockErr;
+}
+
+
+// main T-/H-mode compression function
+#ifdef __AVX2__
+uint32_t compressBlockTH( uint8_t* src, Luma& l, uint32_t& compressed1, uint32_t& compressed2, bool& tMode, __m128i r8, __m128i g8, __m128i b8 )
+#else
+uint32_t compressBlockTH( uint8_t *src, Luma& l, uint32_t& compressed1, uint32_t& compressed2, bool &tMode )
+#endif
+{
+#ifdef __AVX2__
+ alignas( 8 ) uint8_t luma[16] = { 0, };
+ _mm_storeu_si128 ( (__m128i* )luma, l.luma8 );
+#elif defined __ARM_NEON && defined __aarch64__
+ alignas( 8 ) uint8_t luma[16] = { 0 };
+ vst1q_u8( luma, l.luma8 );
+#else
+ uint8_t* luma = l.val;
+#endif
+
+ uint8_t pixIdx[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+
+ // 1) sorts the pairs of (luma, pix_idx)
+ insertionSort( luma, pixIdx );
+
+ // 2) finds the min (left+right)
+ uint8_t minSumRangeIdx = 0;
+ uint16_t minSumRangeValue;
+ uint16_t sum;
+ static const uint8_t diffBonus[15] = {8, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 8};
+ const int16_t temp = luma[15] - luma[0];
+
+ minSumRangeValue = luma[15] - luma[1] + diffBonus[0];
+ for( uint8_t i = 1; i < 14; i++ )
+ {
+ sum = temp - luma[i+1] + luma[i] + diffBonus[i];
+ if( minSumRangeValue > sum )
+ {
+ minSumRangeValue = sum;
+ minSumRangeIdx = i;
+ }
+ }
+
+ sum = luma[14] - luma[0] + diffBonus[14];
+ if( minSumRangeValue > sum )
+ {
+ minSumRangeValue = sum;
+ minSumRangeIdx = 14;
+ }
+ uint8_t lRange, rRange;
+
+ lRange = luma[minSumRangeIdx] - luma[0];
+ rRange = luma[15] - luma[minSumRangeIdx + 1];
+
+ // 3) sets a proper mode
+ bool swap = false;
+ if( lRange >= rRange )
+ {
+ if( lRange >= rRange * 2 )
+ {
+ swap = true;
+ tMode = true;
+ }
+ }
+ else
+ {
+ if( lRange * 2 <= rRange ) tMode = true;
+ }
+ // 4) calculates the two base colors
+ uint8_t rangeIdx[4] = { pixIdx[0], pixIdx[minSumRangeIdx], pixIdx[minSumRangeIdx + 1], pixIdx[15] };
+
+ uint16_t r[4], g[4], b[4];
+ for( uint8_t i = 0; i < 4; ++i )
+ {
+ uint8_t idx = rangeIdx[i] * 4;
+ b[i] = src[idx];
+ g[i] = src[idx + 1];
+ r[i] = src[idx + 2];
+ }
+
+ uint8_t mid_rgb[2][3];
+ if( swap )
+ {
+ mid_rgb[1][B] = ( b[0] + b[1] ) / 2;
+ mid_rgb[1][G] = ( g[0] + g[1] ) / 2;
+ mid_rgb[1][R] = ( r[0] + r[1] ) / 2;
+
+ uint16_t sum_rgb[3] = { 0, 0, 0 };
+ for( uint8_t i = minSumRangeIdx + 1; i < 16; i++ )
+ {
+ uint8_t idx = pixIdx[i] * 4;
+ sum_rgb[B] += src[idx];
+ sum_rgb[G] += src[idx + 1];
+ sum_rgb[R] += src[idx + 2];
+ }
+ const uint8_t temp = 15 - minSumRangeIdx;
+ mid_rgb[0][B] = sum_rgb[B] / temp;
+ mid_rgb[0][G] = sum_rgb[G] / temp;
+ mid_rgb[0][R] = sum_rgb[R] / temp;
+ }
+ else
+ {
+ mid_rgb[0][B] = (b[0] + b[1]) / 2;
+ mid_rgb[0][G] = (g[0] + g[1]) / 2;
+ mid_rgb[0][R] = (r[0] + r[1]) / 2;
+ if( tMode )
+ {
+ uint16_t sum_rgb[3] = { 0, 0, 0 };
+ for( uint8_t i = minSumRangeIdx + 1; i < 16; i++ )
+ {
+ uint8_t idx = pixIdx[i] * 4;
+ sum_rgb[B] += src[idx];
+ sum_rgb[G] += src[idx + 1];
+ sum_rgb[R] += src[idx + 2];
+ }
+ const uint8_t temp = 15 - minSumRangeIdx;
+ mid_rgb[1][B] = sum_rgb[B] / temp;
+ mid_rgb[1][G] = sum_rgb[G] / temp;
+ mid_rgb[1][R] = sum_rgb[R] / temp;
+ }
+ else
+ {
+ mid_rgb[1][B] = (b[2] + b[3]) / 2;
+ mid_rgb[1][G] = (g[2] + g[3]) / 2;
+ mid_rgb[1][R] = (r[2] + r[3]) / 2;
+ }
+ }
+
+ // 5) sets the start distance index
+ uint32_t startDistCandidate;
+ uint32_t avgDist;
+ if( tMode )
+ {
+ if( swap )
+ {
+ avgDist = ( b[1] - b[0] + g[1] - g[0] + r[1] - r[0] ) / 6;
+ }
+ else
+ {
+ avgDist = ( b[3] - b[2] + g[3] - g[2] + r[3] - r[2] ) / 6;
+ }
+ }
+ else
+ {
+ avgDist = ( b[1] - b[0] + g[1] - g[0] + r[1] - r[0] + b[3] - b[2] + g[3] - g[2] + r[3] - r[2] ) / 12;
+ }
+
+ if( avgDist <= 16)
+ {
+ startDistCandidate = 0;
+ }
+ else if( avgDist <= 23 )
+ {
+ startDistCandidate = 1;
+ }
+ else if( avgDist <= 32 )
+ {
+ startDistCandidate = 2;
+ }
+ else if( avgDist <= 41 )
+ {
+ startDistCandidate = 3;
+ }
+ else
+ {
+ startDistCandidate = 4;
+ }
+
+ uint32_t bestErr = MaxError;
+ uint32_t bestPixIndices;
+ uint8_t bestDist = 10;
+ uint8_t colorsRGB444[2][3];
+ compressColor( mid_rgb, colorsRGB444, tMode );
+ compressed1 = 0;
+
+ // 6) finds the best candidate with the lowest error
+#ifdef __AVX2__
+ // Vectorized ver
+ bestErr = calculateErrorTH( tMode, colorsRGB444, bestDist, bestPixIndices, startDistCandidate, r8, g8, b8 );
+#else
+ // Scalar ver
+ bestErr = calculateErrorTH( tMode, src, colorsRGB444, bestDist, bestPixIndices, startDistCandidate );
+#endif
+
+ // 7) outputs the final T or H block
+ if( tMode )
+ {
+ // Put the compress params into the compression block
+ compressed1 |= ( colorsRGB444[0][R] & 0xf ) << 23;
+ compressed1 |= ( colorsRGB444[0][G] & 0xf ) << 19;
+ compressed1 |= ( colorsRGB444[0][B] ) << 15;
+ compressed1 |= ( colorsRGB444[1][R] ) << 11;
+ compressed1 |= ( colorsRGB444[1][G] ) << 7;
+ compressed1 |= ( colorsRGB444[1][B] ) << 3;
+ compressed1 |= bestDist & 0x7;
+ }
+ else
+ {
+ int bestRGB444ColPacked[2];
+ bestRGB444ColPacked[0] = (colorsRGB444[0][R] << 8) + (colorsRGB444[0][G] << 4) + colorsRGB444[0][B];
+ bestRGB444ColPacked[1] = (colorsRGB444[1][R] << 8) + (colorsRGB444[1][G] << 4) + colorsRGB444[1][B];
+ if( ( bestRGB444ColPacked[0] >= bestRGB444ColPacked[1] ) ^ ( ( bestDist & 1 ) == 1 ) )
+ {
+ swapColors( colorsRGB444 );
+ // Reshuffle pixel indices to to exchange C1 with C3, and C2 with C4
+ bestPixIndices = ( 0x55555555 & bestPixIndices ) | ( 0xaaaaaaaa & ( ~bestPixIndices ) );
+ }
+
+ // Put the compress params into the compression block
+ compressed1 |= ( colorsRGB444[0][R] & 0xf ) << 22;
+ compressed1 |= ( colorsRGB444[0][G] & 0xf ) << 18;
+ compressed1 |= ( colorsRGB444[0][B] & 0xf ) << 14;
+ compressed1 |= ( colorsRGB444[1][R] & 0xf ) << 10;
+ compressed1 |= ( colorsRGB444[1][G] & 0xf ) << 6;
+ compressed1 |= ( colorsRGB444[1][B] & 0xf ) << 2;
+ compressed1 |= ( bestDist >> 1 ) & 0x3;
+ }
+
+ bestPixIndices = indexConversion( bestPixIndices );
+ compressed2 = 0;
+ compressed2 = ( compressed2 & ~( ( 0x2 << 31 ) - 1 ) ) | ( bestPixIndices & ( ( 2 << 31 ) - 1 ) );
+
+ return bestErr;
+}
+//#endif
+
template<class T, class S>
static etcpak_force_inline uint64_t EncodeSelectors( uint64_t d, const T terr[2][8], const S tsel[16][8], const uint32_t* id, const uint64_t value, const uint64_t error)
{
@@ -2025,7 +2589,7 @@ static inline int16_t hMax( __m128i buffer, uint8_t& idx )
return result;
}
-#elif defined __ARM_NEON
+#elif defined __ARM_NEON && defined __aarch64__
static inline int16_t hMax( uint8x16_t buffer, uint8_t& idx )
{
const uint8_t max = vmaxvq_u8( buffer );
@@ -2072,7 +2636,7 @@ static inline int16_t hMin( __m128i buffer, uint8_t& idx )
idx = _tzcnt_u32( _mm_movemask_epi8( mask ) );
return result;
}
-#elif defined __ARM_NEON
+#elif defined __ARM_NEON && defined __aarch64__
static inline int16_t hMin( uint8x16_t buffer, uint8_t& idx )
{
const uint8_t min = vminvq_u8( buffer );
@@ -2109,8 +2673,153 @@ static inline int16_t hMin( uint8x16_t buffer, uint8_t& idx )
}
#endif
-static etcpak_force_inline void CalculateLuma( const uint8_t* src, Luma& luma )
+// During search it is not convenient to store the bits the way they are stored in the
+// file format. Hence, after search, it is converted to this format.
+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved.
+static inline void stuff59bits( unsigned int thumbT59W1, unsigned int thumbT59W2, unsigned int& thumbTW1, unsigned int& thumbTW2 )
{
+ // Put bits in twotimer configuration for 59 (red overflows)
+ //
+ // Go from this bit layout:
+ //
+ // |63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 37 36 35|34 33 32|
+ // |----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|--dist--|
+ //
+ // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00|
+ // |----------------------------------------index bits---------------------------------------------|
+ //
+ //
+ // To this:
+ //
+ // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
+ // -----------------------------------------------------------------------------------------------
+ // |// // //|R0a |//|R0b |G0 |B0 |R1 |G1 |B1 |da |df|db|
+ // -----------------------------------------------------------------------------------------------
+ //
+ // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00|
+ // |----------------------------------------index bits---------------------------------------------|
+ //
+ // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
+ // -----------------------------------------------------------------------------------------------
+ // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |df|fp|
+ // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bt|bt|
+ // ------------------------------------------------------------------------------------------------
+
+ uint8_t R0a;
+ uint8_t bit, a, b, c, d, bits;
+
+ R0a = ( thumbT59W1 >> 25 ) & 0x3;
+
+ // Fix middle part
+ thumbTW1 = thumbT59W1 << 1;
+ // Fix R0a (top two bits of R0)
+ thumbTW1 = ( thumbTW1 & ~( 0x3 << 27 ) ) | ( ( R0a & 0x3 ) << 27 );
+ // Fix db (lowest bit of d)
+ thumbTW1 = ( thumbTW1 & ~0x1 ) | ( thumbT59W1 & 0x1 );
+
+ // Make sure that red overflows:
+ a = ( thumbTW1 >> 28 ) & 0x1;
+ b = ( thumbTW1 >> 27 ) & 0x1;
+ c = ( thumbTW1 >> 25 ) & 0x1;
+ d = ( thumbTW1 >> 24 ) & 0x1;
+
+ // The following bit abcd bit sequences should be padded with ones: 0111, 1010, 1011, 1101, 1110, 1111
+ // The following logical expression checks for the presence of any of those:
+ bit = ( a & c ) | ( !a & b & c & d ) | ( a & b & !c & d );
+ bits = 0xf * bit;
+ thumbTW1 = ( thumbTW1 & ~( 0x7 << 29 ) ) | ( bits & 0x7 ) << 29;
+ thumbTW1 = ( thumbTW1 & ~( 0x1 << 26 ) ) | ( !bit & 0x1 ) << 26;
+
+ // Set diffbit
+ thumbTW1 = ( thumbTW1 & ~0x2 ) | 0x2;
+ thumbTW2 = thumbT59W2;
+}
+
+// During search it is not convenient to store the bits the way they are stored in the
+// file format. Hence, after search, it is converted to this format.
+// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2005-2013. All Rights Reserved.
+static inline void stuff58bits( unsigned int thumbH58W1, unsigned int thumbH58W2, unsigned int& thumbHW1, unsigned int& thumbHW2 )
+{
+ // Put bits in twotimer configuration for 58 (red doesn't overflow, green does)
+ //
+ // Go from this bit layout:
+ //
+ //
+ // |63 62 61 60 59 58|57 56 55 54|53 52 51 50|49 48 47 46|45 44 43 42|41 40 39 38|37 36 35 34|33 32|
+ // |-------empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green 1--|--blue 1---|d2 d1|
+ //
+ // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00|
+ // |---------------------------------------index bits----------------------------------------------|
+ //
+ // To this:
+ //
+ // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
+ // -----------------------------------------------------------------------------------------------
+ // |//|R0 |G0 |// // //|G0|B0|//|B0b |R1 |G1 |B0 |d2|df|d1|
+ // -----------------------------------------------------------------------------------------------
+ //
+ // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00|
+ // |---------------------------------------index bits----------------------------------------------|
+ //
+ // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
+ // -----------------------------------------------------------------------------------------------
+ // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 | table | table |df|fp|
+ // | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bt|bt|
+ // -----------------------------------------------------------------------------------------------
+ //
+ //
+ // Thus, what we are really doing is going from this bit layout:
+ //
+ //
+ // |63 62 61 60 59 58|57 56 55 54 53 52 51|50 49|48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33|32 |
+ // |-------empty-----|part0---------------|part1|part2------------------------------------------|part3|
+ //
+ // To this:
+ //
+ // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32
+ // --------------------------------------------------------------------------------------------------|
+ // |//|part0 |// // //|part1|//|part2 |df|part3|
+ // --------------------------------------------------------------------------------------------------|
+
+ unsigned int part0, part1, part2, part3;
+ uint8_t bit, a, b, c, d, bits;
+
+ // move parts
+ part0 = ( thumbH58W1 >> 19 ) & 0x7f;
+ part1 = ( thumbH58W1 >> 17 ) & 0x3;
+ part2 = ( thumbH58W1 >> 1 ) & 0xffff;
+ part3 = thumbH58W1 & 0x1;
+ thumbHW1 = 0;
+ thumbHW1 = ( thumbHW1 & ~( 0x7f << 24 ) ) | ( ( part0 & 0x7f ) << 24 );
+ thumbHW1 = ( thumbHW1 & ~( 0x3 << 19 ) ) | ( ( part1 & 0x3 ) << 19 );
+ thumbHW1 = ( thumbHW1 & ~( 0xffff << 2 ) ) | ( ( part2 & 0xffff ) << 2 );
+ thumbHW1 = ( thumbHW1 & ~0x1 ) | ( part3 & 0x1 );
+
+ // Make sure that red does not overflow:
+ bit = ( thumbHW1 >> 30 ) & 0x1;
+ thumbHW1 = ( thumbHW1 & ~( 0x1 << 31 ) ) | ( ( !bit & 0x1 ) << 31 );
+
+ // Make sure that green overflows:
+ a = ( thumbHW1 >> 20 ) & 0x1;
+ b = ( thumbHW1 >> 19 ) & 0x1;
+ c = ( thumbHW1 >> 17 ) & 0x1;
+ d = ( thumbHW1 >> 16 ) & 0x1;
+ // The following bit abcd bit sequences should be padded with ones: 0111, 1010, 1011, 1101, 1110, 1111
+ // The following logical expression checks for the presence of any of those:
+ bit = ( a & c ) | ( !a & b & c & d ) | ( a & b & !c & d );
+ bits = 0xf * bit;
+ thumbHW1 = ( thumbHW1 & ~( 0x7 << 21 ) ) | ( ( bits & 0x7 ) << 21 );
+ thumbHW1 = ( thumbHW1 & ~( 0x1 << 18 ) ) | ( ( !bit & 0x1 ) << 18 );
+
+ // Set diffbit
+ thumbHW1 = ( thumbHW1 & ~0x2 ) | 0x2;
+ thumbHW2 = thumbH58W2;
+}
+
+#if defined __AVX2__ || (defined __ARM_NEON && defined __aarch64__)
+static etcpak_force_inline Channels GetChannels( const uint8_t* src )
+{
+ Channels ch;
#ifdef __AVX2__
__m128i d0 = _mm_loadu_si128( ( (__m128i*)src ) + 0 );
__m128i d1 = _mm_loadu_si128( ( (__m128i*)src ) + 1 );
@@ -2128,30 +2837,10 @@ static etcpak_force_inline void CalculateLuma( const uint8_t* src, Luma& luma )
__m128i b1 = _mm_unpackhi_epi32( rgb2, rgb3 );
// swap channels
- __m128i b8 = _mm_unpacklo_epi64( rg0, rg1 );
- __m128i g8 = _mm_unpackhi_epi64( rg0, rg1 );
- __m128i r8 = _mm_unpacklo_epi64( b0, b1 );
-
- __m256i b16_luma = _mm256_mullo_epi16( _mm256_cvtepu8_epi16( b8 ), _mm256_set1_epi16( 14 ) );
- __m256i g16_luma = _mm256_mullo_epi16( _mm256_cvtepu8_epi16( g8 ), _mm256_set1_epi16( 76 ) );
- __m256i r16_luma = _mm256_mullo_epi16( _mm256_cvtepu8_epi16( r8 ), _mm256_set1_epi16( 38 ) );
-
- __m256i luma_16bit = _mm256_add_epi16( _mm256_add_epi16( g16_luma, r16_luma ), b16_luma );
- __m256i luma_8bit_m256i = _mm256_srli_epi16( luma_16bit, 7 );
- __m128i luma_8bit_lo = _mm256_extractf128_si256( luma_8bit_m256i, 0 );
- __m128i luma_8bit_hi = _mm256_extractf128_si256( luma_8bit_m256i, 1 );
-
- static const __m128i interleaving_mask_lo = _mm_set_epi8( 15, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 0 );
- static const __m128i interleaving_mask_hi = _mm_set_epi8( 14, 12, 10, 8, 6, 4, 2, 0, 15, 13, 11, 9, 7, 5, 3, 1 );
- __m128i luma_8bit_lo_moved = _mm_shuffle_epi8( luma_8bit_lo, interleaving_mask_lo );
- __m128i luma_8bit_hi_moved = _mm_shuffle_epi8( luma_8bit_hi, interleaving_mask_hi );
- __m128i luma_8bit = _mm_or_si128( luma_8bit_hi_moved, luma_8bit_lo_moved );
- luma.luma8 = luma_8bit;
-
- // min/max calculation
- luma.min = hMin( luma_8bit, luma.minIdx ) * 0.00392156f;
- luma.max = hMax( luma_8bit, luma.maxIdx ) * 0.00392156f;
-#elif defined __ARM_NEON
+ ch.b8 = _mm_unpacklo_epi64( rg0, rg1 );
+ ch.g8 = _mm_unpackhi_epi64( rg0, rg1 );
+ ch.r8 = _mm_unpacklo_epi64( b0, b1 );
+#elif defined __ARM_NEON && defined __aarch64__
//load pixel data into 4 rows
uint8x16_t px0 = vld1q_u8( src + 0 );
uint8x16_t px1 = vld1q_u8( src + 16 );
@@ -2172,12 +2861,48 @@ static etcpak_force_inline void CalculateLuma( const uint8_t* src, Luma& luma )
uint8x16x2_t red = vzipq_u8( rr, uint8x16_t() );
uint8x16x2_t grn = vzipq_u8( gg, uint8x16_t() );
uint8x16x2_t blu = vzipq_u8( bb, uint8x16_t() );
- uint16x8_t red0 = vmulq_n_u16( vreinterpretq_u16_u8( red.val[0] ), 14 );
- uint16x8_t red1 = vmulq_n_u16( vreinterpretq_u16_u8( red.val[1] ), 14 );
- uint16x8_t grn0 = vmulq_n_u16( vreinterpretq_u16_u8( grn.val[0] ), 76 );
- uint16x8_t grn1 = vmulq_n_u16( vreinterpretq_u16_u8( grn.val[1] ), 76 );
- uint16x8_t blu0 = vmulq_n_u16( vreinterpretq_u16_u8( blu.val[0] ), 38 );
- uint16x8_t blu1 = vmulq_n_u16( vreinterpretq_u16_u8( blu.val[1] ), 38 );
+ ch.r = red;
+ ch.b = blu;
+ ch.g = grn;
+#endif
+ return ch;
+}
+#endif
+
+#if defined __AVX2__ || (defined __ARM_NEON && defined __aarch64__)
+static etcpak_force_inline void CalculateLuma( Channels& ch, Luma& luma )
+#else
+static etcpak_force_inline void CalculateLuma( const uint8_t* src, Luma& luma )
+#endif
+{
+#ifdef __AVX2__
+ __m256i b16_luma = _mm256_mullo_epi16( _mm256_cvtepu8_epi16( ch.b8 ), _mm256_set1_epi16( 14 ) );
+ __m256i g16_luma = _mm256_mullo_epi16( _mm256_cvtepu8_epi16( ch.g8 ), _mm256_set1_epi16( 76 ) );
+ __m256i r16_luma = _mm256_mullo_epi16( _mm256_cvtepu8_epi16( ch.r8 ), _mm256_set1_epi16( 38 ) );
+
+ __m256i luma_16bit = _mm256_add_epi16( _mm256_add_epi16( g16_luma, r16_luma ), b16_luma );
+ __m256i luma_8bit_m256i = _mm256_srli_epi16( luma_16bit, 7 );
+ __m128i luma_8bit_lo = _mm256_extractf128_si256( luma_8bit_m256i, 0 );
+ __m128i luma_8bit_hi = _mm256_extractf128_si256( luma_8bit_m256i, 1 );
+
+ static const __m128i interleaving_mask_lo = _mm_set_epi8( 15, 13, 11, 9, 7, 5, 3, 1, 14, 12, 10, 8, 6, 4, 2, 0 );
+ static const __m128i interleaving_mask_hi = _mm_set_epi8( 14, 12, 10, 8, 6, 4, 2, 0, 15, 13, 11, 9, 7, 5, 3, 1 );
+ __m128i luma_8bit_lo_moved = _mm_shuffle_epi8( luma_8bit_lo, interleaving_mask_lo );
+ __m128i luma_8bit_hi_moved = _mm_shuffle_epi8( luma_8bit_hi, interleaving_mask_hi );
+ __m128i luma_8bit = _mm_or_si128( luma_8bit_hi_moved, luma_8bit_lo_moved );
+ luma.luma8 = luma_8bit;
+
+ // min/max calculation
+ luma.min = hMin( luma_8bit, luma.minIdx ) * 0.00392156f;
+ luma.max = hMax( luma_8bit, luma.maxIdx ) * 0.00392156f;
+#elif defined __ARM_NEON && defined __aarch64__
+ //load pixel data into 4 rows
+ uint16x8_t red0 = vmulq_n_u16( vreinterpretq_u16_u8( ch.r.val[0] ), 14 );
+ uint16x8_t red1 = vmulq_n_u16( vreinterpretq_u16_u8( ch.r.val[1] ), 14 );
+ uint16x8_t grn0 = vmulq_n_u16( vreinterpretq_u16_u8( ch.g.val[0] ), 76 );
+ uint16x8_t grn1 = vmulq_n_u16( vreinterpretq_u16_u8( ch.g.val[1] ), 76 );
+ uint16x8_t blu0 = vmulq_n_u16( vreinterpretq_u16_u8( ch.b.val[0] ), 38 );
+ uint16x8_t blu1 = vmulq_n_u16( vreinterpretq_u16_u8( ch.b.val[1] ), 38 );
//calculate luma for rows 0,1 and 2,3
uint16x8_t lum_r01 = vaddq_u16( vaddq_u16( red0, grn0 ), blu0 );
@@ -2253,7 +2978,7 @@ static etcpak_force_inline uint8_t SelectModeETC2( const Luma& luma )
{
return ModeTH;
}
- return 0;
+ return ModeUndecided;
}
static etcpak_force_inline uint64_t ProcessRGB_ETC2( const uint8_t* src, bool useHeuristics )
@@ -2267,33 +2992,33 @@ static etcpak_force_inline uint64_t ProcessRGB_ETC2( const uint8_t* src, bool us
#endif
uint8_t mode = ModeUndecided;
+ Luma luma;
+#ifdef __AVX2__
+ Channels ch = GetChannels( src );
if( useHeuristics )
{
- Luma luma;
- CalculateLuma( src, luma );
+ CalculateLuma( ch, luma );
mode = SelectModeETC2( luma );
}
-#ifdef __AVX2__
- auto plane = Planar_AVX2( src, mode );
+ auto plane = Planar_AVX2( ch, mode, useHeuristics );
if( useHeuristics && mode == ModePlanar ) return plane.plane;
- alignas(32) v4i a[8];
-
+ alignas( 32 ) v4i a[8];
__m128i err0 = PrepareAverages_AVX2( a, plane.sum4 );
// Get index of minimum error (err0)
- __m128i err1 = _mm_shuffle_epi32(err0, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128i err1 = _mm_shuffle_epi32( err0, _MM_SHUFFLE( 2, 3, 0, 1 ) );
__m128i errMin0 = _mm_min_epu32(err0, err1);
- __m128i errMin1 = _mm_shuffle_epi32(errMin0, _MM_SHUFFLE(1, 0, 3, 2));
- __m128i errMin2 = _mm_min_epu32(errMin1, errMin0);
+ __m128i errMin1 = _mm_shuffle_epi32( errMin0, _MM_SHUFFLE( 1, 0, 3, 2 ) );
+ __m128i errMin2 = _mm_min_epu32( errMin1, errMin0 );
- __m128i errMask = _mm_cmpeq_epi32(errMin2, err0);
+ __m128i errMask = _mm_cmpeq_epi32( errMin2, err0 );
- uint32_t mask = _mm_movemask_epi8(errMask);
+ uint32_t mask = _mm_movemask_epi8( errMask );
- size_t idx = _bit_scan_forward(mask) >> 2;
+ size_t idx = _bit_scan_forward( mask ) >> 2;
d = EncodeAverages_AVX2( a, idx );
@@ -2309,12 +3034,54 @@ static etcpak_force_inline uint64_t ProcessRGB_ETC2( const uint8_t* src, bool us
FindBestFit_2x4_AVX2( terr, tsel, a, idx * 2, src );
}
- return EncodeSelectors_AVX2( d, terr, tsel, (idx % 2) == 1, plane.plane, plane.error );
+ if( useHeuristics )
+ {
+ if( mode == ModeTH )
+ {
+ uint64_t result = 0;
+ uint64_t error = 0;
+ uint32_t compressed[4] = { 0, 0, 0, 0 };
+ bool tMode = false;
+
+ error = compressBlockTH( (uint8_t*)src, luma, compressed[0], compressed[1], tMode, ch.r8, ch.g8, ch.b8 );
+ if( tMode )
+ {
+ stuff59bits( compressed[0], compressed[1], compressed[2], compressed[3] );
+ }
+ else
+ {
+ stuff58bits( compressed[0], compressed[1], compressed[2], compressed[3] );
+ }
+
+ result = (uint32_t)_bswap( compressed[2] );
+ result |= static_cast<uint64_t>( _bswap( compressed[3] ) ) << 32;
+
+ plane.plane = result;
+ plane.error = error;
+ }
+ else
+ {
+ plane.plane = 0;
+ plane.error = MaxError;
+ }
+ }
+
+ return EncodeSelectors_AVX2( d, terr, tsel, ( idx % 2 ) == 1, plane.plane, plane.error );
#else
+ if( useHeuristics )
+ {
+#if defined __ARM_NEON && defined __aarch64__
+ Channels ch = GetChannels( src );
+ CalculateLuma( ch, luma );
+#else
+ CalculateLuma( src, luma );
+#endif
+ mode = SelectModeETC2( luma );
+ }
#ifdef __ARM_NEON
- auto result = Planar_NEON( src, mode );
+ auto result = Planar_NEON( src, mode, useHeuristics );
#else
- auto result = Planar( src, mode );
+ auto result = Planar( src, mode, useHeuristics );
#endif
if( result.second == 0 ) return result.first;
@@ -2333,6 +3100,33 @@ static etcpak_force_inline uint64_t ProcessRGB_ETC2( const uint8_t* src, bool us
auto id = g_id[idx];
FindBestFit( terr, tsel, a, id, src );
+ if( useHeuristics )
+ {
+ if( mode == ModeTH )
+ {
+ uint32_t compressed[4] = { 0, 0, 0, 0 };
+ bool tMode = false;
+
+ result.second = compressBlockTH( (uint8_t*)src, luma, compressed[0], compressed[1], tMode );
+ if( tMode )
+ {
+ stuff59bits( compressed[0], compressed[1], compressed[2], compressed[3] );
+ }
+ else
+ {
+ stuff58bits( compressed[0], compressed[1], compressed[2], compressed[3] );
+ }
+
+ result.first = (uint32_t)_bswap( compressed[2] );
+ result.first |= static_cast<uint64_t>( _bswap( compressed[3] ) ) << 32;
+ }
+ else
+ {
+ result.first = 0;
+ result.second = MaxError;
+ }
+ }
+
return EncodeSelectors( d, terr, tsel, id, result.first, result.second );
#endif
}