summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/file_access.cpp7
-rw-r--r--core/io/resource_loader.cpp51
-rw-r--r--core/io/resource_loader.h9
-rw-r--r--core/os/condition_variable.h60
-rw-r--r--core/os/mutex.h69
-rw-r--r--doc/classes/Control.xml2
-rw-r--r--doc/classes/EditorFileDialog.xml10
-rw-r--r--doc/classes/EditorSettings.xml18
-rw-r--r--doc/classes/SpriteFrames.xml4
-rw-r--r--doc/classes/VoxelGI.xml2
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp3
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp4
-rw-r--r--drivers/gles3/rasterizer_gles3.h2
-rw-r--r--drivers/gles3/storage/material_storage.cpp3
-rw-r--r--drivers/vulkan/vulkan_context.cpp5
-rw-r--r--editor/editor_file_dialog.cpp17
-rw-r--r--editor/editor_file_dialog.h2
-rw-r--r--editor/editor_node.cpp5
-rw-r--r--editor/editor_settings.cpp18
-rw-r--r--editor/editor_themes.cpp6
-rw-r--r--editor/import/resource_importer_scene.h12
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp6
-rw-r--r--editor/plugins/script_text_editor.cpp9
-rw-r--r--editor/plugins/text_editor.cpp9
-rw-r--r--editor/project_converter_3_to_4.cpp10
-rw-r--r--editor/project_manager.cpp14
-rw-r--r--editor/renames_map_3_to_4.cpp2
-rw-r--r--misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj4
-rw-r--r--modules/cvtt/image_compress_cvtt.cpp23
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml14
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp7
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp3
-rw-r--r--modules/gdscript/gdscript_compiler.cpp13
-rw-r--r--modules/gdscript/gdscript_vm.cpp38
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/not_found_type.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/not_found_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.gd18
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.out7
-rw-r--r--modules/multiplayer/scene_replication_config.cpp12
-rw-r--r--platform/android/export/gradle_export_util.cpp3
-rw-r--r--platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt23
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java7
-rw-r--r--platform/android/java_godot_lib_jni.cpp16
-rw-r--r--platform/android/java_godot_lib_jni.h1
-rw-r--r--platform/linuxbsd/tts_linux.cpp9
-rw-r--r--platform/linuxbsd/tts_linux.h2
-rw-r--r--platform/linuxbsd/x11/key_mapping_x11.cpp4
-rw-r--r--platform/macos/key_mapping_macos.mm4
-rw-r--r--platform/windows/display_server_windows.cpp2
-rw-r--r--platform/windows/export/export_plugin.cpp5
-rw-r--r--platform/windows/key_mapping_windows.cpp4
-rw-r--r--scene/gui/label.cpp234
-rw-r--r--scene/gui/label.h5
-rw-r--r--scene/gui/rich_text_label.cpp18
-rw-r--r--scene/resources/sprite_frames.cpp2
-rw-r--r--scene/resources/tile_set.cpp5
-rw-r--r--scene/resources/tile_set.h1
-rw-r--r--servers/rendering/renderer_compositor.cpp4
-rw-r--r--servers/rendering/renderer_compositor.h2
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp4
-rw-r--r--servers/rendering/renderer_rd/effects/tone_mapper.cpp2
-rw-r--r--servers/rendering/renderer_rd/effects/vrs.cpp2
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp17
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp15
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp5
-rw-r--r--servers/rendering/renderer_rd/renderer_compositor_rd.h3
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssao.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssil.glsl4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp10
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp10
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp78
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h3
-rw-r--r--servers/rendering/renderer_viewport.cpp2
-rw-r--r--servers/rendering/shader_language.cpp19
-rw-r--r--servers/rendering/shader_language.h2
-rw-r--r--thirdparty/README.md5
-rw-r--r--thirdparty/cvtt/ConvectionKernels_BC67.cpp339
-rw-r--r--thirdparty/cvtt/patches/revert_BC6H_reorg.patch393
83 files changed, 1462 insertions, 333 deletions
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 0e9084de84..3d10151327 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -133,8 +133,8 @@ Ref<FileAccess> FileAccess::open_encrypted(const String &p_path, ModeFlags p_mod
Ref<FileAccessEncrypted> fae;
fae.instantiate();
Error err = fae->open_and_parse(fa, p_key, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ last_file_open_error = err;
if (err) {
- last_file_open_error = err;
return Ref<FileAccess>();
}
return fae;
@@ -149,8 +149,8 @@ Ref<FileAccess> FileAccess::open_encrypted_pass(const String &p_path, ModeFlags
Ref<FileAccessEncrypted> fae;
fae.instantiate();
Error err = fae->open_and_parse_password(fa, p_pass, (p_mode_flags == WRITE) ? FileAccessEncrypted::MODE_WRITE_AES256 : FileAccessEncrypted::MODE_READ);
+ last_file_open_error = err;
if (err) {
- last_file_open_error = err;
return Ref<FileAccess>();
}
return fae;
@@ -161,9 +161,8 @@ Ref<FileAccess> FileAccess::open_compressed(const String &p_path, ModeFlags p_mo
fac.instantiate();
fac->configure("GCPF", (Compression::Mode)p_compress_mode);
Error err = fac->open_internal(p_path, p_mode_flags);
-
+ last_file_open_error = err;
if (err) {
- last_file_open_error = err;
return Ref<FileAccess>();
}
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index fc3547261b..22bf8571bf 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/io/file_access.h"
#include "core/io/resource_importer.h"
+#include "core/os/condition_variable.h"
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
@@ -233,7 +234,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
ThreadLoadTask &load_task = *(ThreadLoadTask *)p_userdata;
load_task.loader_id = Thread::get_caller_id();
- if (load_task.semaphore) {
+ if (load_task.cond_var) {
//this is an actual thread, so wait for Ok from semaphore
thread_load_semaphore->wait(); //wait until its ok to start loading
}
@@ -247,7 +248,7 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
} else {
load_task.status = THREAD_LOAD_LOADED;
}
- if (load_task.semaphore) {
+ if (load_task.cond_var) {
if (load_task.start_next && thread_waiting_count > 0) {
thread_waiting_count--;
//thread loading count remains constant, this ends but another one begins
@@ -258,11 +259,9 @@ void ResourceLoader::_thread_load_function(void *p_userdata) {
print_lt("END: load count: " + itos(thread_loading_count) + " / wait count: " + itos(thread_waiting_count) + " / suspended count: " + itos(thread_suspended_count) + " / active: " + itos(thread_loading_count - thread_suspended_count));
- for (int i = 0; i < load_task.poll_requests; i++) {
- load_task.semaphore->post();
- }
- memdelete(load_task.semaphore);
- load_task.semaphore = nullptr;
+ load_task.cond_var->notify_all();
+ memdelete(load_task.cond_var);
+ load_task.cond_var = nullptr;
}
if (load_task.resource.is_valid()) {
@@ -373,7 +372,7 @@ Error ResourceLoader::load_threaded_request(const String &p_path, const String &
if (load_task.resource.is_null()) { //needs to be loaded in thread
- load_task.semaphore = memnew(Semaphore);
+ load_task.cond_var = memnew(ConditionVariable);
if (thread_loading_count < thread_load_max) {
thread_loading_count++;
thread_load_semaphore->post(); //we have free threads, so allow one
@@ -438,9 +437,8 @@ ResourceLoader::ThreadLoadStatus ResourceLoader::load_threaded_get_status(const
Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path, Error *r_error) {
String local_path = _validate_local_path(p_path);
- thread_load_mutex->lock();
+ MutexLock thread_load_lock(*thread_load_mutex);
if (!thread_load_tasks.has(local_path)) {
- thread_load_mutex->unlock();
if (r_error) {
*r_error = ERR_INVALID_PARAMETER;
}
@@ -449,13 +447,21 @@ Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path, Error *r_e
ThreadLoadTask &load_task = thread_load_tasks[local_path];
- //semaphore still exists, meaning it's still loading, request poll
- Semaphore *semaphore = load_task.semaphore;
- if (semaphore) {
- load_task.poll_requests++;
+ if (!load_task.cond_var && load_task.status == THREAD_LOAD_IN_PROGRESS) {
+ // A condition variable was never created for this task.
+ // That happens when a load has been initiated with subthreads disabled,
+ // but now another load thread needs to interact with this one (either
+ // because of subthreads being used this time, or because it's simply a
+ // threaded load running on a different thread).
+ // Since we want to be notified when the load ends, we must create the
+ // condition variable now.
+ load_task.cond_var = memnew(ConditionVariable);
+ }
+ //cond var still exists, meaning it's still loading, request poll
+ if (load_task.cond_var) {
{
- // As we got a semaphore, this means we are going to have to wait
+ // As we got a cond var, this means we are going to have to wait
// until the sub-resource is done loading
//
// As this thread will become 'blocked' we should "exchange" its
@@ -477,14 +483,13 @@ Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path, Error *r_e
print_lt("GET: load count: " + itos(thread_loading_count) + " / wait count: " + itos(thread_waiting_count) + " / suspended count: " + itos(thread_suspended_count) + " / active: " + itos(thread_loading_count - thread_suspended_count));
}
- thread_load_mutex->unlock();
- semaphore->wait();
- thread_load_mutex->lock();
+ do {
+ load_task.cond_var->wait(thread_load_lock);
+ } while (load_task.cond_var); // In case of spurious wakeup.
thread_suspended_count--;
if (!thread_load_tasks.has(local_path)) { //may have been erased during unlock and this was always an invalid call
- thread_load_mutex->unlock();
if (r_error) {
*r_error = ERR_INVALID_PARAMETER;
}
@@ -507,8 +512,6 @@ Ref<Resource> ResourceLoader::load_threaded_get(const String &p_path, Error *r_e
thread_load_tasks.erase(local_path);
}
- thread_load_mutex->unlock();
-
return resource;
}
@@ -1067,7 +1070,7 @@ void ResourceLoader::remove_custom_loaders() {
}
void ResourceLoader::initialize() {
- thread_load_mutex = memnew(Mutex);
+ thread_load_mutex = memnew(SafeBinaryMutex<BINARY_MUTEX_TAG>);
thread_load_max = OS::get_singleton()->get_processor_count();
thread_loading_count = 0;
thread_waiting_count = 0;
@@ -1090,7 +1093,9 @@ bool ResourceLoader::create_missing_resources_if_class_unavailable = false;
bool ResourceLoader::abort_on_missing_resource = true;
bool ResourceLoader::timestamp_on_load = false;
-Mutex *ResourceLoader::thread_load_mutex = nullptr;
+template <>
+thread_local uint32_t SafeBinaryMutex<ResourceLoader::BINARY_MUTEX_TAG>::count = 0;
+SafeBinaryMutex<ResourceLoader::BINARY_MUTEX_TAG> *ResourceLoader::thread_load_mutex = nullptr;
HashMap<String, ResourceLoader::ThreadLoadTask> ResourceLoader::thread_load_tasks;
Semaphore *ResourceLoader::thread_load_semaphore = nullptr;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index c47b6c950a..72c1f90653 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -37,6 +37,8 @@
#include "core/os/semaphore.h"
#include "core/os/thread.h"
+class ConditionVariable;
+
class ResourceFormatLoader : public RefCounted {
GDCLASS(ResourceFormatLoader, RefCounted);
@@ -105,6 +107,8 @@ public:
THREAD_LOAD_LOADED
};
+ static const int BINARY_MUTEX_TAG = 1;
+
private:
static Ref<ResourceFormatLoader> loader[MAX_LOADERS];
static int loader_count;
@@ -136,7 +140,7 @@ private:
struct ThreadLoadTask {
Thread *thread = nullptr;
Thread::ID loader_id = 0;
- Semaphore *semaphore = nullptr;
+ ConditionVariable *cond_var = nullptr;
String local_path;
String remapped_path;
String type_hint;
@@ -149,12 +153,11 @@ private:
bool use_sub_threads = false;
bool start_next = true;
int requests = 0;
- int poll_requests = 0;
HashSet<String> sub_tasks;
};
static void _thread_load_function(void *p_userdata);
- static Mutex *thread_load_mutex;
+ static SafeBinaryMutex<BINARY_MUTEX_TAG> *thread_load_mutex;
static HashMap<String, ThreadLoadTask> thread_load_tasks;
static Semaphore *thread_load_semaphore;
static int thread_waiting_count;
diff --git a/core/os/condition_variable.h b/core/os/condition_variable.h
new file mode 100644
index 0000000000..6037ff327d
--- /dev/null
+++ b/core/os/condition_variable.h
@@ -0,0 +1,60 @@
+/**************************************************************************/
+/* condition_variable.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef CONDITION_VARIABLE_H
+#define CONDITION_VARIABLE_H
+
+#include <condition_variable>
+
+// An object one or multiple threads can wait on a be notified by some other.
+// Normally, you want to use a semaphore for such scenarios, but when the
+// condition is something different than a count being greater than zero
+// (which is the built-in logic in a semaphore) or you want to provide your
+// own mutex to tie the wait-notify to some other behavior, you need to use this.
+
+class ConditionVariable {
+ mutable std::condition_variable condition;
+
+public:
+ template <class BinaryMutexT>
+ _ALWAYS_INLINE_ void wait(const MutexLock<BinaryMutexT> &p_lock) const {
+ condition.wait(const_cast<std::unique_lock<std::mutex> &>(p_lock.lock));
+ }
+
+ _ALWAYS_INLINE_ void notify_one() const {
+ condition.notify_one();
+ }
+
+ _ALWAYS_INLINE_ void notify_all() const {
+ condition.notify_all();
+ }
+};
+
+#endif // CONDITION_VARIABLE_H
diff --git a/core/os/mutex.h b/core/os/mutex.h
index ceedcb235a..90cc1632e8 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -31,12 +31,20 @@
#ifndef MUTEX_H
#define MUTEX_H
+#include "core/error/error_macros.h"
#include "core/typedefs.h"
#include <mutex>
+template <class MutexT>
+class MutexLock;
+
template <class StdMutexT>
class MutexImpl {
+ friend class MutexLock<MutexImpl<StdMutexT>>;
+
+ using StdMutexType = StdMutexT;
+
mutable StdMutexT mutex;
public:
@@ -53,18 +61,65 @@ public:
}
};
+// A very special kind of mutex, used in scenarios where these
+// requirements hold at the same time:
+// - Must be used with a condition variable (only binary mutexes are suitable).
+// - Must have recursive semnantics (or simulate, as this one does).
+// The implementation keeps the lock count in TS. Therefore, only
+// one object of each version of the template can exists; hence the Tag argument.
+// Tags must be unique across the Godot codebase.
+// Also, don't forget to declare the thread_local variable on each use.
+template <int Tag>
+class SafeBinaryMutex {
+ friend class MutexLock<SafeBinaryMutex>;
+
+ using StdMutexType = std::mutex;
+
+ mutable std::mutex mutex;
+ static thread_local uint32_t count;
+
+public:
+ _ALWAYS_INLINE_ void lock() const {
+ if (++count == 1) {
+ mutex.lock();
+ }
+ }
+
+ _ALWAYS_INLINE_ void unlock() const {
+ DEV_ASSERT(count);
+ if (--count == 0) {
+ mutex.unlock();
+ }
+ }
+
+ _ALWAYS_INLINE_ bool try_lock() const {
+ if (count) {
+ count++;
+ return true;
+ } else {
+ if (mutex.try_lock()) {
+ count++;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ ~SafeBinaryMutex() {
+ DEV_ASSERT(!count);
+ }
+};
+
template <class MutexT>
class MutexLock {
- const MutexT &mutex;
+ friend class ConditionVariable;
+
+ std::unique_lock<typename MutexT::StdMutexType> lock;
public:
_ALWAYS_INLINE_ explicit MutexLock(const MutexT &p_mutex) :
- mutex(p_mutex) {
- mutex.lock();
- }
-
- _ALWAYS_INLINE_ ~MutexLock() {
- mutex.unlock();
+ lock(p_mutex.mutex) {
}
};
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 5693876194..f2ab6cb07e 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -801,7 +801,7 @@
Shows the given control at the mouse pointer. A good time to call this method is in [method _get_drag_data]. The control must not be in the scene tree. You should not free the control, and you should not keep a reference to the control beyond the duration of the drag. It will be deleted automatically after the drag has ended.
[codeblocks]
[gdscript]
- export (Color, RGBA) var color = Color(1, 0, 0, 1)
+ @export var color = Color(1, 0, 0, 1)
func _get_drag_data(position):
# Use a control that is not in the tree
diff --git a/doc/classes/EditorFileDialog.xml b/doc/classes/EditorFileDialog.xml
index 29a8f470a1..7f8808acc7 100644
--- a/doc/classes/EditorFileDialog.xml
+++ b/doc/classes/EditorFileDialog.xml
@@ -25,6 +25,13 @@
Removes all filters except for "All Files (*)".
</description>
</method>
+ <method name="get_line_edit">
+ <return type="LineEdit" />
+ <description>
+ Returns the LineEdit for the selected file.
+ [b]Warning:[/b] This is a required internal node, removing and freeing it may cause a crash. If you wish to hide it or any of its children, use their [member CanvasItem.visible] property.
+ </description>
+ </method>
<method name="get_vbox">
<return type="VBoxContainer" />
<description>
@@ -62,6 +69,9 @@
<member name="file_mode" type="int" setter="set_file_mode" getter="get_file_mode" enum="EditorFileDialog.FileMode" default="4">
The dialog's open or save mode, which affects the selection behavior. See [enum FileMode]
</member>
+ <member name="filters" type="PackedStringArray" setter="set_filters" getter="get_filters" default="PackedStringArray()">
+ The available file type filters. For example, this shows only [code].png[/code] and [code].gd[/code] files: [code]set_filters(PackedStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]))[/code]. Multiple file types can also be specified in a single filter. [code]"*.png, *.jpg, *.jpeg ; Supported Images"[/code] will show both PNG and JPEG files when selected.
+ </member>
<member name="show_hidden_files" type="bool" setter="set_show_hidden_files" getter="is_showing_hidden_files" default="false">
If [code]true[/code], hidden files and directories will be visible in the [EditorFileDialog]. This property is synchronized with [member EditorSettings.filesystem/file_dialog/show_hidden_files].
</member>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 70ea69a336..86b84849f8 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -607,10 +607,6 @@
<member name="interface/theme/draw_extra_borders" type="bool" setter="" getter="">
If [code]true[/code], draws additional borders around interactive UI elements in the editor. This is automatically enabled when using the [b]Black (OLED)[/b] theme preset, as this theme preset uses a fully black background.
</member>
- <member name="interface/theme/enable_touchscreen_touch_area" type="bool" setter="" getter="">
- If [code]true[/code], increases the touch area for the UI elements to improve usability on touchscreen devices.
- [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices.
- </member>
<member name="interface/theme/icon_and_font_color" type="int" setter="" getter="">
The icon and font color scheme to use in the editor.
- [b]Auto[/b] determines the color scheme to use automatically based on [member interface/theme/base_color].
@@ -627,6 +623,18 @@
<member name="interface/theme/relationship_line_opacity" type="float" setter="" getter="">
The opacity to use when drawing relationship lines in the editor's [Tree]-based GUIs (such as the Scene tree dock).
</member>
+ <member name="interface/touchscreen/enable_long_press_as_right_click" type="bool" setter="" getter="">
+ If [code]true[/code], long press on touchscreen is treated as right click.
+ [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices.
+ </member>
+ <member name="interface/touchscreen/enable_pan_and_scale_gestures" type="bool" setter="" getter="">
+ If [code]true[/code], enable two finger pan and scale gestures on touchscreen devices.
+ [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices.
+ </member>
+ <member name="interface/touchscreen/increase_scrollbar_touch_area" type="bool" setter="" getter="">
+ If [code]true[/code], increases the scrollbar touch area to improve usability on touchscreen devices.
+ [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices.
+ </member>
<member name="network/debug/remote_host" type="String" setter="" getter="">
The address to listen to when starting the remote debugger. This can be set to [code]0.0.0.0[/code] to allow external clients to connect to the remote debugger (instead of restricting the remote debugger to connections from [code]localhost[/code]).
</member>
@@ -757,7 +765,7 @@
</member>
<member name="text_editor/behavior/indent/type" type="int" setter="" getter="">
The indentation style to use (tabs or spaces).
- [b]Note:[/b] The [url=$DOCS_URL/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation.
+ [b]Note:[/b] The [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation.
</member>
<member name="text_editor/behavior/navigation/drag_and_drop_selection" type="bool" setter="" getter="">
If [code]true[/code], allows drag-and-dropping text in the script editor to move text. Disable this if you find yourself accidentally drag-and-dropping text in the script editor.
diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml
index 195f3598d5..59a56e7ca6 100644
--- a/doc/classes/SpriteFrames.xml
+++ b/doc/classes/SpriteFrames.xml
@@ -73,9 +73,9 @@
<description>
Returns a relative duration of the frame [param idx] in the [param anim] animation (defaults to [code]1.0[/code]). For example, a frame with a duration of [code]2.0[/code] is displayed twice as long as a frame with a duration of [code]1.0[/code]. You can calculate the absolute duration (in seconds) of a frame using the following formula:
[codeblock]
- absolute_duration = relative_duration / (animation_fps * abs(speed_scale))
+ absolute_duration = relative_duration / (animation_fps * abs(playing_speed))
[/codeblock]
- In this example, [code]speed_scale[/code] refers to either [member AnimatedSprite2D.speed_scale] or [member AnimatedSprite3D.speed_scale].
+ In this example, [code]playing_speed[/code] refers to either [method AnimatedSprite2D.get_playing_speed] or [method AnimatedSprite3D.get_playing_speed].
</description>
</method>
<method name="get_frame_texture" qualifiers="const">
diff --git a/doc/classes/VoxelGI.xml b/doc/classes/VoxelGI.xml
index cc78426736..e453fbd855 100644
--- a/doc/classes/VoxelGI.xml
+++ b/doc/classes/VoxelGI.xml
@@ -11,7 +11,7 @@
[b]Note:[/b] Meshes should have sufficiently thick walls to avoid light leaks (avoid one-sided walls). For interior levels, enclose your level geometry in a sufficiently large box and bridge the loops to close the mesh. To further prevent light leaks, you can also strategically place temporary [MeshInstance3D] nodes with their [member GeometryInstance3D.gi_mode] set to [constant GeometryInstance3D.GI_MODE_STATIC]. These temporary nodes can then be hidden after baking the [VoxelGI] node.
</description>
<tutorials>
- <link title="GI probes">$DOCS_URL/tutorials/3d/gi_probes.html</link>
+ <link title="VoxelGI">$DOCS_URL/tutorials/3d/using_voxel_gi.html</link>
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<methods>
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 9c6e6baaec..2f7e68e463 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -224,13 +224,12 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_
l = l->next_ptr;
ERR_CONTINUE(!clight);
}
- Transform2D to_light_xform = (p_canvas_transform * l->light_shader_xform).affine_inverse();
Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
state.light_uniforms[index].position[0] = canvas_light_pos.x;
state.light_uniforms[index].position[1] = canvas_light_pos.y;
- _update_transform_2d_to_mat2x4(to_light_xform, state.light_uniforms[index].matrix);
+ _update_transform_2d_to_mat2x4(l->light_shader_xform.affine_inverse(), state.light_uniforms[index].matrix);
_update_transform_2d_to_mat2x4(l->xform_cache.affine_inverse(), state.light_uniforms[index].shadow_matrix);
state.light_uniforms[index].height = l->height * (p_canvas_transform.columns[0].length() + p_canvas_transform.columns[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index a9ec48fcd5..7cbce428cb 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -198,7 +198,11 @@ void RasterizerGLES3::finalize() {
memdelete(config);
}
+RasterizerGLES3 *RasterizerGLES3::singleton = nullptr;
+
RasterizerGLES3::RasterizerGLES3() {
+ singleton = this;
+
#ifdef GLAD_ENABLED
if (!gladLoaderLoadGL()) {
ERR_PRINT("Error initializing GLAD");
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index 0ba84ce412..e29ccefdbd 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -67,6 +67,7 @@ protected:
GLES3::CopyEffects *copy_effects = nullptr;
RasterizerCanvasGLES3 *canvas = nullptr;
RasterizerSceneGLES3 *scene = nullptr;
+ static RasterizerGLES3 *singleton;
void _blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer, bool p_first = true);
@@ -107,6 +108,7 @@ public:
_ALWAYS_INLINE_ double get_frame_delta_time() const { return delta; }
_ALWAYS_INLINE_ double get_total_time() const { return time_total; }
+ static RasterizerGLES3 *get_singleton() { return singleton; }
RasterizerGLES3();
~RasterizerGLES3();
};
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 2c530e3ae6..c585895f4b 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -38,6 +38,7 @@
#include "texture_storage.h"
#include "drivers/gles3/rasterizer_canvas_gles3.h"
+#include "drivers/gles3/rasterizer_gles3.h"
using namespace GLES3;
@@ -1721,7 +1722,7 @@ MaterialStorage::MaterialStorage() {
actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP;
actions.default_repeat = ShaderLanguage::REPEAT_ENABLE;
- actions.check_multiview_samplers = true;
+ actions.check_multiview_samplers = RasterizerGLES3::get_singleton()->is_xr_enabled();
actions.global_buffer_array_variable = "global_shader_uniforms";
shaders.compiler_scene.initialize(actions);
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index b8cea7136d..f185a5cb88 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -101,6 +101,7 @@ VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice p_device, const VkRender
attachments.push_back(att);
}
+ Vector<Vector<VkAttachmentReference>> attachment_references;
Vector<VkSubpassDescription> subpasses;
for (uint32_t i = 0; i < p_create_info->subpassCount; i++) {
// Here we need to do more, again it's just stripping out type and next
@@ -124,6 +125,10 @@ VkResult VulkanContext::vkCreateRenderPass2KHR(VkDevice p_device, const VkRender
p_create_info->pSubpasses[i].preserveAttachmentCount, /* preserveAttachmentCount */
p_create_info->pSubpasses[i].pPreserveAttachments /* pPreserveAttachments */
};
+ attachment_references.push_back(input_attachments);
+ attachment_references.push_back(color_attachments);
+ attachment_references.push_back(resolve_attachments);
+ attachment_references.push_back(depth_attachments);
subpasses.push_back(subpass);
}
diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp
index 50826f572a..b4ef719ab0 100644
--- a/editor/editor_file_dialog.cpp
+++ b/editor/editor_file_dialog.cpp
@@ -1015,6 +1015,19 @@ void EditorFileDialog::add_filter(const String &p_filter, const String &p_descri
invalidate();
}
+void EditorFileDialog::set_filters(const Vector<String> &p_filters) {
+ if (filters == p_filters) {
+ return;
+ }
+ filters = p_filters;
+ update_filters();
+ invalidate();
+}
+
+Vector<String> EditorFileDialog::get_filters() const {
+ return filters;
+}
+
String EditorFileDialog::get_current_dir() const {
return dir_access->get_current_dir();
}
@@ -1570,6 +1583,8 @@ void EditorFileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_filters"), &EditorFileDialog::clear_filters);
ClassDB::bind_method(D_METHOD("add_filter", "filter", "description"), &EditorFileDialog::add_filter, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("set_filters", "filters"), &EditorFileDialog::set_filters);
+ ClassDB::bind_method(D_METHOD("get_filters"), &EditorFileDialog::get_filters);
ClassDB::bind_method(D_METHOD("get_current_dir"), &EditorFileDialog::get_current_dir);
ClassDB::bind_method(D_METHOD("get_current_file"), &EditorFileDialog::get_current_file);
ClassDB::bind_method(D_METHOD("get_current_path"), &EditorFileDialog::get_current_path);
@@ -1579,6 +1594,7 @@ void EditorFileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_file_mode", "mode"), &EditorFileDialog::set_file_mode);
ClassDB::bind_method(D_METHOD("get_file_mode"), &EditorFileDialog::get_file_mode);
ClassDB::bind_method(D_METHOD("get_vbox"), &EditorFileDialog::get_vbox);
+ ClassDB::bind_method(D_METHOD("get_line_edit"), &EditorFileDialog::get_line_edit);
ClassDB::bind_method(D_METHOD("set_access", "access"), &EditorFileDialog::set_access);
ClassDB::bind_method(D_METHOD("get_access"), &EditorFileDialog::get_access);
ClassDB::bind_method(D_METHOD("set_show_hidden_files", "show"), &EditorFileDialog::set_show_hidden_files);
@@ -1605,6 +1621,7 @@ void EditorFileDialog::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir", PROPERTY_HINT_DIR, "", PROPERTY_USAGE_NONE), "set_current_dir", "get_current_dir");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file", PROPERTY_HINT_FILE, "*", PROPERTY_USAGE_NONE), "set_current_file", "get_current_file");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_current_path", "get_current_path");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "filters"), "set_filters", "get_filters");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_overwrite_warning"), "set_disable_overwrite_warning", "is_overwrite_warning_disabled");
diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h
index 1944cacf70..e3515f8073 100644
--- a/editor/editor_file_dialog.h
+++ b/editor/editor_file_dialog.h
@@ -242,6 +242,8 @@ public:
void popup_file_dialog();
void clear_filters();
void add_filter(const String &p_filter, const String &p_description = "");
+ void set_filters(const Vector<String> &p_filters);
+ Vector<String> get_filters() const;
void set_enable_multiple_selection(bool p_enable);
Vector<String> get_selected_files() const;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 3555caac8a..5e8a4e230e 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -696,7 +696,8 @@ void EditorNode::_notification(int p_what) {
EditorSettings::get_singleton()->check_changed_settings_in_group("interface/editor/code_font") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/theme") ||
EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/help/help") ||
- EditorSettings::get_singleton()->check_changed_settings_in_group("filesystem/file_dialog/thumbnail_size");
+ EditorSettings::get_singleton()->check_changed_settings_in_group("filesystem/file_dialog/thumbnail_size") ||
+ EditorSettings::get_singleton()->check_changed_settings_in_group("run/output/font_size");
if (theme_changed) {
theme = create_custom_theme(theme_base->get_theme());
@@ -3525,7 +3526,7 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Only try to load the script if it has a name. Else, the plugin has no init script.
if (script_path.length() > 0) {
script_path = addon_path.get_base_dir().path_join(script_path);
- scr = ResourceLoader::load(script_path);
+ scr = ResourceLoader::load(script_path, "Script", ResourceFormatLoader::CACHE_MODE_IGNORE);
if (scr.is_null()) {
show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), script_path));
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index b4f5eeda84..037bfbfd99 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -450,7 +450,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// Theme
EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Black (OLED),Custom")
- EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/enable_touchscreen_touch_area", DisplayServer::get_singleton()->is_touchscreen_available(), "")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/icon_and_font_color", 0, "Auto,Dark,Light")
EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/base_color", Color(0.2, 0.23, 0.31), "")
EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/accent_color", Color(0.41, 0.61, 0.91), "")
@@ -463,6 +462,14 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/additional_spacing", 0.0, "0,5,0.1")
EDITOR_SETTING_USAGE(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "interface/theme/custom_theme", "", "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED)
+ // Touchscreen
+ bool has_touchscreen_ui = DisplayServer::get_singleton()->is_touchscreen_available();
+ EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/increase_scrollbar_touch_area", has_touchscreen_ui, "")
+ EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_long_press_as_right_click", has_touchscreen_ui, "")
+ set_restart_if_changed("interface/touchscreen/enable_long_press_as_right_click", true);
+ EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_pan_and_scale_gestures", has_touchscreen_ui, "")
+ set_restart_if_changed("interface/touchscreen/enable_pan_and_scale_gestures", true);
+
// Scene tabs
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/scene_tabs/display_close_button", 1, "Never,If Tab Active,Always"); // TabBar::CloseButtonDisplayPolicy
_initial_set("interface/scene_tabs/show_thumbnail_on_hover", true);
@@ -739,7 +746,16 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects.
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "project_manager/sorting_order", 0, "Last Edited,Name,Path")
+
+#if defined(WEB_ENABLED)
+ // Web platform only supports `gl_compatibility`.
+ EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_NONE, "project_manager/default_renderer", "gl_compatibility", "forward_plus,mobile,gl_compatibility")
+#elif defined(ANDROID_ENABLED)
+ // Use more suitable rendering method by default.
+ EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_NONE, "project_manager/default_renderer", "mobile", "forward_plus,mobile,gl_compatibility")
+#else
EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_NONE, "project_manager/default_renderer", "forward_plus", "forward_plus,mobile,gl_compatibility")
+#endif
if (p_extra_config.is_valid()) {
if (p_extra_config->has_section("init_projects") && p_extra_config->has_section_key("init_projects", "list")) {
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 304a7acff1..2ab15c1c2c 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -394,7 +394,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
Color accent_color = EDITOR_GET("interface/theme/accent_color");
Color base_color = EDITOR_GET("interface/theme/base_color");
float contrast = EDITOR_GET("interface/theme/contrast");
- bool enable_touchscreen_touch_area = EDITOR_GET("interface/theme/enable_touchscreen_touch_area");
+ bool increase_scrollbar_touch_area = EDITOR_GET("interface/touchscreen/increase_scrollbar_touch_area");
bool draw_extra_borders = EDITOR_GET("interface/theme/draw_extra_borders");
float icon_saturation = EDITOR_GET("interface/theme/icon_saturation");
float relationship_line_opacity = EDITOR_GET("interface/theme/relationship_line_opacity");
@@ -1526,7 +1526,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// HScrollBar
Ref<Texture2D> empty_icon = memnew(ImageTexture);
- if (enable_touchscreen_touch_area) {
+ if (increase_scrollbar_touch_area) {
theme->set_stylebox("scroll", "HScrollBar", make_line_stylebox(separator_color, 50));
} else {
theme->set_stylebox("scroll", "HScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1));
@@ -1544,7 +1544,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("decrement_pressed", "HScrollBar", empty_icon);
// VScrollBar
- if (enable_touchscreen_touch_area) {
+ if (increase_scrollbar_touch_area) {
theme->set_stylebox("scroll", "VScrollBar", make_line_stylebox(separator_color, 50, 1, 1, true));
} else {
theme->set_stylebox("scroll", "VScrollBar", make_stylebox(theme->get_icon(SNAME("GuiScrollBg"), SNAME("EditorIcons")), 5, 5, 5, 5, 1, 1, 1, 1));
diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h
index 295d2643b8..24d2569420 100644
--- a/editor/import/resource_importer_scene.h
+++ b/editor/import/resource_importer_scene.h
@@ -410,6 +410,8 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh>
box.instantiate();
if (p_options.has(SNAME("primitive/size"))) {
box->set_size(p_options[SNAME("primitive/size")].operator Vector3() * p_applied_root_scale);
+ } else {
+ box->set_size(Vector3(2, 2, 2) * p_applied_root_scale);
}
Vector<Ref<Shape3D>> shapes;
@@ -421,6 +423,8 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh>
sphere.instantiate();
if (p_options.has(SNAME("primitive/radius"))) {
sphere->set_radius(p_options[SNAME("primitive/radius")].operator float() * p_applied_root_scale);
+ } else {
+ sphere->set_radius(1.0f * p_applied_root_scale);
}
Vector<Ref<Shape3D>> shapes;
@@ -431,9 +435,13 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh>
cylinder.instantiate();
if (p_options.has(SNAME("primitive/height"))) {
cylinder->set_height(p_options[SNAME("primitive/height")].operator float() * p_applied_root_scale);
+ } else {
+ cylinder->set_height(1.0f * p_applied_root_scale);
}
if (p_options.has(SNAME("primitive/radius"))) {
cylinder->set_radius(p_options[SNAME("primitive/radius")].operator float() * p_applied_root_scale);
+ } else {
+ cylinder->set_radius(1.0f * p_applied_root_scale);
}
Vector<Ref<Shape3D>> shapes;
@@ -444,9 +452,13 @@ Vector<Ref<Shape3D>> ResourceImporterScene::get_collision_shapes(const Ref<Mesh>
capsule.instantiate();
if (p_options.has(SNAME("primitive/height"))) {
capsule->set_height(p_options[SNAME("primitive/height")].operator float() * p_applied_root_scale);
+ } else {
+ capsule->set_height(1.0f * p_applied_root_scale);
}
if (p_options.has(SNAME("primitive/radius"))) {
capsule->set_radius(p_options[SNAME("primitive/radius")].operator float() * p_applied_root_scale);
+ } else {
+ capsule->set_radius(1.0f * p_applied_root_scale);
}
Vector<Ref<Shape3D>> shapes;
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 9defb4de9b..f4d97a5427 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -506,7 +506,11 @@ void Polygon3DEditor::edit(Node *p_node) {
wip.clear();
wip_active = false;
edited_point = -1;
- p_node->add_child(imgeom);
+ if (imgeom->get_parent()) {
+ imgeom->reparent(p_node, false);
+ } else {
+ p_node->add_child(imgeom);
+ }
_polygon_draw();
set_process(true);
prev_depth = -1;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 5e70a407dd..c1a5283662 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1225,8 +1225,13 @@ void ScriptTextEditor::_edit_option(int p_op) {
code_editor->duplicate_selection();
} break;
case EDIT_TOGGLE_FOLD_LINE: {
- for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) {
- tx->toggle_foldable_line(tx->get_caret_line(caret_idx));
+ int previous_line = -1;
+ for (int caret_idx : tx->get_caret_index_edit_order()) {
+ int line_idx = tx->get_caret_line(caret_idx);
+ if (line_idx != previous_line) {
+ tx->toggle_foldable_line(line_idx);
+ previous_line = line_idx;
+ }
}
tx->queue_redraw();
} break;
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index ceb170d7d8..9c0d76a6d3 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -397,8 +397,13 @@ void TextEditor::_edit_option(int p_op) {
code_editor->duplicate_selection();
} break;
case EDIT_TOGGLE_FOLD_LINE: {
- for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) {
- tx->toggle_foldable_line(tx->get_caret_line(caret_idx));
+ int previous_line = -1;
+ for (int caret_idx : tx->get_caret_index_edit_order()) {
+ int line_idx = tx->get_caret_line(caret_idx);
+ if (line_idx != previous_line) {
+ tx->toggle_foldable_line(line_idx);
+ previous_line = line_idx;
+ }
}
tx->queue_redraw();
} break;
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index d1f3c3902a..0e7476d045 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -410,6 +410,12 @@ bool ProjectConverter3To4::convert() {
rename_common(RenamesMap3To4::input_map_renames, reg_container.input_map_regexes, lines);
} else if (file_name.ends_with(".csproj")) {
// TODO
+ } else if (file_name.ends_with(".import")) {
+ for (int x = 0; x < lines.size(); x++) {
+ if (lines[x].contains("nodes/root_type=\"Spatial\"")) {
+ lines.set(x, "nodes/root_type=\"Node3D\"");
+ }
+ }
} else {
ERR_PRINT(file_name + " is not supported!");
continue;
@@ -636,7 +642,7 @@ Vector<String> ProjectConverter3To4::check_for_files() {
String file_name = dir->_get_next();
while (file_name != "") {
- if (file_name == ".git" || file_name == ".import" || file_name == ".godot") {
+ if (file_name == ".git" || file_name == ".godot") {
file_name = dir->_get_next();
continue;
}
@@ -644,7 +650,7 @@ Vector<String> ProjectConverter3To4::check_for_files() {
directories_to_check.append(current_dir.path_join(file_name) + "/");
} else {
bool proper_extension = false;
- if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".gdshader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj"))
+ if (file_name.ends_with(".gd") || file_name.ends_with(".shader") || file_name.ends_with(".gdshader") || file_name.ends_with(".tscn") || file_name.ends_with(".tres") || file_name.ends_with(".godot") || file_name.ends_with(".cs") || file_name.ends_with(".csproj") || file_name.ends_with(".import"))
proper_extension = true;
if (proper_extension) {
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index c00ef326d0..2f3f4dd2e1 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -911,33 +911,41 @@ public:
Button *rs_button = memnew(CheckBox);
rs_button->set_button_group(renderer_button_group);
rs_button->set_text(TTR("Forward+"));
+#if defined(WEB_ENABLED)
+ rs_button->set_disabled(true);
+#endif
rs_button->set_meta(SNAME("rendering_method"), "forward_plus");
rs_button->connect("pressed", callable_mp(this, &ProjectDialog::_renderer_selected));
rvb->add_child(rs_button);
if (default_renderer_type == "forward_plus") {
rs_button->set_pressed(true);
}
-
rs_button = memnew(CheckBox);
rs_button->set_button_group(renderer_button_group);
rs_button->set_text(TTR("Mobile"));
+#if defined(WEB_ENABLED)
+ rs_button->set_disabled(true);
+#endif
rs_button->set_meta(SNAME("rendering_method"), "mobile");
rs_button->connect("pressed", callable_mp(this, &ProjectDialog::_renderer_selected));
rvb->add_child(rs_button);
if (default_renderer_type == "mobile") {
rs_button->set_pressed(true);
}
-
rs_button = memnew(CheckBox);
rs_button->set_button_group(renderer_button_group);
rs_button->set_text(TTR("Compatibility"));
+#if !defined(GLES3_ENABLED)
+ rs_button->set_disabled(true);
+#endif
rs_button->set_meta(SNAME("rendering_method"), "gl_compatibility");
rs_button->connect("pressed", callable_mp(this, &ProjectDialog::_renderer_selected));
rvb->add_child(rs_button);
+#if defined(GLES3_ENABLED)
if (default_renderer_type == "gl_compatibility") {
rs_button->set_pressed(true);
}
-
+#endif
rshc->add_child(memnew(VSeparator));
// Right hand side, used for text explaining each choice.
diff --git a/editor/renames_map_3_to_4.cpp b/editor/renames_map_3_to_4.cpp
index 277df4e66c..d7cac9a2b9 100644
--- a/editor/renames_map_3_to_4.cpp
+++ b/editor/renames_map_3_to_4.cpp
@@ -1174,7 +1174,7 @@ const char *RenamesMap3To4::gdscript_properties_renames[][2] = {
{ "unit_db", "volume_db" }, // AudioStreamPlayer3D
{ "unit_offset", "progress_ratio" }, // PathFollow2D, PathFollow3D
{ "vseparation", "v_separation" }, // Theme
- { "frames", "sprite_frames" }, // AnimatedSprite2D, AnimatedSprite3D
+ // { "frames", "sprite_frames" }, // AnimatedSprite2D, AnimatedSprite3D -- GH-73696
{ nullptr, nullptr },
};
diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
index 16e58172b2..09e8bf4cc7 100644
--- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
+++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj
@@ -14,7 +14,6 @@
1FF8DBB11FBA9DE1009DE660 /* dummy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */; };
D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D07CD44D1C5D589C00B7FB28 /* Images.xcassets */; };
9039D3BE24C093AC0020482C /* MoltenVK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9039D3BD24C093AC0020482C /* MoltenVK.xcframework */; };
- 9073252C24BF980B0063BCD4 /* vulkan in Resources */ = {isa = PBXBuildFile; fileRef = 905036DC24BF932E00301046 /* vulkan */; };
D0BCFE4618AEBDA2004A7AAE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE4418AEBDA2004A7AAE /* InfoPlist.strings */; };
D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */ = {isa = PBXBuildFile; fileRef = D0BCFE7718AEBFEB004A7AAE /* $binary.pck */; };
$pbx_launch_screen_build_reference
@@ -42,7 +41,6 @@
1FF4C1881F584E6300A41E41 /* $binary.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "$binary.entitlements"; sourceTree = "<group>"; };
1FF8DBB01FBA9DE1009DE660 /* dummy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dummy.cpp; sourceTree = "<group>"; };
9039D3BD24C093AC0020482C /* MoltenVK.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MoltenVK; path = MoltenVK.xcframework; sourceTree = "<group>"; };
- 905036DC24BF932E00301046 /* vulkan */ = {isa = PBXFileReference; lastKnownFileType = folder; name = vulkan; path = "$binary/vulkan"; sourceTree = "<group>"; };
D07CD44D1C5D589C00B7FB28 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
D0BCFE3418AEBDA2004A7AAE /* $binary.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "$binary.app"; sourceTree = BUILT_PRODUCTS_DIR; };
D0BCFE4318AEBDA2004A7AAE /* $binary-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "$binary-Info.plist"; sourceTree = "<group>"; };
@@ -72,7 +70,6 @@
D0BCFE2B18AEBDA2004A7AAE = {
isa = PBXGroup;
children = (
- 905036DC24BF932E00301046 /* vulkan */,
1F1575711F582BE20003B888 /* dylibs */,
D0BCFE7718AEBFEB004A7AAE /* $binary.pck */,
D0BCFE4118AEBDA2004A7AAE /* $binary */,
@@ -185,7 +182,6 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 9073252C24BF980B0063BCD4 /* vulkan in Resources */,
D07CD44E1C5D589C00B7FB28 /* Images.xcassets in Resources */,
D0BCFE7818AEBFEB004A7AAE /* $binary.pck in Resources */,
$pbx_launch_screen_build_phase
diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp
index f19228cb18..ad70772270 100644
--- a/modules/cvtt/image_compress_cvtt.cpp
+++ b/modules/cvtt/image_compress_cvtt.cpp
@@ -30,8 +30,8 @@
#include "image_compress_cvtt.h"
+#include "core/object/worker_thread_pool.h"
#include "core/os/os.h"
-#include "core/os/thread.h"
#include "core/string/print_string.h"
#include "core/templates/safe_refcount.h"
@@ -129,6 +129,18 @@ static void _digest_row_task(const CVTTCompressionJobParams &p_job_params, const
}
}
+static void _digest_job_queue(void *p_job_queue, uint32_t p_index) {
+ CVTTCompressionJobQueue *job_queue = static_cast<CVTTCompressionJobQueue *>(p_job_queue);
+ uint32_t num_tasks = job_queue->num_tasks;
+ uint32_t total_threads = WorkerThreadPool::get_singleton()->get_thread_count();
+ uint32_t start = p_index * num_tasks / total_threads;
+ uint32_t end = (p_index + 1 == total_threads) ? num_tasks : ((p_index + 1) * num_tasks / total_threads);
+
+ for (uint32_t i = start; i < end; i++) {
+ _digest_row_task(job_queue->job_params, job_queue->job_tasks[i]);
+ }
+}
+
void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) {
if (p_image->get_format() >= Image::FORMAT_BPTC_RGBA) {
return; //do not compress, already compressed
@@ -220,7 +232,7 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) {
row_task.in_mm_bytes = in_bytes;
row_task.out_mm_bytes = out_bytes;
- _digest_row_task(job_queue.job_params, row_task);
+ tasks.push_back(row_task);
out_bytes += 16 * (bw / 4);
}
@@ -230,6 +242,13 @@ void image_compress_cvtt(Image *p_image, Image::UsedChannels p_channels) {
h = MAX(h / 2, 1);
}
+ const CVTTCompressionRowTask *tasks_rb = tasks.ptr();
+
+ job_queue.job_tasks = &tasks_rb[0];
+ job_queue.num_tasks = static_cast<uint32_t>(tasks.size());
+ WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&_digest_job_queue, &job_queue, WorkerThreadPool::get_singleton()->get_thread_count(), -1, true, SNAME("CVTT Compress"));
+ WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
+
p_image->set_data(p_image->get_width(), p_image->get_height(), p_image->has_mipmaps(), target_format, data);
}
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 08c8763493..045505b720 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -126,6 +126,20 @@
<param index="0" name="value" type="Variant" />
<param index="1" name="type" type="Variant" />
<description>
+ Returns [code]true[/code] if [param value] is an instance of [param type]. The [param type] value must be one of the following:
+ - A constant from the [enum Variant.Type] enumeration, for example [constant TYPE_INT].
+ - An [Object]-derived class which exists in [ClassDB], for example [Node].
+ - A [Script] (you can use any class, including inner one).
+ Unlike the right operand of the [code]is[/code] operator, [param type] can be a non-constant value. The [code]is[/code] operator supports more features (such as typed arrays) and is more performant. Use the operator instead of this method if you do not need dynamic type checking.
+ Examples:
+ [codeblock]
+ print(is_instance_of(a, TYPE_INT))
+ print(is_instance_of(a, Node))
+ print(is_instance_of(a, MyClass))
+ print(is_instance_of(a, MyClass.InnerClass))
+ [/codeblock]
+ [b]Note:[/b] If [param value] and/or [param type] are freed objects (see [method @GlobalScope.is_instance_valid]), or [param type] is not one of the above options, this method will raise an runtime error.
+ See also [method @GlobalScope.typeof], [method type_exists], [method Array.is_same_typed] (and other [Array] methods).
</description>
</method>
<method name="len">
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 38f9163f70..5ce01a08bf 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -657,6 +657,10 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
} else if (ProjectSettings::get_singleton()->has_autoload(first) && ProjectSettings::get_singleton()->get_autoload(first).is_singleton) {
const ProjectSettings::AutoloadInfo &autoload = ProjectSettings::get_singleton()->get_autoload(first);
Ref<GDScriptParserRef> ref = get_parser_for(autoload.path);
+ if (ref.is_null()) {
+ push_error(vformat(R"(The referenced autoload "%s" (from "%s") could not be loaded.)", first, autoload.path), p_type);
+ return bad_type;
+ }
if (ref->raise_status(GDScriptParserRef::INHERITANCE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse singleton "%s" from "%s".)", first, autoload.path), p_type);
return bad_type;
@@ -727,7 +731,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
}
}
if (!result.is_set()) {
- push_error(vformat(R"("%s" was not found in the current scope.)", first), p_type);
+ push_error(vformat(R"(Could not find type "%s" in the current scope.)", first), p_type);
return bad_type;
}
@@ -1534,6 +1538,7 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
// Check if the function signature matches the parent. If not it's an error since it breaks polymorphism.
// Not for the constructor which can vary in signature.
GDScriptParser::DataType base_type = parser->current_class->base_type;
+ base_type.is_meta_type = false;
GDScriptParser::DataType parent_return_type;
List<GDScriptParser::DataType> parameters_types;
int default_par_count = 0;
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index a13bf8009f..5b092e3691 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -581,7 +581,8 @@ void GDScriptByteCodeGenerator::write_unary_operator(const Address &p_target, Va
}
void GDScriptByteCodeGenerator::write_binary_operator(const Address &p_target, Variant::Operator p_operator, const Address &p_left_operand, const Address &p_right_operand) {
- if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand)) {
+ // Avoid validated evaluator for modulo and division when operands are int, since there's no check for division by zero.
+ if (HAS_BUILTIN_TYPE(p_left_operand) && HAS_BUILTIN_TYPE(p_right_operand) && ((p_operator != Variant::OP_DIVIDE && p_operator != Variant::OP_MODULE) || p_left_operand.type.builtin_type != Variant::INT || p_right_operand.type.builtin_type != Variant::INT)) {
if (p_target.mode == Address::TEMPORARY) {
Variant::Type result_type = Variant::get_operator_return_type(p_operator, p_left_operand.type.builtin_type, p_right_operand.type.builtin_type);
Variant::Type temp_type = temporaries[p_target.address].type;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index efa75528fc..35c9946bc1 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -2265,13 +2265,15 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type, p_script);
+ int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type];
+ p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
+ ERR_FAIL_COND_V(p_script->native.is_null(), ERR_BUG);
+
// Inheritance
switch (base_type.kind) {
- case GDScriptDataType::NATIVE: {
- int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type];
- p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
- ERR_FAIL_COND_V(p_script->native.is_null(), ERR_BUG);
- } break;
+ case GDScriptDataType::NATIVE:
+ // Nothing more to do.
+ break;
case GDScriptDataType::GDSCRIPT: {
Ref<GDScript> base = Ref<GDScript>(base_type.script_type);
if (base.is_null()) {
@@ -2303,7 +2305,6 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
p_script->base = base;
p_script->_base = base.ptr();
p_script->member_indices = base->member_indices;
- p_script->native = base->native;
} break;
default: {
_set_error("Parser bug: invalid inheritance.", nullptr);
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index ba400b8e15..83d2ed6010 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -1326,28 +1326,30 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_BREAK;
}
- ScriptInstance *scr_inst = val_obj->get_script_instance();
- if (!scr_inst) {
- err_text = "Trying to assign value of type '" + val_obj->get_class_name() +
- "' to a variable of type '" + base_type->get_path().get_file() + "'.";
- OPCODE_BREAK;
- }
+ if (val_obj) { // src is not null
+ ScriptInstance *scr_inst = val_obj->get_script_instance();
+ if (!scr_inst) {
+ err_text = "Trying to assign value of type '" + val_obj->get_class_name() +
+ "' to a variable of type '" + base_type->get_path().get_file() + "'.";
+ OPCODE_BREAK;
+ }
- Script *src_type = val_obj->get_script_instance()->get_script().ptr();
- bool valid = false;
+ Script *src_type = scr_inst->get_script().ptr();
+ bool valid = false;
- while (src_type) {
- if (src_type == base_type) {
- valid = true;
- break;
+ while (src_type) {
+ if (src_type == base_type) {
+ valid = true;
+ break;
+ }
+ src_type = src_type->get_base_script().ptr();
}
- src_type = src_type->get_base_script().ptr();
- }
- if (!valid) {
- err_text = "Trying to assign value of type '" + val_obj->get_script_instance()->get_script()->get_path().get_file() +
- "' to a variable of type '" + base_type->get_path().get_file() + "'.";
- OPCODE_BREAK;
+ if (!valid) {
+ err_text = "Trying to assign value of type '" + val_obj->get_script_instance()->get_script()->get_path().get_file() +
+ "' to a variable of type '" + base_type->get_path().get_file() + "'.";
+ OPCODE_BREAK;
+ }
}
}
#endif // DEBUG_ENABLED
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.gd
new file mode 100644
index 0000000000..1644295b38
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.gd
@@ -0,0 +1,3 @@
+func test():
+ var foo: Foo
+ print('not ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.out b/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.out
new file mode 100644
index 0000000000..3f6c2d868d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/not_found_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Could not find type "Foo" in the current scope.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.gd b/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.gd
new file mode 100644
index 0000000000..6c056530f6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.gd
@@ -0,0 +1,10 @@
+func test():
+ print("ok")
+
+# https://github.com/godotengine/godot/issues/71994
+class A:
+ extends RefCounted
+class B:
+ extends A
+ func duplicate():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.out b/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.out
new file mode 100644
index 0000000000..1b47ed10dc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/inheritance_signature_check_no_meta.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+ok
diff --git a/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.gd b/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.gd
new file mode 100644
index 0000000000..1b47680a7b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.gd
@@ -0,0 +1,18 @@
+extends Node
+
+class LocalClass extends Node:
+ pass
+
+func test():
+ var typed: LocalClass = get_node_or_null("does_not_exist")
+ var untyped = null
+ var node_1: LocalClass = typed
+ var node_2: LocalClass = untyped
+ var node_3 = typed
+ var node_4 = untyped
+ print(typed)
+ print(untyped)
+ print(node_1)
+ print(node_2)
+ print(node_3)
+ print(node_4)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.out b/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.out
new file mode 100644
index 0000000000..d66b72f5c3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/script_typed_assign_null.out
@@ -0,0 +1,7 @@
+GDTEST_OK
+<Object#null>
+<null>
+<Object#null>
+<null>
+<Object#null>
+<null>
diff --git a/modules/multiplayer/scene_replication_config.cpp b/modules/multiplayer/scene_replication_config.cpp
index c8621e7357..f8006228de 100644
--- a/modules/multiplayer/scene_replication_config.cpp
+++ b/modules/multiplayer/scene_replication_config.cpp
@@ -114,6 +114,8 @@ void SceneReplicationConfig::add_property(const NodePath &p_path, int p_index) {
if (p_index < 0 || p_index == properties.size()) {
properties.push_back(ReplicationProperty(p_path));
+ sync_props.push_back(p_path);
+ spawn_props.push_back(p_path);
return;
}
@@ -126,6 +128,16 @@ void SceneReplicationConfig::add_property(const NodePath &p_path, int p_index) {
c++;
}
properties.insert_before(I, ReplicationProperty(p_path));
+ sync_props.clear();
+ spawn_props.clear();
+ for (const ReplicationProperty &prop : properties) {
+ if (prop.sync) {
+ sync_props.push_back(p_path);
+ }
+ if (prop.spawn) {
+ spawn_props.push_back(p_path);
+ }
+ }
}
void SceneReplicationConfig::remove_property(const NodePath &p_path) {
diff --git a/platform/android/export/gradle_export_util.cpp b/platform/android/export/gradle_export_util.cpp
index b889d58199..61f8c5574b 100644
--- a/platform/android/export/gradle_export_util.cpp
+++ b/platform/android/export/gradle_export_util.cpp
@@ -305,6 +305,9 @@ String _get_activity_tag(const Ref<EditorExportPreset> &p_preset, bool p_uses_xr
" <!-- OpenXR category tag to indicate the activity starts in an immersive OpenXR mode. \n"
" See https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#android-runtime-category. -->\n"
" <category android:name=\"org.khronos.openxr.intent.category.IMMERSIVE_HMD\" />\n"
+ "\n"
+ " <!-- Enable VR access on HTC Vive Focus devices. -->\n"
+ " <category android:name=\"com.htc.intent.category.VRAPP\" />\n"
" </intent-filter>\n";
} else {
manifest_activity_text += " <intent-filter>\n"
diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
index 71385315ae..42ef1436f3 100644
--- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
+++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt
@@ -40,6 +40,7 @@ import android.util.Log
import android.widget.Toast
import androidx.window.layout.WindowMetricsCalculator
import org.godotengine.godot.FullScreenGodotApp
+import org.godotengine.godot.GodotLib
import org.godotengine.godot.utils.PermissionsUtil
import org.godotengine.godot.utils.ProcessPhoenix
import java.util.*
@@ -90,11 +91,19 @@ open class GodotEditor : FullScreenGodotApp() {
}
super.onCreate(savedInstanceState)
+ }
+
+ override fun onGodotSetupCompleted() {
+ super.onGodotSetupCompleted()
+ val longPressEnabled = enableLongPressGestures()
+ val panScaleEnabled = enablePanAndScaleGestures()
- // Enable long press, panning and scaling gestures
- godotFragment?.renderView?.inputHandler?.apply {
- enableLongPress(enableLongPressGestures())
- enablePanningAndScalingGestures(enablePanAndScaleGestures())
+ runOnUiThread {
+ // Enable long press, panning and scaling gestures
+ godotFragment?.renderView?.inputHandler?.apply {
+ enableLongPress(longPressEnabled)
+ enablePanningAndScalingGestures(panScaleEnabled)
+ }
}
}
@@ -210,12 +219,14 @@ open class GodotEditor : FullScreenGodotApp() {
/**
* Enable long press gestures for the Godot Android editor.
*/
- protected open fun enableLongPressGestures() = true
+ protected open fun enableLongPressGestures() =
+ java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_long_press_as_right_click"))
/**
* Enable pan and scale gestures for the Godot Android editor.
*/
- protected open fun enablePanAndScaleGestures() = true
+ protected open fun enablePanAndScaleGestures() =
+ java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_pan_and_scale_gestures"))
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index 75a01dc787..d9aab950df 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -190,6 +190,13 @@ public class GodotLib {
public static native String getGlobal(String p_key);
/**
+ * Used to access Godot's editor settings.
+ * @param settingKey Setting key
+ * @return String value of the setting
+ */
+ public static native String getEditorSetting(String settingKey);
+
+ /**
* Invoke method |p_method| on the Godot object specified by |p_id|
* @param p_id Id of the Godot object to invoke
* @param p_method Name of the method to invoke
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index e7abe580f1..1a0087e18d 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -57,6 +57,10 @@
#include <android/native_window_jni.h>
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif
+
static JavaClassWrapper *java_class_wrapper = nullptr;
static OS_Android *os_android = nullptr;
static AndroidInputHandler *input_handler = nullptr;
@@ -427,6 +431,18 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *
return env->NewStringUTF(GLOBAL_GET(js).operator String().utf8().get_data());
}
+JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getEditorSetting(JNIEnv *env, jclass clazz, jstring p_setting_key) {
+ String editor_setting = "";
+#ifdef TOOLS_ENABLED
+ String godot_setting_key = jstring_to_string(p_setting_key, env);
+ editor_setting = EDITOR_GET(godot_setting_key).operator String();
+#else
+ WARN_PRINT("Access to the Editor Settings in only available on Editor builds");
+#endif
+
+ return env->NewStringUTF(editor_setting.utf8().get_data());
+}
+
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) {
Object *obj = ObjectDB::get_instance(ObjectID(ID));
ERR_FAIL_NULL(obj);
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index 0020ddffd2..59ab2448d7 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -61,6 +61,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jclass clazz);
JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path);
+JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getEditorSetting(JNIEnv *env, jclass clazz, jstring p_setting_key);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height);
diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp
index 6b8584ef6c..ce0199e87f 100644
--- a/platform/linuxbsd/tts_linux.cpp
+++ b/platform/linuxbsd/tts_linux.cpp
@@ -35,11 +35,6 @@
TTS_Linux *TTS_Linux::singleton = nullptr;
-void TTS_Linux::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_speech_event", "msg_id", "client_id", "type"), &TTS_Linux::_speech_event);
- ClassDB::bind_method(D_METHOD("_speech_index_mark", "msg_id", "client_id", "type", "index_mark"), &TTS_Linux::_speech_index_mark);
-}
-
void TTS_Linux::speech_init_thread_func(void *p_userdata) {
TTS_Linux *tts = (TTS_Linux *)p_userdata;
if (tts) {
@@ -82,7 +77,7 @@ void TTS_Linux::speech_init_thread_func(void *p_userdata) {
void TTS_Linux::speech_event_index_mark(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type, char *p_index_mark) {
TTS_Linux *tts = TTS_Linux::get_singleton();
if (tts) {
- tts->call_deferred(SNAME("_speech_index_mark"), p_msg_id, p_client_id, (int)p_type, String::utf8(p_index_mark));
+ callable_mp(tts, &TTS_Linux::_speech_index_mark).call_deferred(p_msg_id, p_client_id, (int)p_type, String::utf8(p_index_mark));
}
}
@@ -97,7 +92,7 @@ void TTS_Linux::_speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_ty
void TTS_Linux::speech_event_callback(size_t p_msg_id, size_t p_client_id, SPDNotificationType p_type) {
TTS_Linux *tts = TTS_Linux::get_singleton();
if (tts) {
- tts->call_deferred(SNAME("_speech_event"), p_msg_id, p_client_id, (int)p_type);
+ callable_mp(tts, &TTS_Linux::_speech_event).call_deferred(p_msg_id, p_client_id, (int)p_type);
}
}
diff --git a/platform/linuxbsd/tts_linux.h b/platform/linuxbsd/tts_linux.h
index 3fcbe3207b..4134f8fa2f 100644
--- a/platform/linuxbsd/tts_linux.h
+++ b/platform/linuxbsd/tts_linux.h
@@ -46,7 +46,6 @@
#endif
class TTS_Linux : public Object {
- GDCLASS(TTS_Linux, Object);
_THREAD_SAFE_CLASS_
List<DisplayServer::TTSUtterance> queue;
@@ -65,7 +64,6 @@ class TTS_Linux : public Object {
static TTS_Linux *singleton;
protected:
- static void _bind_methods();
void _speech_event(size_t p_msg_id, size_t p_client_id, int p_type);
void _speech_index_mark(size_t p_msg_id, size_t p_client_id, int p_type, const String &p_index_mark);
diff --git a/platform/linuxbsd/x11/key_mapping_x11.cpp b/platform/linuxbsd/x11/key_mapping_x11.cpp
index e5eba6ccad..f21c151288 100644
--- a/platform/linuxbsd/x11/key_mapping_x11.cpp
+++ b/platform/linuxbsd/x11/key_mapping_x11.cpp
@@ -217,8 +217,8 @@ void KeyMappingX11::initialize() {
scancode_map[0x1F] = Key::I;
scancode_map[0x20] = Key::O;
scancode_map[0x21] = Key::P;
- scancode_map[0x22] = Key::BRACELEFT;
- scancode_map[0x23] = Key::BRACERIGHT;
+ scancode_map[0x22] = Key::BRACKETLEFT;
+ scancode_map[0x23] = Key::BRACKETRIGHT;
scancode_map[0x24] = Key::ENTER;
scancode_map[0x25] = Key::CTRL;
scancode_map[0x26] = Key::A;
diff --git a/platform/macos/key_mapping_macos.mm b/platform/macos/key_mapping_macos.mm
index 31b71ac1b8..c3f147e33f 100644
--- a/platform/macos/key_mapping_macos.mm
+++ b/platform/macos/key_mapping_macos.mm
@@ -98,10 +98,10 @@ void KeyMappingMacOS::initialize() {
keysym_map[0x1b] = Key::MINUS;
keysym_map[0x1c] = Key::KEY_8;
keysym_map[0x1d] = Key::KEY_0;
- keysym_map[0x1e] = Key::BRACERIGHT;
+ keysym_map[0x1e] = Key::BRACKETRIGHT;
keysym_map[0x1f] = Key::O;
keysym_map[0x20] = Key::U;
- keysym_map[0x21] = Key::BRACELEFT;
+ keysym_map[0x21] = Key::BRACKETLEFT;
keysym_map[0x22] = Key::I;
keysym_map[0x23] = Key::P;
keysym_map[0x24] = Key::ENTER;
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index d2889a3442..92af3fef69 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -4237,7 +4237,7 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
window_position = screen_get_position(p_screen) + (screen_get_size(p_screen) - p_resolution) / 2;
}
- WindowID main_window = _create_window(p_mode, p_vsync_mode, 0, Rect2i(window_position, p_resolution));
+ WindowID main_window = _create_window(p_mode, p_vsync_mode, p_flags, Rect2i(window_position, p_resolution));
ERR_FAIL_COND_MSG(main_window == INVALID_WINDOW_ID, "Failed to create main window.");
joypad = new JoypadWindows(&windows[MAIN_WINDOW_ID].hWnd);
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 4107a8a17e..22297f4c29 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -490,6 +490,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
return FAILED;
}
#else
+ int id_type = 1;
if (p_preset->get("codesign/identity") != "") {
args.push_back("-pkcs12");
args.push_back(p_preset->get("codesign/identity"));
@@ -500,7 +501,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
#endif
//password
- if (p_preset->get("codesign/password") != "") {
+ if ((id_type == 1) && (p_preset->get("codesign/password") != "")) {
#ifdef WINDOWS_ENABLED
args.push_back("/p");
#else
@@ -574,7 +575,7 @@ Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_p
String str;
Error err = OS::get_singleton()->execute(signtool_path, args, &str, nullptr, true);
if (err != OK || (str.find("not found") != -1) || (str.find("not recognized") != -1)) {
-#ifndef WINDOWS_ENABLED
+#ifdef WINDOWS_ENABLED
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start signtool executable. Configure signtool path in the Editor Settings (Export > Windows > signtool), or disable \"Codesign\" in the export preset."));
#else
add_message(EXPORT_MESSAGE_WARNING, TTR("Code Signing"), TTR("Could not start osslsigncode executable. Configure signtool path in the Editor Settings (Export > Windows > osslsigncode), or disable \"Codesign\" in the export preset."));
diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp
index d43f74126d..aa393464b6 100644
--- a/platform/windows/key_mapping_windows.cpp
+++ b/platform/windows/key_mapping_windows.cpp
@@ -257,8 +257,8 @@ void KeyMappingWindows::initialize() {
scansym_map[0x17] = Key::I;
scansym_map[0x18] = Key::O;
scansym_map[0x19] = Key::P;
- scansym_map[0x1A] = Key::BRACELEFT;
- scansym_map[0x1B] = Key::BRACERIGHT;
+ scansym_map[0x1A] = Key::BRACKETLEFT;
+ scansym_map[0x1B] = Key::BRACKETRIGHT;
scansym_map[0x1C] = Key::ENTER;
scansym_map[0x1D] = Key::CTRL;
scansym_map[0x1E] = Key::A;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index b861d7af01..59f7511894 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -86,7 +86,7 @@ int Label::get_line_height(int p_line) const {
}
}
-bool Label::_shape() {
+void Label::_shape() {
Ref<StyleBox> style = theme_cache.normal_style;
int width = (get_size().width - style->get_minimum_size().width);
@@ -101,7 +101,7 @@ bool Label::_shape() {
}
const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
- ERR_FAIL_COND_V(font.is_null(), true);
+ ERR_FAIL_COND(font.is_null());
String txt = (uppercase) ? TS->string_to_upper(xl_text, language) : xl_text;
if (visible_chars >= 0 && visible_chars_behavior == TextServer::VC_CHARS_BEFORE_SHAPING) {
txt = txt.substr(0, visible_chars);
@@ -121,7 +121,6 @@ bool Label::_shape() {
dirty = false;
font_dirty = false;
lines_dirty = true;
- // Note for future maintainers: forgetting stable width here (e.g., setting it to -1) may fix still undiscovered bugs.
}
if (lines_dirty) {
@@ -129,143 +128,126 @@ bool Label::_shape() {
TS->free_rid(lines_rid[i]);
}
lines_rid.clear();
- }
-
- Size2i prev_minsize = minsize;
- minsize = Size2();
- bool can_process_lines = false;
- if (xl_text.length() == 0) {
- can_process_lines = true;
- lines_dirty = false;
- } else {
- // With autowrap on or off with trimming enabled, we won't compute the minimum size until width is stable
- // (two shape requests in a row with the same width.) This avoids situations in which the initial width is
- // very narrow and the label would break text into many very short lines, causing a very tall label that can
- // leave a deformed container. In the remaining case (namely, autowrap off and no trimming), the label is
- // free to dictate its own width, something that will be taken advtantage of.
- bool can_dictate_width = autowrap_mode == TextServer::AUTOWRAP_OFF && overrun_behavior == TextServer::OVERRUN_NO_TRIMMING;
- bool is_width_stable = get_size().width == stable_width;
- can_process_lines = can_dictate_width || is_width_stable;
- stable_width = get_size().width;
-
- if (can_process_lines) {
- if (lines_dirty) {
- BitField<TextServer::LineBreakFlag> autowrap_flags = TextServer::BREAK_MANDATORY;
- switch (autowrap_mode) {
- case TextServer::AUTOWRAP_WORD_SMART:
- autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE | TextServer::BREAK_MANDATORY;
- break;
- case TextServer::AUTOWRAP_WORD:
- autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY;
- break;
- case TextServer::AUTOWRAP_ARBITRARY:
- autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY;
- break;
- case TextServer::AUTOWRAP_OFF:
- break;
- }
- autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES;
+ BitField<TextServer::LineBreakFlag> autowrap_flags = TextServer::BREAK_MANDATORY;
+ switch (autowrap_mode) {
+ case TextServer::AUTOWRAP_WORD_SMART:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_WORD:
+ autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_ARBITRARY:
+ autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY;
+ break;
+ case TextServer::AUTOWRAP_OFF:
+ break;
+ }
+ autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES;
- PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
- for (int i = 0; i < line_breaks.size(); i = i + 2) {
- RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
- lines_rid.push_back(line);
- }
- }
+ PackedInt32Array line_breaks = TS->shaped_text_get_line_breaks(text_rid, width, 0, autowrap_flags);
+ for (int i = 0; i < line_breaks.size(); i = i + 2) {
+ RID line = TS->shaped_text_substr(text_rid, line_breaks[i], line_breaks[i + 1] - line_breaks[i]);
+ lines_rid.push_back(line);
+ }
+ }
- if (can_dictate_width) {
- for (int i = 0; i < lines_rid.size(); i++) {
- if (minsize.width < TS->shaped_text_get_size(lines_rid[i]).x) {
- minsize.width = TS->shaped_text_get_size(lines_rid[i]).x;
- }
- }
+ if (xl_text.length() == 0) {
+ minsize = Size2(1, get_line_height());
+ return;
+ }
- width = (minsize.width - style->get_minimum_size().width);
+ if (autowrap_mode == TextServer::AUTOWRAP_OFF) {
+ minsize.width = 0.0f;
+ for (int i = 0; i < lines_rid.size(); i++) {
+ if (minsize.width < TS->shaped_text_get_size(lines_rid[i]).x) {
+ minsize.width = TS->shaped_text_get_size(lines_rid[i]).x;
}
+ }
+ }
- if (lines_dirty) {
- BitField<TextServer::TextOverrunFlag> overrun_flags = TextServer::OVERRUN_NO_TRIM;
- switch (overrun_behavior) {
- case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
- overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
- overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
- overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
- break;
- case TextServer::OVERRUN_TRIM_ELLIPSIS:
- overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
- overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
- break;
- case TextServer::OVERRUN_TRIM_WORD:
- overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
- overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
- break;
- case TextServer::OVERRUN_TRIM_CHAR:
- overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
- break;
- case TextServer::OVERRUN_NO_TRIMMING:
- break;
- }
+ if (lines_dirty) {
+ BitField<TextServer::TextOverrunFlag> overrun_flags = TextServer::OVERRUN_NO_TRIM;
+ switch (overrun_behavior) {
+ case TextServer::OVERRUN_TRIM_WORD_ELLIPSIS:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
+ break;
+ case TextServer::OVERRUN_TRIM_ELLIPSIS:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_ADD_ELLIPSIS);
+ break;
+ case TextServer::OVERRUN_TRIM_WORD:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM_WORD_ONLY);
+ break;
+ case TextServer::OVERRUN_TRIM_CHAR:
+ overrun_flags.set_flag(TextServer::OVERRUN_TRIM);
+ break;
+ case TextServer::OVERRUN_NO_TRIMMING:
+ break;
+ }
- // Fill after min_size calculation.
+ // Fill after min_size calculation.
- int visible_lines = lines_rid.size();
- if (max_lines_visible >= 0 && visible_lines > max_lines_visible) {
- visible_lines = max_lines_visible;
- }
- if (autowrap_mode != TextServer::AUTOWRAP_OFF) {
- bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
- if (lines_hidden) {
- overrun_flags.set_flag(TextServer::OVERRUN_ENFORCE_ELLIPSIS);
- }
- if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- for (int i = 0; i < lines_rid.size(); i++) {
- if (i < visible_lines - 1 || lines_rid.size() == 1) {
- TS->shaped_text_fit_to_width(lines_rid[i], width);
- } else if (i == (visible_lines - 1)) {
- TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
- }
- }
- } else if (lines_hidden) {
+ if (autowrap_mode != TextServer::AUTOWRAP_OFF) {
+ int visible_lines = get_visible_line_count();
+ bool lines_hidden = visible_lines > 0 && visible_lines < lines_rid.size();
+ if (lines_hidden) {
+ overrun_flags.set_flag(TextServer::OVERRUN_ENFORCE_ELLIPSIS);
+ }
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ for (int i = 0; i < lines_rid.size(); i++) {
+ if (i < visible_lines - 1 || lines_rid.size() == 1) {
+ TS->shaped_text_fit_to_width(lines_rid[i], width);
+ } else if (i == (visible_lines - 1)) {
TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
}
- } else {
- // Autowrap disabled.
- for (int i = 0; i < lines_rid.size(); i++) {
- if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
- TS->shaped_text_fit_to_width(lines_rid[i], width);
- overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE);
- TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
- TS->shaped_text_fit_to_width(lines_rid[i], width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
- } else {
- TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
- }
- }
- }
-
- int last_line = MIN(lines_rid.size(), visible_lines + lines_skipped);
- int line_spacing = settings.is_valid() ? settings->get_line_spacing() : theme_cache.line_spacing;
- for (int64_t i = lines_skipped; i < last_line; i++) {
- minsize.height += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing;
}
-
- lines_dirty = false;
+ } else if (lines_hidden) {
+ TS->shaped_text_overrun_trim_to_width(lines_rid[visible_lines - 1], width, overrun_flags);
}
} else {
- callable_mp(this, &Label::_shape).call_deferred();
+ // Autowrap disabled.
+ for (int i = 0; i < lines_rid.size(); i++) {
+ if (horizontal_alignment == HORIZONTAL_ALIGNMENT_FILL) {
+ TS->shaped_text_fit_to_width(lines_rid[i], width);
+ overrun_flags.set_flag(TextServer::OVERRUN_JUSTIFICATION_AWARE);
+ TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
+ TS->shaped_text_fit_to_width(lines_rid[i], width, TextServer::JUSTIFICATION_WORD_BOUND | TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_CONSTRAIN_ELLIPSIS);
+ } else {
+ TS->shaped_text_overrun_trim_to_width(lines_rid[i], width, overrun_flags);
+ }
+ }
}
+ lines_dirty = false;
}
- if (draw_pending) {
- queue_redraw();
- draw_pending = false;
- }
+ _update_visible();
- if (minsize != prev_minsize) {
+ if (autowrap_mode == TextServer::AUTOWRAP_OFF || !clip || overrun_behavior == TextServer::OVERRUN_NO_TRIMMING) {
update_minimum_size();
}
+}
+
+void Label::_update_visible() {
+ int line_spacing = settings.is_valid() ? settings->get_line_spacing() : theme_cache.line_spacing;
+ Ref<StyleBox> style = theme_cache.normal_style;
+ int lines_visible = lines_rid.size();
- return can_process_lines;
+ if (max_lines_visible >= 0 && lines_visible > max_lines_visible) {
+ lines_visible = max_lines_visible;
+ }
+
+ minsize.height = 0;
+ int last_line = MIN(lines_rid.size(), lines_visible + lines_skipped);
+ for (int64_t i = lines_skipped; i < last_line; i++) {
+ minsize.height += TS->shaped_text_get_size(lines_rid[i]).y + line_spacing;
+ if (minsize.height > (get_size().height - style->get_minimum_size().height + line_spacing)) {
+ break;
+ }
+ }
}
inline void draw_glyph(const Glyph &p_gl, const RID &p_canvas, const Color &p_font_color, const Vector2 &p_ofs) {
@@ -375,11 +357,7 @@ void Label::_notification(int p_what) {
}
if (dirty || font_dirty || lines_dirty) {
- if (!_shape()) {
- // There will be another pass.
- draw_pending = true;
- break;
- }
+ _shape();
}
RID ci = get_canvas_item();
@@ -622,8 +600,6 @@ void Label::_notification(int p_what) {
}
ofs.y += TS->shaped_text_get_descent(lines_rid[i]) + vsep + line_spacing;
}
-
- draw_pending = false;
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -915,7 +891,7 @@ void Label::set_lines_skipped(int p_lines) {
}
lines_skipped = p_lines;
- lines_dirty = true;
+ _update_visible();
queue_redraw();
}
@@ -929,7 +905,7 @@ void Label::set_max_lines_visible(int p_lines) {
}
max_lines_visible = p_lines;
- lines_dirty = true;
+ _update_visible();
queue_redraw();
}
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 36b85f7af8..2350525236 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -46,7 +46,6 @@ private:
bool clip = false;
TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_NO_TRIMMING;
Size2 minsize;
- real_t stable_width = -1;
bool uppercase = false;
bool lines_dirty = true;
@@ -65,7 +64,6 @@ private:
float visible_ratio = 1.0;
int lines_skipped = 0;
int max_lines_visible = -1;
- bool draw_pending = false;
Ref<LabelSettings> settings;
@@ -83,7 +81,8 @@ private:
int font_shadow_outline_size;
} theme_cache;
- bool _shape();
+ void _update_visible();
+ void _shape();
void _invalidate();
protected:
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 973b02b3a3..44478d45cc 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -1165,7 +1165,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (ul_started) {
ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width);
}
if (_find_hint(it, nullptr) && underline_hint) {
@@ -1178,7 +1178,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (dot_ul_started) {
dot_ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, MAX(2.0, underline_width * 2));
}
if (_find_strikethrough(it)) {
@@ -1191,7 +1191,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
} else if (st_started) {
st_started = false;
float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width);
}
@@ -1334,19 +1334,19 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (ul_started) {
ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width);
}
if (dot_ul_started) {
dot_ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, MAX(2.0, underline_width * 2));
}
if (st_started) {
st_started = false;
float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width);
}
}
@@ -1356,19 +1356,19 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
if (ul_started) {
ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_line(ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), ul_color, underline_width);
}
if (dot_ul_started) {
dot_ul_started = false;
float y_off = TS->shaped_text_get_underline_position(rid);
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_dashed_line(dot_ul_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), dot_ul_color, underline_width, MAX(2.0, underline_width * 2));
}
if (st_started) {
st_started = false;
float y_off = -TS->shaped_text_get_ascent(rid) + TS->shaped_text_get_size(rid).y / 2;
- float underline_width = TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale;
+ float underline_width = MAX(1.0, TS->shaped_text_get_underline_thickness(rid) * theme_cache.base_scale);
draw_line(st_start + Vector2(0, y_off), p_ofs + Vector2(off.x, off.y + y_off), st_color, underline_width);
}
// Draw foreground color box
diff --git a/scene/resources/sprite_frames.cpp b/scene/resources/sprite_frames.cpp
index 818be38681..17aaf579dd 100644
--- a/scene/resources/sprite_frames.cpp
+++ b/scene/resources/sprite_frames.cpp
@@ -201,6 +201,7 @@ void SpriteFrames::_set_animations(const Array &p_animations) {
anim.loop = d["loop"];
Array frames = d["frames"];
for (int j = 0; j < frames.size(); j++) {
+#ifndef DISABLE_DEPRECATED
// For compatibility.
Ref<Resource> res = frames[j];
if (res.is_valid()) {
@@ -208,6 +209,7 @@ void SpriteFrames::_set_animations(const Array &p_animations) {
anim.frames.push_back(frame);
continue;
}
+#endif
Dictionary f = frames[j];
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index d4b2be355e..efe04ce4e1 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -2527,6 +2527,11 @@ void TileSet::reset_state() {
while (!source_ids.is_empty()) {
remove_source(source_ids[0]);
}
+
+ tile_shape = TILE_SHAPE_SQUARE;
+ tile_layout = TILE_LAYOUT_STACKED;
+ tile_offset_axis = TILE_OFFSET_AXIS_HORIZONTAL;
+ tile_size = Size2i(16, 16);
}
const Vector2i TileSetSource::INVALID_ATLAS_COORDS = Vector2i(-1, -1);
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index ad25629a1c..d62bac8570 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -308,7 +308,6 @@ private:
TileLayout tile_layout = TILE_LAYOUT_STACKED;
TileOffsetAxis tile_offset_axis = TILE_OFFSET_AXIS_HORIZONTAL;
Size2i tile_size = Size2i(16, 16); //Size2(64, 64);
- Vector2 tile_skew = Vector2(0, 0);
// Rendering.
bool uv_clipping = false;
diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp
index 069b51feaa..a6083fe70d 100644
--- a/servers/rendering/renderer_compositor.cpp
+++ b/servers/rendering/renderer_compositor.cpp
@@ -35,6 +35,8 @@
#include "core/string/print_string.h"
#include "servers/xr_server.h"
+RendererCompositor *RendererCompositor::singleton = nullptr;
+
RendererCompositor *(*RendererCompositor::_create_func)() = nullptr;
bool RendererCompositor::low_end = false;
@@ -47,6 +49,8 @@ bool RendererCompositor::is_xr_enabled() const {
}
RendererCompositor::RendererCompositor() {
+ singleton = this;
+
if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
xr_enabled = GLOBAL_GET("xr/shaders/enabled");
} else {
diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h
index 9fb79a290b..ff7792741c 100644
--- a/servers/rendering/renderer_compositor.h
+++ b/servers/rendering/renderer_compositor.h
@@ -70,6 +70,7 @@ struct BlitToScreen {
class RendererCompositor {
private:
bool xr_enabled = false;
+ static RendererCompositor *singleton;
protected:
static RendererCompositor *(*_create_func)();
@@ -107,6 +108,7 @@ public:
static bool is_low_end() { return low_end; };
virtual bool is_xr_enabled() const;
+ static RendererCompositor *get_singleton() { return singleton; }
RendererCompositor();
virtual ~RendererCompositor() {}
};
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index bcea9225ea..86484c982a 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -110,7 +110,7 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
copy_to_fb.shader.initialize(copy_modes);
- if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
copy_to_fb.shader.set_variant_enabled(COPY_TO_FB_MULTIVIEW, false);
copy_to_fb.shader.set_variant_enabled(COPY_TO_FB_MULTIVIEW_WITH_DEPTH, false);
}
@@ -266,7 +266,7 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) {
specular_merge.shader.initialize(specular_modes);
- if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
specular_merge.shader.set_variant_enabled(SPECULAR_MERGE_ADD_MULTIVIEW, false);
specular_merge.shader.set_variant_enabled(SPECULAR_MERGE_SSR_MULTIVIEW, false);
specular_merge.shader.set_variant_enabled(SPECULAR_MERGE_ADDITIVE_ADD_MULTIVIEW, false);
diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp
index 7b152b524f..821960bb3b 100644
--- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp
+++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp
@@ -56,7 +56,7 @@ ToneMapper::ToneMapper() {
tonemap.shader.initialize(tonemap_modes);
- if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
tonemap.shader.set_variant_enabled(TONEMAP_MODE_NORMAL_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_BICUBIC_GLOW_FILTER_MULTIVIEW, false);
tonemap.shader.set_variant_enabled(TONEMAP_MODE_1D_LUT_MULTIVIEW, false);
diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp
index 4bc5d7b597..6ec8612029 100644
--- a/servers/rendering/renderer_rd/effects/vrs.cpp
+++ b/servers/rendering/renderer_rd/effects/vrs.cpp
@@ -44,7 +44,7 @@ VRS::VRS() {
vrs_shader.shader.initialize(vrs_modes);
- if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
vrs_shader.shader.set_variant_enabled(VRS_MULTIVIEW, false);
}
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 7fff349b3c..788ec1cee4 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -276,7 +276,7 @@ void SkyRD::ReflectionData::update_reflection_data(int p_size, int p_mipmaps, bo
int mipmaps = p_mipmaps;
uint32_t w = p_size, h = p_size;
- EffectsRD *effects = RendererCompositorRD::singleton->get_effects();
+ EffectsRD *effects = RendererCompositorRD::get_singleton()->get_effects();
ERR_FAIL_NULL_MSG(effects, "Effects haven't been initialized");
bool prefer_raster_effects = effects->get_prefer_raster_effects();
@@ -756,7 +756,7 @@ void SkyRD::init() {
sky_shader.shader.initialize(sky_modes, defines);
- if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
sky_shader.shader.set_variant_enabled(SKY_VERSION_BACKGROUND_MULTIVIEW, false);
sky_shader.shader.set_variant_enabled(SKY_VERSION_HALF_RES_MULTIVIEW, false);
sky_shader.shader.set_variant_enabled(SKY_VERSION_QUARTER_RES_MULTIVIEW, false);
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 6d5e55ee6a..e0128bfe25 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -2865,10 +2865,13 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::LightStorage *light_storage = RendererRD::LightStorage::get_singleton();
+ bool is_multiview = false;
+
Ref<RenderSceneBuffersRD> rb; // handy for not having to fully type out p_render_data->render_buffers all the time...
Ref<RenderBufferDataForwardClustered> rb_data;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
rb = p_render_data->render_buffers;
+ is_multiview = rb->get_view_count() > 1;
if (rb->has_custom_data(RB_SCOPE_FORWARD_CLUSTERED)) {
// Our forward clustered custom data buffer will only be available when we're rendering our normal view.
// This will not be available when rendering reflection probes.
@@ -3011,7 +3014,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) {
texture = rb->get_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH);
} else {
- texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
+ texture = texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
}
u.append_id(texture);
uniforms.push_back(u);
@@ -3021,7 +3024,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 11;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID bbt = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
- RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -3030,7 +3033,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 12;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
+ RID texture = rb_data.is_valid() && rb_data->has_normal_roughness() ? rb_data->get_normal_roughness() : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_NORMAL : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_NORMAL);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -3040,7 +3043,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 13;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID aot = rb.is_valid() && rb->has_texture(RB_SCOPE_SSAO, RB_FINAL) ? rb->get_texture(RB_SCOPE_SSAO, RB_FINAL) : RID();
- RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = aot.is_valid() ? aot : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -3049,7 +3052,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 14;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_AMBIENT) : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -3058,7 +3061,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
RD::Uniform u;
u.binding = 15;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = rb_data.is_valid() && rb->has_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) ? rb->get_texture(RB_SCOPE_GI, RB_TEX_REFLECTION) : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
@@ -3126,7 +3129,7 @@ RID RenderForwardClustered::_setup_render_pass_uniform_set(RenderListType p_rend
u.binding = 20;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
RID ssil = rb.is_valid() && rb->has_texture(RB_SCOPE_SSIL, RB_FINAL) ? rb->get_texture(RB_SCOPE_SSIL, RB_FINAL) : RID();
- RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = ssil.is_valid() ? ssil : texture_storage->texture_rd_get_default(is_multiview ? RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK : RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
u.append_id(texture);
uniforms.push_back(u);
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 3b3979b198..ff180b5465 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -504,7 +504,7 @@ void SceneShaderForwardClustered::init(const String p_defines) {
shader.initialize(shader_versions, p_defines);
- if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_MULTIVIEW, false);
shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_MULTIVIEW, false);
shader.set_variant_enabled(SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI_MULTIVIEW, false);
@@ -730,7 +730,7 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.global_buffer_array_variable = "global_shader_uniforms.data";
actions.instance_uniform_index_variable = "instances.data[instance_index_interp].instance_uniforms_ofs";
- actions.check_multiview_samplers = true; // make sure we check sampling multiview textures
+ actions.check_multiview_samplers = RendererCompositorRD::get_singleton()->is_xr_enabled(); // Make sure we check sampling multiview textures.
compiler.initialize(actions);
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 45fe067a6f..6c39560729 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -358,10 +358,13 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
//there should always be enough uniform buffers for render passes, otherwise bugs
ERR_FAIL_INDEX_V(p_index, (int)scene_state.uniform_buffers.size(), RID());
+ bool is_multiview = false;
+
Ref<RenderBufferDataForwardMobile> rb_data;
Ref<RenderSceneBuffersRD> rb;
if (p_render_data && p_render_data->render_buffers.is_valid()) {
rb = p_render_data->render_buffers;
+ is_multiview = rb->get_view_count() > 1;
if (rb->has_custom_data(RB_SCOPE_MOBILE)) {
// Our forward mobile custom data buffer will only be available when we're rendering our normal view.
// This will not be available when rendering reflection probes.
@@ -495,6 +498,8 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RID texture;
if (rb.is_valid() && rb->has_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH)) {
texture = rb->get_texture(RB_SCOPE_BUFFERS, RB_TEX_BACK_DEPTH);
+ } else if (is_multiview) {
+ texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH);
} else {
texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_DEPTH);
}
@@ -505,8 +510,14 @@ RID RenderForwardMobile::_setup_render_pass_uniform_set(RenderListType p_render_
RD::Uniform u;
u.binding = 10;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- RID bbt = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
- RID texture = bbt.is_valid() ? bbt : texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ RID texture = rb_data.is_valid() ? rb->get_back_buffer_texture() : RID();
+ if (texture.is_null()) {
+ if (is_multiview) {
+ texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH);
+ } else {
+ texture = texture_storage->texture_rd_get_default(RendererRD::TextureStorage::DEFAULT_RD_TEXTURE_BLACK);
+ }
+ }
u.append_id(texture);
uniforms.push_back(u);
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index cc4a7dfa47..0e992eb965 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -421,7 +421,7 @@ void SceneShaderForwardMobile::init(const String p_defines) {
shader.initialize(shader_versions, p_defines);
- if (!RendererCompositorRD::singleton->is_xr_enabled()) {
+ if (!RendererCompositorRD::get_singleton()->is_xr_enabled()) {
shader.set_variant_enabled(SHADER_VERSION_COLOR_PASS_MULTIVIEW, false);
shader.set_variant_enabled(SHADER_VERSION_LIGHTMAP_COLOR_PASS_MULTIVIEW, false);
shader.set_variant_enabled(SHADER_VERSION_SHADOW_PASS_MULTIVIEW, false);
@@ -610,7 +610,7 @@ void SceneShaderForwardMobile::init(const String p_defines) {
actions.instance_uniform_index_variable = "draw_call.instance_uniforms_ofs";
actions.apply_luminance_multiplier = true; // apply luminance multiplier to screen texture
- actions.check_multiview_samplers = true; // make sure we check sampling multiview textures
+ actions.check_multiview_samplers = RendererCompositorRD::get_singleton()->is_xr_enabled(); // Make sure we check sampling multiview textures.
compiler.initialize(actions);
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index f102bc0650..78bdd3f541 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -919,7 +919,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
} break;
case Item::Command::TYPE_ANIMATION_SLICE: {
const Item::CommandAnimationSlice *as = static_cast<const Item::CommandAnimationSlice *>(c);
- double current_time = RendererCompositorRD::singleton->get_total_time();
+ double current_time = RendererCompositorRD::get_singleton()->get_total_time();
double local_time = Math::fposmod(current_time - as->offset, as->animation_length);
skipping = !(local_time >= as->slice_begin && local_time < as->slice_end);
@@ -1252,13 +1252,12 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
l = l->next_ptr;
ERR_CONTINUE(!clight);
}
- Transform2D to_light_xform = (p_canvas_transform * l->light_shader_xform).affine_inverse();
Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
state.light_uniforms[index].position[0] = canvas_light_pos.x;
state.light_uniforms[index].position[1] = canvas_light_pos.y;
- _update_transform_2d_to_mat2x4(to_light_xform, state.light_uniforms[index].matrix);
+ _update_transform_2d_to_mat2x4(l->light_shader_xform.affine_inverse(), state.light_uniforms[index].matrix);
_update_transform_2d_to_mat2x4(l->xform_cache.affine_inverse(), state.light_uniforms[index].shadow_matrix);
state.light_uniforms[index].height = l->height * (p_canvas_transform.columns[0].length() + p_canvas_transform.columns[1].length()) * 0.5; //approximate height conversion to the canvas size, since all calculations are done in canvas coords to avoid precision loss
diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h
index 43c8d78dee..eae4327908 100644
--- a/servers/rendering/renderer_rd/renderer_compositor_rd.h
+++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h
@@ -101,6 +101,7 @@ protected:
double delta = 0.0;
static uint64_t frame;
+ static RendererCompositorRD *singleton;
public:
RendererUtilities *get_utilities() { return utilities; };
@@ -145,7 +146,7 @@ public:
low_end = false;
}
- static RendererCompositorRD *singleton;
+ static RendererCompositorRD *get_singleton() { return singleton; }
RendererCompositorRD();
~RendererCompositorRD();
};
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
index ffaa6872c9..58efc68bc7 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
@@ -307,8 +307,8 @@ void generate_SSAO_shadows_internal(out float r_shadow_term, out vec4 r_edges, o
// edge mask for between this and left/right/top/bottom neighbor pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge)
vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0);
- // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats
- pix_center_pos *= 0.9992;
+ // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer.
+ pix_center_pos *= 0.99;
if (!p_adaptive_base && (p_quality_level >= SSAO_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) {
edgesLRTB = calculate_edges(pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z);
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
index de7b97953f..fac13b0e3f 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
@@ -321,8 +321,8 @@ void generate_SSIL(out vec3 r_color, out vec4 r_edges, out float r_obscurance, o
// edge mask for between this and left/right/top/bottom neighbor pixels - not used in quality level 0 so initialize to "no edge" (1 is no edge, 0 is edge)
vec4 edgesLRTB = vec4(1.0, 1.0, 1.0, 1.0);
- // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer; a lot smaller offsets needed when using 32bit floats
- pix_center_pos *= 0.9992;
+ // Move center pixel slightly towards camera to avoid imprecision artifacts due to using of 16bit depth buffer.
+ pix_center_pos *= 0.99;
if (!p_adaptive_base && (p_quality_level >= SSIL_DEPTH_BASED_EDGES_ENABLE_AT_QUALITY_PRESET)) {
edgesLRTB = calculate_edges(pix_z, pix_left_z, pix_right_z, pix_top_z, pix_bottom_z);
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 00fb8acca8..3ed5d7dda8 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -774,7 +774,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
p_particles->phase = new_phase;
- frame_params.time = RendererCompositorRD::singleton->get_total_time();
+ frame_params.time = RendererCompositorRD::get_singleton()->get_total_time();
frame_params.delta = p_delta * p_particles->speed_scale;
frame_params.random_seed = p_particles->random_seed;
frame_params.explosiveness = p_particles->explosiveness;
@@ -1228,7 +1228,7 @@ void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p
RD::get_singleton()->compute_list_dispatch_threads(compute_list, particles->amount, 1, 1);
RD::get_singleton()->compute_list_end();
- RendererCompositorRD::singleton->get_effects()->sort_buffer(particles->particles_sort_uniform_set, particles->amount);
+ RendererCompositorRD::get_singleton()->get_effects()->sort_buffer(particles->particles_sort_uniform_set, particles->amount);
}
if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) {
@@ -1341,7 +1341,7 @@ void ParticlesStorage::update_particles() {
particles->inactive = false;
particles->inactive_time = 0;
} else {
- particles->inactive_time += particles->speed_scale * RendererCompositorRD::singleton->get_frame_delta_time();
+ particles->inactive_time += particles->speed_scale * RendererCompositorRD::get_singleton()->get_frame_delta_time();
if (particles->inactive_time > particles->lifetime * 1.2) {
particles->inactive = true;
continue;
@@ -1442,7 +1442,7 @@ void ParticlesStorage::update_particles() {
frame_time = 1.0 / fixed_fps;
decr = frame_time;
}
- double delta = RendererCompositorRD::singleton->get_frame_delta_time();
+ double delta = RendererCompositorRD::get_singleton()->get_frame_delta_time();
if (delta > 0.1) { //avoid recursive stalls if fps goes below 10
delta = 0.1;
} else if (delta <= 0.0) { //unlikely but..
@@ -1461,7 +1461,7 @@ void ParticlesStorage::update_particles() {
if (zero_time_scale) {
_particles_process(particles, 0.0);
} else {
- _particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time());
+ _particles_process(particles, RendererCompositorRD::get_singleton()->get_frame_delta_time());
}
}
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index f5d6404f01..e1dc9f8624 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -486,6 +486,11 @@ Ref<RenderBufferCustomDataRD> RenderSceneBuffersRD::get_custom_data(const String
// Depth texture
bool RenderSceneBuffersRD::has_depth_texture() {
+ if (render_target.is_null()) {
+ // not applicable when there is no render target (likely this is for a reflection probe)
+ return false;
+ }
+
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RID depth = texture_storage->render_target_get_override_depth(render_target);
if (depth.is_valid()) {
@@ -496,6 +501,11 @@ bool RenderSceneBuffersRD::has_depth_texture() {
}
RID RenderSceneBuffersRD::get_depth_texture() {
+ if (render_target.is_null()) {
+ // not applicable when there is no render target (likely this is for a reflection probe)
+ return RID();
+ }
+
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RID depth = texture_storage->render_target_get_override_depth(render_target);
if (depth.is_valid()) {
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 0ee9b28826..50b324a9fd 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -362,7 +362,7 @@ TextureStorage::TextureStorage() {
}
}
- { //create default array
+ { //create default array white
RD::TextureFormat tformat;
tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
@@ -388,6 +388,82 @@ TextureStorage::TextureStorage() {
}
}
+ { //create default array black
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.array_layers = 1;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+
+ Vector<uint8_t> pv;
+ pv.resize(16 * 4);
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 0);
+ pv.set(i * 4 + 1, 0);
+ pv.set(i * 4 + 2, 0);
+ pv.set(i * 4 + 3, 0);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+ }
+
+ { //create default array normal
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.array_layers = 1;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT;
+ tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+
+ Vector<uint8_t> pv;
+ pv.resize(16 * 4);
+ for (int i = 0; i < 16; i++) {
+ pv.set(i * 4 + 0, 128);
+ pv.set(i * 4 + 1, 128);
+ pv.set(i * 4 + 2, 255);
+ pv.set(i * 4 + 3, 255);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vpv;
+ vpv.push_back(pv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_NORMAL] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv);
+ }
+ }
+
+ { //create default array depth
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_D16_UNORM;
+ tformat.width = 4;
+ tformat.height = 4;
+ tformat.array_layers = 1;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_UPDATE_BIT | RD::TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
+ tformat.texture_type = RD::TEXTURE_TYPE_2D_ARRAY;
+
+ Vector<uint8_t> sv;
+ sv.resize(16 * 2);
+ uint16_t *ptr = (uint16_t *)sv.ptrw();
+ for (int i = 0; i < 16; i++) {
+ ptr[i] = Math::make_half_float(1.0f);
+ }
+
+ {
+ Vector<Vector<uint8_t>> vsv;
+ vsv.push_back(sv);
+ default_rd_textures[DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vsv);
+ }
+ }
+
{ // default atlas texture
RD::TextureFormat tformat;
tformat.format = RD::DATA_FORMAT_R8G8B8A8_UNORM;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index c16f5274ad..b6bb9fa52f 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -62,6 +62,9 @@ public:
DEFAULT_RD_TEXTURE_3D_WHITE,
DEFAULT_RD_TEXTURE_3D_BLACK,
DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE,
+ DEFAULT_RD_TEXTURE_2D_ARRAY_BLACK,
+ DEFAULT_RD_TEXTURE_2D_ARRAY_NORMAL,
+ DEFAULT_RD_TEXTURE_2D_ARRAY_DEPTH,
DEFAULT_RD_TEXTURE_2D_UINT,
DEFAULT_RD_TEXTURE_VRS,
DEFAULT_RD_TEXTURE_MAX
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 0e2a3c682d..f609fa6023 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -349,7 +349,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
Transform2D scale;
scale.scale(cl->rect_cache.size);
scale.columns[2] = cl->rect_cache.position;
- cl->light_shader_xform = cl->xform * scale;
+ cl->light_shader_xform = xf * cl->xform * scale;
if (cl->use_shadow) {
cl->shadows_next_ptr = lights_with_shadow;
if (lights_with_shadow == nullptr) {
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 940363a7e8..958e960ab2 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -33,6 +33,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/templates/local_vector.h"
+#include "servers/rendering/renderer_compositor.h"
#include "servers/rendering_server.h"
#include "shader_types.h"
@@ -3055,7 +3056,7 @@ const ShaderLanguage::BuiltinFuncConstArgs ShaderLanguage::builtin_func_const_ar
bool ShaderLanguage::is_const_suffix_lut_initialized = false;
-bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) {
+bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function) {
ERR_FAIL_COND_V(p_func->op != OP_CALL && p_func->op != OP_CONSTRUCT, false);
Vector<DataType> args;
@@ -3479,6 +3480,9 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI
}
}
+ if (r_is_custom_function) {
+ *r_is_custom_function = true;
+ }
return true;
}
}
@@ -5251,7 +5255,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
return nullptr;
}
- if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name)) {
+ bool is_custom_func = false;
+ if (!_validate_function_call(p_block, p_function_info, func, &func->return_cache, &func->struct_name, &is_custom_func)) {
_set_error(vformat(RTR("No matching function found for: '%s'."), String(funcname->name)));
return nullptr;
}
@@ -5391,6 +5396,16 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
//being sampler, this either comes from a uniform
ShaderNode::Uniform *u = &shader->uniforms[varname];
ERR_CONTINUE(u->type != call_function->arguments[i].type); //this should have been validated previously
+
+ if (RendererCompositor::get_singleton()->is_xr_enabled() && is_custom_func) {
+ ShaderNode::Uniform::Hint hint = u->hint;
+
+ if (hint == ShaderNode::Uniform::HINT_DEPTH_TEXTURE || hint == ShaderNode::Uniform::HINT_SCREEN_TEXTURE || hint == ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) {
+ _set_error(vformat(RTR("Unable to pass a multiview texture sampler as a parameter to custom function. Consider to sample it in the main function and then pass the vector result to it."), get_uniform_hint_name(hint)));
+ return nullptr;
+ }
+ }
+
//propagate
if (!_propagate_function_call_sampler_uniform_settings(name, i, u->filter, u->repeat)) {
return nullptr;
diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h
index aea61e42c3..220160e5fd 100644
--- a/servers/rendering/shader_language.h
+++ b/servers/rendering/shader_language.h
@@ -1088,7 +1088,7 @@ private:
bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b);
bool _compare_datatypes_in_nodes(Node *a, Node *b);
- bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str);
+ bool _validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str, bool *r_is_custom_function = nullptr);
bool _parse_function_arguments(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, int *r_complete_arg = nullptr);
bool _propagate_function_call_sampler_uniform_settings(StringName p_name, int p_argument, TextureFilter p_filter, TextureRepeat p_repeat);
bool _propagate_function_call_sampler_builtin_reference(StringName p_name, int p_argument, const StringName &p_builtin);
diff --git a/thirdparty/README.md b/thirdparty/README.md
index f883a3a6da..92e0a91596 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -70,6 +70,11 @@ Files extracted from upstream source:
- all .cpp, .h, and .txt files except the folders MakeTables and etc2packer.
+Changes related to BC6H packing and unpacking made upstream in
+https://github.com/elasota/cvtt/commit/2e4b6b2747aec11f4cc6dd09ef43fa8ce769f6e2
+have been removed as they caused massive quality regressions. Apply the patches
+in the `patches/` folder when syncing on newer upstream commits.
+
## doctest
diff --git a/thirdparty/cvtt/ConvectionKernels_BC67.cpp b/thirdparty/cvtt/ConvectionKernels_BC67.cpp
index 021d658c08..011f51570b 100644
--- a/thirdparty/cvtt/ConvectionKernels_BC67.cpp
+++ b/thirdparty/cvtt/ConvectionKernels_BC67.cpp
@@ -76,6 +76,205 @@ namespace cvtt
};
}
+ namespace BC6HData
+ {
+ enum EField
+ {
+ NA, // N/A
+ M, // Mode
+ D, // Shape
+ RW,
+ RX,
+ RY,
+ RZ,
+ GW,
+ GX,
+ GY,
+ GZ,
+ BW,
+ BX,
+ BY,
+ BZ,
+ };
+
+ struct ModeDescriptor
+ {
+ EField m_eField;
+ uint8_t m_uBit;
+ };
+
+ const ModeDescriptor g_modeDescriptors[14][82] =
+ {
+ { // Mode 1 (0x00) - 10 5 5 5
+ { M, 0 },{ M, 1 },{ GY, 4 },{ BY, 4 },{ BZ, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 2 (0x01) - 7 6 6 6
+ { M, 0 },{ M, 1 },{ GY, 5 },{ GZ, 4 },{ GZ, 5 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ BZ, 0 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ BY, 5 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BZ, 3 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 3 (0x02) - 11 5 4 4
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RW,10 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,10 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,10 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 4 (0x06) - 11 4 5 4
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,10 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GW,10 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,10 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ BZ, 0 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ GY, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 5 (0x0a) - 11 4 4 5
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,10 },
+ { BY, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,10 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BW,10 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ BZ, 1 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ BZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 6 (0x0e) - 9 5 5 5
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 7 (0x12) - 8 6 5 5
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ GZ, 4 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BZ, 3 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 8 (0x16) - 8 5 6 5
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ BZ, 0 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GY, 5 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ GZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 9 (0x1a) - 8 5 5 6
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ BY, 5 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 10 (0x1e) - 6 6 6 6
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ GZ, 4 },{ BZ, 0 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GY, 5 },{ BY, 5 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ GZ, 5 },{ BZ, 3 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
+ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
+ { D, 3 },{ D, 4 },
+ },
+
+ { // Mode 11 (0x03) - 10 10
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RX, 8 },{ RX, 9 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GX, 8 },{ GX, 9 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BX, 8 },{ BX, 9 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },
+ },
+
+ { // Mode 12 (0x07) - 11 9
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RX, 8 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GX, 8 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BX, 8 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },
+ },
+
+ { // Mode 13 (0x0b) - 12 8
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
+ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RW,11 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
+ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GW,11 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
+ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BW,11 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },
+ },
+
+ { // Mode 14 (0x0f) - 16 4
+ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
+ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
+ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
+ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,15 },
+ { RW,14 },{ RW,13 },{ RW,12 },{ RW,11 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,15 },
+ { GW,14 },{ GW,13 },{ GW,12 },{ GW,11 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,15 },
+ { BW,14 },{ BW,13 },{ BW,12 },{ BW,11 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
+ { NA, 0 },{ NA, 0 },
+ },
+ };
+ }
+
namespace BC7Data
{
enum AlphaMode
@@ -2998,9 +3197,9 @@ void cvtt::Internal::BC6HComputer::Pack(uint32_t flags, const PixelBlockF16* inp
const BC7Data::BC6HModeInfo& modeInfo = BC7Data::g_hdrModes[mode];
- BC6H_IO::WriteFunc_t writeFunc = BC6H_IO::g_writeFuncs[mode];
+ const BC6HData::ModeDescriptor *desc = BC6HData::g_modeDescriptors[mode];
- const int headerBits = modeInfo.m_partitioned ? 82 : 65;
+ const size_t headerBits = modeInfo.m_partitioned ? 82 : 65;
for (int subset = 0; subset < 2; subset++)
{
@@ -3017,16 +3216,58 @@ void cvtt::Internal::BC6HComputer::Pack(uint32_t flags, const PixelBlockF16* inp
uint16_t modeID = modeInfo.m_modeID;
PackingVector pv;
+ pv.Init();
- {
- uint32_t header[3];
- writeFunc(header, modeID, partition,
- eps[0][0][0], eps[0][1][0], eps[1][0][0], eps[1][1][0],
- eps[0][0][1], eps[0][1][1], eps[1][0][1], eps[1][1][1],
- eps[0][0][2], eps[0][1][2], eps[1][0][2], eps[1][1][2]
- );
-
- pv.InitPacked(header, headerBits);
+ for (size_t i = 0; i < headerBits; i++) {
+ int32_t codedValue = 0;
+ switch (desc[i].m_eField) {
+ case BC6HData::M:
+ codedValue = modeID;
+ break;
+ case BC6HData::D:
+ codedValue = partition;
+ break;
+ case BC6HData::RW:
+ codedValue = eps[0][0][0];
+ break;
+ case BC6HData::RX:
+ codedValue = eps[0][1][0];
+ break;
+ case BC6HData::RY:
+ codedValue = eps[1][0][0];
+ break;
+ case BC6HData::RZ:
+ codedValue = eps[1][1][0];
+ break;
+ case BC6HData::GW:
+ codedValue = eps[0][0][1];
+ break;
+ case BC6HData::GX:
+ codedValue = eps[0][1][1];
+ break;
+ case BC6HData::GY:
+ codedValue = eps[1][0][1];
+ break;
+ case BC6HData::GZ:
+ codedValue = eps[1][1][1];
+ break;
+ case BC6HData::BW:
+ codedValue = eps[0][0][2];
+ break;
+ case BC6HData::BX:
+ codedValue = eps[0][1][2];
+ break;
+ case BC6HData::BY:
+ codedValue = eps[1][0][2];
+ break;
+ case BC6HData::BZ:
+ codedValue = eps[1][1][2];
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ pv.Pack(static_cast<uint16_t>((codedValue >> desc[i].m_uBit) & 1), 1);
}
int fixupIndex1 = 0;
@@ -3058,11 +3299,14 @@ void cvtt::Internal::BC6HComputer::SignExtendSingle(int &v, int bits)
void cvtt::Internal::BC6HComputer::UnpackOne(PixelBlockF16 &output, const uint8_t *pBC, bool isSigned)
{
+ UnpackingVector pv;
+ pv.Init(pBC);
+
int numModeBits = 2;
- int modeBits = pBC[0] & 0x3;
+ int modeBits = pv.Unpack(2);
if (modeBits != 0 && modeBits != 1)
{
- modeBits = pBC[0] & 0x1f;
+ modeBits |= pv.Unpack(3) << 2;
numModeBits += 3;
}
@@ -3088,10 +3332,10 @@ void cvtt::Internal::BC6HComputer::UnpackOne(PixelBlockF16 &output, const uint8_
}
const BC7Data::BC6HModeInfo& modeInfo = BC7Data::g_hdrModes[mode];
- const int headerBits = modeInfo.m_partitioned ? 82 : 65;
- const BC6H_IO::ReadFunc_t readFunc = BC6H_IO::g_readFuncs[mode];
+ const size_t headerBits = modeInfo.m_partitioned ? 82 : 65;
+ const BC6HData::ModeDescriptor *desc = BC6HData::g_modeDescriptors[mode];
- uint16_t partition = 0;
+ int32_t partition = 0;
int32_t eps[2][2][3];
for (int subset = 0; subset < 2; subset++)
@@ -3099,24 +3343,55 @@ void cvtt::Internal::BC6HComputer::UnpackOne(PixelBlockF16 &output, const uint8_
for (int ch = 0; ch < 3; ch++)
eps[subset][epi][ch] = 0;
- UnpackingVector pv;
- pv.Init(pBC);
-
- {
- uint32_t header[3];
- uint16_t codedEPs[2][2][3];
- pv.UnpackStart(header, headerBits);
+ for (size_t i = numModeBits; i < headerBits; i++) {
+ int32_t *pCodedValue = NULL;
- readFunc(header, partition,
- codedEPs[0][0][0], codedEPs[0][1][0], codedEPs[1][0][0], codedEPs[1][1][0],
- codedEPs[0][0][1], codedEPs[0][1][1], codedEPs[1][0][1], codedEPs[1][1][1],
- codedEPs[0][0][2], codedEPs[0][1][2], codedEPs[1][0][2], codedEPs[1][1][2]
- );
+ switch (desc[i].m_eField) {
+ case BC6HData::D:
+ pCodedValue = &partition;
+ break;
+ case BC6HData::RW:
+ pCodedValue = &eps[0][0][0];
+ break;
+ case BC6HData::RX:
+ pCodedValue = &eps[0][1][0];
+ break;
+ case BC6HData::RY:
+ pCodedValue = &eps[1][0][0];
+ break;
+ case BC6HData::RZ:
+ pCodedValue = &eps[1][1][0];
+ break;
+ case BC6HData::GW:
+ pCodedValue = &eps[0][0][1];
+ break;
+ case BC6HData::GX:
+ pCodedValue = &eps[0][1][1];
+ break;
+ case BC6HData::GY:
+ pCodedValue = &eps[1][0][1];
+ break;
+ case BC6HData::GZ:
+ pCodedValue = &eps[1][1][1];
+ break;
+ case BC6HData::BW:
+ pCodedValue = &eps[0][0][2];
+ break;
+ case BC6HData::BX:
+ pCodedValue = &eps[0][1][2];
+ break;
+ case BC6HData::BY:
+ pCodedValue = &eps[1][0][2];
+ break;
+ case BC6HData::BZ:
+ pCodedValue = &eps[1][1][2];
+ break;
+ default:
+ assert(false);
+ break;
+ }
- for (int subset = 0; subset < 2; subset++)
- for (int epi = 0; epi < 2; epi++)
- for (int ch = 0; ch < 3; ch++)
- eps[subset][epi][ch] = codedEPs[subset][epi][ch];
+ (*pCodedValue) |= pv.Unpack(1) << desc[i].m_uBit;
}
uint16_t modeID = modeInfo.m_modeID;
diff --git a/thirdparty/cvtt/patches/revert_BC6H_reorg.patch b/thirdparty/cvtt/patches/revert_BC6H_reorg.patch
new file mode 100644
index 0000000000..11f9b9db46
--- /dev/null
+++ b/thirdparty/cvtt/patches/revert_BC6H_reorg.patch
@@ -0,0 +1,393 @@
+diff --git a/thirdparty/cvtt/ConvectionKernels_BC67.cpp b/thirdparty/cvtt/ConvectionKernels_BC67.cpp
+index 021d658c08..011f51570b 100644
+--- a/thirdparty/cvtt/ConvectionKernels_BC67.cpp
++++ b/thirdparty/cvtt/ConvectionKernels_BC67.cpp
+@@ -76,6 +76,205 @@ namespace cvtt
+ };
+ }
+
++ namespace BC6HData
++ {
++ enum EField
++ {
++ NA, // N/A
++ M, // Mode
++ D, // Shape
++ RW,
++ RX,
++ RY,
++ RZ,
++ GW,
++ GX,
++ GY,
++ GZ,
++ BW,
++ BX,
++ BY,
++ BZ,
++ };
++
++ struct ModeDescriptor
++ {
++ EField m_eField;
++ uint8_t m_uBit;
++ };
++
++ const ModeDescriptor g_modeDescriptors[14][82] =
++ {
++ { // Mode 1 (0x00) - 10 5 5 5
++ { M, 0 },{ M, 1 },{ GY, 4 },{ BY, 4 },{ BZ, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
++ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 2 (0x01) - 7 6 6 6
++ { M, 0 },{ M, 1 },{ GY, 5 },{ GZ, 4 },{ GZ, 5 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ BZ, 0 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ BY, 5 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BZ, 3 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
++ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 3 (0x02) - 11 5 4 4
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { RW,10 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,10 },
++ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,10 },
++ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
++ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 4 (0x06) - 11 4 5 4
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,10 },
++ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { GW,10 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,10 },
++ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ BZ, 0 },
++ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ GY, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 5 (0x0a) - 11 4 4 5
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,10 },
++ { BY, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,10 },
++ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BW,10 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ BZ, 1 },
++ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ BZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 6 (0x0e) - 9 5 5 5
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
++ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 7 (0x12) - 8 6 5 5
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ GZ, 4 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BZ, 3 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
++ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 8 (0x16) - 8 5 6 5
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ BZ, 0 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GY, 5 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ GZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BZ, 1 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
++ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 9 (0x1a) - 8 5 5 6
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ BY, 5 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { GZ, 4 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { BZ, 0 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
++ { BZ, 2 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ BZ, 3 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 10 (0x1e) - 6 6 6 6
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ GZ, 4 },{ BZ, 0 },{ BZ, 1 },{ BY, 4 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GY, 5 },{ BY, 5 },{ BZ, 2 },{ GY, 4 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ GZ, 5 },{ BZ, 3 },{ BZ, 5 },{ BZ, 4 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { RX, 5 },{ GY, 0 },{ GY, 1 },{ GY, 2 },{ GY, 3 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { GX, 5 },{ GZ, 0 },{ GZ, 1 },{ GZ, 2 },{ GZ, 3 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BX, 5 },{ BY, 0 },{ BY, 1 },{ BY, 2 },{ BY, 3 },{ RY, 0 },{ RY, 1 },{ RY, 2 },{ RY, 3 },{ RY, 4 },
++ { RY, 5 },{ RZ, 0 },{ RZ, 1 },{ RZ, 2 },{ RZ, 3 },{ RZ, 4 },{ RZ, 5 },{ D, 0 },{ D, 1 },{ D, 2 },
++ { D, 3 },{ D, 4 },
++ },
++
++ { // Mode 11 (0x03) - 10 10
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RX, 8 },{ RX, 9 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GX, 8 },{ GX, 9 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BX, 8 },{ BX, 9 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
++ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
++ { NA, 0 },{ NA, 0 },
++ },
++
++ { // Mode 12 (0x07) - 11 9
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RX, 8 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GX, 8 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BX, 8 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
++ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
++ { NA, 0 },{ NA, 0 },
++ },
++
++ { // Mode 13 (0x0b) - 12 8
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RX, 4 },
++ { RX, 5 },{ RX, 6 },{ RX, 7 },{ RW,11 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GX, 4 },
++ { GX, 5 },{ GX, 6 },{ GX, 7 },{ GW,11 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BX, 4 },
++ { BX, 5 },{ BX, 6 },{ BX, 7 },{ BW,11 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
++ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
++ { NA, 0 },{ NA, 0 },
++ },
++
++ { // Mode 14 (0x0f) - 16 4
++ { M, 0 },{ M, 1 },{ M, 2 },{ M, 3 },{ M, 4 },{ RW, 0 },{ RW, 1 },{ RW, 2 },{ RW, 3 },{ RW, 4 },
++ { RW, 5 },{ RW, 6 },{ RW, 7 },{ RW, 8 },{ RW, 9 },{ GW, 0 },{ GW, 1 },{ GW, 2 },{ GW, 3 },{ GW, 4 },
++ { GW, 5 },{ GW, 6 },{ GW, 7 },{ GW, 8 },{ GW, 9 },{ BW, 0 },{ BW, 1 },{ BW, 2 },{ BW, 3 },{ BW, 4 },
++ { BW, 5 },{ BW, 6 },{ BW, 7 },{ BW, 8 },{ BW, 9 },{ RX, 0 },{ RX, 1 },{ RX, 2 },{ RX, 3 },{ RW,15 },
++ { RW,14 },{ RW,13 },{ RW,12 },{ RW,11 },{ RW,10 },{ GX, 0 },{ GX, 1 },{ GX, 2 },{ GX, 3 },{ GW,15 },
++ { GW,14 },{ GW,13 },{ GW,12 },{ GW,11 },{ GW,10 },{ BX, 0 },{ BX, 1 },{ BX, 2 },{ BX, 3 },{ BW,15 },
++ { BW,14 },{ BW,13 },{ BW,12 },{ BW,11 },{ BW,10 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
++ { NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },{ NA, 0 },
++ { NA, 0 },{ NA, 0 },
++ },
++ };
++ }
++
+ namespace BC7Data
+ {
+ enum AlphaMode
+@@ -2998,9 +3197,9 @@ void cvtt::Internal::BC6HComputer::Pack(uint32_t flags, const PixelBlockF16* inp
+
+ const BC7Data::BC6HModeInfo& modeInfo = BC7Data::g_hdrModes[mode];
+
+- BC6H_IO::WriteFunc_t writeFunc = BC6H_IO::g_writeFuncs[mode];
++ const BC6HData::ModeDescriptor *desc = BC6HData::g_modeDescriptors[mode];
+
+- const int headerBits = modeInfo.m_partitioned ? 82 : 65;
++ const size_t headerBits = modeInfo.m_partitioned ? 82 : 65;
+
+ for (int subset = 0; subset < 2; subset++)
+ {
+@@ -3017,16 +3216,58 @@ void cvtt::Internal::BC6HComputer::Pack(uint32_t flags, const PixelBlockF16* inp
+ uint16_t modeID = modeInfo.m_modeID;
+
+ PackingVector pv;
++ pv.Init();
+
+- {
+- uint32_t header[3];
+- writeFunc(header, modeID, partition,
+- eps[0][0][0], eps[0][1][0], eps[1][0][0], eps[1][1][0],
+- eps[0][0][1], eps[0][1][1], eps[1][0][1], eps[1][1][1],
+- eps[0][0][2], eps[0][1][2], eps[1][0][2], eps[1][1][2]
+- );
+-
+- pv.InitPacked(header, headerBits);
++ for (size_t i = 0; i < headerBits; i++) {
++ int32_t codedValue = 0;
++ switch (desc[i].m_eField) {
++ case BC6HData::M:
++ codedValue = modeID;
++ break;
++ case BC6HData::D:
++ codedValue = partition;
++ break;
++ case BC6HData::RW:
++ codedValue = eps[0][0][0];
++ break;
++ case BC6HData::RX:
++ codedValue = eps[0][1][0];
++ break;
++ case BC6HData::RY:
++ codedValue = eps[1][0][0];
++ break;
++ case BC6HData::RZ:
++ codedValue = eps[1][1][0];
++ break;
++ case BC6HData::GW:
++ codedValue = eps[0][0][1];
++ break;
++ case BC6HData::GX:
++ codedValue = eps[0][1][1];
++ break;
++ case BC6HData::GY:
++ codedValue = eps[1][0][1];
++ break;
++ case BC6HData::GZ:
++ codedValue = eps[1][1][1];
++ break;
++ case BC6HData::BW:
++ codedValue = eps[0][0][2];
++ break;
++ case BC6HData::BX:
++ codedValue = eps[0][1][2];
++ break;
++ case BC6HData::BY:
++ codedValue = eps[1][0][2];
++ break;
++ case BC6HData::BZ:
++ codedValue = eps[1][1][2];
++ break;
++ default:
++ assert(false);
++ break;
++ }
++ pv.Pack(static_cast<uint16_t>((codedValue >> desc[i].m_uBit) & 1), 1);
+ }
+
+ int fixupIndex1 = 0;
+@@ -3058,11 +3299,14 @@ void cvtt::Internal::BC6HComputer::SignExtendSingle(int &v, int bits)
+
+ void cvtt::Internal::BC6HComputer::UnpackOne(PixelBlockF16 &output, const uint8_t *pBC, bool isSigned)
+ {
++ UnpackingVector pv;
++ pv.Init(pBC);
++
+ int numModeBits = 2;
+- int modeBits = pBC[0] & 0x3;
++ int modeBits = pv.Unpack(2);
+ if (modeBits != 0 && modeBits != 1)
+ {
+- modeBits = pBC[0] & 0x1f;
++ modeBits |= pv.Unpack(3) << 2;
+ numModeBits += 3;
+ }
+
+@@ -3088,10 +3332,10 @@ void cvtt::Internal::BC6HComputer::UnpackOne(PixelBlockF16 &output, const uint8_
+ }
+
+ const BC7Data::BC6HModeInfo& modeInfo = BC7Data::g_hdrModes[mode];
+- const int headerBits = modeInfo.m_partitioned ? 82 : 65;
+- const BC6H_IO::ReadFunc_t readFunc = BC6H_IO::g_readFuncs[mode];
++ const size_t headerBits = modeInfo.m_partitioned ? 82 : 65;
++ const BC6HData::ModeDescriptor *desc = BC6HData::g_modeDescriptors[mode];
+
+- uint16_t partition = 0;
++ int32_t partition = 0;
+ int32_t eps[2][2][3];
+
+ for (int subset = 0; subset < 2; subset++)
+@@ -3099,24 +3343,55 @@ void cvtt::Internal::BC6HComputer::UnpackOne(PixelBlockF16 &output, const uint8_
+ for (int ch = 0; ch < 3; ch++)
+ eps[subset][epi][ch] = 0;
+
+- UnpackingVector pv;
+- pv.Init(pBC);
+-
+- {
+- uint32_t header[3];
+- uint16_t codedEPs[2][2][3];
+- pv.UnpackStart(header, headerBits);
++ for (size_t i = numModeBits; i < headerBits; i++) {
++ int32_t *pCodedValue = NULL;
+
+- readFunc(header, partition,
+- codedEPs[0][0][0], codedEPs[0][1][0], codedEPs[1][0][0], codedEPs[1][1][0],
+- codedEPs[0][0][1], codedEPs[0][1][1], codedEPs[1][0][1], codedEPs[1][1][1],
+- codedEPs[0][0][2], codedEPs[0][1][2], codedEPs[1][0][2], codedEPs[1][1][2]
+- );
++ switch (desc[i].m_eField) {
++ case BC6HData::D:
++ pCodedValue = &partition;
++ break;
++ case BC6HData::RW:
++ pCodedValue = &eps[0][0][0];
++ break;
++ case BC6HData::RX:
++ pCodedValue = &eps[0][1][0];
++ break;
++ case BC6HData::RY:
++ pCodedValue = &eps[1][0][0];
++ break;
++ case BC6HData::RZ:
++ pCodedValue = &eps[1][1][0];
++ break;
++ case BC6HData::GW:
++ pCodedValue = &eps[0][0][1];
++ break;
++ case BC6HData::GX:
++ pCodedValue = &eps[0][1][1];
++ break;
++ case BC6HData::GY:
++ pCodedValue = &eps[1][0][1];
++ break;
++ case BC6HData::GZ:
++ pCodedValue = &eps[1][1][1];
++ break;
++ case BC6HData::BW:
++ pCodedValue = &eps[0][0][2];
++ break;
++ case BC6HData::BX:
++ pCodedValue = &eps[0][1][2];
++ break;
++ case BC6HData::BY:
++ pCodedValue = &eps[1][0][2];
++ break;
++ case BC6HData::BZ:
++ pCodedValue = &eps[1][1][2];
++ break;
++ default:
++ assert(false);
++ break;
++ }
+
+- for (int subset = 0; subset < 2; subset++)
+- for (int epi = 0; epi < 2; epi++)
+- for (int ch = 0; ch < 3; ch++)
+- eps[subset][epi][ch] = codedEPs[subset][epi][ch];
++ (*pCodedValue) |= pv.Unpack(1) << desc[i].m_uBit;
+ }
+
+ uint16_t modeID = modeInfo.m_modeID;