diff options
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; |