diff options
686 files changed, 22112 insertions, 10117 deletions
diff --git a/.github/workflows/android_builds.yml b/.github/workflows/android_builds.yml index 68e5575b3b..5cb66a40ab 100644 --- a/.github/workflows/android_builds.yml +++ b/.github/workflows/android_builds.yml @@ -19,6 +19,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: recursive - name: Set up Java 17 uses: actions/setup-java@v4 diff --git a/.github/workflows/godot_cpp_test.yml b/.github/workflows/godot_cpp_test.yml index f352afbc6b..7350920810 100644 --- a/.github/workflows/godot_cpp_test.yml +++ b/.github/workflows/godot_cpp_test.yml @@ -19,6 +19,8 @@ jobs: name: "Build and test Godot CPP" steps: - uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup python and scons uses: ./.github/actions/godot-deps diff --git a/.github/workflows/ios_builds.yml b/.github/workflows/ios_builds.yml index 6557120d87..e205d551ed 100644 --- a/.github/workflows/ios_builds.yml +++ b/.github/workflows/ios_builds.yml @@ -19,6 +19,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Godot build cache uses: ./.github/actions/godot-cache diff --git a/.github/workflows/linux_builds.yml b/.github/workflows/linux_builds.yml index 4cc6d92fb8..0420a02b1d 100644 --- a/.github/workflows/linux_builds.yml +++ b/.github/workflows/linux_builds.yml @@ -86,6 +86,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: recursive # Need newer mesa for lavapipe to work properly. - name: Linux dependencies for tests diff --git a/.github/workflows/macos_builds.yml b/.github/workflows/macos_builds.yml index c245077175..4967fe379f 100644 --- a/.github/workflows/macos_builds.yml +++ b/.github/workflows/macos_builds.yml @@ -34,6 +34,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Godot build cache uses: ./.github/actions/godot-cache diff --git a/.github/workflows/static_checks.yml b/.github/workflows/static_checks.yml index 0d5c1906b5..0ed7432833 100644 --- a/.github/workflows/static_checks.yml +++ b/.github/workflows/static_checks.yml @@ -32,7 +32,7 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | if [ "${{ github.event_name }}" == "pull_request" ]; then - files=$(gh pr diff ${{ github.event.pull_request.number }} --name-only) + files=$(git diff-tree --no-commit-id --name-only -r HEAD^1..HEAD 2> /dev/null || true) elif [ "${{ github.event_name }}" == "push" -a "${{ github.event.forced }}" == "false" -a "${{ github.event.created }}" == "false" ]; then files=$(git diff-tree --no-commit-id --name-only -r ${{ github.event.before }}..${{ github.event.after }} 2> /dev/null || true) fi diff --git a/.github/workflows/web_builds.yml b/.github/workflows/web_builds.yml index a1b7f95cec..47f7e4d458 100644 --- a/.github/workflows/web_builds.yml +++ b/.github/workflows/web_builds.yml @@ -38,6 +38,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: recursive - name: Set up Emscripten latest uses: mymindstorm/setup-emsdk@v14 diff --git a/.github/workflows/windows_builds.yml b/.github/workflows/windows_builds.yml index 18ed92b57f..5443ba20ab 100644 --- a/.github/workflows/windows_builds.yml +++ b/.github/workflows/windows_builds.yml @@ -39,6 +39,8 @@ jobs: steps: - uses: actions/checkout@v4 + with: + submodules: recursive - name: Setup Godot build cache uses: ./.github/actions/godot-cache diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9e9da655cc..7122363f77 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,10 +39,10 @@ repos: entry: python3 misc/scripts/copyright_headers.py exclude: | (?x)^( - tests/python_build.*| .*thirdparty.*| - .*platform/android/java/lib/src/com.*| .*-so_wrap.*| + core/math/bvh_.*\.inc$| + platform/android/java/lib/src/com.*| platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.*| platform/android/java/lib/src/org/godotengine/godot/gl/EGLLogWrapper.*| platform/android/java/lib/src/org/godotengine/godot/utils/ProcessPhoenix.* diff --git a/core/config/engine.cpp b/core/config/engine.cpp index d714ec42c2..9f4bff3779 100644 --- a/core/config/engine.cpp +++ b/core/config/engine.cpp @@ -266,6 +266,12 @@ void Engine::print_header(const String &p_string) const { } } +void Engine::print_header_rich(const String &p_string) const { + if (_print_header) { + print_line_rich(p_string); + } +} + void Engine::add_singleton(const Singleton &p_singleton) { ERR_FAIL_COND_MSG(singleton_ptrs.has(p_singleton.name), vformat("Can't register singleton '%s' because it already exists.", p_singleton.name)); singletons.push_back(p_singleton); diff --git a/core/config/engine.h b/core/config/engine.h index be7cd62f66..d1495b36c2 100644 --- a/core/config/engine.h +++ b/core/config/engine.h @@ -126,6 +126,7 @@ public: void set_print_error_messages(bool p_enabled); bool is_printing_error_messages() const; void print_header(const String &p_string) const; + void print_header_rich(const String &p_string) const; void set_frame_delay(uint32_t p_msec); uint32_t get_frame_delay() const; diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp index ce7fa1074b..14023c5c75 100644 --- a/core/config/project_settings.cpp +++ b/core/config/project_settings.cpp @@ -1523,6 +1523,8 @@ ProjectSettings::ProjectSettings() { GLOBAL_DEF("debug/settings/crash_handler/message.editor", String("Please include this when reporting the bug on: https://github.com/godotengine/godot/issues")); GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/occlusion_culling/bvh_build_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), 2); + GLOBAL_DEF_RST("rendering/occlusion_culling/jitter_projection", true); + GLOBAL_DEF_RST("internationalization/rendering/force_right_to_left_layout_direction", false); GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "internationalization/rendering/root_node_layout_direction", PROPERTY_HINT_ENUM, "Based on Application Locale,Left-to-Right,Right-to-Left,Based on System Locale"), 0); diff --git a/core/core_bind.cpp b/core/core_bind.cpp index 6927db002b..8c85030783 100644 --- a/core/core_bind.cpp +++ b/core/core_bind.cpp @@ -283,8 +283,8 @@ String OS::read_string_from_stdin() { int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r_output, bool p_read_stderr, bool p_open_console) { List<String> args; - for (int i = 0; i < p_arguments.size(); i++) { - args.push_back(p_arguments[i]); + for (const String &arg : p_arguments) { + args.push_back(arg); } String pipe; int exitcode = 0; @@ -296,10 +296,18 @@ int OS::execute(const String &p_path, const Vector<String> &p_arguments, Array r return exitcode; } +Dictionary OS::execute_with_pipe(const String &p_path, const Vector<String> &p_arguments) { + List<String> args; + for (const String &arg : p_arguments) { + args.push_back(arg); + } + return ::OS::get_singleton()->execute_with_pipe(p_path, args); +} + int OS::create_instance(const Vector<String> &p_arguments) { List<String> args; - for (int i = 0; i < p_arguments.size(); i++) { - args.push_back(p_arguments[i]); + for (const String &arg : p_arguments) { + args.push_back(arg); } ::OS::ProcessID pid = 0; Error err = ::OS::get_singleton()->create_instance(args, &pid); @@ -311,8 +319,8 @@ int OS::create_instance(const Vector<String> &p_arguments) { int OS::create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console) { List<String> args; - for (int i = 0; i < p_arguments.size(); i++) { - args.push_back(p_arguments[i]); + for (const String &arg : p_arguments) { + args.push_back(arg); } ::OS::ProcessID pid = 0; Error err = ::OS::get_singleton()->create_process(p_path, args, &pid, p_open_console); @@ -587,6 +595,7 @@ void OS::_bind_methods() { ClassDB::bind_method(D_METHOD("get_executable_path"), &OS::get_executable_path); ClassDB::bind_method(D_METHOD("read_string_from_stdin"), &OS::read_string_from_stdin); ClassDB::bind_method(D_METHOD("execute", "path", "arguments", "output", "read_stderr", "open_console"), &OS::execute, DEFVAL(Array()), DEFVAL(false), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("execute_with_pipe", "path", "arguments"), &OS::execute_with_pipe); ClassDB::bind_method(D_METHOD("create_process", "path", "arguments", "open_console"), &OS::create_process, DEFVAL(false)); ClassDB::bind_method(D_METHOD("create_instance", "arguments"), &OS::create_instance); ClassDB::bind_method(D_METHOD("kill", "pid"), &OS::kill); diff --git a/core/core_bind.h b/core/core_bind.h index 305f616cef..d46321cf5c 100644 --- a/core/core_bind.h +++ b/core/core_bind.h @@ -156,6 +156,7 @@ public: String get_executable_path() const; String read_string_from_stdin(); int execute(const String &p_path, const Vector<String> &p_arguments, Array r_output = Array(), bool p_read_stderr = false, bool p_open_console = false); + Dictionary execute_with_pipe(const String &p_path, const Vector<String> &p_arguments); int create_process(const String &p_path, const Vector<String> &p_arguments, bool p_open_console = false); int create_instance(const Vector<String> &p_arguments); Error kill(int p_pid); diff --git a/core/crypto/crypto.h b/core/crypto/crypto.h index 0248b04034..fbd01be86d 100644 --- a/core/crypto/crypto.h +++ b/core/crypto/crypto.h @@ -153,17 +153,17 @@ public: class ResourceFormatLoaderCrypto : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; class ResourceFormatSaverCrypto : public ResourceFormatSaver { public: - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; - virtual bool recognize(const Ref<Resource> &p_resource) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; }; #endif // CRYPTO_H diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index 5d43dceece..0ed4c3380c 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -735,7 +735,7 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb bool library_copied = false; if (Engine::get_singleton()->is_editor_hint()) { if (!FileAccess::exists(abs_path)) { - ERR_PRINT("GDExtension library not found: " + library_path); + ERR_PRINT("GDExtension library not found: " + abs_path); return ERR_FILE_NOT_FOUND; } @@ -750,7 +750,7 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb Error copy_err = DirAccess::copy_absolute(abs_path, copy_path); if (copy_err) { - ERR_PRINT("Error copying GDExtension library: " + library_path); + ERR_PRINT("Error copying GDExtension library: " + abs_path); return ERR_CANT_CREATE; } FileAccess::set_hidden_attribute(copy_path, true); diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index a2b948a38a..2d0cb6a5ba 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -176,10 +176,10 @@ class GDExtensionResourceLoader : public ResourceFormatLoader { public: static Error load_gdextension_resource(const String &p_path, Ref<GDExtension> &p_extension); - virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; #ifdef TOOLS_ENABLED diff --git a/core/input/input.cpp b/core/input/input.cpp index 3de0ed39ec..c24a59203f 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -894,7 +894,7 @@ void Input::action_press(const StringName &p_action, float p_strength) { } action_state.exact = true; action_state.api_pressed = true; - action_state.api_strength = p_strength; + action_state.api_strength = CLAMP(p_strength, 0.0f, 1.0f); _update_action_cache(p_action, action_state); } diff --git a/core/input/input_builders.py b/core/input/input_builders.py index eabdefe543..ae848f4e7c 100644 --- a/core/input/input_builders.py +++ b/core/input/input_builders.py @@ -13,7 +13,7 @@ def make_default_controller_mappings(target, source, env): # ensure mappings have a consistent order platform_mappings: dict = OrderedDict() for src_path in source: - with open(str(src_path), "r") as f: + with open(str(src_path), "r", encoding="utf-8") as f: # read mapping file and skip header mapping_file_lines = f.readlines()[2:] diff --git a/core/input/input_event.cpp b/core/input/input_event.cpp index bd1fde5a85..bf1de8d3b2 100644 --- a/core/input/input_event.cpp +++ b/core/input/input_event.cpp @@ -132,6 +132,8 @@ void InputEvent::_bind_methods() { ClassDB::bind_method(D_METHOD("xformed_by", "xform", "local_ofs"), &InputEvent::xformed_by, DEFVAL(Vector2())); ADD_PROPERTY(PropertyInfo(Variant::INT, "device"), "set_device", "get_device"); + + BIND_CONSTANT(DEVICE_ID_EMULATION); } /////////////////////////////////// diff --git a/core/input/input_map.cpp b/core/input/input_map.cpp index 5d6de1ad9a..7fd1806b31 100644 --- a/core/input/input_map.cpp +++ b/core/input/input_map.cpp @@ -383,6 +383,7 @@ static const _BuiltinActionDisplayName _builtin_action_display_names[] = { { "ui_text_select_all", TTRC("Select All") }, { "ui_text_select_word_under_caret", TTRC("Select Word Under Caret") }, { "ui_text_add_selection_for_next_occurrence", TTRC("Add Selection for Next Occurrence") }, + { "ui_text_skip_selection_for_next_occurrence", TTRC("Skip Selection for Next Occurrence") }, { "ui_text_clear_carets_and_selection", TTRC("Clear Carets and Selection") }, { "ui_text_toggle_insert_mode", TTRC("Toggle Insert Mode") }, { "ui_text_submit", TTRC("Submit Text") }, @@ -722,6 +723,10 @@ const HashMap<String, List<Ref<InputEvent>>> &InputMap::get_builtins() { default_builtin_cache.insert("ui_text_add_selection_for_next_occurrence", inputs); inputs = List<Ref<InputEvent>>(); + inputs.push_back(InputEventKey::create_reference(Key::D | KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT)); + default_builtin_cache.insert("ui_text_skip_selection_for_next_occurrence", inputs); + + inputs = List<Ref<InputEvent>>(); inputs.push_back(InputEventKey::create_reference(Key::ESCAPE)); default_builtin_cache.insert("ui_text_clear_carets_and_selection", inputs); diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 55286277fa..d2a5103953 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -47,6 +47,7 @@ thread_local Error FileAccess::last_file_open_error = OK; Ref<FileAccess> FileAccess::create(AccessType p_access) { ERR_FAIL_INDEX_V(p_access, ACCESS_MAX, nullptr); + ERR_FAIL_NULL_V(create_func[p_access], nullptr); Ref<FileAccess> ret = create_func[p_access](); ret->_set_access_type(p_access); @@ -75,7 +76,8 @@ Ref<FileAccess> FileAccess::create_for_path(const String &p_path) { ret = create(ACCESS_RESOURCES); } else if (p_path.begins_with("user://")) { ret = create(ACCESS_USERDATA); - + } else if (p_path.begins_with("pipe://")) { + ret = create(ACCESS_PIPE); } else { ret = create(ACCESS_FILESYSTEM); } @@ -209,6 +211,9 @@ String FileAccess::fix_path(const String &p_path) const { } } break; + case ACCESS_PIPE: { + return r_path; + } break; case ACCESS_FILESYSTEM: { return r_path; } break; diff --git a/core/io/file_access.h b/core/io/file_access.h index 122ae3b190..0b631f68b1 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -50,6 +50,7 @@ public: ACCESS_RESOURCES, ACCESS_USERDATA, ACCESS_FILESYSTEM, + ACCESS_PIPE, ACCESS_MAX }; diff --git a/core/io/image_loader.h b/core/io/image_loader.h index e9b434522d..26af650344 100644 --- a/core/io/image_loader.h +++ b/core/io/image_loader.h @@ -103,10 +103,10 @@ public: class ResourceFormatLoaderImage : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; #endif // IMAGE_LOADER_H diff --git a/core/io/json.h b/core/io/json.h index a21cc542fd..801fa29b4b 100644 --- a/core/io/json.h +++ b/core/io/json.h @@ -98,17 +98,17 @@ public: class ResourceFormatLoaderJSON : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; class ResourceFormatSaverJSON : public ResourceFormatSaver { public: - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; - virtual bool recognize(const Ref<Resource> &p_resource) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; }; #endif // JSON_H diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp index bc2493d360..b25fcccd7f 100644 --- a/core/io/marshalls.cpp +++ b/core/io/marshalls.cpp @@ -30,7 +30,10 @@ #include "marshalls.h" +#include "core/core_string_names.h" +#include "core/io/resource_loader.h" #include "core/object/ref_counted.h" +#include "core/object/script_language.h" #include "core/os/keyboard.h" #include "core/string/print_string.h" @@ -55,9 +58,22 @@ ObjectID EncodedObjectAsID::get_object_id() const { #define ERR_FAIL_ADD_OF(a, b, err) ERR_FAIL_COND_V(((int32_t)(b)) < 0 || ((int32_t)(a)) < 0 || ((int32_t)(a)) > INT_MAX - ((int32_t)(b)), err) #define ERR_FAIL_MUL_OF(a, b, err) ERR_FAIL_COND_V(((int32_t)(a)) < 0 || ((int32_t)(b)) <= 0 || ((int32_t)(a)) > INT_MAX / ((int32_t)(b)), err) -#define ENCODE_MASK 0xFF -#define ENCODE_FLAG_64 1 << 16 -#define ENCODE_FLAG_OBJECT_AS_ID 1 << 16 +// Byte 0: `Variant::Type`, byte 1: unused, bytes 2 and 3: additional data. +#define HEADER_TYPE_MASK 0xFF + +// For `Variant::INT`, `Variant::FLOAT` and other math types. +#define HEADER_DATA_FLAG_64 (1 << 16) + +// For `Variant::OBJECT`. +#define HEADER_DATA_FLAG_OBJECT_AS_ID (1 << 16) + +// For `Variant::ARRAY`. +// Occupies bits 16 and 17. +#define HEADER_DATA_FIELD_TYPED_ARRAY_MASK (0b11 << 16) +#define HEADER_DATA_FIELD_TYPED_ARRAY_NONE (0b00 << 16) +#define HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN (0b01 << 16) +#define HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME (0b10 << 16) +#define HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT (0b11 << 16) static Error _decode_string(const uint8_t *&buf, int &len, int *r_len, String &r_string) { ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); @@ -101,9 +117,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); - uint32_t type = decode_uint32(buf); + uint32_t header = decode_uint32(buf); - ERR_FAIL_COND_V((type & ENCODE_MASK) >= Variant::VARIANT_MAX, ERR_INVALID_DATA); + ERR_FAIL_COND_V((header & HEADER_TYPE_MASK) >= Variant::VARIANT_MAX, ERR_INVALID_DATA); buf += 4; len -= 4; @@ -114,7 +130,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int // Note: We cannot use sizeof(real_t) for decoding, in case a different size is encoded. // Decoding math types always checks for the encoded size, while encoding always uses compilation setting. // This does lead to some code duplication for decoding, but compatibility is the priority. - switch (type & ENCODE_MASK) { + switch (header & HEADER_TYPE_MASK) { case Variant::NIL: { r_variant = Variant(); } break; @@ -127,7 +143,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } } break; case Variant::INT: { - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); int64_t val = decode_uint64(buf); r_variant = val; @@ -146,7 +162,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::FLOAT: { - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double), ERR_INVALID_DATA); double val = decode_double(buf); r_variant = val; @@ -176,7 +192,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int // math types case Variant::VECTOR2: { Vector2 val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 2, ERR_INVALID_DATA); val.x = decode_double(&buf[0]); val.y = decode_double(&buf[sizeof(double)]); @@ -210,7 +226,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::RECT2: { Rect2 val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); val.position.x = decode_double(&buf[0]); val.position.y = decode_double(&buf[sizeof(double)]); @@ -250,7 +266,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::VECTOR3: { Vector3 val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 3, ERR_INVALID_DATA); val.x = decode_double(&buf[0]); val.y = decode_double(&buf[sizeof(double)]); @@ -287,7 +303,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::VECTOR4: { Vector4 val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); val.x = decode_double(&buf[0]); val.y = decode_double(&buf[sizeof(double)]); @@ -327,7 +343,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::TRANSFORM2D: { Transform2D val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA); for (int i = 0; i < 3; i++) { for (int j = 0; j < 2; j++) { @@ -355,7 +371,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::PLANE: { Plane val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); val.normal.x = decode_double(&buf[0]); val.normal.y = decode_double(&buf[sizeof(double)]); @@ -381,7 +397,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::QUATERNION: { Quaternion val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 4, ERR_INVALID_DATA); val.x = decode_double(&buf[0]); val.y = decode_double(&buf[sizeof(double)]); @@ -407,7 +423,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::AABB: { AABB val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 6, ERR_INVALID_DATA); val.position.x = decode_double(&buf[0]); val.position.y = decode_double(&buf[sizeof(double)]); @@ -437,7 +453,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::BASIS: { Basis val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 9, ERR_INVALID_DATA); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -465,7 +481,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::TRANSFORM3D: { Transform3D val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 12, ERR_INVALID_DATA); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -499,7 +515,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::PROJECTION: { Projection val; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_COND_V((size_t)len < sizeof(double) * 16, ERR_INVALID_DATA); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { @@ -560,12 +576,12 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int uint32_t namecount = strlen &= 0x7FFFFFFF; uint32_t subnamecount = decode_uint32(buf + 4); - uint32_t flags = decode_uint32(buf + 8); + uint32_t np_flags = decode_uint32(buf + 8); len -= 12; buf += 12; - if (flags & 2) { // Obsolete format with property separate from subpath + if (np_flags & 2) { // Obsolete format with property separate from subpath. subnamecount++; } @@ -589,7 +605,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } } - r_variant = NodePath(names, subnames, flags & 1); + r_variant = NodePath(names, subnames, np_flags & 1); } else { //old format, just a string @@ -608,8 +624,8 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = RID::from_uint64(id); } break; case Variant::OBJECT: { - if (type & ENCODE_FLAG_OBJECT_AS_ID) { - //this _is_ allowed + if (header & HEADER_DATA_FLAG_OBJECT_AS_ID) { + // This _is_ allowed. ERR_FAIL_COND_V(len < 8, ERR_INVALID_DATA); ObjectID val = ObjectID(decode_uint64(buf)); if (r_len) { @@ -625,7 +641,6 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int r_variant = obj_as_id; } - } else { ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED); @@ -672,7 +687,16 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int (*r_len) += used; } - obj->set(str, value); + if (str == "script") { + ERR_FAIL_COND_V_MSG(value.get_type() != Variant::STRING, ERR_INVALID_DATA, "Invalid value for \"script\" property, expected script path as String."); + String path = value; + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'."); + Ref<Script> script = ResourceLoader::load(path, "Script"); + ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, "Can't load script at path: '" + path + "'."); + obj->set_script(script); + } else { + obj->set(str, value); + } } if (Object::cast_to<RefCounted>(obj)) { @@ -747,7 +771,60 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } break; case Variant::ARRAY: { + Variant::Type builtin_type = Variant::VARIANT_MAX; + StringName class_name; + Ref<Script> script; + + switch (header & HEADER_DATA_FIELD_TYPED_ARRAY_MASK) { + case HEADER_DATA_FIELD_TYPED_ARRAY_NONE: + break; // Untyped array. + case HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN: { + ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); + + int32_t bt = decode_uint32(buf); + buf += 4; + len -= 4; + if (r_len) { + (*r_len) += 4; + } + + ERR_FAIL_INDEX_V(bt, Variant::VARIANT_MAX, ERR_INVALID_DATA); + builtin_type = (Variant::Type)bt; + ERR_FAIL_COND_V(!p_allow_objects && builtin_type == Variant::OBJECT, ERR_UNAUTHORIZED); + } break; + case HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME: { + ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED); + + String str; + Error err = _decode_string(buf, len, r_len, str); + if (err) { + return err; + } + + builtin_type = Variant::OBJECT; + class_name = str; + } break; + case HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT: { + ERR_FAIL_COND_V(!p_allow_objects, ERR_UNAUTHORIZED); + + String path; + Error err = _decode_string(buf, len, r_len, path); + if (err) { + return err; + } + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://") || !ResourceLoader::exists(path, "Script"), ERR_INVALID_DATA, "Invalid script path: '" + path + "'."); + script = ResourceLoader::load(path, "Script"); + ERR_FAIL_COND_V_MSG(script.is_null(), ERR_INVALID_DATA, "Can't load script at path: '" + path + "'."); + + builtin_type = Variant::OBJECT; + class_name = script->get_instance_base_type(); + } break; + default: + ERR_FAIL_V(ERR_INVALID_DATA); // Future proofing. + } + ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA); + int32_t count = decode_uint32(buf); // bool shared = count&0x80000000; count &= 0x7FFFFFFF; @@ -760,6 +837,9 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int } Array varr; + if (builtin_type != Variant::VARIANT_MAX) { + varr.set_typed(builtin_type, class_name, script); + } for (int i = 0; i < count; i++) { int used = 0; @@ -936,7 +1016,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Vector<Vector2> varray; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_MUL_OF(count, sizeof(double) * 2, ERR_INVALID_DATA); ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 2 > (size_t)len, ERR_INVALID_DATA); @@ -996,7 +1076,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int Vector<Vector3> varray; - if (type & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { ERR_FAIL_MUL_OF(count, sizeof(double) * 3, ERR_INVALID_DATA); ERR_FAIL_COND_V(count < 0 || count * sizeof(double) * 3 > (size_t)len, ERR_INVALID_DATA); @@ -1122,20 +1202,20 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo r_len = 0; - uint32_t flags = 0; + uint32_t header = p_variant.get_type(); switch (p_variant.get_type()) { case Variant::INT: { int64_t val = p_variant; if (val > (int64_t)INT_MAX || val < (int64_t)INT_MIN) { - flags |= ENCODE_FLAG_64; + header |= HEADER_DATA_FLAG_64; } } break; case Variant::FLOAT: { double d = p_variant; float f = d; if (double(f) != d) { - flags |= ENCODE_FLAG_64; + header |= HEADER_DATA_FLAG_64; } } break; case Variant::OBJECT: { @@ -1151,7 +1231,23 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } if (!p_full_objects) { - flags |= ENCODE_FLAG_OBJECT_AS_ID; + header |= HEADER_DATA_FLAG_OBJECT_AS_ID; + } + } break; + case Variant::ARRAY: { + Array array = p_variant; + if (array.is_typed()) { + Ref<Script> script = array.get_typed_script(); + if (script.is_valid()) { + ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE); + header |= HEADER_DATA_FIELD_TYPED_ARRAY_SCRIPT; + } else if (array.get_typed_class_name() != StringName()) { + ERR_FAIL_COND_V(!p_full_objects, ERR_UNAVAILABLE); + header |= HEADER_DATA_FIELD_TYPED_ARRAY_CLASS_NAME; + } else { + ERR_FAIL_COND_V(!p_full_objects && array.get_typed_builtin() == Variant::OBJECT, ERR_UNAVAILABLE); + header |= HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN; + } } } break; #ifdef REAL_T_IS_DOUBLE @@ -1168,7 +1264,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo case Variant::BASIS: case Variant::RECT2: case Variant::AABB: { - flags |= ENCODE_FLAG_64; + header |= HEADER_DATA_FLAG_64; } break; #endif // REAL_T_IS_DOUBLE default: { @@ -1176,7 +1272,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } if (buf) { - encode_uint32(p_variant.get_type() | flags, buf); + encode_uint32(header, buf); buf += 4; } r_len += 4; @@ -1194,7 +1290,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::INT: { - if (flags & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { //64 bits if (buf) { encode_uint64(p_variant.operator int64_t(), buf); @@ -1210,7 +1306,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } } break; case Variant::FLOAT: { - if (flags & ENCODE_FLAG_64) { + if (header & HEADER_DATA_FLAG_64) { if (buf) { encode_double(p_variant.operator double(), buf); } @@ -1523,8 +1619,21 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo _encode_string(E.name, buf, r_len); + Variant value; + + if (E.name == CoreStringNames::get_singleton()->_script) { + Ref<Script> script = obj->get_script(); + if (script.is_valid()) { + String path = script->get_path(); + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), ERR_UNAVAILABLE, "Failed to encode a path to a custom script."); + value = path; + } + } else { + value = obj->get(E.name); + } + int len; - Error err = encode_variant(obj->get(E.name), buf, len, p_full_objects, p_depth + 1); + Error err = encode_variant(value, buf, len, p_full_objects, p_depth + 1); ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(len % 4, ERR_BUG); r_len += len; @@ -1594,24 +1703,41 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo } break; case Variant::ARRAY: { - Array v = p_variant; + Array array = p_variant; + + if (array.is_typed()) { + Variant variant = array.get_typed_script(); + Ref<Script> script = variant; + if (script.is_valid()) { + String path = script->get_path(); + ERR_FAIL_COND_V_MSG(path.is_empty() || !path.begins_with("res://"), ERR_UNAVAILABLE, "Failed to encode a path to a custom script for an array type."); + _encode_string(path, buf, r_len); + } else if (array.get_typed_class_name() != StringName()) { + _encode_string(array.get_typed_class_name(), buf, r_len); + } else { + if (buf) { + encode_uint32(array.get_typed_builtin(), buf); + buf += 4; + } + r_len += 4; + } + } if (buf) { - encode_uint32(uint32_t(v.size()), buf); + encode_uint32(uint32_t(array.size()), buf); buf += 4; } - r_len += 4; - for (int i = 0; i < v.size(); i++) { + for (int i = 0; i < array.size(); i++) { int len; - Error err = encode_variant(v.get(i), buf, len, p_full_objects, p_depth + 1); + Error err = encode_variant(array.get(i), buf, len, p_full_objects, p_depth + 1); ERR_FAIL_COND_V(err, err); ERR_FAIL_COND_V(len % 4, ERR_BUG); - r_len += len; if (buf) { buf += len; } + r_len += len; } } break; diff --git a/core/io/resource.cpp b/core/io/resource.cpp index 5edb045760..dc974a545a 100644 --- a/core/io/resource.cpp +++ b/core/io/resource.cpp @@ -214,6 +214,7 @@ Error Resource::copy_from(const Ref<Resource> &p_resource) { } return OK; } + void Resource::reload_from_file() { String path = get_path(); if (!path.is_resource_file()) { diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index e01c5fa467..222e633e58 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -110,16 +110,16 @@ public: class ResourceFormatLoaderBinary : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; - virtual String get_resource_script_class(const String &p_path) const; - virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes); - virtual ResourceUID::ID get_resource_uid(const String &p_path) const; - virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); - virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map); + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; + virtual String get_resource_script_class(const String &p_path) const override; + virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override; + virtual ResourceUID::ID get_resource_uid(const String &p_path) const override; + virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override; + virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map) override; }; class ResourceFormatSaverBinaryInstance { @@ -181,10 +181,10 @@ public: class ResourceFormatSaverBinary : public ResourceFormatSaver { public: static ResourceFormatSaverBinary *singleton; - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid); - virtual bool recognize(const Ref<Resource> &p_resource) const; - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid) override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; ResourceFormatSaverBinary(); }; diff --git a/core/io/resource_importer.h b/core/io/resource_importer.h index e17644058a..dbd9e70d16 100644 --- a/core/io/resource_importer.h +++ b/core/io/resource_importer.h @@ -59,22 +59,22 @@ class ResourceFormatImporter : public ResourceFormatLoader { public: static ResourceFormatImporter *get_singleton() { return singleton; } - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; - virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; - virtual ResourceUID::ID get_resource_uid(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const override; + virtual bool recognize_path(const String &p_path, const String &p_for_type = String()) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; + virtual ResourceUID::ID get_resource_uid(const String &p_path) const override; virtual Variant get_resource_metadata(const String &p_path) const; - virtual bool is_import_valid(const String &p_path) const; - virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); - virtual bool is_imported(const String &p_path) const { return recognize_path(p_path); } - virtual String get_import_group_file(const String &p_path) const; - virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes); - virtual bool exists(const String &p_path) const; - - virtual int get_import_order(const String &p_path) const; + virtual bool is_import_valid(const String &p_path) const override; + virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override; + virtual bool is_imported(const String &p_path) const override { return recognize_path(p_path); } + virtual String get_import_group_file(const String &p_path) const override; + virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override; + virtual bool exists(const String &p_path) const override; + + virtual int get_import_order(const String &p_path) const override; Error get_import_order_threads_and_importer(const String &p_path, int &r_order, bool &r_can_threads, String &r_importer) const; diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 16e7c28cbe..a695826e59 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -38,10 +38,10 @@ class TranslationLoaderPO : public ResourceFormatLoader { public: static Ref<Resource> load_translation(Ref<FileAccess> f, Error *r_error = nullptr); - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; TranslationLoaderPO() {} }; diff --git a/core/math/a_star.compat.inc b/core/math/a_star.compat.inc new file mode 100644 index 0000000000..664d7ffd5e --- /dev/null +++ b/core/math/a_star.compat.inc @@ -0,0 +1,59 @@ +/**************************************************************************/ +/* a_star.compat.inc */ +/**************************************************************************/ +/* 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 DISABLE_DEPRECATED + +Vector<int64_t> AStar3D::_get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) { + return get_id_path(p_from_id, p_to_id, false); +} + +Vector<Vector3> AStar3D::_get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) { + return get_point_path(p_from_id, p_to_id, false); +} + +void AStar3D::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar3D::_get_id_path_bind_compat_88047); + ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar3D::_get_point_path_bind_compat_88047); +} + +Vector<int64_t> AStar2D::_get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) { + return get_id_path(p_from_id, p_to_id, false); +} + +Vector<Vector2> AStar2D::_get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id) { + return get_point_path(p_from_id, p_to_id, false); +} + +void AStar2D::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar2D::_get_id_path_bind_compat_88047); + ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar2D::_get_point_path_bind_compat_88047); +} + +#endif // DISABLE_DEPRECATED diff --git a/core/math/a_star.cpp b/core/math/a_star.cpp index fb54058bd9..4497604947 100644 --- a/core/math/a_star.cpp +++ b/core/math/a_star.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "a_star.h" +#include "a_star.compat.inc" #include "core/math/geometry_3d.h" #include "core/object/script_language.h" @@ -319,6 +320,7 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const { } bool AStar3D::_solve(Point *begin_point, Point *end_point) { + last_closest_point = nullptr; pass++; if (!end_point->enabled) { @@ -332,11 +334,18 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) { begin_point->g_score = 0; begin_point->f_score = _estimate_cost(begin_point->id, end_point->id); + begin_point->abs_g_score = 0; + begin_point->abs_f_score = _estimate_cost(begin_point->id, end_point->id); open_list.push_back(begin_point); while (!open_list.is_empty()) { Point *p = open_list[0]; // The currently processed point. + // Find point closer to end_point, or same distance to end_point but closer to begin_point. + if (last_closest_point == nullptr || last_closest_point->abs_f_score > p->abs_f_score || (last_closest_point->abs_f_score >= p->abs_f_score && last_closest_point->abs_g_score > p->abs_g_score)) { + last_closest_point = p; + } + if (p == end_point) { found_route = true; break; @@ -368,6 +377,8 @@ bool AStar3D::_solve(Point *begin_point, Point *end_point) { e->prev_point = p; e->g_score = tentative_g_score; e->f_score = e->g_score + _estimate_cost(e->id, end_point->id); + e->abs_g_score = tentative_g_score; + e->abs_f_score = e->f_score - e->g_score; if (new_point) { // The position of the new points is already known. sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr()); @@ -414,7 +425,7 @@ real_t AStar3D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { return from_point->pos.distance_to(to_point->pos); } -Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) { +Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) { Point *a = nullptr; bool from_exists = points.lookup(p_from_id, a); ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector3>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id)); @@ -434,7 +445,12 @@ Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) { bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<Vector3>(); + if (!p_allow_partial_path || last_closest_point == nullptr) { + return Vector<Vector3>(); + } + + // Use closest point instead. + end_point = last_closest_point; } Point *p = end_point; @@ -463,7 +479,7 @@ Vector<Vector3> AStar3D::get_point_path(int64_t p_from_id, int64_t p_to_id) { return path; } -Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) { +Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) { Point *a = nullptr; bool from_exists = points.lookup(p_from_id, a); ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); @@ -483,7 +499,12 @@ Vector<int64_t> AStar3D::get_id_path(int64_t p_from_id, int64_t p_to_id) { bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<int64_t>(); + if (!p_allow_partial_path || last_closest_point == nullptr) { + return Vector<int64_t>(); + } + + // Use closest point instead. + end_point = last_closest_point; } Point *p = end_point; @@ -555,8 +576,8 @@ void AStar3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_closest_point", "to_position", "include_disabled"), &AStar3D::get_closest_point, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &AStar3D::get_closest_position_in_segment); - ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar3D::get_point_path); - ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar3D::get_id_path); + ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStar3D::get_point_path, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStar3D::get_id_path, DEFVAL(false)); GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id") GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id") @@ -688,7 +709,7 @@ real_t AStar2D::_compute_cost(int64_t p_from_id, int64_t p_to_id) { return from_point->pos.distance_to(to_point->pos); } -Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) { +Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) { AStar3D::Point *a = nullptr; bool from_exists = astar.points.lookup(p_from_id, a); ERR_FAIL_COND_V_MSG(!from_exists, Vector<Vector2>(), vformat("Can't get point path. Point with id: %d doesn't exist.", p_from_id)); @@ -707,7 +728,12 @@ Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) { bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<Vector2>(); + if (!p_allow_partial_path || astar.last_closest_point == nullptr) { + return Vector<Vector2>(); + } + + // Use closest point instead. + end_point = astar.last_closest_point; } AStar3D::Point *p = end_point; @@ -736,7 +762,7 @@ Vector<Vector2> AStar2D::get_point_path(int64_t p_from_id, int64_t p_to_id) { return path; } -Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) { +Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path) { AStar3D::Point *a = nullptr; bool from_exists = astar.points.lookup(p_from_id, a); ERR_FAIL_COND_V_MSG(!from_exists, Vector<int64_t>(), vformat("Can't get id path. Point with id: %d doesn't exist.", p_from_id)); @@ -756,7 +782,12 @@ Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) { bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<int64_t>(); + if (!p_allow_partial_path || astar.last_closest_point == nullptr) { + return Vector<int64_t>(); + } + + // Use closest point instead. + end_point = astar.last_closest_point; } AStar3D::Point *p = end_point; @@ -786,6 +817,7 @@ Vector<int64_t> AStar2D::get_id_path(int64_t p_from_id, int64_t p_to_id) { } bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) { + astar.last_closest_point = nullptr; astar.pass++; if (!end_point->enabled) { @@ -799,11 +831,18 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) { begin_point->g_score = 0; begin_point->f_score = _estimate_cost(begin_point->id, end_point->id); + begin_point->abs_g_score = 0; + begin_point->abs_f_score = _estimate_cost(begin_point->id, end_point->id); open_list.push_back(begin_point); while (!open_list.is_empty()) { AStar3D::Point *p = open_list[0]; // The currently processed point. + // Find point closer to end_point, or same distance to end_point but closer to begin_point. + if (astar.last_closest_point == nullptr || astar.last_closest_point->abs_f_score > p->abs_f_score || (astar.last_closest_point->abs_f_score >= p->abs_f_score && astar.last_closest_point->abs_g_score > p->abs_g_score)) { + astar.last_closest_point = p; + } + if (p == end_point) { found_route = true; break; @@ -835,6 +874,8 @@ bool AStar2D::_solve(AStar3D::Point *begin_point, AStar3D::Point *end_point) { e->prev_point = p; e->g_score = tentative_g_score; e->f_score = e->g_score + _estimate_cost(e->id, end_point->id); + e->abs_g_score = tentative_g_score; + e->abs_f_score = e->f_score - e->g_score; if (new_point) { // The position of the new points is already known. sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr()); @@ -874,8 +915,8 @@ void AStar2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_closest_point", "to_position", "include_disabled"), &AStar2D::get_closest_point, DEFVAL(false)); ClassDB::bind_method(D_METHOD("get_closest_position_in_segment", "to_position"), &AStar2D::get_closest_position_in_segment); - ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStar2D::get_point_path); - ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStar2D::get_id_path); + ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStar2D::get_point_path, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStar2D::get_id_path, DEFVAL(false)); GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id") GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id") diff --git a/core/math/a_star.h b/core/math/a_star.h index 0758500c8a..8e054c4789 100644 --- a/core/math/a_star.h +++ b/core/math/a_star.h @@ -60,6 +60,10 @@ class AStar3D : public RefCounted { real_t f_score = 0; uint64_t open_pass = 0; uint64_t closed_pass = 0; + + // Used for getting closest_point_of_last_pathing_call. + real_t abs_g_score = 0; + real_t abs_f_score = 0; }; struct SortPoints { @@ -109,6 +113,7 @@ class AStar3D : public RefCounted { OAHashMap<int64_t, Point *> points; HashSet<Segment, Segment> segments; + Point *last_closest_point = nullptr; bool _solve(Point *begin_point, Point *end_point); @@ -121,6 +126,12 @@ protected: GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t) GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t) +#ifndef DISABLE_DEPRECATED + Vector<int64_t> _get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id); + Vector<Vector3> _get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id); + static void _bind_compatibility_methods(); +#endif + public: int64_t get_available_point_id() const; @@ -149,8 +160,8 @@ public: int64_t get_closest_point(const Vector3 &p_point, bool p_include_disabled = false) const; Vector3 get_closest_position_in_segment(const Vector3 &p_point) const; - Vector<Vector3> get_point_path(int64_t p_from_id, int64_t p_to_id); - Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id); + Vector<Vector3> get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false); + Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false); AStar3D() {} ~AStar3D(); @@ -171,6 +182,12 @@ protected: GDVIRTUAL2RC(real_t, _estimate_cost, int64_t, int64_t) GDVIRTUAL2RC(real_t, _compute_cost, int64_t, int64_t) +#ifndef DISABLE_DEPRECATED + Vector<int64_t> _get_id_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id); + Vector<Vector2> _get_point_path_bind_compat_88047(int64_t p_from_id, int64_t p_to_id); + static void _bind_compatibility_methods(); +#endif + public: int64_t get_available_point_id() const; @@ -199,8 +216,8 @@ public: int64_t get_closest_point(const Vector2 &p_point, bool p_include_disabled = false) const; Vector2 get_closest_position_in_segment(const Vector2 &p_point) const; - Vector<Vector2> get_point_path(int64_t p_from_id, int64_t p_to_id); - Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id); + Vector<Vector2> get_point_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false); + Vector<int64_t> get_id_path(int64_t p_from_id, int64_t p_to_id, bool p_allow_partial_path = false); AStar2D() {} ~AStar2D() {} diff --git a/core/math/a_star_grid_2d.compat.inc b/core/math/a_star_grid_2d.compat.inc new file mode 100644 index 0000000000..e7124c2477 --- /dev/null +++ b/core/math/a_star_grid_2d.compat.inc @@ -0,0 +1,48 @@ +/**************************************************************************/ +/* a_star_grid_2d.compat.inc */ +/**************************************************************************/ +/* 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 DISABLE_DEPRECATED + +#include "core/variant/typed_array.h" + +TypedArray<Vector2i> AStarGrid2D::_get_id_path_bind_compat_88047(const Vector2i &p_from_id, const Vector2i &p_to_id) { + return get_id_path(p_from_id, p_to_id, false); +} + +Vector<Vector2> AStarGrid2D::_get_point_path_bind_compat_88047(const Vector2i &p_from_id, const Vector2i &p_to_id) { + return get_point_path(p_from_id, p_to_id, false); +} + +void AStarGrid2D::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::_get_id_path_bind_compat_88047); + ClassDB::bind_compatibility_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::_get_point_path_bind_compat_88047); +} + +#endif // DISABLE_DEPRECATED diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp index d17f465ab8..f272407869 100644 --- a/core/math/a_star_grid_2d.cpp +++ b/core/math/a_star_grid_2d.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "a_star_grid_2d.h" +#include "a_star_grid_2d.compat.inc" #include "core/variant/typed_array.h" @@ -446,6 +447,7 @@ void AStarGrid2D::_get_nbors(Point *p_point, LocalVector<Point *> &r_nbors) { } bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) { + last_closest_point = nullptr; pass++; if (p_end_point->solid) { @@ -459,12 +461,19 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) { p_begin_point->g_score = 0; p_begin_point->f_score = _estimate_cost(p_begin_point->id, p_end_point->id); + p_begin_point->abs_g_score = 0; + p_begin_point->abs_f_score = _estimate_cost(p_begin_point->id, p_end_point->id); open_list.push_back(p_begin_point); end = p_end_point; while (!open_list.is_empty()) { Point *p = open_list[0]; // The currently processed point. + // Find point closer to end_point, or same distance to end_point but closer to begin_point. + if (last_closest_point == nullptr || last_closest_point->abs_f_score > p->abs_f_score || (last_closest_point->abs_f_score >= p->abs_f_score && last_closest_point->abs_g_score > p->abs_g_score)) { + last_closest_point = p; + } + if (p == p_end_point) { found_route = true; break; @@ -508,6 +517,9 @@ bool AStarGrid2D::_solve(Point *p_begin_point, Point *p_end_point) { e->g_score = tentative_g_score; e->f_score = e->g_score + _estimate_cost(e->id, p_end_point->id); + e->abs_g_score = tentative_g_score; + e->abs_f_score = e->f_score - e->g_score; + if (new_point) { // The position of the new points is already known. sorter.push_heap(0, open_list.size() - 1, 0, e, open_list.ptr()); } else { @@ -546,7 +558,7 @@ Vector2 AStarGrid2D::get_point_position(const Vector2i &p_id) const { return _get_point_unchecked(p_id)->pos; } -Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) { +Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id, bool p_allow_partial_path) { ERR_FAIL_COND_V_MSG(dirty, Vector<Vector2>(), "Grid is not initialized. Call the update method."); ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), Vector<Vector2>(), vformat("Can't get id path. Point %s out of bounds %s.", p_from_id, region)); ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), Vector<Vector2>(), vformat("Can't get id path. Point %s out of bounds %s.", p_to_id, region)); @@ -565,7 +577,12 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec bool found_route = _solve(begin_point, end_point); if (!found_route) { - return Vector<Vector2>(); + if (!p_allow_partial_path || last_closest_point == nullptr) { + return Vector<Vector2>(); + } + + // Use closest point instead. + end_point = last_closest_point; } Point *p = end_point; @@ -594,7 +611,7 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec return path; } -TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id) { +TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const Vector2i &p_to_id, bool p_allow_partial_path) { ERR_FAIL_COND_V_MSG(dirty, TypedArray<Vector2i>(), "Grid is not initialized. Call the update method."); ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_from_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point %s out of bounds %s.", p_from_id, region)); ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_to_id), TypedArray<Vector2i>(), vformat("Can't get id path. Point %s out of bounds %s.", p_to_id, region)); @@ -613,7 +630,12 @@ TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const V bool found_route = _solve(begin_point, end_point); if (!found_route) { - return TypedArray<Vector2i>(); + if (!p_allow_partial_path || last_closest_point == nullptr) { + return TypedArray<Vector2i>(); + } + + // Use closest point instead. + end_point = last_closest_point; } Point *p = end_point; @@ -672,8 +694,8 @@ void AStarGrid2D::_bind_methods() { ClassDB::bind_method(D_METHOD("clear"), &AStarGrid2D::clear); ClassDB::bind_method(D_METHOD("get_point_position", "id"), &AStarGrid2D::get_point_position); - ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id"), &AStarGrid2D::get_point_path); - ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id"), &AStarGrid2D::get_id_path); + ClassDB::bind_method(D_METHOD("get_point_path", "from_id", "to_id", "allow_partial_path"), &AStarGrid2D::get_point_path, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("get_id_path", "from_id", "to_id", "allow_partial_path"), &AStarGrid2D::get_id_path, DEFVAL(false)); GDVIRTUAL_BIND(_estimate_cost, "from_id", "to_id") GDVIRTUAL_BIND(_compute_cost, "from_id", "to_id") diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h index 69cb77dd3e..1a9f6dcc11 100644 --- a/core/math/a_star_grid_2d.h +++ b/core/math/a_star_grid_2d.h @@ -89,6 +89,10 @@ private: uint64_t open_pass = 0; uint64_t closed_pass = 0; + // Used for getting last_closest_point. + real_t abs_g_score = 0; + real_t abs_f_score = 0; + Point() {} Point(const Vector2i &p_id, const Vector2 &p_pos) : @@ -109,6 +113,7 @@ private: LocalVector<LocalVector<Point>> points; Point *end = nullptr; + Point *last_closest_point = nullptr; uint64_t pass = 1; @@ -152,6 +157,12 @@ protected: GDVIRTUAL2RC(real_t, _estimate_cost, Vector2i, Vector2i) GDVIRTUAL2RC(real_t, _compute_cost, Vector2i, Vector2i) +#ifndef DISABLE_DEPRECATED + TypedArray<Vector2i> _get_id_path_bind_compat_88047(const Vector2i &p_from, const Vector2i &p_to); + Vector<Vector2> _get_point_path_bind_compat_88047(const Vector2i &p_from, const Vector2i &p_to); + static void _bind_compatibility_methods(); +#endif + public: void set_region(const Rect2i &p_region); Rect2i get_region() const; @@ -198,8 +209,8 @@ public: void clear(); Vector2 get_point_position(const Vector2i &p_id) const; - Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to); - TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to); + Vector<Vector2> get_point_path(const Vector2i &p_from, const Vector2i &p_to, bool p_allow_partial_path = false); + TypedArray<Vector2i> get_id_path(const Vector2i &p_from, const Vector2i &p_to, bool p_allow_partial_path = false); }; VARIANT_ENUM_CAST(AStarGrid2D::DiagonalMode); diff --git a/core/math/aabb.h b/core/math/aabb.h index 7927c431eb..48a883e64c 100644 --- a/core/math/aabb.h +++ b/core/math/aabb.h @@ -101,7 +101,7 @@ struct _NO_DISCARD_ AABB { _FORCE_INLINE_ void expand_to(const Vector3 &p_vector); /** expand to contain a point if necessary */ _FORCE_INLINE_ AABB abs() const { - return AABB(Vector3(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0), position.z + MIN(size.z, (real_t)0)), size.abs()); + return AABB(position + size.min(Vector3()), size.abs()); } Variant intersects_segment_bind(const Vector3 &p_from, const Vector3 &p_to) const; diff --git a/core/math/delaunay_3d.h b/core/math/delaunay_3d.h index 7df8c37e3c..846acdecc3 100644 --- a/core/math/delaunay_3d.h +++ b/core/math/delaunay_3d.h @@ -281,9 +281,7 @@ public: } Vector3i grid_pos = Vector3i(points[i] * ACCEL_GRID_SIZE); - grid_pos.x = CLAMP(grid_pos.x, 0, ACCEL_GRID_SIZE - 1); - grid_pos.y = CLAMP(grid_pos.y, 0, ACCEL_GRID_SIZE - 1); - grid_pos.z = CLAMP(grid_pos.z, 0, ACCEL_GRID_SIZE - 1); + grid_pos = grid_pos.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); for (List<Simplex *>::Element *E = acceleration_grid[grid_pos.x][grid_pos.y][grid_pos.z].front(); E;) { List<Simplex *>::Element *N = E->next(); //may be deleted @@ -339,12 +337,8 @@ public: Vector3 extents = Vector3(radius2, radius2, radius2); Vector3i from = Vector3i((center - extents) * ACCEL_GRID_SIZE); Vector3i to = Vector3i((center + extents) * ACCEL_GRID_SIZE); - from.x = CLAMP(from.x, 0, ACCEL_GRID_SIZE - 1); - from.y = CLAMP(from.y, 0, ACCEL_GRID_SIZE - 1); - from.z = CLAMP(from.z, 0, ACCEL_GRID_SIZE - 1); - to.x = CLAMP(to.x, 0, ACCEL_GRID_SIZE - 1); - to.y = CLAMP(to.y, 0, ACCEL_GRID_SIZE - 1); - to.z = CLAMP(to.z, 0, ACCEL_GRID_SIZE - 1); + from = from.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); + to = to.clamp(Vector3i(), Vector3i(ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1, ACCEL_GRID_SIZE - 1)); for (int32_t x = from.x; x <= to.x; x++) { for (int32_t y = from.y; y <= to.y; y++) { diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h index f586b845c3..26fc517f7f 100644 --- a/core/math/dynamic_bvh.h +++ b/core/math/dynamic_bvh.h @@ -376,13 +376,8 @@ void DynamicBVH::convex_query(const Plane *p_planes, int p_plane_count, const Ve volume.min = p_points[0]; volume.max = p_points[0]; } else { - volume.min.x = MIN(volume.min.x, p_points[i].x); - volume.min.y = MIN(volume.min.y, p_points[i].y); - volume.min.z = MIN(volume.min.z, p_points[i].z); - - volume.max.x = MAX(volume.max.x, p_points[i].x); - volume.max.y = MAX(volume.max.y, p_points[i].y); - volume.max.z = MAX(volume.max.z, p_points[i].z); + volume.min = volume.min.min(p_points[i]); + volume.max = volume.max.max(p_points[i]); } } diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h index fbcaa018a8..1502b2807c 100644 --- a/core/math/geometry_2d.h +++ b/core/math/geometry_2d.h @@ -377,10 +377,8 @@ public: Vector2 further_away_opposite(1e20, 1e20); for (int i = 0; i < c; i++) { - further_away.x = MAX(p[i].x, further_away.x); - further_away.y = MAX(p[i].y, further_away.y); - further_away_opposite.x = MIN(p[i].x, further_away_opposite.x); - further_away_opposite.y = MIN(p[i].y, further_away_opposite.y); + further_away = further_away.max(p[i]); + further_away_opposite = further_away_opposite.min(p[i]); } // Make point outside that won't intersect with points in segment from p_point. diff --git a/core/math/projection.cpp b/core/math/projection.cpp index 9d5dc8b4d6..d3cf11f91a 100644 --- a/core/math/projection.cpp +++ b/core/math/projection.cpp @@ -719,7 +719,8 @@ Projection Projection::operator*(const Projection &p_matrix) const { return new_matrix; } -void Projection::set_depth_correction(bool p_flip_y) { +void Projection::set_depth_correction(bool p_flip_y, bool p_reverse_z, bool p_remap_z) { + // p_remap_z is used to convert from OpenGL-style clip space (-1 - 1) to Vulkan style (0 - 1). real_t *m = &columns[0][0]; m[0] = 1; @@ -732,11 +733,11 @@ void Projection::set_depth_correction(bool p_flip_y) { m[7] = 0.0; m[8] = 0.0; m[9] = 0.0; - m[10] = 0.5; + m[10] = p_remap_z ? (p_reverse_z ? -0.5 : 0.5) : (p_reverse_z ? -1.0 : 1.0); m[11] = 0.0; m[12] = 0.0; m[13] = 0.0; - m[14] = 0.5; + m[14] = p_remap_z ? 0.5 : 0.0; m[15] = 1.0; } diff --git a/core/math/projection.h b/core/math/projection.h index b98f636344..7bba9b337e 100644 --- a/core/math/projection.h +++ b/core/math/projection.h @@ -69,7 +69,7 @@ struct _NO_DISCARD_ Projection { void set_identity(); void set_zero(); void set_light_bias(); - void set_depth_correction(bool p_flip_y = true); + void set_depth_correction(bool p_flip_y = true, bool p_reverse_z = true, bool p_remap_z = true); void set_light_atlas_rect(const Rect2 &p_rect); void set_perspective(real_t p_fovy_degrees, real_t p_aspect, real_t p_z_near, real_t p_z_far, bool p_flip_fov = false); diff --git a/core/math/random_pcg.cpp b/core/math/random_pcg.cpp index e083820494..55787a0b57 100644 --- a/core/math/random_pcg.cpp +++ b/core/math/random_pcg.cpp @@ -52,7 +52,7 @@ int64_t RandomPCG::rand_weighted(const Vector<float> &p_weights) { weights_sum += weights[i]; } - float remaining_distance = Math::randf() * weights_sum; + float remaining_distance = randf() * weights_sum; for (int64_t i = 0; i < weights_size; ++i) { remaining_distance -= weights[i]; if (remaining_distance < 0) { diff --git a/core/math/rect2.h b/core/math/rect2.h index 0f874d4857..497ed8cf04 100644 --- a/core/math/rect2.h +++ b/core/math/rect2.h @@ -152,14 +152,12 @@ struct _NO_DISCARD_ Rect2 { return Rect2(); } - new_rect.position.x = MAX(p_rect.position.x, position.x); - new_rect.position.y = MAX(p_rect.position.y, position.y); + new_rect.position = p_rect.position.max(position); Point2 p_rect_end = p_rect.position + p_rect.size; Point2 end = position + size; - new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; - new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; + new_rect.size = p_rect_end.min(end) - new_rect.position; return new_rect; } @@ -172,11 +170,9 @@ struct _NO_DISCARD_ Rect2 { #endif Rect2 new_rect; - new_rect.position.x = MIN(p_rect.position.x, position.x); - new_rect.position.y = MIN(p_rect.position.y, position.y); + new_rect.position = p_rect.position.min(position); - new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); - new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); + new_rect.size = (p_rect.position + p_rect.size).max(position + size); new_rect.size = new_rect.size - new_rect.position; // Make relative again. @@ -282,7 +278,7 @@ struct _NO_DISCARD_ Rect2 { } _FORCE_INLINE_ Rect2 abs() const { - return Rect2(Point2(position.x + MIN(size.x, (real_t)0), position.y + MIN(size.y, (real_t)0)), size.abs()); + return Rect2(position + size.min(Point2()), size.abs()); } _FORCE_INLINE_ Rect2 round() const { diff --git a/core/math/rect2i.h b/core/math/rect2i.h index 205b2c7198..64806414c7 100644 --- a/core/math/rect2i.h +++ b/core/math/rect2i.h @@ -95,14 +95,12 @@ struct _NO_DISCARD_ Rect2i { return Rect2i(); } - new_rect.position.x = MAX(p_rect.position.x, position.x); - new_rect.position.y = MAX(p_rect.position.y, position.y); + new_rect.position = p_rect.position.max(position); Point2i p_rect_end = p_rect.position + p_rect.size; Point2i end = position + size; - new_rect.size.x = MIN(p_rect_end.x, end.x) - new_rect.position.x; - new_rect.size.y = MIN(p_rect_end.y, end.y) - new_rect.position.y; + new_rect.size = p_rect_end.min(end) - new_rect.position; return new_rect; } @@ -115,11 +113,9 @@ struct _NO_DISCARD_ Rect2i { #endif Rect2i new_rect; - new_rect.position.x = MIN(p_rect.position.x, position.x); - new_rect.position.y = MIN(p_rect.position.y, position.y); + new_rect.position = p_rect.position.min(position); - new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x, position.x + size.x); - new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y, position.y + size.y); + new_rect.size = (p_rect.position + p_rect.size).max(position + size); new_rect.size = new_rect.size - new_rect.position; // Make relative again. @@ -217,7 +213,7 @@ struct _NO_DISCARD_ Rect2i { } _FORCE_INLINE_ Rect2i abs() const { - return Rect2i(Point2i(position.x + MIN(size.x, 0), position.y + MIN(size.y, 0)), size.abs()); + return Rect2i(position + size.min(Point2i()), size.abs()); } _FORCE_INLINE_ void set_end(const Vector2i &p_end) { diff --git a/core/math/transform_interpolator.cpp b/core/math/transform_interpolator.cpp new file mode 100644 index 0000000000..7cfe880b5a --- /dev/null +++ b/core/math/transform_interpolator.cpp @@ -0,0 +1,76 @@ +/**************************************************************************/ +/* transform_interpolator.cpp */ +/**************************************************************************/ +/* 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. */ +/**************************************************************************/ + +#include "transform_interpolator.h" + +#include "core/math/transform_2d.h" + +void TransformInterpolator::interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction) { + // Extract parameters. + Vector2 p1 = p_prev.get_origin(); + Vector2 p2 = p_curr.get_origin(); + + // Special case for physics interpolation, if flipping, don't interpolate basis. + // If the determinant polarity changes, the handedness of the coordinate system changes. + if (_sign(p_prev.determinant()) != _sign(p_curr.determinant())) { + r_result.columns[0] = p_curr.columns[0]; + r_result.columns[1] = p_curr.columns[1]; + r_result.set_origin(p1.lerp(p2, p_fraction)); + return; + } + + real_t r1 = p_prev.get_rotation(); + real_t r2 = p_curr.get_rotation(); + + Size2 s1 = p_prev.get_scale(); + Size2 s2 = p_curr.get_scale(); + + // Slerp rotation. + Vector2 v1(Math::cos(r1), Math::sin(r1)); + Vector2 v2(Math::cos(r2), Math::sin(r2)); + + real_t dot = v1.dot(v2); + + dot = CLAMP(dot, -1, 1); + + Vector2 v; + + if (dot > 0.9995f) { + v = v1.lerp(v2, p_fraction).normalized(); // Linearly interpolate to avoid numerical precision issues. + } else { + real_t angle = p_fraction * Math::acos(dot); + Vector2 v3 = (v2 - v1 * dot).normalized(); + v = v1 * Math::cos(angle) + v3 * Math::sin(angle); + } + + // Construct matrix. + r_result = Transform2D(Math::atan2(v.y, v.x), p1.lerp(p2, p_fraction)); + r_result.scale_basis(s1.lerp(s2, p_fraction)); +} diff --git a/scene/2d/tile_map_layer_group.h b/core/math/transform_interpolator.h index d80c244f80..a9bce2bd7f 100644 --- a/scene/2d/tile_map_layer_group.h +++ b/core/math/transform_interpolator.h @@ -1,5 +1,5 @@ /**************************************************************************/ -/* tile_map_layer_group.h */ +/* transform_interpolator.h */ /**************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,46 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ -#ifndef TILE_MAP_LAYER_GROUP_H -#define TILE_MAP_LAYER_GROUP_H +#ifndef TRANSFORM_INTERPOLATOR_H +#define TRANSFORM_INTERPOLATOR_H -#include "scene/2d/node_2d.h" +#include "core/math/math_defs.h" -class TileSet; - -class TileMapLayerGroup : public Node2D { - GDCLASS(TileMapLayerGroup, Node2D); +struct Transform2D; +class TransformInterpolator { private: - mutable Vector<StringName> selected_layers; - bool highlight_selected_layer = true; - -#ifdef TOOLS_ENABLED - void _cleanup_selected_layers(); -#endif - void _tile_set_changed(); - -protected: - Ref<TileSet> tile_set; - - virtual void remove_child_notify(Node *p_child) override; - - static void _bind_methods(); + static bool _sign(real_t p_val) { return p_val >= 0; } public: -#ifdef TOOLS_ENABLED - // For editor use. - void set_selected_layers(Vector<StringName> p_layer_names); - Vector<StringName> get_selected_layers() const; - void set_highlight_selected_layer(bool p_highlight_selected_layer); - bool is_highlighting_selected_layer() const; -#endif - - // Accessors. - void set_tileset(const Ref<TileSet> &p_tileset); - Ref<TileSet> get_tileset() const; - - ~TileMapLayerGroup(); + static void interpolate_transform_2d(const Transform2D &p_prev, const Transform2D &p_curr, Transform2D &r_result, real_t p_fraction); }; -#endif // TILE_MAP_LAYER_GROUP_H +#endif // TRANSFORM_INTERPOLATOR_H diff --git a/core/object/object.cpp b/core/object/object.cpp index 8ec2b802bb..8b6fd587e0 100644 --- a/core/object/object.cpp +++ b/core/object/object.cpp @@ -1100,11 +1100,6 @@ bool Object::_has_user_signal(const StringName &p_name) const { return signal_map[p_name].user.name.length() > 0; } -struct _ObjectSignalDisconnectData { - StringName signal; - Callable callable; -}; - Error Object::_emit_signal(const Variant **p_args, int p_argcount, Callable::CallError &r_error) { if (unlikely(p_argcount < 1)) { r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; @@ -1153,26 +1148,43 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int // which is needed in certain edge cases; e.g., https://github.com/godotengine/godot/issues/73889. Ref<RefCounted> rc = Ref<RefCounted>(Object::cast_to<RefCounted>(this)); - List<_ObjectSignalDisconnectData> disconnect_data; - // Ensure that disconnecting the signal or even deleting the object // will not affect the signal calling. - LocalVector<Connection> slot_conns; - slot_conns.resize(s->slot_map.size()); - { - uint32_t idx = 0; - for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) { - slot_conns[idx++] = slot_kv.value.conn; + Callable *slot_callables = (Callable *)alloca(sizeof(Callable) * s->slot_map.size()); + uint32_t *slot_flags = (uint32_t *)alloca(sizeof(uint32_t) * s->slot_map.size()); + uint32_t slot_count = 0; + + for (const KeyValue<Callable, SignalData::Slot> &slot_kv : s->slot_map) { + memnew_placement(&slot_callables[slot_count], Callable(slot_kv.value.conn.callable)); + slot_flags[slot_count] = slot_kv.value.conn.flags; + ++slot_count; + } + + DEV_ASSERT(slot_count == s->slot_map.size()); + + // Disconnect all one-shot connections before emitting to prevent recursion. + for (uint32_t i = 0; i < slot_count; ++i) { + bool disconnect = slot_flags[i] & CONNECT_ONE_SHOT; +#ifdef TOOLS_ENABLED + if (disconnect && (slot_flags[i] & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) { + // This signal was connected from the editor, and is being edited. Just don't disconnect for now. + disconnect = false; + } +#endif + if (disconnect) { + _disconnect(p_name, slot_callables[i]); } - DEV_ASSERT(idx == s->slot_map.size()); } OBJ_DEBUG_LOCK Error err = OK; - for (const Connection &c : slot_conns) { - if (!c.callable.is_valid()) { + for (uint32_t i = 0; i < slot_count; ++i) { + const Callable &callable = slot_callables[i]; + const uint32_t &flags = slot_flags[i]; + + if (!callable.is_valid()) { // Target might have been deleted during signal callback, this is expected and OK. continue; } @@ -1180,51 +1192,34 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int const Variant **args = p_args; int argc = p_argcount; - if (c.flags & CONNECT_DEFERRED) { - MessageQueue::get_singleton()->push_callablep(c.callable, args, argc, true); + if (flags & CONNECT_DEFERRED) { + MessageQueue::get_singleton()->push_callablep(callable, args, argc, true); } else { Callable::CallError ce; _emitting = true; Variant ret; - c.callable.callp(args, argc, ret, ce); + callable.callp(args, argc, ret, ce); _emitting = false; if (ce.error != Callable::CallError::CALL_OK) { #ifdef DEBUG_ENABLED - if (c.flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (script.is_null() || !Ref<Script>(script)->is_tool())) { + if (flags & CONNECT_PERSIST && Engine::get_singleton()->is_editor_hint() && (script.is_null() || !Ref<Script>(script)->is_tool())) { continue; } #endif - Object *target = c.callable.get_object(); + Object *target = callable.get_object(); if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD && target && !ClassDB::class_exists(target->get_class_name())) { //most likely object is not initialized yet, do not throw error. } else { - ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(c.callable, args, argc, ce) + "."); + ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(callable, args, argc, ce) + "."); err = ERR_METHOD_NOT_FOUND; } } } - - bool disconnect = c.flags & CONNECT_ONE_SHOT; -#ifdef TOOLS_ENABLED - if (disconnect && (c.flags & CONNECT_PERSIST) && Engine::get_singleton()->is_editor_hint()) { - //this signal was connected from the editor, and is being edited. just don't disconnect for now - disconnect = false; - } -#endif - if (disconnect) { - _ObjectSignalDisconnectData dd; - dd.signal = p_name; - dd.callable = c.callable; - disconnect_data.push_back(dd); - } } - while (!disconnect_data.is_empty()) { - const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get(); - - _disconnect(dd.signal, dd.callable); - disconnect_data.pop_front(); + for (uint32_t i = 0; i < slot_count; ++i) { + slot_callables[i].~Callable(); } return err; @@ -1535,7 +1530,7 @@ String Object::tr(const StringName &p_message, const StringName &p_context) cons return p_message; } - if (Engine::get_singleton()->is_editor_hint()) { + if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { String tr_msg = TranslationServer::get_singleton()->extractable_translate(p_message, p_context); if (!tr_msg.is_empty() && tr_msg != p_message) { return tr_msg; @@ -1556,7 +1551,7 @@ String Object::tr_n(const StringName &p_message, const StringName &p_message_plu return p_message_plural; } - if (Engine::get_singleton()->is_editor_hint()) { + if (Engine::get_singleton()->is_editor_hint() || Engine::get_singleton()->is_project_manager_hint()) { String tr_msg = TranslationServer::get_singleton()->extractable_translate_plural(p_message, p_message_plural, p_n, p_context); if (!tr_msg.is_empty() && tr_msg != p_message && tr_msg != p_message_plural) { return tr_msg; diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp index 1196c2f787..73da0ba2af 100644 --- a/core/object/script_language.cpp +++ b/core/object/script_language.cpp @@ -34,6 +34,7 @@ #include "core/core_string_names.h" #include "core/debugger/engine_debugger.h" #include "core/debugger/script_debugger.h" +#include "core/io/resource_loader.h" #include <stdint.h> @@ -170,6 +171,24 @@ void Script::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "source_code", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_source_code", "get_source_code"); } +void Script::reload_from_file() { +#ifdef TOOLS_ENABLED + // Replicates how the ScriptEditor reloads script resources, which generally handles it. + // However, when scripts are to be reloaded but aren't open in the internal editor, we go through here instead. + const Ref<Script> rel = ResourceLoader::load(ResourceLoader::path_remap(get_path()), get_class(), ResourceFormatLoader::CACHE_MODE_IGNORE); + if (rel.is_null()) { + return; + } + + set_source_code(rel->get_source_code()); + set_last_modified_time(rel->get_last_modified_time()); + + reload(); +#else + Resource::reload_from_file(); +#endif +} + void ScriptServer::set_scripting_enabled(bool p_enabled) { scripting_enabled = p_enabled; } diff --git a/core/object/script_language.h b/core/object/script_language.h index be50e58d79..c6c6f3de9f 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -125,6 +125,8 @@ protected: Dictionary _get_script_constant_map(); public: + virtual void reload_from_file() override; + virtual bool can_instantiate() const = 0; virtual Ref<Script> get_base_script() const = 0; //for script inheritance diff --git a/core/os/main_loop.h b/core/os/main_loop.h index b45eb38aeb..e48541d074 100644 --- a/core/os/main_loop.h +++ b/core/os/main_loop.h @@ -62,6 +62,7 @@ public: }; virtual void initialize(); + virtual void iteration_prepare() {} virtual bool physics_process(double p_time); virtual bool process(double p_time); virtual void finalize(); diff --git a/core/os/os.h b/core/os/os.h index e0dda0b155..370e724c53 100644 --- a/core/os/os.h +++ b/core/os/os.h @@ -56,7 +56,8 @@ class OS { bool _verbose_stdout = false; bool _debug_stdout = false; String _local_clipboard; - int _exit_code = EXIT_FAILURE; // unexpected exit is marked as failure + // Assume success by default, all failure cases need to set EXIT_FAILURE explicitly. + int _exit_code = EXIT_SUCCESS; bool _allow_hidpi = false; bool _allow_layered = false; bool _stdout_enabled = true; @@ -169,6 +170,7 @@ public: virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const { return Vector<String>(); }; virtual String get_executable_path() const; virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) = 0; + virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) { return Dictionary(); } virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) = 0; virtual Error create_instance(const List<String> &p_arguments, ProcessID *r_child_id = nullptr) { return create_process(get_executable_path(), p_arguments, r_child_id); }; virtual Error kill(const ProcessID &p_pid) = 0; diff --git a/core/string/translation.cpp b/core/string/translation.cpp index 0a0052d6cb..613edd11cd 100644 --- a/core/string/translation.cpp +++ b/core/string/translation.cpp @@ -776,9 +776,9 @@ void TranslationServer::set_property_translation(const Ref<Translation> &p_trans property_translation = p_translation; } -StringName TranslationServer::property_translate(const StringName &p_message) const { +StringName TranslationServer::property_translate(const StringName &p_message, const StringName &p_context) const { if (property_translation.is_valid()) { - StringName r = property_translation->get_message(p_message); + StringName r = property_translation->get_message(p_message, p_context); if (r) { return r; } diff --git a/core/string/translation.h b/core/string/translation.h index 470ba88232..78d6721347 100644 --- a/core/string/translation.h +++ b/core/string/translation.h @@ -183,7 +183,7 @@ public: StringName tool_translate(const StringName &p_message, const StringName &p_context = "") const; StringName tool_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; void set_property_translation(const Ref<Translation> &p_translation); - StringName property_translate(const StringName &p_message) const; + StringName property_translate(const StringName &p_message, const StringName &p_context = "") const; void set_doc_translation(const Ref<Translation> &p_translation); StringName doc_translate(const StringName &p_message, const StringName &p_context = "") const; StringName doc_translate_plural(const StringName &p_message, const StringName &p_message_plural, int p_n, const StringName &p_context = "") const; diff --git a/core/string/ustring.cpp b/core/string/ustring.cpp index a7e12138f2..bdef1b9bbe 100644 --- a/core/string/ustring.cpp +++ b/core/string/ustring.cpp @@ -927,52 +927,49 @@ static _FORCE_INLINE_ signed char natural_cmp_common(const char32_t *&r_this_str return 0; } -signed char String::naturalcasecmp_to(const String &p_str) const { - const char32_t *this_str = get_data(); - const char32_t *that_str = p_str.get_data(); - - if (this_str && that_str) { - while (*this_str == '.' || *that_str == '.') { - if (*this_str++ != '.') { +static _FORCE_INLINE_ signed char naturalcasecmp_to_base(const char32_t *p_this_str, const char32_t *p_that_str) { + if (p_this_str && p_that_str) { + while (*p_this_str == '.' || *p_that_str == '.') { + if (*p_this_str++ != '.') { return 1; } - if (*that_str++ != '.') { + if (*p_that_str++ != '.') { return -1; } - if (!*that_str) { + if (!*p_that_str) { return 1; } - if (!*this_str) { + if (!*p_this_str) { return -1; } } - while (*this_str) { - if (!*that_str) { + while (*p_this_str) { + if (!*p_that_str) { return 1; - } else if (is_digit(*this_str)) { - if (!is_digit(*that_str)) { + } else if (is_digit(*p_this_str)) { + if (!is_digit(*p_that_str)) { return -1; } - signed char ret = natural_cmp_common(this_str, that_str); + signed char ret = natural_cmp_common(p_this_str, p_that_str); if (ret) { return ret; } - } else if (is_digit(*that_str)) { + } else if (is_digit(*p_that_str)) { return 1; } else { - if (*this_str < *that_str) { // If current character in this is less, we are less. + if (*p_this_str < *p_that_str) { // If current character in this is less, we are less. return -1; - } else if (*this_str > *that_str) { // If current character in this is greater, we are greater. + } else if (*p_this_str > *p_that_str) { // If current character in this is greater, we are greater. return 1; } - this_str++; - that_str++; + p_this_str++; + p_that_str++; } } - if (*that_str) { + if (*p_that_str) { return -1; } } @@ -980,52 +977,56 @@ signed char String::naturalcasecmp_to(const String &p_str) const { return 0; } -signed char String::naturalnocasecmp_to(const String &p_str) const { +signed char String::naturalcasecmp_to(const String &p_str) const { const char32_t *this_str = get_data(); const char32_t *that_str = p_str.get_data(); - if (this_str && that_str) { - while (*this_str == '.' || *that_str == '.') { - if (*this_str++ != '.') { + return naturalcasecmp_to_base(this_str, that_str); +} + +static _FORCE_INLINE_ signed char naturalnocasecmp_to_base(const char32_t *p_this_str, const char32_t *p_that_str) { + if (p_this_str && p_that_str) { + while (*p_this_str == '.' || *p_that_str == '.') { + if (*p_this_str++ != '.') { return 1; } - if (*that_str++ != '.') { + if (*p_that_str++ != '.') { return -1; } - if (!*that_str) { + if (!*p_that_str) { return 1; } - if (!*this_str) { + if (!*p_this_str) { return -1; } } - while (*this_str) { - if (!*that_str) { + while (*p_this_str) { + if (!*p_that_str) { return 1; - } else if (is_digit(*this_str)) { - if (!is_digit(*that_str)) { + } else if (is_digit(*p_this_str)) { + if (!is_digit(*p_that_str)) { return -1; } - signed char ret = natural_cmp_common(this_str, that_str); + signed char ret = natural_cmp_common(p_this_str, p_that_str); if (ret) { return ret; } - } else if (is_digit(*that_str)) { + } else if (is_digit(*p_that_str)) { return 1; } else { - if (_find_upper(*this_str) < _find_upper(*that_str)) { // If current character in this is less, we are less. + if (_find_upper(*p_this_str) < _find_upper(*p_that_str)) { // If current character in this is less, we are less. return -1; - } else if (_find_upper(*this_str) > _find_upper(*that_str)) { // If current character in this is greater, we are greater. + } else if (_find_upper(*p_this_str) > _find_upper(*p_that_str)) { // If current character in this is greater, we are greater. return 1; } - this_str++; - that_str++; + p_this_str++; + p_that_str++; } } - if (*that_str) { + if (*p_that_str) { return -1; } } @@ -1033,6 +1034,53 @@ signed char String::naturalnocasecmp_to(const String &p_str) const { return 0; } +signed char String::naturalnocasecmp_to(const String &p_str) const { + const char32_t *this_str = get_data(); + const char32_t *that_str = p_str.get_data(); + + return naturalnocasecmp_to_base(this_str, that_str); +} + +static _FORCE_INLINE_ signed char file_cmp_common(const char32_t *&r_this_str, const char32_t *&r_that_str) { + // Compare leading `_` sequences. + while ((*r_this_str == '_' && *r_that_str) || (*r_this_str && *r_that_str == '_')) { + // Sort `_` lower than everything except `.` + if (*r_this_str != '_') { + return *r_this_str == '.' ? -1 : 1; + } else if (*r_that_str != '_') { + return *r_that_str == '.' ? 1 : -1; + } + r_this_str++; + r_that_str++; + } + + return 0; +} + +signed char String::filecasecmp_to(const String &p_str) const { + const char32_t *this_str = get_data(); + const char32_t *that_str = p_str.get_data(); + + signed char ret = file_cmp_common(this_str, that_str); + if (ret) { + return ret; + } + + return naturalcasecmp_to_base(this_str, that_str); +} + +signed char String::filenocasecmp_to(const String &p_str) const { + const char32_t *this_str = get_data(); + const char32_t *that_str = p_str.get_data(); + + signed char ret = file_cmp_common(this_str, that_str); + if (ret) { + return ret; + } + + return naturalnocasecmp_to_base(this_str, that_str); +} + const char32_t *String::get_data() const { static const char32_t zero = 0; return size() ? &operator[](0) : &zero; @@ -1822,7 +1870,7 @@ Error String::parse_utf8(const char *p_utf8, int p_len, bool p_skip_cr) { bool decode_failed = false; { const char *ptrtmp = p_utf8; - const char *ptrtmp_limit = &p_utf8[p_len]; + const char *ptrtmp_limit = p_len >= 0 ? &p_utf8[p_len] : nullptr; int skip = 0; uint8_t c_start = 0; while (ptrtmp != ptrtmp_limit && *ptrtmp) { @@ -2099,7 +2147,7 @@ Error String::parse_utf16(const char16_t *p_utf16, int p_len) { bool decode_error = false; { const char16_t *ptrtmp = p_utf16; - const char16_t *ptrtmp_limit = &p_utf16[p_len]; + const char16_t *ptrtmp_limit = p_len >= 0 ? &p_utf16[p_len] : nullptr; uint32_t c_prev = 0; bool skip = false; while (ptrtmp != ptrtmp_limit && *ptrtmp) { diff --git a/core/string/ustring.h b/core/string/ustring.h index 0fb72fccd2..fa904c8200 100644 --- a/core/string/ustring.h +++ b/core/string/ustring.h @@ -265,6 +265,9 @@ public: signed char nocasecmp_to(const String &p_str) const; signed char naturalcasecmp_to(const String &p_str) const; signed char naturalnocasecmp_to(const String &p_str) const; + // Special sorting for file names. Names starting with `_` are put before all others except those starting with `.`, otherwise natural comparison is used. + signed char filecasecmp_to(const String &p_str) const; + signed char filenocasecmp_to(const String &p_str) const; const char32_t *get_data() const; /* standard size stuff */ @@ -499,6 +502,12 @@ struct NaturalNoCaseComparator { } }; +struct FileNoCaseComparator { + bool operator()(const String &p_a, const String &p_b) const { + return p_a.filenocasecmp_to(p_b) < 0; + } +}; + template <typename L, typename R> _FORCE_INLINE_ bool is_str_less(const L *l_ptr, const R *r_ptr) { while (true) { diff --git a/core/templates/local_vector.h b/core/templates/local_vector.h index 6478297fd1..e0047e0782 100644 --- a/core/templates/local_vector.h +++ b/core/templates/local_vector.h @@ -104,6 +104,22 @@ public: return false; } + U erase_multiple_unordered(const T &p_val) { + U from = 0; + U occurrences = 0; + while (true) { + int64_t idx = find(p_val, from); + + if (idx == -1) { + break; + } + remove_at_unordered(idx); + from = idx; + occurrences++; + } + return occurrences; + } + void invert() { for (U i = 0; i < count / 2; i++) { SWAP(data[i], data[count - i - 1]); diff --git a/core/variant/type_info.h b/core/variant/type_info.h index 32c410463b..9c52db3345 100644 --- a/core/variant/type_info.h +++ b/core/variant/type_info.h @@ -296,6 +296,7 @@ public: _FORCE_INLINE_ constexpr BitField(T p_value) { value = (int64_t)p_value; } _FORCE_INLINE_ operator int64_t() const { return value; } _FORCE_INLINE_ operator Variant() const { return value; } + _FORCE_INLINE_ BitField<T> operator^(const BitField<T> &p_b) const { return BitField<T>(value ^ p_b.value); } }; #define TEMPL_MAKE_BITFIELD_TYPE_INFO(m_enum, m_impl) \ diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp index 5f04c42536..ba7c44e405 100644 --- a/core/variant/variant_call.cpp +++ b/core/variant/variant_call.cpp @@ -1644,6 +1644,8 @@ static void _register_variant_builtin_methods() { bind_string_method(nocasecmp_to, sarray("to"), varray()); bind_string_method(naturalcasecmp_to, sarray("to"), varray()); bind_string_method(naturalnocasecmp_to, sarray("to"), varray()); + bind_string_method(filecasecmp_to, sarray("to"), varray()); + bind_string_method(filenocasecmp_to, sarray("to"), varray()); bind_string_method(length, sarray(), varray()); bind_string_method(substr, sarray("from", "len"), varray(-1)); bind_string_method(get_slice, sarray("delimiter", "slice"), varray()); diff --git a/doc/classes/AStar2D.xml b/doc/classes/AStar2D.xml index f10e80e048..c877b3de78 100644 --- a/doc/classes/AStar2D.xml +++ b/doc/classes/AStar2D.xml @@ -139,8 +139,10 @@ <return type="PackedInt64Array" /> <param index="0" name="from_id" type="int" /> <param index="1" name="to_id" type="int" /> + <param index="2" name="allow_partial_path" type="bool" default="false" /> <description> Returns an array with the IDs of the points that form the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path. + If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached. [codeblocks] [gdscript] var astar = AStar2D.new() @@ -228,8 +230,10 @@ <return type="PackedVector2Array" /> <param index="0" name="from_id" type="int" /> <param index="1" name="to_id" type="int" /> + <param index="2" name="allow_partial_path" type="bool" default="false" /> <description> Returns an array with the points that are in the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path. + If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached. [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector2Array] and will print an error message. </description> </method> diff --git a/doc/classes/AStar3D.xml b/doc/classes/AStar3D.xml index e2afeef377..c8a80a9012 100644 --- a/doc/classes/AStar3D.xml +++ b/doc/classes/AStar3D.xml @@ -168,8 +168,10 @@ <return type="PackedInt64Array" /> <param index="0" name="from_id" type="int" /> <param index="1" name="to_id" type="int" /> + <param index="2" name="allow_partial_path" type="bool" default="false" /> <description> Returns an array with the IDs of the points that form the path found by AStar3D between the given points. The array is ordered from the starting point to the ending point of the path. + If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached. [codeblocks] [gdscript] var astar = AStar3D.new() @@ -255,8 +257,10 @@ <return type="PackedVector3Array" /> <param index="0" name="from_id" type="int" /> <param index="1" name="to_id" type="int" /> + <param index="2" name="allow_partial_path" type="bool" default="false" /> <description> Returns an array with the points that are in the path found by AStar3D between the given points. The array is ordered from the starting point to the ending point of the path. + If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached. [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message. </description> </method> diff --git a/doc/classes/AStarGrid2D.xml b/doc/classes/AStarGrid2D.xml index 4501bec314..794e40fde9 100644 --- a/doc/classes/AStarGrid2D.xml +++ b/doc/classes/AStarGrid2D.xml @@ -75,16 +75,20 @@ <return type="Vector2i[]" /> <param index="0" name="from_id" type="Vector2i" /> <param index="1" name="to_id" type="Vector2i" /> + <param index="2" name="allow_partial_path" type="bool" default="false" /> <description> Returns an array with the IDs of the points that form the path found by AStar2D between the given points. The array is ordered from the starting point to the ending point of the path. + If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached. </description> </method> <method name="get_point_path"> <return type="PackedVector2Array" /> <param index="0" name="from_id" type="Vector2i" /> <param index="1" name="to_id" type="Vector2i" /> + <param index="2" name="allow_partial_path" type="bool" default="false" /> <description> Returns an array with the points that are in the path found by [AStarGrid2D] between the given points. The array is ordered from the starting point to the ending point of the path. + If there is no valid path to the target, and [param allow_partial_path] is [code]true[/code], returns a path to the point closest to the target that can be reached. [b]Note:[/b] This method is not thread-safe. If called from a [Thread], it will return an empty [PackedVector3Array] and will print an error message. </description> </method> diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml index d7fb735b4d..960bbe68ad 100644 --- a/doc/classes/AnimationNode.xml +++ b/doc/classes/AnimationNode.xml @@ -6,6 +6,13 @@ <description> Base resource for [AnimationTree] nodes. In general, it's not used directly, but you can create custom ones with custom blending formulas. Inherit this when creating animation nodes mainly for use in [AnimationNodeBlendTree], otherwise [AnimationRootNode] should be used instead. + You can access the time information as read-only parameter which is processed and stored in the previous frame for all nodes except [AnimationNodeOutput]. + [b]Note:[/b] If more than two inputs exist in the [AnimationNode], which time information takes precedence depends on the type of [AnimationNode]. + [codeblock] + var current_length = $AnimationTree[parameters/AnimationNodeName/current_length] + var current_position = $AnimationTree[parameters/AnimationNodeName/current_position] + var current_delta = $AnimationTree[parameters/AnimationNodeName/current_delta] + [/codeblock] </description> <tutorials> <link title="Using AnimationTree">$DOCS_URL/tutorials/animation/animation_tree.html</link> @@ -56,7 +63,7 @@ When inheriting from [AnimationRootNode], implement this virtual method to return whether the [param parameter] is read-only. Parameters are custom local memory used for your animation nodes, given a resource can be reused in multiple trees. </description> </method> - <method name="_process" qualifiers="virtual const"> + <method name="_process" qualifiers="virtual const" deprecated="Currently this is mostly useless as there is a lack of many APIs to extend AnimationNode by GDScript. It is planned that a more flexible API using structures will be provided in the future."> <return type="float" /> <param index="0" name="time" type="float" /> <param index="1" name="seek" type="bool" /> @@ -65,7 +72,7 @@ <description> When inheriting from [AnimationRootNode], implement this virtual method to run some code when this animation node is processed. The [param time] parameter is a relative delta, unless [param seek] is [code]true[/code], in which case it is absolute. Here, call the [method blend_input], [method blend_node] or [method blend_animation] functions. You can also use [method get_parameter] and [method set_parameter] to modify local memory. - This function should return the time left for the current animation to finish (if unsure, pass the value from the main blend being called). + This function should return the delta. </description> </method> <method name="add_input"> diff --git a/doc/classes/AnimationNodeAnimation.xml b/doc/classes/AnimationNodeAnimation.xml index d965d31b03..5683371182 100644 --- a/doc/classes/AnimationNodeAnimation.xml +++ b/doc/classes/AnimationNodeAnimation.xml @@ -15,9 +15,27 @@ <member name="animation" type="StringName" setter="set_animation" getter="get_animation" default="&"""> Animation to use as an output. It is one of the animations provided by [member AnimationTree.anim_player]. </member> + <member name="loop_mode" type="int" setter="set_loop_mode" getter="get_loop_mode" enum="Animation.LoopMode"> + If [member use_custom_timeline] is [code]true[/code], override the loop settings of the original [Animation] resource with the value. + </member> <member name="play_mode" type="int" setter="set_play_mode" getter="get_play_mode" enum="AnimationNodeAnimation.PlayMode" default="0"> Determines the playback direction of the animation. </member> + <member name="start_offset" type="float" setter="set_start_offset" getter="get_start_offset"> + If [member use_custom_timeline] is [code]true[/code], offset the start position of the animation. + This is useful for adjusting which foot steps first in 3D walking animations. + </member> + <member name="stretch_time_scale" type="bool" setter="set_stretch_time_scale" getter="is_stretching_time_scale"> + If [code]true[/code], scales the time so that the length specified in [member timeline_length] is one cycle. + This is useful for matching the periods of walking and running animations. + If [code]false[/code], the original animation length is respected. If you set the loop to [member loop_mode], the animation will loop in [member timeline_length]. + </member> + <member name="timeline_length" type="float" setter="set_timeline_length" getter="get_timeline_length"> + If [member use_custom_timeline] is [code]true[/code], offset the start position of the animation. + </member> + <member name="use_custom_timeline" type="bool" setter="set_use_custom_timeline" getter="is_using_custom_timeline" default="false"> + If [code]true[/code], [AnimationNode] provides an animation based on the [Animation] resource with some parameters adjusted. + </member> </members> <constants> <constant name="PLAY_MODE_FORWARD" value="0" enum="PlayMode"> diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml index ac7cf70133..6ff2d6f6db 100644 --- a/doc/classes/AnimationNodeOneShot.xml +++ b/doc/classes/AnimationNodeOneShot.xml @@ -66,17 +66,22 @@ <member name="autorestart_random_delay" type="float" setter="set_autorestart_random_delay" getter="get_autorestart_random_delay" default="0.0"> If [member autorestart] is [code]true[/code], a random additional delay (in seconds) between 0 and this value will be added to [member autorestart_delay]. </member> + <member name="break_loop_at_end" type="bool" setter="set_break_loop_at_end" getter="is_loop_broken_at_end" default="false"> + If [code]true[/code], breaks the loop at the end of the loop cycle for transition, even if the animation is looping. + </member> <member name="fadein_curve" type="Curve" setter="set_fadein_curve" getter="get_fadein_curve"> Determines how cross-fading between animations is eased. If empty, the transition will be linear. </member> <member name="fadein_time" type="float" setter="set_fadein_time" getter="get_fadein_time" default="0.0"> The fade-in duration. For example, setting this to [code]1.0[/code] for a 5 second length animation will produce a cross-fade that starts at 0 second and ends at 1 second during the animation. + [b]Note:[/b] [AnimationNodeOneShot] transitions the current state after the end of the fading. When [AnimationNodeOutput] is considered as the most upstream, so the [member fadein_time] is scaled depending on the downstream delta. For example, if this value is set to [code]1.0[/code] and a [AnimationNodeTimeScale] with a value of [code]2.0[/code] is chained downstream, the actual processing time will be 0.5 second. </member> <member name="fadeout_curve" type="Curve" setter="set_fadeout_curve" getter="get_fadeout_curve"> Determines how cross-fading between animations is eased. If empty, the transition will be linear. </member> <member name="fadeout_time" type="float" setter="set_fadeout_time" getter="get_fadeout_time" default="0.0"> The fade-out duration. For example, setting this to [code]1.0[/code] for a 5 second length animation will produce a cross-fade that starts at 4 second and ends at 5 second during the animation. + [b]Note:[/b] [AnimationNodeOneShot] transitions the current state after the end of the fading. When [AnimationNodeOutput] is considered as the most upstream, so the [member fadeout_time] is scaled depending on the downstream delta. For example, if this value is set to [code]1.0[/code] and an [AnimationNodeTimeScale] with a value of [code]2.0[/code] is chained downstream, the actual processing time will be 0.5 second. </member> <member name="mix_mode" type="int" setter="set_mix_mode" getter="get_mix_mode" enum="AnimationNodeOneShot.MixMode" default="0"> The blend type. diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml index 7b7797f594..7bd0bd7e7e 100644 --- a/doc/classes/AnimationNodeStateMachineTransition.xml +++ b/doc/classes/AnimationNodeStateMachineTransition.xml @@ -28,6 +28,9 @@ <member name="advance_mode" type="int" setter="set_advance_mode" getter="get_advance_mode" enum="AnimationNodeStateMachineTransition.AdvanceMode" default="1"> Determines whether the transition should disabled, enabled when using [method AnimationNodeStateMachinePlayback.travel], or traversed automatically if the [member advance_condition] and [member advance_expression] checks are true (if assigned). </member> + <member name="break_loop_at_end" type="bool" setter="set_break_loop_at_end" getter="is_loop_broken_at_end" default="false"> + If [code]true[/code], breaks the loop at the end of the loop cycle for transition, even if the animation is looping. + </member> <member name="priority" type="int" setter="set_priority" getter="get_priority" default="1"> Lower priority transitions are preferred when travelling through the tree via [method AnimationNodeStateMachinePlayback.travel] or [member advance_mode] is set to [constant ADVANCE_MODE_AUTO]. </member> @@ -42,6 +45,7 @@ </member> <member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0"> The time to cross-fade between this state and the next. + [b]Note:[/b] [AnimationNodeStateMachine] transitions the current state immediately after the start of the fading. The precise remaining time can only be inferred from the main animation. When [AnimationNodeOutput] is considered as the most upstream, so the [member xfade_time] is not scaled depending on the downstream delta. See also [member AnimationNodeOneShot.fadeout_time]. </member> </members> <signals> diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml index 3e1a0a28b5..775a208735 100644 --- a/doc/classes/AnimationNodeTransition.xml +++ b/doc/classes/AnimationNodeTransition.xml @@ -42,6 +42,13 @@ <link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link> </tutorials> <methods> + <method name="is_input_loop_broken_at_end" qualifiers="const"> + <return type="bool" /> + <param index="0" name="input" type="int" /> + <description> + Returns whether the animation breaks the loop at the end of the loop cycle for transition. + </description> + </method> <method name="is_input_reset" qualifiers="const"> <return type="bool" /> <param index="0" name="input" type="int" /> @@ -64,6 +71,14 @@ Enables or disables auto-advance for the given [param input] index. If enabled, state changes to the next input after playing the animation once. If enabled for the last input state, it loops to the first. </description> </method> + <method name="set_input_break_loop_at_end"> + <return type="void" /> + <param index="0" name="input" type="int" /> + <param index="1" name="enable" type="bool" /> + <description> + If [code]true[/code], breaks the loop at the end of the loop cycle for transition, even if the animation is looping. + </description> + </method> <method name="set_input_reset"> <return type="void" /> <param index="0" name="input" type="int" /> @@ -85,6 +100,7 @@ </member> <member name="xfade_time" type="float" setter="set_xfade_time" getter="get_xfade_time" default="0.0"> Cross-fading time (in seconds) between each animation connected to the inputs. + [b]Note:[/b] [AnimationNodeTransition] transitions the current state immediately after the start of the fading. The precise remaining time can only be inferred from the main animation. When [AnimationNodeOutput] is considered as the most upstream, so the [member xfade_time] is not scaled depending on the downstream delta. See also [member AnimationNodeOneShot.fadeout_time]. </member> </members> </class> diff --git a/doc/classes/AudioEffectHardLimiter.xml b/doc/classes/AudioEffectHardLimiter.xml new file mode 100644 index 0000000000..7616b91f97 --- /dev/null +++ b/doc/classes/AudioEffectHardLimiter.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="AudioEffectHardLimiter" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Adds a hard limiter audio effect to an Audio bus. + </brief_description> + <description> + A limiter is an effect designed to disallow sound from going over a given dB threshold. Hard limiters predict volume peaks, and will smoothly apply gain reduction when a peak crosses the ceiling threshold to prevent clipping and distortion. It preserves the waveform and prevents it from crossing the ceiling threshold. Adding one in the Master bus is recommended as a safety measure to prevent sudden volume peaks from occurring, and to prevent distortion caused by clipping. + </description> + <tutorials> + <link title="Audio buses">$DOCS_URL/tutorials/audio/audio_buses.html</link> + </tutorials> + <members> + <member name="ceiling_db" type="float" setter="set_ceiling_db" getter="get_ceiling_db" default="-0.3"> + The waveform's maximum allowed value, in decibels. This value can range from [code]-24.0[/code] to [code]0.0[/code]. + The default value of [code]-0.3[/code] prevents potential inter-sample peaks (ISP) from crossing over 0 dB, which can cause slight distortion on some older hardware. + </member> + <member name="pre_gain_db" type="float" setter="set_pre_gain_db" getter="get_pre_gain_db" default="0.0"> + Gain to apply before limiting, in decibels. + </member> + <member name="release" type="float" setter="set_release" getter="get_release" default="0.1"> + Time it takes in seconds for the gain reduction to fully release. + </member> + </members> +</class> diff --git a/doc/classes/AudioEffectLimiter.xml b/doc/classes/AudioEffectLimiter.xml index 57861d0485..b1a80cd9ef 100644 --- a/doc/classes/AudioEffectLimiter.xml +++ b/doc/classes/AudioEffectLimiter.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="AudioEffectLimiter" inherits="AudioEffect" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="AudioEffectLimiter" inherits="AudioEffect" deprecated="Use [AudioEffectHardLimiter] instead." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Adds a soft-clip limiter audio effect to an Audio bus. </brief_description> diff --git a/doc/classes/CollisionPolygon2D.xml b/doc/classes/CollisionPolygon2D.xml index 12f7024518..29535ffd64 100644 --- a/doc/classes/CollisionPolygon2D.xml +++ b/doc/classes/CollisionPolygon2D.xml @@ -4,7 +4,7 @@ A node that provides a polygon shape to a [CollisionObject2D] parent. </brief_description> <description> - A node that provides a thickened polygon shape (a prism) to a [CollisionObject2D] parent and allows to edit it. The polygon can be concave or convex. This can give a detection shape to an [Area2D] or turn [PhysicsBody2D] into a solid object. + A node that provides a polygon shape to a [CollisionObject2D] parent and allows to edit it. The polygon can be concave or convex. This can give a detection shape to an [Area2D], turn [PhysicsBody2D] into a solid object, or give a hollow shape to a [StaticBody2D]. [b]Warning:[/b] A non-uniformly scaled [CollisionShape2D] will likely not behave as expected. Make sure to keep its scale the same on all axes and adjust its shape resource instead. </description> <tutorials> diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml index 43c3f5c1be..cc32964e87 100644 --- a/doc/classes/Control.xml +++ b/doc/classes/Control.xml @@ -1012,6 +1012,7 @@ Distance between the node's top edge and its parent control, based on [member anchor_top]. Offsets are often controlled by one or multiple parent [Container] nodes, so you should not modify them manually if your node is a direct child of a [Container]. Offsets update automatically when you move or resize the node. </member> + <member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" overrides="Node" enum="Node.PhysicsInterpolationMode" default="2" /> <member name="pivot_offset" type="Vector2" setter="set_pivot_offset" getter="get_pivot_offset" default="Vector2(0, 0)"> By default, the node's pivot is its top-left corner. When you change its [member rotation] or [member scale], it will rotate or scale around this pivot. Set this property to [member size] / 2 to pivot around the Control's center. </member> @@ -1181,6 +1182,14 @@ - One of the node's theme property overrides is changed. - The node enters the scene tree. [b]Note:[/b] As an optimization, this notification won't be sent from changes that occur while this node is outside of the scene tree. Instead, all of the theme item updates can be applied at once when the node enters the scene tree. + [b]Note:[/b] This notification is received alongside [constant Node.NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup theming for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method Node.is_node_ready]. + [codeblock] + func _notification(what): + if what == NOTIFICATION_THEME_CHANGED: + if not is_node_ready(): + await ready # Wait until ready signal. + $Label.add_theme_color_override("font_color", Color.YELLOW) + [/codeblock] </constant> <constant name="NOTIFICATION_SCROLL_BEGIN" value="47"> Sent when this node is inside a [ScrollContainer] which has begun being scrolled when dragging the scrollable area [i]with a touch event[/i]. This notification is [i]not[/i] sent when scrolling by dragging the scrollbar, scrolling with the mouse wheel or scrolling with keyboard/gamepad events. diff --git a/doc/classes/DTLSServer.xml b/doc/classes/DTLSServer.xml index f4c75a731d..41e241779a 100644 --- a/doc/classes/DTLSServer.xml +++ b/doc/classes/DTLSServer.xml @@ -45,7 +45,7 @@ { private DtlsServer _dtls = new DtlsServer(); private UdpServer _server = new UdpServer(); - private Godot.Collections.Array<PacketPeerDTLS> _peers = new Godot.Collections.Array<PacketPeerDTLS>(); + private Godot.Collections.Array<PacketPeerDtls> _peers = new Godot.Collections.Array<PacketPeerDtls>(); public override void _Ready() { @@ -59,8 +59,8 @@ { while (Server.IsConnectionAvailable()) { - PacketPeerUDP peer = _server.TakeConnection(); - PacketPeerDTLS dtlsPeer = _dtls.TakeConnection(peer); + PacketPeerUdp peer = _server.TakeConnection(); + PacketPeerDtls dtlsPeer = _dtls.TakeConnection(peer); if (dtlsPeer.GetStatus() != PacketPeerDtls.Status.Handshaking) { continue; // It is normal that 50% of the connections fails due to cookie exchange. diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml index ecb8438edb..9eb5f9e334 100644 --- a/doc/classes/DisplayServer.xml +++ b/doc/classes/DisplayServer.xml @@ -103,7 +103,7 @@ <param index="3" name="callback" type="Callable" /> <description> Shows a text input dialog which uses the operating system's native look-and-feel. [param callback] should accept a single [String] parameter which contains the text field's contents. - [b]Note:[/b] This method is implemented only on macOS and Windows. + [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_INPUT] feature. Supported platforms include macOS and Windows. </description> </method> <method name="dialog_show"> @@ -114,7 +114,7 @@ <param index="3" name="callback" type="Callable" /> <description> Shows a text dialog which uses the operating system's native look-and-feel. [param callback] should accept a single [int] parameter which corresponds to the index of the pressed button. - [b]Note:[/b] This method is implemented only on macOS and Windows. + [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature. Supported platforms include macOS and Windows. </description> </method> <method name="enable_for_stealing_focus"> @@ -138,7 +138,7 @@ Displays OS native dialog for selecting files or directories in the file system. Each filter string in the [param filters] array should be formatted like this: [code]*.txt,*.doc;Text Files[/code]. The description text of the filter is optional and can be omitted. See also [member FileDialog.filters]. Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int[/code]. - [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS. + [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_FILE] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS. [b]Note:[/b] [param current_directory] might be ignored. [b]Note:[/b] On Linux, [param show_hidden] is ignored. [b]Note:[/b] On macOS, native file dialogs have no title. @@ -164,7 +164,7 @@ - [code]"values"[/code] - [PackedStringArray] of values. If empty, boolean option (check box) is used. - [code]"default"[/code] - default selected option index ([int]) or default boolean value ([bool]). Callbacks have the following arguments: [code]status: bool, selected_paths: PackedStringArray, selected_filter_index: int, selected_option: Dictionary[/code]. - [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS. + [b]Note:[/b] This method is implemented if the display server has the [constant FEATURE_NATIVE_DIALOG_FILE] feature. Supported platforms include Linux (X11/Wayland), Windows, and macOS. [b]Note:[/b] [param current_directory] might be ignored. [b]Note:[/b] On Linux (X11), [param show_hidden] is ignored. [b]Note:[/b] On macOS, native file dialogs have no title. @@ -553,7 +553,7 @@ <param index="0" name="menu_root" type="String" /> <param index="1" name="tag" type="Variant" /> <description> - Returns the index of the item with the specified [param tag]. Index is automatically assigned to each item by the engine. Index can not be set manually. + Returns the index of the item with the specified [param tag]. Indices are automatically assigned to each item by the engine, and cannot be set manually. [b]Note:[/b] This method is implemented only on macOS. </description> </method> @@ -562,7 +562,7 @@ <param index="0" name="menu_root" type="String" /> <param index="1" name="text" type="String" /> <description> - Returns the index of the item with the specified [param text]. Index is automatically assigned to each item by the engine. Index can not be set manually. + Returns the index of the item with the specified [param text]. Indices are automatically assigned to each item by the engine, and cannot be set manually. [b]Note:[/b] This method is implemented only on macOS. </description> </method> @@ -1784,7 +1784,7 @@ Display server supports setting the mouse cursor shape to a custom image. [b]Windows, macOS, Linux (X11/Wayland), Web[/b] </constant> <constant name="FEATURE_NATIVE_DIALOG" value="9" enum="Feature"> - Display server supports spawning dialogs using the operating system's native look-and-feel. [b]Windows, macOS, Linux (X11/Wayland)[/b] + Display server supports spawning text dialogs using the operating system's native look-and-feel. See [method dialog_show]. [b]Windows, macOS[/b] </constant> <constant name="FEATURE_IME" value="10" enum="Feature"> Display server supports [url=https://en.wikipedia.org/wiki/Input_method]Input Method Editor[/url], which is commonly used for inputting Chinese/Japanese/Korean text. This is handled by the operating system, rather than by Godot. [b]Windows, macOS, Linux (X11)[/b] @@ -1825,6 +1825,12 @@ <constant name="FEATURE_NATIVE_HELP" value="23" enum="Feature"> Display server supports native help system search callbacks. See [method help_set_search_callbacks]. </constant> + <constant name="FEATURE_NATIVE_DIALOG_INPUT" value="24" enum="Feature"> + Display server supports spawning text input dialogs using the operating system's native look-and-feel. See [method dialog_input_text]. [b]Windows, macOS[/b] + </constant> + <constant name="FEATURE_NATIVE_DIALOG_FILE" value="25" enum="Feature"> + Display server supports spawning dialogs for selecting files or directories using the operating system's native look-and-feel. See [method file_dialog_show] and [method file_dialog_with_options_show]. [b]Windows, macOS, Linux (X11/Wayland)[/b] + </constant> <constant name="MOUSE_MODE_VISIBLE" value="0" enum="MouseMode"> Makes the mouse cursor visible if it is hidden. </constant> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index f446d5bb1f..9f0b86e877 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -448,6 +448,9 @@ The color to use for the TileMap editor's grid. [b]Note:[/b] Only effective if [member editors/tiles_editor/display_grid] is [code]true[/code]. </member> + <member name="editors/tiles_editor/highlight_selected_layer" type="bool" setter="" getter=""> + Highlight the currently selected TileMapLayer by dimming the other ones in the scene. + </member> <member name="editors/visual_editors/category_colors/color_color" type="Color" setter="" getter=""> The color of a graph node's header when it belongs to the "Color" category. </member> @@ -1031,6 +1034,12 @@ The number of pixels to scroll with every mouse wheel increment. Higher values make the script scroll by faster when using the mouse wheel. [b]Note:[/b] You can hold down [kbd]Alt[/kbd] while using the mouse wheel to temporarily scroll 5 times faster. </member> + <member name="text_editor/completion/add_node_path_literals" type="bool" setter="" getter=""> + If [code]true[/code], uses [NodePath] instead of [String] when appropriate for code autocompletion or for drag and dropping object properties into the script editor. + </member> + <member name="text_editor/completion/add_string_name_literals" type="bool" setter="" getter=""> + If [code]true[/code], uses [StringName] instead of [String] when appropriate for code autocompletion. + </member> <member name="text_editor/completion/add_type_hints" type="bool" setter="" getter=""> If [code]true[/code], adds [url=$DOCS_URL/tutorials/scripting/gdscript/static_typing.html]GDScript static typing[/url] hints such as [code]-> void[/code] and [code]: int[/code] when using code autocompletion or when creating onready variables by drag and dropping nodes into the script editor while pressing the [kbd]Ctrl[/kbd] key. If [code]true[/code], newly created scripts will also automatically have type hints added to their method parameters and return types. </member> diff --git a/doc/classes/HTTPClient.xml b/doc/classes/HTTPClient.xml index 25b6a48283..b6007a3b6b 100644 --- a/doc/classes/HTTPClient.xml +++ b/doc/classes/HTTPClient.xml @@ -156,9 +156,9 @@ [/gdscript] [csharp] var fields = new Godot.Collections.Dictionary { { "username", "user" }, { "password", "pass" } }; - string queryString = new HTTPClient().QueryStringFromDict(fields); + string queryString = new HttpClient().QueryStringFromDict(fields); string[] headers = { "Content-Type: application/x-www-form-urlencoded", $"Content-Length: {queryString.Length}" }; - var result = new HTTPClient().Request(HTTPClient.Method.Post, "index.php", headers, queryString); + var result = new HttpClient().Request(HttpClient.Method.Post, "index.php", headers, queryString); [/csharp] [/codeblocks] [b]Note:[/b] The [param body] parameter is ignored if [param method] is [constant HTTPClient.METHOD_GET]. This is because GET methods can't contain request data. As a workaround, you can pass request data as a query string in the URL. See [method String.uri_encode] for an example. diff --git a/doc/classes/HTTPRequest.xml b/doc/classes/HTTPRequest.xml index 03c1ce2e00..6efa675a71 100644 --- a/doc/classes/HTTPRequest.xml +++ b/doc/classes/HTTPRequest.xml @@ -43,7 +43,7 @@ public override void _Ready() { // Create an HTTP request node and connect its completion signal. - var httpRequest = new HTTPRequest(); + var httpRequest = new HttpRequest(); AddChild(httpRequest); httpRequest.RequestCompleted += HttpRequestCompleted; @@ -61,7 +61,7 @@ { { "name", "Godette" } }); - error = httpRequest.Request("https://httpbin.org/post", null, HTTPClient.Method.Post, body); + error = httpRequest.Request("https://httpbin.org/post", null, HttpClient.Method.Post, body); if (error != Error.Ok) { GD.PushError("An error occurred in the HTTP request."); @@ -115,7 +115,7 @@ public override void _Ready() { // Create an HTTP request node and connect its completion signal. - var httpRequest = new HTTPRequest(); + var httpRequest = new HttpRequest(); AddChild(httpRequest); httpRequest.RequestCompleted += HttpRequestCompleted; @@ -130,7 +130,7 @@ // Called when the HTTP request is completed. private void HttpRequestCompleted(long result, long responseCode, string[] headers, byte[] body) { - if (result != (long)HTTPRequest.Result.Success) + if (result != (long)HttpRequest.Result.Success) { GD.PushError("Image couldn't be downloaded. Try a different image."); } diff --git a/doc/classes/HeightMapShape3D.xml b/doc/classes/HeightMapShape3D.xml index ba79cbc89a..7e3055b34e 100644 --- a/doc/classes/HeightMapShape3D.xml +++ b/doc/classes/HeightMapShape3D.xml @@ -6,6 +6,19 @@ <description> A 3D heightmap shape, intended for use in physics. Usually used to provide a shape for a [CollisionShape3D]. This is useful for terrain, but it is limited as overhangs (such as caves) cannot be stored. Holes in a [HeightMapShape3D] are created by assigning very low values to points in the desired area. [b]Performance:[/b] [HeightMapShape3D] is faster to check collisions against than [ConcavePolygonShape3D], but it is significantly slower than primitive shapes like [BoxShape3D]. + A heightmap collision shape can also be build by using an [Image] reference: + [codeblocks] + [gdscript] + var heightmap_texture: Texture = ResourceLoader.load("res://heightmap_image.exr") + var heightmap_image: Image = heightmap_texture.get_image() + heightmap_image.convert(Image.FORMAT_RF) + + var height_min: float = 0.0 + var height_max: float = 10.0 + + update_map_data_from_image(heightmap_image, height_min, height_max) + [/gdscript] + [/codeblocks] </description> <tutorials> </tutorials> @@ -22,6 +35,17 @@ Returns the smallest height value found in [member map_data]. Recalculates only when [member map_data] changes. </description> </method> + <method name="update_map_data_from_image"> + <return type="void" /> + <param index="0" name="image" type="Image" /> + <param index="1" name="height_min" type="float" /> + <param index="2" name="height_max" type="float" /> + <description> + Updates [member map_data] with data read from an [Image] reference. Automatically resizes heightmap [member map_width] and [member map_depth] to fit the full image width and height. + The image needs to be in either [constant Image.FORMAT_RF] (32 bit), [constant Image.FORMAT_RH] (16 bit), or [constant Image.FORMAT_R8] (8 bit). + Each image pixel is read in as a float on the range from [code]0.0[/code] (black pixel) to [code]1.0[/code] (white pixel). This range value gets remapped to [param height_min] and [param height_max] to form the final height value. + </description> + </method> </methods> <members> <member name="map_data" type="PackedFloat32Array" setter="set_map_data" getter="get_map_data" default="PackedFloat32Array(0, 0, 0, 0)"> diff --git a/doc/classes/InputEvent.xml b/doc/classes/InputEvent.xml index 391d060fc3..96a4612466 100644 --- a/doc/classes/InputEvent.xml +++ b/doc/classes/InputEvent.xml @@ -117,7 +117,12 @@ <members> <member name="device" type="int" setter="set_device" getter="get_device" default="0"> The event's device ID. - [b]Note:[/b] This device ID will always be [code]-1[/code] for emulated mouse input from a touchscreen. This can be used to distinguish emulated mouse input from physical mouse input. + [b]Note:[/b] [member device] can be negative for special use cases that don't refer to devices physically present on the system. See [constant DEVICE_ID_EMULATION]. </member> </members> + <constants> + <constant name="DEVICE_ID_EMULATION" value="-1"> + Device ID used for emulated mouse input from a touchscreen, or for emulated touch input from a mouse. This can be used to distinguish emulated mouse input from physical mouse input, or emulated touch input from physical touch input. + </constant> + </constants> </class> diff --git a/doc/classes/InputEventMIDI.xml b/doc/classes/InputEventMIDI.xml index 0f0b756651..4dcaf98747 100644 --- a/doc/classes/InputEventMIDI.xml +++ b/doc/classes/InputEventMIDI.xml @@ -37,13 +37,13 @@ public override void _Input(InputEvent inputEvent) { - if (inputEvent is InputEventMIDI midiEvent) + if (inputEvent is InputEventMidi midiEvent) { PrintMIDIInfo(midiEvent); } } - private void PrintMIDIInfo(InputEventMIDI midiEvent) + private void PrintMIDIInfo(InputEventMidi midiEvent) { GD.Print(midiEvent); GD.Print($"Channel {midiEvent.Channel}"); diff --git a/doc/classes/NativeMenu.xml b/doc/classes/NativeMenu.xml index cc81c81a24..475874dee7 100644 --- a/doc/classes/NativeMenu.xml +++ b/doc/classes/NativeMenu.xml @@ -53,7 +53,7 @@ An [param accelerator] can optionally be defined, which is a keyboard shortcut that can be pressed to trigger the menu button even if it's not currently open. The [param accelerator] is generally a combination of [enum KeyModifierMask]s and [enum Key]s using bitwise OR such as [code]KEY_MASK_CTRL | KEY_A[/code] ([kbd]Ctrl + A[/kbd]). [b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag]. [b]Note:[/b] This method is implemented on macOS and Windows. - [b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows. + [b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored. </description> </method> <method name="add_icon_check_item"> @@ -72,7 +72,7 @@ An [param accelerator] can optionally be defined, which is a keyboard shortcut that can be pressed to trigger the menu button even if it's not currently open. The [param accelerator] is generally a combination of [enum KeyModifierMask]s and [enum Key]s using bitwise OR such as [code]KEY_MASK_CTRL | KEY_A[/code] ([kbd]Ctrl + A[/kbd]). [b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag]. [b]Note:[/b] This method is implemented on macOS and Windows. - [b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows. + [b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored. </description> </method> <method name="add_icon_item"> @@ -91,7 +91,7 @@ An [param accelerator] can optionally be defined, which is a keyboard shortcut that can be pressed to trigger the menu button even if it's not currently open. The [param accelerator] is generally a combination of [enum KeyModifierMask]s and [enum Key]s using bitwise OR such as [code]KEY_MASK_CTRL | KEY_A[/code] ([kbd]Ctrl + A[/kbd]). [b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag]. [b]Note:[/b] This method is implemented on macOS and Windows. - [b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows. + [b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored. </description> </method> <method name="add_icon_radio_check_item"> @@ -111,7 +111,7 @@ [b]Note:[/b] Radio-checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it. [b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag]. [b]Note:[/b] This method is implemented on macOS and Windows. - [b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows. + [b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored. </description> </method> <method name="add_item"> @@ -129,7 +129,7 @@ An [param accelerator] can optionally be defined, which is a keyboard shortcut that can be pressed to trigger the menu button even if it's not currently open. The [param accelerator] is generally a combination of [enum KeyModifierMask]s and [enum Key]s using bitwise OR such as [code]KEY_MASK_CTRL | KEY_A[/code] ([kbd]Ctrl + A[/kbd]). [b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag]. [b]Note:[/b] This method is implemented on macOS and Windows. - [b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows. + [b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored. </description> </method> <method name="add_multistate_item"> @@ -151,7 +151,7 @@ [b]Note:[/b] By default, there's no indication of the current item state, it should be changed manually. [b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag]. [b]Note:[/b] This method is implemented on macOS and Windows. - [b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows. + [b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored. </description> </method> <method name="add_radio_check_item"> @@ -170,7 +170,7 @@ [b]Note:[/b] Radio-checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it. [b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag]. [b]Note:[/b] This method is implemented on macOS and Windows. - [b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows. + [b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored. </description> </method> <method name="add_separator"> @@ -211,12 +211,21 @@ [b]Note:[/b] This method is implemented on macOS and Windows. </description> </method> + <method name="find_item_index_with_submenu" qualifiers="const"> + <return type="int" /> + <param index="0" name="rid" type="RID" /> + <param index="1" name="submenu_rid" type="RID" /> + <description> + Returns the index of the item with the submenu specified by [param submenu_rid]. Indices are automatically assigned to each item by the engine, and cannot be set manually. + [b]Note:[/b] This method is implemented on macOS and Windows. + </description> + </method> <method name="find_item_index_with_tag" qualifiers="const"> <return type="int" /> <param index="0" name="rid" type="RID" /> <param index="1" name="tag" type="Variant" /> <description> - Returns the index of the item with the specified [param tag]. Index is automatically assigned to each item by the engine. Index can not be set manually. + Returns the index of the item with the specified [param tag]. Indices are automatically assigned to each item by the engine, and cannot be set manually. [b]Note:[/b] This method is implemented on macOS and Windows. </description> </method> @@ -225,7 +234,7 @@ <param index="0" name="rid" type="RID" /> <param index="1" name="text" type="String" /> <description> - Returns the index of the item with the specified [param text]. Index is automatically assigned to each item by the engine. Index can not be set manually. + Returns the index of the item with the specified [param text]. Indices are automatically assigned to each item by the engine, and cannot be set manually. [b]Note:[/b] This method is implemented on macOS and Windows. </description> </method> @@ -496,7 +505,7 @@ <param index="0" name="rid" type="RID" /> <param index="1" name="is_rtl" type="bool" /> <description> - Sets the menu text layout directtion. + Sets the menu text layout direction from right-to-left if [param is_rtl] is [code]true[/code]. [b]Note:[/b] This method is implemented on macOS and Windows. </description> </method> diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml index b786b67933..ae6cd9596c 100644 --- a/doc/classes/Node.xml +++ b/doc/classes/Node.xml @@ -100,7 +100,7 @@ <return type="void" /> <param index="0" name="event" type="InputEvent" /> <description> - Called when an [InputEventKey] or [InputEventShortcut] hasn't been consumed by [method _input] or any GUI [Control] item. It is called before [method _unhandled_key_input] and [method _unhandled_input]. The input event propagates up through the node tree until a node consumes it. + Called when an [InputEventKey], [InputEventShortcut], or [InputEventJoypadButton] hasn't been consumed by [method _input] or any GUI [Control] item. It is called before [method _unhandled_key_input] and [method _unhandled_input]. The input event propagates up through the node tree until a node consumes it. It is only called if shortcut processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_shortcut_input]. To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called. This method can be used to handle shortcuts. For generic GUI events, use [method _input] instead. Gameplay events should usually be handled with either [method _unhandled_input] or [method _unhandled_key_input]. @@ -187,7 +187,7 @@ <param index="0" name="message" type="String" /> <param index="1" name="context" type="StringName" default="""" /> <description> - Translates a [param message], using the translation catalogs configured in the Project Settings. Further [param context] can be specified to help with the translation. + Translates a [param message], using the translation catalogs configured in the Project Settings. Further [param context] can be specified to help with the translation. Note that most [Control] nodes automatically translate their strings, so this method is mostly useful for formatted strings or custom drawn text. This method works the same as [method Object.tr], with the addition of respecting the [member auto_translate_mode] state. If [method Object.can_translate_messages] is [code]false[/code], or no translation is available, this method returns the [param message] without changes. See [method Object.set_message_translation]. For detailed examples, see [url=$DOCS_URL/tutorials/i18n/internationalizing_games.html]Internationalizing games[/url]. @@ -619,6 +619,21 @@ [method request_ready] resets it back to [code]false[/code]. </description> </method> + <method name="is_physics_interpolated" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if physics interpolation is enabled for this node (see [member physics_interpolation_mode]). + [b]Note:[/b] Interpolation will only be active if both the flag is set [b]and[/b] physics interpolation is enabled within the [SceneTree]. This can be tested using [method is_physics_interpolated_and_enabled]. + </description> + </method> + <method name="is_physics_interpolated_and_enabled" qualifiers="const"> + <return type="bool" /> + <description> + Returns [code]true[/code] if physics interpolation is enabled (see [member physics_interpolation_mode]) [b]and[/b] enabled in the [SceneTree]. + This is a convenience version of [method is_physics_interpolated] that also checks whether physics interpolation is enabled globally. + See [member SceneTree.physics_interpolation] and [member ProjectSettings.physics/common/physics_interpolation]. + </description> + </method> <method name="is_physics_processing" qualifiers="const"> <return type="bool" /> <description> @@ -780,8 +795,9 @@ <return type="void" /> <param index="0" name="node" type="Node" /> <param index="1" name="keep_groups" type="bool" default="false" /> + <param index="2" name="keep_children" type="bool" default="true" /> <description> - Replaces this node by the given [param node]. All children of this node are moved to [param node]. + Replaces this node by the given [param node]. If [param keep_children] is [code]true[/code] all children of this node are moved to [param node]. If [param keep_groups] is [code]true[/code], the [param node] is added to the same groups that the replaced node is in (see [method add_to_group]). [b]Warning:[/b] The replaced node is removed from the tree, but it is [b]not[/b] deleted. To prevent memory leaks, store a reference to the node in a variable, or use [method Object.free]. </description> @@ -793,6 +809,15 @@ [b]Note:[/b] This method only affects the current node. If the node's children also need to request ready, this method needs to be called for each one of them. When the node and its children enter the tree again, the order of [method _ready] callbacks will be the same as normal. </description> </method> + <method name="reset_physics_interpolation"> + <return type="void" /> + <description> + When physics interpolation is active, moving a node to a radically different transform (such as placement within a level) can result in a visible glitch as the object is rendered moving from the old to new position over the physics tick. + That glitch can be prevented by calling this method, which temporarily disables interpolation until the physics tick is complete. + The notification [constant NOTIFICATION_RESET_PHYSICS_INTERPOLATION] will be received by the node and all children recursively. + [b]Note:[/b] This function should be called [b]after[/b] moving the node, rather than before. + </description> + </method> <method name="rpc" qualifiers="vararg"> <return type="int" enum="Error" /> <param index="0" name="method" type="StringName" /> @@ -964,6 +989,10 @@ The owner of this node. The owner must be an ancestor of this node. When packing the owner node in a [PackedScene], all the nodes it owns are also saved with it. [b]Note:[/b] In the editor, nodes not owned by the scene root are usually not displayed in the Scene dock, and will [b]not[/b] be saved. To prevent this, remember to set the owner after calling [method add_child]. See also (see [member unique_name_in_owner]) </member> + <member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" enum="Node.PhysicsInterpolationMode" default="0"> + Allows enabling or disabling physics interpolation per node, offering a finer grain of control than turning physics interpolation on and off globally. See [member ProjectSettings.physics/common/physics_interpolation] and [member SceneTree.physics_interpolation] for the global setting. + [b]Note:[/b] When teleporting a node to a distant position you should temporarily disable interpolation with [method Node.reset_physics_interpolation]. + </member> <member name="process_mode" type="int" setter="set_process_mode" getter="get_process_mode" enum="Node.ProcessMode" default="0"> The node's processing behavior (see [enum ProcessMode]). To check if the node can process in its current mode, use [method can_process]. </member> @@ -1122,6 +1151,9 @@ <constant name="NOTIFICATION_ENABLED" value="29"> Notification received when the node is enabled again after being disabled. See [constant PROCESS_MODE_DISABLED]. </constant> + <constant name="NOTIFICATION_RESET_PHYSICS_INTERPOLATION" value="2001"> + Notification received when [method reset_physics_interpolation] is called on the node or its ancestors. + </constant> <constant name="NOTIFICATION_EDITOR_PRE_SAVE" value="9001"> Notification received right before the scene with the node is saved in the editor. This notification is only sent in the Godot editor and will not occur in exported projects. </constant> @@ -1170,7 +1202,15 @@ Implemented only on iOS. </constant> <constant name="NOTIFICATION_TRANSLATION_CHANGED" value="2010"> - Notification received when translations may have changed. Can be triggered by the user changing the locale. Can be used to respond to language changes, for example to change the UI strings on the fly. Useful when working with the built-in translation support, like [method Object.tr]. + Notification received when translations may have changed. Can be triggered by the user changing the locale, changing [member auto_translate_mode] or when the node enters the scene tree. Can be used to respond to language changes, for example to change the UI strings on the fly. Useful when working with the built-in translation support, like [method Object.tr]. + [b]Note:[/b] This notification is received alongside [constant NOTIFICATION_ENTER_TREE], so if you are instantiating a scene, the child nodes will not be initialized yet. You can use it to setup translations for this node, child nodes created from script, or if you want to access child nodes added in the editor, make sure the node is ready using [method is_node_ready]. + [codeblock] + func _notification(what): + if what == NOTIFICATION_TRANSLATION_CHANGED: + if not is_node_ready(): + await ready # Wait until ready signal. + $Label.text = atr("%d Bananas") % banana_counter + [/codeblock] </constant> <constant name="NOTIFICATION_WM_ABOUT" value="2011"> Notification received from the OS when a request for "About" information is sent. @@ -1237,6 +1277,15 @@ <constant name="FLAG_PROCESS_THREAD_MESSAGES_ALL" value="3" enum="ProcessThreadMessages" is_bitfield="true"> Allows this node to process threaded messages created with [method call_deferred_thread_group] right before either [method _process] or [method _physics_process] are called. </constant> + <constant name="PHYSICS_INTERPOLATION_MODE_INHERIT" value="0" enum="PhysicsInterpolationMode"> + Inherits [member physics_interpolation_mode] from the node's parent. This is the default for any newly created node. + </constant> + <constant name="PHYSICS_INTERPOLATION_MODE_ON" value="1" enum="PhysicsInterpolationMode"> + Enables physics interpolation for this node and for children set to [constant PHYSICS_INTERPOLATION_MODE_INHERIT]. This is the default for the root node. + </constant> + <constant name="PHYSICS_INTERPOLATION_MODE_OFF" value="2" enum="PhysicsInterpolationMode"> + Disables physics interpolation for this node and for children set to [constant PHYSICS_INTERPOLATION_MODE_INHERIT]. + </constant> <constant name="DUPLICATE_SIGNALS" value="1" enum="DuplicateFlags"> Duplicate the node's signal connections. </constant> diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml index be7394a30b..bd1bd9afa7 100644 --- a/doc/classes/OS.xml +++ b/doc/classes/OS.xml @@ -50,9 +50,9 @@ <param index="1" name="arguments" type="PackedStringArray" /> <param index="2" name="open_console" type="bool" default="false" /> <description> - Creates a new process that runs independently of Godot. It will not terminate when Godot terminates. The path specified in [param path] must exist and be executable file or macOS .app bundle. Platform path resolution will be used. The [param arguments] are used in the given order and separated by a space. + Creates a new process that runs independently of Godot. It will not terminate when Godot terminates. The path specified in [param path] must exist and be an executable file or macOS [code].app[/code] bundle. The path is resolved based on the current platform. The [param arguments] are used in the given order and separated by a space. On Windows, if [param open_console] is [code]true[/code] and the process is a console app, a new terminal window will be opened. - If the process is successfully created, this method returns its process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). Otherwise this method returns [code]-1[/code]. + If the process is successfully created, this method returns its process ID, which you can use to monitor the process (and potentially terminate it with [method kill]). Otherwise, this method returns [code]-1[/code]. For example, running another instance of the project: [codeblocks] [gdscript] @@ -63,7 +63,7 @@ [/csharp] [/codeblocks] See [method execute] if you wish to run an external command and retrieve the results. - [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. + [b]Note:[/b] This method is implemented on Android, Linux, macOS, and Windows. [b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export or system .app bundle, system .app bundles will ignore arguments. </description> </method> @@ -120,7 +120,7 @@ OS.Execute("CMD.exe", new string[] {"/C", "cd %TEMP% && dir"}, output); [/csharp] [/codeblocks] - [b]Note:[/b] This method is implemented on Android, iOS, Linux, macOS and Windows. + [b]Note:[/b] This method is implemented on Android, Linux, macOS, and Windows. [b]Note:[/b] To execute a Windows command interpreter built-in command, specify [code]cmd.exe[/code] in [param path], [code]/c[/code] as the first argument, and the desired command as the second argument. [b]Note:[/b] To execute a PowerShell built-in command, specify [code]powershell.exe[/code] in [param path], [code]-Command[/code] as the first argument, and the desired command as the second argument. [b]Note:[/b] To execute a Unix shell built-in command, specify shell executable name in [param path], [code]-c[/code] as the first argument, and the desired command as the second argument. @@ -128,6 +128,23 @@ [b]Note:[/b] On Android, system commands such as [code]dumpsys[/code] can only be run on a rooted device. </description> </method> + <method name="execute_with_pipe"> + <return type="Dictionary" /> + <param index="0" name="path" type="String" /> + <param index="1" name="arguments" type="PackedStringArray" /> + <description> + Creates a new process that runs independently of Godot with redirected IO. It will not terminate when Godot terminates. The path specified in [param path] must exist and be an executable file or macOS [code].app[/code] bundle. The path is resolved based on the current platform. The [param arguments] are used in the given order and separated by a space. + If the process cannot be created, this method returns an empty [Dictionary]. Otherwise, this method returns a [Dictionary] with the following keys: + - [code]"stdio"[/code] - [FileAccess] to access the process stdin and stdout pipes (read/write). + - [code]"stderr"[/code] - [FileAccess] to access the process stderr pipe (read only). + - [code]"pid"[/code] - Process ID as an [int], which you can use to monitor the process (and potentially terminate it with [method kill]). + [b]Note:[/b] This method is implemented on Android, Linux, macOS, and Windows. + [b]Note:[/b] To execute a Windows command interpreter built-in command, specify [code]cmd.exe[/code] in [param path], [code]/c[/code] as the first argument, and the desired command as the second argument. + [b]Note:[/b] To execute a PowerShell built-in command, specify [code]powershell.exe[/code] in [param path], [code]-Command[/code] as the first argument, and the desired command as the second argument. + [b]Note:[/b] To execute a Unix shell built-in command, specify shell executable name in [param path], [code]-c[/code] as the first argument, and the desired command as the second argument. + [b]Note:[/b] On macOS, sandboxed applications are limited to run only embedded helper executables, specified during export or system .app bundle, system .app bundles will ignore arguments. + </description> + </method> <method name="find_keycode_from_string" qualifiers="const"> <return type="int" enum="Key" /> <param index="0" name="string" type="String" /> diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml index 85b9cf16f2..b69326b6e0 100644 --- a/doc/classes/Object.xml +++ b/doc/classes/Object.xml @@ -1024,7 +1024,7 @@ <param index="0" name="message" type="StringName" /> <param index="1" name="context" type="StringName" default="&""" /> <description> - Translates a [param message], using the translation catalogs configured in the Project Settings. Further [param context] can be specified to help with the translation. + Translates a [param message], using the translation catalogs configured in the Project Settings. Further [param context] can be specified to help with the translation. Note that most [Control] nodes automatically translate their strings, so this method is mostly useful for formatted strings or custom drawn text. If [method can_translate_messages] is [code]false[/code], or no translation is available, this method returns the [param message] without changes. See [method set_message_translation]. For detailed examples, see [url=$DOCS_URL/tutorials/i18n/internationalizing_games.html]Internationalizing games[/url]. </description> diff --git a/doc/classes/PCKPacker.xml b/doc/classes/PCKPacker.xml index 2627c8b7d3..494e9966ac 100644 --- a/doc/classes/PCKPacker.xml +++ b/doc/classes/PCKPacker.xml @@ -13,7 +13,7 @@ packer.flush() [/gdscript] [csharp] - var packer = new PCKPacker(); + var packer = new PckPacker(); packer.PckStart("test.pck"); packer.AddFile("res://text.txt", "text.txt"); packer.Flush(); diff --git a/doc/classes/PacketPeerUDP.xml b/doc/classes/PacketPeerUDP.xml index 41457761fd..12d3178797 100644 --- a/doc/classes/PacketPeerUDP.xml +++ b/doc/classes/PacketPeerUDP.xml @@ -121,7 +121,7 @@ return [/gdscript] [csharp] - var socket = new PacketPeerUDP(); + var socket = new PacketPeerUdp(); // Server socket.SetDestAddress("127.0.0.1", 789); socket.PutPacket("Time to stop".ToAsciiBuffer()); diff --git a/doc/classes/Parallax2D.xml b/doc/classes/Parallax2D.xml index 6db29b7a33..472aeb0bd3 100644 --- a/doc/classes/Parallax2D.xml +++ b/doc/classes/Parallax2D.xml @@ -25,6 +25,7 @@ <member name="limit_end" type="Vector2" setter="set_limit_end" getter="get_limit_end" default="Vector2(1e+07, 1e+07)"> Bottom-right limits for scrolling to end. If the camera is outside of this limit, the [Parallax2D] will stop scrolling. Must be higher than [member limit_begin] and the viewport size combined to work. </member> + <member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" overrides="Node" enum="Node.PhysicsInterpolationMode" default="2" /> <member name="repeat_size" type="Vector2" setter="set_repeat_size" getter="get_repeat_size" default="Vector2(0, 0)"> Repeats the [Texture2D] of each of this node's children and offsets them by this value. When scrolling, the node's position loops, giving the illusion of an infinite scrolling background if the values are larger than the screen size. If an axis is set to [code]0[/code], the [Texture2D] will not be repeated. </member> @@ -40,7 +41,7 @@ </member> <member name="scroll_scale" type="Vector2" setter="set_scroll_scale" getter="get_scroll_scale" default="Vector2(1, 1)"> Multiplier to the final [Parallax2D]'s offset. Can be used to simulate distance from the camera. - For example, a value of [code]1[/code] scrolls at the same speed as the camera. A value greater than [code]1[/code] scrolls faster, making objects appear closer. Less than [code]1[/code] scrolls slower, making object appear closer and a value of [code]0[/code] stops the objects completely. + For example, a value of [code]1[/code] scrolls at the same speed as the camera. A value greater than [code]1[/code] scrolls faster, making objects appear closer. Less than [code]1[/code] scrolls slower, making objects appear further, and a value of [code]0[/code] stops the objects completely. </member> </members> </class> diff --git a/doc/classes/ParallaxLayer.xml b/doc/classes/ParallaxLayer.xml index fb92c9d85f..12482d6f66 100644 --- a/doc/classes/ParallaxLayer.xml +++ b/doc/classes/ParallaxLayer.xml @@ -23,5 +23,6 @@ <member name="motion_scale" type="Vector2" setter="set_motion_scale" getter="get_motion_scale" default="Vector2(1, 1)"> Multiplies the ParallaxLayer's motion. If an axis is set to [code]0[/code], it will not scroll. </member> + <member name="physics_interpolation_mode" type="int" setter="set_physics_interpolation_mode" getter="get_physics_interpolation_mode" overrides="Node" enum="Node.PhysicsInterpolationMode" default="2" /> </members> </class> diff --git a/doc/classes/PhysicsServer3D.xml b/doc/classes/PhysicsServer3D.xml index 4735091f20..e40d73862b 100644 --- a/doc/classes/PhysicsServer3D.xml +++ b/doc/classes/PhysicsServer3D.xml @@ -740,7 +740,7 @@ <param index="1" name="axis" type="int" enum="Vector3.Axis" /> <param index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" /> <description> - Gets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants). + Returns the value of a generic 6DOF joint flag. See [enum G6DOFJointAxisFlag] for the list of available flags. </description> </method> <method name="generic_6dof_joint_get_param" qualifiers="const"> @@ -749,7 +749,7 @@ <param index="1" name="axis" type="int" enum="Vector3.Axis" /> <param index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" /> <description> - Gets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants). + Returns the value of a generic 6DOF joint parameter. See [enum G6DOFJointAxisParam] for the list of available parameters. </description> </method> <method name="generic_6dof_joint_set_flag"> @@ -759,7 +759,7 @@ <param index="2" name="flag" type="int" enum="PhysicsServer3D.G6DOFJointAxisFlag" /> <param index="3" name="enable" type="bool" /> <description> - Sets a generic_6_DOF_joint flag (see [enum G6DOFJointAxisFlag] constants). + Sets the value of a given generic 6DOF joint flag. See [enum G6DOFJointAxisFlag] for the list of available flags. </description> </method> <method name="generic_6dof_joint_set_param"> @@ -769,7 +769,7 @@ <param index="2" name="param" type="int" enum="PhysicsServer3D.G6DOFJointAxisParam" /> <param index="3" name="value" type="float" /> <description> - Sets a generic_6_DOF_joint parameter (see [enum G6DOFJointAxisParam] constants). + Sets the value of a given generic 6DOF joint parameter. See [enum G6DOFJointAxisParam] for the list of available parameters. </description> </method> <method name="get_process_info"> @@ -876,6 +876,7 @@ <param index="3" name="body_B" type="RID" /> <param index="4" name="local_ref_B" type="Transform3D" /> <description> + Make the joint a generic six degrees of freedom (6DOF) joint. Use [method generic_6dof_joint_set_flag] and [method generic_6dof_joint_set_param] to set the joint's flags and parameters respectively. </description> </method> <method name="joint_make_hinge"> @@ -1497,6 +1498,12 @@ <constant name="G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT" value="6" enum="G6DOFJointAxisParam"> The maximum force that the linear motor can apply while trying to reach the target velocity. </constant> + <constant name="G6DOF_JOINT_LINEAR_SPRING_STIFFNESS" value="7" enum="G6DOFJointAxisParam"> + </constant> + <constant name="G6DOF_JOINT_LINEAR_SPRING_DAMPING" value="8" enum="G6DOFJointAxisParam"> + </constant> + <constant name="G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT" value="9" enum="G6DOFJointAxisParam"> + </constant> <constant name="G6DOF_JOINT_ANGULAR_LOWER_LIMIT" value="10" enum="G6DOFJointAxisParam"> The minimum rotation in negative direction to break loose and rotate around the axes. </constant> @@ -1524,18 +1531,34 @@ <constant name="G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT" value="18" enum="G6DOFJointAxisParam"> Maximum acceleration for the motor at the axes. </constant> + <constant name="G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS" value="19" enum="G6DOFJointAxisParam"> + </constant> + <constant name="G6DOF_JOINT_ANGULAR_SPRING_DAMPING" value="20" enum="G6DOFJointAxisParam"> + </constant> + <constant name="G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT" value="21" enum="G6DOFJointAxisParam"> + </constant> + <constant name="G6DOF_JOINT_MAX" value="22" enum="G6DOFJointAxisParam"> + Represents the size of the [enum G6DOFJointAxisParam] enum. + </constant> <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT" value="0" enum="G6DOFJointAxisFlag"> If set, linear motion is possible within the given limits. </constant> <constant name="G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT" value="1" enum="G6DOFJointAxisFlag"> If set, rotational motion is possible. </constant> + <constant name="G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING" value="2" enum="G6DOFJointAxisFlag"> + </constant> + <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING" value="3" enum="G6DOFJointAxisFlag"> + </constant> <constant name="G6DOF_JOINT_FLAG_ENABLE_MOTOR" value="4" enum="G6DOFJointAxisFlag"> If set, there is a rotational motor across these axes. </constant> <constant name="G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR" value="5" enum="G6DOFJointAxisFlag"> If set, there is a linear motor on this axis that targets a specific velocity. </constant> + <constant name="G6DOF_JOINT_FLAG_MAX" value="6" enum="G6DOFJointAxisFlag"> + Represents the size of the [enum G6DOFJointAxisFlag] enum. + </constant> <constant name="SHAPE_WORLD_BOUNDARY" value="0" enum="ShapeType"> The [Shape3D] is a [WorldBoundaryShape3D]. </constant> diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 407041289c..4d3e838bb1 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -1334,6 +1334,12 @@ <member name="input/ui_text_select_word_under_caret.macos" type="Dictionary" setter="" getter=""> macOS specific override for the shortcut to select the word currently under the caret. </member> + <member name="input/ui_text_skip_selection_for_next_occurrence" type="Dictionary" setter="" getter=""> + If no selection is currently active with the last caret in text fields, searches for the next occurrence of the the word currently under the caret and moves the caret to the next occurrence. The action can be performed sequentially for other occurrences of the word under the last caret. + If a selection is currently active with the last caret in text fields, searches for the next occurrence of the selection, adds a caret, selects the next occurrence then deselects the previous selection and its associated caret. The action can be performed sequentially for other occurrences of the selection of the last caret. + The viewport is adjusted to the latest newly added caret. + [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. + </member> <member name="input/ui_text_submit" type="Dictionary" setter="" getter=""> Default [InputEventAction] to submit a text field. [b]Note:[/b] Default [code]ui_*[/code] actions cannot be removed as they are necessary for the internal logic of several [Control]s. The events assigned to the action can however be modified. @@ -2082,6 +2088,9 @@ <member name="navigation/baking/thread_model/baking_use_multiple_threads" type="bool" setter="" getter="" default="true"> If enabled the async navmesh baking uses multiple threads. </member> + <member name="navigation/baking/use_crash_prevention_checks" type="bool" setter="" getter="" default="true"> + If enabled, and baking would potentially lead to an engine crash, the baking will be interrupted and an error message with explanation will be raised. + </member> <member name="network/limits/debugger/max_chars_per_second" type="int" setter="" getter="" default="32768"> Maximum number of characters allowed to send as output from the debugger. Over this value, content is dropped. This helps not to stall the debugger connection. </member> @@ -2266,9 +2275,15 @@ Controls the maximum number of physics steps that can be simulated each rendered frame. The default value is tuned to avoid "spiral of death" situations where expensive physics simulations trigger more expensive simulations indefinitely. However, the game will appear to slow down if the rendering FPS is less than [code]1 / max_physics_steps_per_frame[/code] of [member physics/common/physics_ticks_per_second]. This occurs even if [code]delta[/code] is consistently used in physics calculations. To avoid this, increase [member physics/common/max_physics_steps_per_frame] if you have increased [member physics/common/physics_ticks_per_second] significantly above its default value. [b]Note:[/b] This property is only read when the project starts. To change the maximum number of simulated physics steps per frame at runtime, set [member Engine.max_physics_steps_per_frame] instead. </member> + <member name="physics/common/physics_interpolation" type="bool" setter="" getter="" default="false"> + If [code]true[/code], the renderer will interpolate the transforms of physics objects between the last two transforms, so that smooth motion is seen even when physics ticks do not coincide with rendered frames. See also [member Node.physics_interpolation_mode] and [method Node.reset_physics_interpolation]. + [b]Note:[/b] If [code]true[/code], the physics jitter fix should be disabled by setting [member physics/common/physics_jitter_fix] to [code]0.0[/code]. + [b]Note:[/b] This property is only read when the project starts. To toggle physics interpolation at runtime, set [member SceneTree.physics_interpolation] instead. + [b]Note:[/b] This feature is currently only implemented in the 2D renderer. + </member> <member name="physics/common/physics_jitter_fix" type="float" setter="" getter="" default="0.5"> Controls how much physics ticks are synchronized with real time. For 0 or less, the ticks are synchronized. Such values are recommended for network games, where clock synchronization matters. Higher values cause higher deviation of in-game clock and real clock, but allows smoothing out framerate jitters. The default value of 0.5 should be good enough for most; values above 2 could cause the game to react to dropped frames with a noticeable delay and are not recommended. - [b]Note:[/b] For best results, when using a custom physics interpolation solution, the physics jitter fix should be disabled by setting [member physics/common/physics_jitter_fix] to [code]0[/code]. + [b]Note:[/b] When using a physics interpolation solution (such as enabling [member physics/common/physics_interpolation] or using a custom solution), the physics jitter fix should be disabled by setting [member physics/common/physics_jitter_fix] to [code]0.0[/code]. [b]Note:[/b] This property is only read when the project starts. To change the physics jitter fix at runtime, set [member Engine.physics_jitter_fix] instead. </member> <member name="physics/common/physics_ticks_per_second" type="int" setter="" getter="" default="60"> @@ -2628,6 +2643,9 @@ The [url=https://en.wikipedia.org/wiki/Bounding_volume_hierarchy]Bounding Volume Hierarchy[/url] quality to use when rendering the occlusion culling buffer. Higher values will result in more accurate occlusion culling, at the cost of higher CPU usage. See also [member rendering/occlusion_culling/occlusion_rays_per_thread]. [b]Note:[/b] This property is only read when the project starts. To adjust the BVH build quality at runtime, use [method RenderingServer.viewport_set_occlusion_culling_build_quality]. </member> + <member name="rendering/occlusion_culling/jitter_projection" type="bool" setter="" getter="" default="true"> + If [code]true[/code], the projection used for rendering the occlusion buffer will be jittered. This can help prevent objects being incorrectly culled when visible through small gaps. + </member> <member name="rendering/occlusion_culling/occlusion_rays_per_thread" type="int" setter="" getter="" default="512"> The number of occlusion rays traced per CPU thread. Higher values will result in more accurate occlusion culling, at the cost of higher CPU usage. The occlusion culling buffer's pixel count is roughly equal to [code]occlusion_rays_per_thread * number_of_logical_cpu_cores[/code], so it will depend on the system's CPU. Therefore, CPUs with fewer cores will use a lower resolution to attempt keeping performance costs even across devices. See also [member rendering/occlusion_culling/bvh_build_quality]. [b]Note:[/b] This property is only read when the project starts. To adjust the number of occlusion rays traced per thread at runtime, use [method RenderingServer.viewport_set_occlusion_rays_per_thread]. diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml index 324e6d50b6..5efda5f83f 100644 --- a/doc/classes/RenderingServer.xml +++ b/doc/classes/RenderingServer.xml @@ -424,6 +424,14 @@ [b]Note:[/b] The equivalent node is [CanvasItem]. </description> </method> + <method name="canvas_item_reset_physics_interpolation"> + <return type="void" /> + <param index="0" name="item" type="RID" /> + <description> + Prevents physics interpolation for the current physics tick. + This is useful when moving a canvas item to a new location, to give an instantaneous change rather than interpolation from the previous location. + </description> + </method> <method name="canvas_item_set_canvas_group_mode"> <return type="void" /> <param index="0" name="item" type="RID" /> @@ -504,6 +512,14 @@ Sets the index for the [CanvasItem]. </description> </method> + <method name="canvas_item_set_interpolated"> + <return type="void" /> + <param index="0" name="item" type="RID" /> + <param index="1" name="interpolated" type="bool" /> + <description> + If [param interpolated] is [code]true[/code], turns on physics interpolation for the canvas item. + </description> + </method> <method name="canvas_item_set_light_mask"> <return type="void" /> <param index="0" name="item" type="RID" /> @@ -612,6 +628,15 @@ Sets the [CanvasItem]'s Z index, i.e. its draw order (lower indexes are drawn first). </description> </method> + <method name="canvas_item_transform_physics_interpolation"> + <return type="void" /> + <param index="0" name="item" type="RID" /> + <param index="1" name="transform" type="Transform2D" /> + <description> + Transforms both the current and previous stored transform for a canvas item. + This allows transforming a canvas item without creating a "glitch" in the interpolation, which is particularly useful for large worlds utilising a shifting origin. + </description> + </method> <method name="canvas_light_attach_to_canvas"> <return type="void" /> <param index="0" name="light" type="RID" /> @@ -644,6 +669,14 @@ [b]Note:[/b] The equivalent node is [LightOccluder2D]. </description> </method> + <method name="canvas_light_occluder_reset_physics_interpolation"> + <return type="void" /> + <param index="0" name="occluder" type="RID" /> + <description> + Prevents physics interpolation for the current physics tick. + This is useful when moving an occluder to a new location, to give an instantaneous change rather than interpolation from the previous location. + </description> + </method> <method name="canvas_light_occluder_set_as_sdf_collision"> <return type="void" /> <param index="0" name="occluder" type="RID" /> @@ -659,6 +692,14 @@ Enables or disables light occluder. </description> </method> + <method name="canvas_light_occluder_set_interpolated"> + <return type="void" /> + <param index="0" name="occluder" type="RID" /> + <param index="1" name="interpolated" type="bool" /> + <description> + If [param interpolated] is [code]true[/code], turns on physics interpolation for the light occluder. + </description> + </method> <method name="canvas_light_occluder_set_light_mask"> <return type="void" /> <param index="0" name="occluder" type="RID" /> @@ -683,6 +724,23 @@ Sets a light occluder's [Transform2D]. </description> </method> + <method name="canvas_light_occluder_transform_physics_interpolation"> + <return type="void" /> + <param index="0" name="occluder" type="RID" /> + <param index="1" name="transform" type="Transform2D" /> + <description> + Transforms both the current and previous stored transform for a light occluder. + This allows transforming an occluder without creating a "glitch" in the interpolation, which is particularly useful for large worlds utilising a shifting origin. + </description> + </method> + <method name="canvas_light_reset_physics_interpolation"> + <return type="void" /> + <param index="0" name="light" type="RID" /> + <description> + Prevents physics interpolation for the current physics tick. + This is useful when moving a canvas item to a new location, to give an instantaneous change rather than interpolation from the previous location. + </description> + </method> <method name="canvas_light_set_blend_mode"> <return type="void" /> <param index="0" name="light" type="RID" /> @@ -723,6 +781,14 @@ Sets a canvas light's height. </description> </method> + <method name="canvas_light_set_interpolated"> + <return type="void" /> + <param index="0" name="light" type="RID" /> + <param index="1" name="interpolated" type="bool" /> + <description> + If [param interpolated] is [code]true[/code], turns on physics interpolation for the canvas light. + </description> + </method> <method name="canvas_light_set_item_cull_mask"> <return type="void" /> <param index="0" name="light" type="RID" /> @@ -829,6 +895,15 @@ Sets the Z range of objects that will be affected by this light. Equivalent to [member Light2D.range_z_min] and [member Light2D.range_z_max]. </description> </method> + <method name="canvas_light_transform_physics_interpolation"> + <return type="void" /> + <param index="0" name="light" type="RID" /> + <param index="1" name="transform" type="Transform2D" /> + <description> + Transforms both the current and previous stored transform for a canvas light. + This allows transforming a light without creating a "glitch" in the interpolation, which is is particularly useful for large worlds utilising a shifting origin. + </description> + </method> <method name="canvas_occluder_polygon_create"> <return type="RID" /> <description> diff --git a/doc/classes/ResourceImporterScene.xml b/doc/classes/ResourceImporterScene.xml index 4e20fe150e..900e028b25 100644 --- a/doc/classes/ResourceImporterScene.xml +++ b/doc/classes/ResourceImporterScene.xml @@ -21,6 +21,9 @@ <member name="animation/import" type="bool" setter="" getter="" default="true"> If [code]true[/code], import animations from the 3D scene. </member> + <member name="animation/import_rest_as_RESET" type="bool" setter="" getter="" default="false"> + If [code]true[/code], adds an [Animation] named [code]RESET[/code], containing the [method Skeleton3D.get_bone_rest] from [Skeleton3D] nodes. This can be useful to extract an animation in the reference pose. + </member> <member name="animation/remove_immutable_tracks" type="bool" setter="" getter="" default="true"> If [code]true[/code], remove animation tracks that only contain default values. This can reduce output file size and memory usage with certain 3D scenes, depending on the contents of their animation tracks. </member> diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index f1bb5a1cf6..bae5fe1205 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -264,6 +264,10 @@ - 2D and 3D physics will be stopped, as well as collision detection and related signals. - Depending on each node's [member Node.process_mode], their [method Node._process], [method Node._physics_process] and [method Node._input] callback methods may not called anymore. </member> + <member name="physics_interpolation" type="bool" setter="set_physics_interpolation_enabled" getter="is_physics_interpolation_enabled" default="false"> + If [code]true[/code], the renderer will interpolate the transforms of physics objects between the last two transforms, so that smooth motion is seen even when physics ticks do not coincide with rendered frames. + The default value of this property is controlled by [member ProjectSettings.physics/common/physics_interpolation]. + </member> <member name="quit_on_go_back" type="bool" setter="set_quit_on_go_back" getter="is_quit_on_go_back" default="true"> If [code]true[/code], the application quits automatically when navigating back (e.g. using the system "Back" button on Android). To handle 'Go Back' button when this option is disabled, use [constant DisplayServer.WINDOW_EVENT_GO_BACK_REQUEST]. diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 17f953f48f..7592342602 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -112,7 +112,7 @@ <description> Performs a case-sensitive comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "Less than" and "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. With different string lengths, returns [code]1[/code] if this string is longer than the [param to] string, or [code]-1[/code] if shorter. Note that the length of empty strings is [i]always[/i] [code]0[/code]. - To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to], [method naturalcasecmp_to], and [method naturalnocasecmp_to]. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to], [method filecasecmp_to], and [method naturalcasecmp_to]. </description> </method> <method name="chr" qualifiers="static"> @@ -184,6 +184,22 @@ Returns a string with [param chars] characters erased starting from [param position]. If [param chars] goes beyond the string's length given the specified [param position], fewer characters will be erased from the returned string. Returns an empty string if either [param position] or [param chars] is negative. Returns the original string unmodified if [param chars] is [code]0[/code]. </description> </method> + <method name="filecasecmp_to" qualifiers="const"> + <return type="int" /> + <param index="0" name="to" type="String" /> + <description> + Like [method naturalcasecmp_to] but prioritises strings that begin with periods ([code].[/code]) and underscores ([code]_[/code]) before any other character. Useful when sorting folders or file names. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method filenocasecmp_to], [method naturalcasecmp_to], and [method casecmp_to]. + </description> + </method> + <method name="filenocasecmp_to" qualifiers="const"> + <return type="int" /> + <param index="0" name="to" type="String" /> + <description> + Like [method naturalnocasecmp_to] but prioritises strings that begin with periods ([code].[/code]) and underscores ([code]_[/code]) before any other character. Useful when sorting folders or file names. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method filecasecmp_to], [method naturalnocasecmp_to], and [method nocasecmp_to]. + </description> + </method> <method name="find" qualifiers="const"> <return type="int" /> <param index="0" name="what" type="String" /> @@ -586,7 +602,7 @@ Performs a [b]case-sensitive[/b], [i]natural order[/i] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "Less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. When used for sorting, natural order comparison orders sequences of numbers by the combined value of each digit as is often expected, instead of the single digit's value. A sorted sequence of numbered strings will be [code]["1", "2", "3", ...][/code], not [code]["1", "10", "2", "3", ...][/code]. With different string lengths, returns [code]1[/code] if this string is longer than the [param to] string, or [code]-1[/code] if shorter. Note that the length of empty strings is [i]always[/i] [code]0[/code]. - To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method naturalnocasecmp_to], [method nocasecmp_to], and [method casecmp_to]. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method naturalnocasecmp_to], [method filecasecmp_to], and [method nocasecmp_to]. </description> </method> <method name="naturalnocasecmp_to" qualifiers="const"> @@ -596,7 +612,7 @@ Performs a [b]case-insensitive[/b], [i]natural order[/i] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "Less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. Internally, lowercase characters are converted to uppercase for the comparison. When used for sorting, natural order comparison orders sequences of numbers by the combined value of each digit as is often expected, instead of the single digit's value. A sorted sequence of numbered strings will be [code]["1", "2", "3", ...][/code], not [code]["1", "10", "2", "3", ...][/code]. With different string lengths, returns [code]1[/code] if this string is longer than the [param to] string, or [code]-1[/code] if shorter. Note that the length of empty strings is [i]always[/i] [code]0[/code]. - To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method naturalcasecmp_to], [method nocasecmp_to], and [method casecmp_to]. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method naturalcasecmp_to], [method filenocasecmp_to], and [method casecmp_to]. </description> </method> <method name="nocasecmp_to" qualifiers="const"> @@ -605,7 +621,7 @@ <description> Performs a [b]case-insensitive[/b] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "Less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. Internally, lowercase characters are converted to uppercase for the comparison. With different string lengths, returns [code]1[/code] if this string is longer than the [param to] string, or [code]-1[/code] if shorter. Note that the length of empty strings is [i]always[/i] [code]0[/code]. - To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method casecmp_to], [method naturalcasecmp_to], and [method naturalnocasecmp_to]. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method casecmp_to], [method filenocasecmp_to], and [method naturalnocasecmp_to]. </description> </method> <method name="num" qualifiers="static"> diff --git a/doc/classes/StringName.xml b/doc/classes/StringName.xml index 41763489f1..e837b65199 100644 --- a/doc/classes/StringName.xml +++ b/doc/classes/StringName.xml @@ -107,7 +107,7 @@ <description> Performs a case-sensitive comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "Less than" and "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. With different string lengths, returns [code]1[/code] if this string is longer than the [param to] string, or [code]-1[/code] if shorter. Note that the length of empty strings is [i]always[/i] [code]0[/code]. - To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to], [method naturalcasecmp_to], and [method naturalnocasecmp_to]. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method nocasecmp_to], [method filecasecmp_to], and [method naturalcasecmp_to]. </description> </method> <method name="contains" qualifiers="const"> @@ -168,6 +168,22 @@ Returns a string with [param chars] characters erased starting from [param position]. If [param chars] goes beyond the string's length given the specified [param position], fewer characters will be erased from the returned string. Returns an empty string if either [param position] or [param chars] is negative. Returns the original string unmodified if [param chars] is [code]0[/code]. </description> </method> + <method name="filecasecmp_to" qualifiers="const"> + <return type="int" /> + <param index="0" name="to" type="String" /> + <description> + Like [method naturalcasecmp_to] but prioritises strings that begin with periods ([code].[/code]) and underscores ([code]_[/code]) before any other character. Useful when sorting folders or file names. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method filenocasecmp_to], [method naturalcasecmp_to], and [method casecmp_to]. + </description> + </method> + <method name="filenocasecmp_to" qualifiers="const"> + <return type="int" /> + <param index="0" name="to" type="String" /> + <description> + Like [method naturalnocasecmp_to] but prioritises strings that begin with periods ([code].[/code]) and underscores ([code]_[/code]) before any other character. Useful when sorting folders or file names. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method filecasecmp_to], [method naturalnocasecmp_to], and [method nocasecmp_to]. + </description> + </method> <method name="find" qualifiers="const"> <return type="int" /> <param index="0" name="what" type="String" /> @@ -562,7 +578,7 @@ Performs a [b]case-sensitive[/b], [i]natural order[/i] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "Less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. When used for sorting, natural order comparison orders sequences of numbers by the combined value of each digit as is often expected, instead of the single digit's value. A sorted sequence of numbered strings will be [code]["1", "2", "3", ...][/code], not [code]["1", "10", "2", "3", ...][/code]. With different string lengths, returns [code]1[/code] if this string is longer than the [param to] string, or [code]-1[/code] if shorter. Note that the length of empty strings is [i]always[/i] [code]0[/code]. - To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method naturalnocasecmp_to], [method nocasecmp_to], and [method casecmp_to]. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method naturalnocasecmp_to], [method filecasecmp_to], and [method nocasecmp_to]. </description> </method> <method name="naturalnocasecmp_to" qualifiers="const"> @@ -572,7 +588,7 @@ Performs a [b]case-insensitive[/b], [i]natural order[/i] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "Less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. Internally, lowercase characters are converted to uppercase for the comparison. When used for sorting, natural order comparison orders sequences of numbers by the combined value of each digit as is often expected, instead of the single digit's value. A sorted sequence of numbered strings will be [code]["1", "2", "3", ...][/code], not [code]["1", "10", "2", "3", ...][/code]. With different string lengths, returns [code]1[/code] if this string is longer than the [param to] string, or [code]-1[/code] if shorter. Note that the length of empty strings is [i]always[/i] [code]0[/code]. - To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method naturalcasecmp_to], [method nocasecmp_to], and [method casecmp_to]. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method naturalcasecmp_to], [method filenocasecmp_to], and [method casecmp_to]. </description> </method> <method name="nocasecmp_to" qualifiers="const"> @@ -581,7 +597,7 @@ <description> Performs a [b]case-insensitive[/b] comparison to another string. Returns [code]-1[/code] if less than, [code]1[/code] if greater than, or [code]0[/code] if equal. "Less than" or "greater than" are determined by the [url=https://en.wikipedia.org/wiki/List_of_Unicode_characters]Unicode code points[/url] of each string, which roughly matches the alphabetical order. Internally, lowercase characters are converted to uppercase for the comparison. With different string lengths, returns [code]1[/code] if this string is longer than the [param to] string, or [code]-1[/code] if shorter. Note that the length of empty strings is [i]always[/i] [code]0[/code]. - To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method casecmp_to], [method naturalcasecmp_to], and [method naturalnocasecmp_to]. + To get a [bool] result from a string comparison, use the [code]==[/code] operator instead. See also [method casecmp_to], [method filenocasecmp_to], and [method naturalnocasecmp_to]. </description> </method> <method name="pad_decimals" qualifiers="const"> diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 04d05e7860..92b54eef21 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1070,6 +1070,12 @@ Provide custom tooltip text. The callback method must take the following args: [code]hovered_word: String[/code]. </description> </method> + <method name="skip_selection_for_next_occurrence"> + <return type="void" /> + <description> + Moves a selection and a caret for the next occurrence of the current selection. If there is no active selection, moves to the next occurrence of the word under caret. + </description> + </method> <method name="start_action"> <return type="void" /> <param index="0" name="action" type="int" enum="TextEdit.EditAction" /> diff --git a/doc/classes/TileData.xml b/doc/classes/TileData.xml index c5b86f079e..91df90580c 100644 --- a/doc/classes/TileData.xml +++ b/doc/classes/TileData.xml @@ -93,7 +93,7 @@ <return type="int" /> <param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" /> <description> - Returns the tile's terrain bit for the given [param peering_bit] direction. + Returns the tile's terrain bit for the given [param peering_bit] direction. To check that a direction is valid, use [method is_valid_terrain_peering_bit]. </description> </method> <method name="is_collision_polygon_one_way" qualifiers="const"> @@ -104,6 +104,13 @@ Returns whether one-way collisions are enabled for the polygon at index [param polygon_index] for TileSet physics layer with index [param layer_id]. </description> </method> + <method name="is_valid_terrain_peering_bit" qualifiers="const"> + <return type="bool" /> + <param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" /> + <description> + Returns whether the given [param peering_bit] direction is valid for this tile. + </description> + </method> <method name="remove_collision_polygon"> <return type="void" /> <param index="0" name="layer_id" type="int" /> @@ -200,7 +207,7 @@ <param index="0" name="peering_bit" type="int" enum="TileSet.CellNeighbor" /> <param index="1" name="terrain" type="int" /> <description> - Sets the tile's terrain bit for the given [param peering_bit] direction. + Sets the tile's terrain bit for the given [param peering_bit] direction. To check that a direction is valid, use [method is_valid_terrain_peering_bit]. </description> </method> </methods> diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml index fc19e1de49..bc8a1d7bf1 100644 --- a/doc/classes/TileMap.xml +++ b/doc/classes/TileMap.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" ?> -<class name="TileMap" inherits="TileMapLayerGroup" keywords="gridmap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> +<class name="TileMap" inherits="Node2D" deprecated="Use multiple [TileMapLayer] nodes instead." keywords="gridmap" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> <brief_description> Node for 2D tile-based maps. </brief_description> @@ -89,7 +89,8 @@ <param index="1" name="coords" type="Vector2i" /> <param index="2" name="use_proxies" type="bool" default="false" /> <description> - Returns the tile alternative ID of the cell on layer [param layer] at [param coords]. If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. + Returns the tile alternative ID of the cell on layer [param layer] at [param coords]. + If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. If [param layer] is negative, the layers are accessed from the last one. </description> </method> @@ -100,7 +101,7 @@ <param index="2" name="use_proxies" type="bool" default="false" /> <description> Returns the tile atlas coordinates ID of the cell on layer [param layer] at coordinates [param coords]. Returns [code]Vector2i(-1, -1)[/code] if the cell does not exist. - If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. + If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw atlas coordinate identifier. See [method TileSet.map_tile_proxy]. If [param layer] is negative, the layers are accessed from the last one. </description> </method> @@ -111,7 +112,7 @@ <param index="2" name="use_proxies" type="bool" default="false" /> <description> Returns the tile source ID of the cell on layer [param layer] at coordinates [param coords]. Returns [code]-1[/code] if the cell does not exist. - If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. + If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw source identifier. See [method TileSet.map_tile_proxy]. If [param layer] is negative, the layers are accessed from the last one. </description> </method> @@ -123,7 +124,6 @@ <description> Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource]. If [param layer] is negative, the layers are accessed from the last one. - If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies, returning the raw alternative identifier. See [method TileSet.map_tile_proxy]. [codeblock] func get_clicked_tile_power(): var clicked_cell = tile_map.local_to_map(tile_map.get_local_mouse_position()) @@ -133,6 +133,7 @@ else: return 0 [/codeblock] + If [param use_proxies] is [code]false[/code], ignores the [TileSet]'s tile proxies. See [method TileSet.map_tile_proxy]. </description> </method> <method name="get_coords_for_body_rid"> @@ -489,6 +490,9 @@ The quadrant size does not apply on Y-sorted layers, as tiles are be grouped by Y position instead in that case. [b]Note:[/b] As quadrants are created according to the map's coordinate system, the quadrant's "square shape" might not look like square in the TileMap's local coordinate system. </member> + <member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset"> + The [TileSet] used by this [TileMap]. The textures, collisions, and additional behavior of all available tiles are stored here. + </member> </members> <signals> <signal name="changed"> diff --git a/doc/classes/TileMapLayer.xml b/doc/classes/TileMapLayer.xml new file mode 100644 index 0000000000..bc8e259599 --- /dev/null +++ b/doc/classes/TileMapLayer.xml @@ -0,0 +1,303 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<class name="TileMapLayer" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> + <brief_description> + Node for 2D tile-based maps. + </brief_description> + <description> + Node for 2D tile-based maps. A [TileMapLayer] uses a [TileSet] which contain a list of tiles which are used to create grid-based maps. Unlike the [TileMap] node, which is deprecated, [TileMapLayer] has only one layer of tiles. You can use several [TileMapLayer] to achieve the same result as a [TileMap] node. + For performance reasons, all TileMap updates are batched at the end of a frame. Notably, this means that scene tiles from a [TileSetScenesCollectionSource] may be initialized after their parent. This is only queued when inside the scene tree. + To force an update earlier on, call [method update_internals]. + </description> + <tutorials> + </tutorials> + <methods> + <method name="_tile_data_runtime_update" qualifiers="virtual"> + <return type="void" /> + <param index="0" name="coords" type="Vector2i" /> + <param index="1" name="tile_data" type="TileData" /> + <description> + Called with a [TileData] object about to be used internally by the [TileMapLayer], allowing its modification at runtime. + This method is only called if [method _use_tile_data_runtime_update] is implemented and returns [code]true[/code] for the given tile [param coords]. + [b]Warning:[/b] The [param tile_data] object's sub-resources are the same as the one in the TileSet. Modifying them might impact the whole TileSet. Instead, make sure to duplicate those resources. + [b]Note:[/b] If the properties of [param tile_data] object should change over time, use [method notify_runtime_tile_data_update] to notify the [TileMapLayer] it needs an update. + </description> + </method> + <method name="_use_tile_data_runtime_update" qualifiers="virtual"> + <return type="bool" /> + <param index="0" name="coords" type="Vector2i" /> + <description> + Should return [code]true[/code] if the tile at coordinates [param coords] requires a runtime update. + [b]Warning:[/b] Make sure this function only returns [code]true[/code] when needed. Any tile processed at runtime without a need for it will imply a significant performance penalty. + [b]Note:[/b] If the result of this function should change, use [method notify_runtime_tile_data_update] to notify the [TileMapLayer] it needs an update. + </description> + </method> + <method name="clear"> + <return type="void" /> + <description> + Clears all cells. + </description> + </method> + <method name="erase_cell"> + <return type="void" /> + <param index="0" name="coords" type="Vector2i" /> + <description> + Erases the cell at coordinates [param coords]. + </description> + </method> + <method name="fix_invalid_tiles"> + <return type="void" /> + <description> + Clears cells containing tiles that do not exist in the [member tile_set]. + </description> + </method> + <method name="get_cell_alternative_tile" qualifiers="const"> + <return type="int" /> + <param index="0" name="coords" type="Vector2i" /> + <description> + Returns the tile alternative ID of the cell at coordinates [param coords]. + </description> + </method> + <method name="get_cell_atlas_coords" qualifiers="const"> + <return type="Vector2i" /> + <param index="0" name="coords" type="Vector2i" /> + <description> + Returns the tile atlas coordinates ID of the cell at coordinates [param coords]. Returns [code]Vector2i(-1, -1)[/code] if the cell does not exist. + </description> + </method> + <method name="get_cell_source_id" qualifiers="const"> + <return type="int" /> + <param index="0" name="coords" type="Vector2i" /> + <description> + Returns the tile source ID of the cell at coordinates [param coords]. Returns [code]-1[/code] if the cell does not exist. + </description> + </method> + <method name="get_cell_tile_data" qualifiers="const"> + <return type="TileData" /> + <param index="0" name="coords" type="Vector2i" /> + <description> + Returns the [TileData] object associated with the given cell, or [code]null[/code] if the cell does not exist or is not a [TileSetAtlasSource]. + [codeblock] + func get_clicked_tile_power(): + var clicked_cell = tile_map_layer.local_to_map(tile_map_layer.get_local_mouse_position()) + var data = tile_map_layer.get_cell_tile_data(clicked_cell) + if data: + return data.get_custom_data("power") + else: + return 0 + [/codeblock] + </description> + </method> + <method name="get_coords_for_body_rid" qualifiers="const"> + <return type="Vector2i" /> + <param index="0" name="body" type="RID" /> + <description> + Returns the coordinates of the tile for given physics body [RID]. Such an [RID] can be retrieved from [method KinematicCollision2D.get_collider_rid], when colliding with a tile. + </description> + </method> + <method name="get_navigation_map" qualifiers="const"> + <return type="RID" /> + <description> + Returns the [RID] of the [NavigationServer2D] navigation used by this [TileMapLayer]. + By default this returns the default [World2D] navigation map, unless a custom map was provided using [method set_navigation_map]. + </description> + </method> + <method name="get_neighbor_cell" qualifiers="const"> + <return type="Vector2i" /> + <param index="0" name="coords" type="Vector2i" /> + <param index="1" name="neighbor" type="int" enum="TileSet.CellNeighbor" /> + <description> + Returns the neighboring cell to the one at coordinates [param coords], identified by the [param neighbor] direction. This method takes into account the different layouts a TileMap can take. + </description> + </method> + <method name="get_pattern"> + <return type="TileMapPattern" /> + <param index="0" name="coords_array" type="Vector2i[]" /> + <description> + Creates and returns a new [TileMapPattern] from the given array of cells. See also [method set_pattern]. + </description> + </method> + <method name="get_surrounding_cells"> + <return type="Vector2i[]" /> + <param index="0" name="coords" type="Vector2i" /> + <description> + Returns the list of all neighboring cells to the one at [param coords]. + </description> + </method> + <method name="get_used_cells" qualifiers="const"> + <return type="Vector2i[]" /> + <description> + Returns a [Vector2i] array with the positions of all cells containing a tile. A cell is considered empty if its source identifier equals [code]-1[/code], its atlas coordinate identifier is [code]Vector2(-1, -1)[/code] and its alternative identifier is [code]-1[/code]. + </description> + </method> + <method name="get_used_cells_by_id" qualifiers="const"> + <return type="Vector2i[]" /> + <param index="0" name="source_id" type="int" default="-1" /> + <param index="1" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" /> + <param index="2" name="alternative_tile" type="int" default="-1" /> + <description> + Returns a [Vector2i] array with the positions of all cells containing a tile. Tiles may be filtered according to their source ([param source_id]), their atlas coordinates ([param atlas_coords]), or alternative id ([param alternative_tile]). + If a parameter has its value set to the default one, this parameter is not used to filter a cell. Thus, if all parameters have their respective default values, this method returns the same result as [method get_used_cells]. + A cell is considered empty if its source identifier equals [code]-1[/code], its atlas coordinate identifier is [code]Vector2(-1, -1)[/code] and its alternative identifier is [code]-1[/code]. + </description> + </method> + <method name="get_used_rect" qualifiers="const"> + <return type="Rect2i" /> + <description> + Returns a rectangle enclosing the used (non-empty) tiles of the map. + </description> + </method> + <method name="has_body_rid" qualifiers="const"> + <return type="bool" /> + <param index="0" name="body" type="RID" /> + <description> + Returns whether the provided [param body] [RID] belongs to one of this [TileMapLayer]'s cells. + </description> + </method> + <method name="local_to_map" qualifiers="const"> + <return type="Vector2i" /> + <param index="0" name="local_position" type="Vector2" /> + <description> + Returns the map coordinates of the cell containing the given [param local_position]. If [param local_position] is in global coordinates, consider using [method Node2D.to_local] before passing it to this method. See also [method map_to_local]. + </description> + </method> + <method name="map_pattern"> + <return type="Vector2i" /> + <param index="0" name="position_in_tilemap" type="Vector2i" /> + <param index="1" name="coords_in_pattern" type="Vector2i" /> + <param index="2" name="pattern" type="TileMapPattern" /> + <description> + Returns for the given coordinates [param coords_in_pattern] in a [TileMapPattern] the corresponding cell coordinates if the pattern was pasted at the [param position_in_tilemap] coordinates (see [method set_pattern]). This mapping is required as in half-offset tile shapes, the mapping might not work by calculating [code]position_in_tile_map + coords_in_pattern[/code]. + </description> + </method> + <method name="map_to_local" qualifiers="const"> + <return type="Vector2" /> + <param index="0" name="map_position" type="Vector2i" /> + <description> + Returns the centered position of a cell in the [TileMapLayer]'s local coordinate space. To convert the returned value into global coordinates, use [method Node2D.to_global]. See also [method local_to_map]. + [b]Note:[/b] This may not correspond to the visual position of the tile, i.e. it ignores the [member TileData.texture_origin] property of individual tiles. + </description> + </method> + <method name="notify_runtime_tile_data_update"> + <return type="void" /> + <description> + Notifies the [TileMapLayer] node that calls to [method _use_tile_data_runtime_update] or [method _tile_data_runtime_update] will lead to different results. This will thus trigger a [TileMapLayer] update. + [b]Warning:[/b] Updating the [TileMapLayer] is computationally expensive and may impact performance. Try to limit the number of calls to this function to avoid unnecessary update. + [b]Note:[/b] This does not trigger a direct update of the [TileMapLayer], the update will be done at the end of the frame as usual (unless you call [method update_internals]). + </description> + </method> + <method name="set_cell"> + <return type="void" /> + <param index="0" name="coords" type="Vector2i" /> + <param index="1" name="source_id" type="int" default="-1" /> + <param index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" /> + <param index="3" name="alternative_tile" type="int" default="0" /> + <description> + Sets the tile identifiers for the cell at coordinates [param coords]. Each tile of the [TileSet] is identified using three parts: + - The source identifier [param source_id] identifies a [TileSetSource] identifier. See [method TileSet.set_source_id], + - The atlas coordinate identifier [param atlas_coords] identifies a tile coordinates in the atlas (if the source is a [TileSetAtlasSource]). For [TileSetScenesCollectionSource] it should always be [code]Vector2i(0, 0)[/code], + - The alternative tile identifier [param alternative_tile] identifies a tile alternative in the atlas (if the source is a [TileSetAtlasSource]), and the scene for a [TileSetScenesCollectionSource]. + If [param source_id] is set to [code]-1[/code], [param atlas_coords] to [code]Vector2i(-1, -1)[/code], or [param alternative_tile] to [code]-1[/code], the cell will be erased. An erased cell gets [b]all[/b] its identifiers automatically set to their respective invalid values, namely [code]-1[/code], [code]Vector2i(-1, -1)[/code] and [code]-1[/code]. + </description> + </method> + <method name="set_cells_terrain_connect"> + <return type="void" /> + <param index="0" name="cells" type="Vector2i[]" /> + <param index="1" name="terrain_set" type="int" /> + <param index="2" name="terrain" type="int" /> + <param index="3" name="ignore_empty_terrains" type="bool" default="true" /> + <description> + Update all the cells in the [param cells] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. If an updated cell has the same terrain as one of its neighboring cells, this function tries to join the two. This function might update neighboring tiles if needed to create correct terrain transitions. + If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. + [b]Note:[/b] To work correctly, this method requires the [TileMapLayer]'s TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results. + </description> + </method> + <method name="set_cells_terrain_path"> + <return type="void" /> + <param index="0" name="path" type="Vector2i[]" /> + <param index="1" name="terrain_set" type="int" /> + <param index="2" name="terrain" type="int" /> + <param index="3" name="ignore_empty_terrains" type="bool" default="true" /> + <description> + Update all the cells in the [param path] coordinates array so that they use the given [param terrain] for the given [param terrain_set]. The function will also connect two successive cell in the path with the same terrain. This function might update neighboring tiles if needed to create correct terrain transitions. + If [param ignore_empty_terrains] is true, empty terrains will be ignored when trying to find the best fitting tile for the given terrain constraints. + [b]Note:[/b] To work correctly, this method requires the [TileMapLayer]'s TileSet to have terrains set up with all required terrain combinations. Otherwise, it may produce unexpected results. + </description> + </method> + <method name="set_navigation_map"> + <return type="void" /> + <param index="0" name="map" type="RID" /> + <description> + Sets a custom [param map] as a [NavigationServer2D] navigation map. If not set, uses the default [World2D] navigation map instead. + </description> + </method> + <method name="set_pattern"> + <return type="void" /> + <param index="0" name="position" type="Vector2i" /> + <param index="1" name="pattern" type="TileMapPattern" /> + <description> + Pastes the [TileMapPattern] at the given [param position] in the tile map. See also [method get_pattern]. + </description> + </method> + <method name="update_internals"> + <return type="void" /> + <description> + Triggers a direct update of the [TileMapLayer]. Usually, calling this function is not needed, as [TileMapLayer] node updates automatically when one of its properties or cells is modified. + However, for performance reasons, those updates are batched and delayed to the end of the frame. Calling this function will force the [TileMapLayer] to update right away instead. + [b]Warning:[/b] Updating the [TileMapLayer] is computationally expensive and may impact performance. Try to limit the number of updates and how many tiles they impact. + </description> + </method> + </methods> + <members> + <member name="collision_enabled" type="bool" setter="set_collision_enabled" getter="is_collision_enabled" default="true"> + Enable or disable collisions. + </member> + <member name="collision_visibility_mode" type="int" setter="set_collision_visibility_mode" getter="get_collision_visibility_mode" enum="TileMapLayer.DebugVisibilityMode" default="0"> + Show or hide the [TileMapLayer]'s collision shapes. If set to [constant DEBUG_VISIBILITY_MODE_DEFAULT], this depends on the show collision debug settings. + </member> + <member name="enabled" type="bool" setter="set_enabled" getter="is_enabled" default="true"> + If [code]false[/code], disables this [TileMapLayer] completely (rendering, collision, navigation, scene tiles, etc.) + </member> + <member name="navigation_enabled" type="bool" setter="set_navigation_enabled" getter="is_navigation_enabled" default="true"> + If [code]true[/code], navigation regions are enabled. + </member> + <member name="navigation_visibility_mode" type="int" setter="set_navigation_visibility_mode" getter="get_navigation_visibility_mode" enum="TileMapLayer.DebugVisibilityMode" default="0"> + Show or hide the [TileMapLayer]'s navigation meshes. If set to [constant DEBUG_VISIBILITY_MODE_DEFAULT], this depends on the show navigation debug settings. + </member> + <member name="rendering_quadrant_size" type="int" setter="set_rendering_quadrant_size" getter="get_rendering_quadrant_size" default="16"> + The [TileMapLayer]'s quadrant size. A quadrant is a group of tiles to be drawn together on a single canvas item, for optimization purposes. [member rendering_quadrant_size] defines the length of a square's side, in the map's coordinate system, that forms the quadrant. Thus, the default quandrant size groups together [code]16 * 16 = 256[/code] tiles. + The quadrant size does not apply on a Y-sorted [TileMapLayer], as tiles are be grouped by Y position instead in that case. + [b]Note:[/b] As quadrants are created according to the map's coordinate system, the quadrant's "square shape" might not look like square in the [TileMapLayer]'s local coordinate system. + </member> + <member name="tile_map_data" type="PackedByteArray" setter="set_tile_map_data_from_array" getter="get_tile_map_data_as_array" default="PackedByteArray(0, 0)"> + The raw tile map data as a byte array. + </member> + <member name="tile_set" type="TileSet" setter="set_tile_set" getter="get_tile_set"> + The [TileSet] used by this layer. The textures, collisions, and additional behavior of all available tiles are stored here. + </member> + <member name="use_kinematic_bodies" type="bool" setter="set_use_kinematic_bodies" getter="is_using_kinematic_bodies" default="false"> + If [code]true[/code], this [TileMapLayer] collision shapes will be instantiated as kinematic bodies. This can be needed for moving [TileMapLayer] nodes (i.e. moving platforms). + </member> + <member name="y_sort_origin" type="int" setter="set_y_sort_origin" getter="get_y_sort_origin" default="0"> + This Y-sort origin value is added to each tile's Y-sort origin value. This allows, for example, to fake a different height level. This can be useful for top-down view games. + </member> + </members> + <signals> + <signal name="changed"> + <description> + Emitted when this [TileMapLayer]'s properties changes. This includes modified cells, properties, or changes made to its assigned [TileSet]. + [b]Note:[/b] This signal may be emitted very often when batch-modifying a [TileMapLayer]. Avoid executing complex processing in a connected function, and consider delaying it to the end of the frame instead (i.e. calling [method Object.call_deferred]). + </description> + </signal> + </signals> + <constants> + <constant name="DEBUG_VISIBILITY_MODE_DEFAULT" value="0" enum="DebugVisibilityMode"> + Hide the collisions or navigation debug shapes in the editor, and use the debug settings to determine their visibility in game (i.e. [member SceneTree.debug_collisions_hint] or [member SceneTree.debug_navigation_hint]). + </constant> + <constant name="DEBUG_VISIBILITY_MODE_FORCE_HIDE" value="2" enum="DebugVisibilityMode"> + Always hide the collisions or navigation debug shapes. + </constant> + <constant name="DEBUG_VISIBILITY_MODE_FORCE_SHOW" value="1" enum="DebugVisibilityMode"> + Always show the collisions or navigation debug shapes. + </constant> + </constants> +</class> diff --git a/doc/classes/TileMapLayerGroup.xml b/doc/classes/TileMapLayerGroup.xml deleted file mode 100644 index 3787d3bb17..0000000000 --- a/doc/classes/TileMapLayerGroup.xml +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" ?> -<class name="TileMapLayerGroup" inherits="Node2D" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd"> - <brief_description> - Groups a set of tile map layers together, allowing them to share a provided [TileSet]. - </brief_description> - <description> - Groups together tile map layers as part or the same map, replacing the [TileMap] node. Child layers will use this node's [member tile_set]. - The editor also uses [TileMapLayerGroup] as a way to store which layers are selected in a given group. This allows highlighting the currently selected layers. - </description> - <tutorials> - </tutorials> - <members> - <member name="tile_set" type="TileSet" setter="set_tileset" getter="get_tileset"> - The assigned [TileSet]. This TileSet will be applied to all child layers. - </member> - </members> -</class> diff --git a/doc/classes/Viewport.xml b/doc/classes/Viewport.xml index 13d84d96d6..dcc817427b 100644 --- a/doc/classes/Viewport.xml +++ b/doc/classes/Viewport.xml @@ -497,10 +497,16 @@ Represents the size of the [enum RenderInfo] enum. </constant> <constant name="RENDER_INFO_TYPE_VISIBLE" value="0" enum="RenderInfoType"> + Visible render pass (excluding shadows). </constant> <constant name="RENDER_INFO_TYPE_SHADOW" value="1" enum="RenderInfoType"> + Shadow render pass. Objects will be rendered several times depending on the number of amounts of lights with shadows and the number of directional shadow splits. </constant> - <constant name="RENDER_INFO_TYPE_MAX" value="2" enum="RenderInfoType"> + <constant name="RENDER_INFO_TYPE_CANVAS" value="2" enum="RenderInfoType"> + Canvas item rendering. This includes all 2D rendering. + </constant> + <constant name="RENDER_INFO_TYPE_MAX" value="3" enum="RenderInfoType"> + Represents the size of the [enum RenderInfoType] enum. </constant> <constant name="DEBUG_DRAW_DISABLED" value="0" enum="DebugDraw"> Objects are displayed normally. diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 304dc9e328..9fa95a93f8 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -38,6 +38,7 @@ #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" +#include "core/math/transform_interpolator.h" #include "servers/rendering/rendering_server_default.h" #include "storage/config.h" #include "storage/material_storage.h" @@ -226,7 +227,15 @@ void RasterizerCanvasGLES3::canvas_render_items(RID p_to_render_target, Item *p_ ERR_CONTINUE(!clight); } - 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 + Transform2D final_xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !l->interpolated) { + final_xform = l->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(l->xform_prev, l->xform_curr, final_xform, f); + } + // Convert light position to canvas coordinates, as all computation is done in canvas coordinates to avoid precision loss. + Vector2 canvas_light_pos = p_canvas_transform.xform(final_xform.get_origin()); state.light_uniforms[index].position[0] = canvas_light_pos.x; state.light_uniforms[index].position[1] = canvas_light_pos.y; @@ -820,7 +829,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform; if (p_offset.x || p_offset.y) { - base_transform *= Transform2D(0, p_offset / p_item->xform.get_scale()); + base_transform *= Transform2D(0, p_offset / p_item->xform_curr.get_scale()); // TODO: Interpolate or explain why not needed. } Transform2D draw_transform; // Used by transform command diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 29cfa251d6..b8cc3928eb 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -823,6 +823,11 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection, } else { camera = p_projection; } + + Projection correction; + correction.set_depth_correction(false, true, false); + camera = correction * camera; + Basis sky_transform = environment_get_sky_orientation(p_env); sky_transform.invert(); sky_transform = sky_transform * p_transform.basis; @@ -933,7 +938,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p Projection cm; cm.set_perspective(90, 1, 0.01, 10.0); Projection correction; - correction.columns[1][1] = -1.0; + correction.set_depth_correction(true, true, false); cm = correction * cm; bool success = material_storage->shaders.sky_shader.version_bind_shader(shader_data->version, SkyShaderGLES3::MODE_CUBEMAP); @@ -1546,7 +1551,7 @@ void RasterizerSceneGLES3::_fill_render_list(RenderListType p_render_list, const // Needs to be called after _setup_lights so that directional_light_count is accurate. void RasterizerSceneGLES3::_setup_environment(const RenderDataGLES3 *p_render_data, bool p_no_fog, const Size2i &p_screen_size, bool p_flip_y, const Color &p_default_bg_color, bool p_pancake_shadows, float p_shadow_bias) { Projection correction; - correction.columns[1][1] = p_flip_y ? -1.0 : 1.0; + correction.set_depth_correction(p_flip_y, true, false); Projection projection = correction * p_render_data->cam_projection; //store camera into ubo GLES3::MaterialStorage::store_camera(projection, scene_state.ubo.projection_matrix); @@ -1801,7 +1806,9 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b shadow_data.blend_splits = uint32_t((shadow_mode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light_storage->light_directional_get_blend_splits(base)); for (int j = 0; j < 4; j++) { Rect2 atlas_rect = li->shadow_transform[j].atlas_rect; - Projection matrix = li->shadow_transform[j].camera; + Projection correction; + correction.set_depth_correction(false, true, false); + Projection matrix = correction * li->shadow_transform[j].camera; float split = li->shadow_transform[MIN(limit, j)].split; Projection bias; @@ -2027,7 +2034,9 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b Projection bias; bias.set_light_bias(); - Projection cm = li->shadow_transform[0].camera; + Projection correction; + correction.set_depth_correction(false, true, false); + Projection cm = correction * li->shadow_transform[0].camera; Projection shadow_mtx = bias * cm * modelview; GLES3::MaterialStorage::store_camera(shadow_mtx, shadow_data.shadow_matrix); } @@ -2274,11 +2283,11 @@ void RasterizerSceneGLES3::_render_shadow_pass(RID p_light, RID p_shadow_atlas, scene_state.reset_gl_state(); scene_state.enable_gl_depth_test(true); scene_state.enable_gl_depth_draw(true); - glDepthFunc(GL_LESS); + glDepthFunc(GL_GREATER); glColorMask(0, 0, 0, 0); glDrawBuffers(0, nullptr); - RasterizerGLES3::clear_depth(1.0); + RasterizerGLES3::clear_depth(0.0); if (needs_clear) { glClear(GL_DEPTH_BUFFER_BIT); } @@ -2515,7 +2524,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ Projection projection = render_data.cam_projection; if (render_data.reflection_probe.is_valid()) { Projection correction; - correction.columns[1][1] = -1.0; + correction.set_depth_correction(true, true, false); projection = correction * render_data.cam_projection; } @@ -2554,11 +2563,11 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ scene_state.enable_gl_depth_test(true); scene_state.enable_gl_depth_draw(true); scene_state.enable_gl_blend(false); - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_GEQUAL); scene_state.enable_gl_scissor_test(false); glColorMask(0, 0, 0, 0); - RasterizerGLES3::clear_depth(1.0); + RasterizerGLES3::clear_depth(0.0); glClear(GL_DEPTH_BUFFER_BIT); glDrawBuffers(0, nullptr); @@ -2590,7 +2599,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ scene_state.enable_gl_scissor_test(false); scene_state.enable_gl_depth_test(true); scene_state.enable_gl_depth_draw(true); - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_GEQUAL); { GLuint db = GL_COLOR_ATTACHMENT0; @@ -2598,7 +2607,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_ } if (!fb_cleared) { - RasterizerGLES3::clear_depth(1.0); + RasterizerGLES3::clear_depth(0.0); glClear(GL_DEPTH_BUFFER_BIT); } @@ -3559,12 +3568,12 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider, scene_state.reset_gl_state(); scene_state.enable_gl_depth_test(true); scene_state.enable_gl_depth_draw(true); - glDepthFunc(GL_LESS); + glDepthFunc(GL_GREATER); glDrawBuffers(0, nullptr); glColorMask(0, 0, 0, 0); - RasterizerGLES3::clear_depth(1.0); + RasterizerGLES3::clear_depth(0.0); glClear(GL_DEPTH_BUFFER_BIT); @@ -3605,7 +3614,7 @@ void RasterizerSceneGLES3::_render_uv2(const PagedArray<RenderGeometryInstance * scene_state.reset_gl_state(); scene_state.enable_gl_depth_test(true); scene_state.enable_gl_depth_draw(true); - glDepthFunc(GL_LESS); + glDepthFunc(GL_GREATER); TightLocalVector<GLenum> draw_buffers; draw_buffers.push_back(GL_COLOR_ATTACHMENT0); @@ -3738,7 +3747,7 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES copy_effects->copy_cube_to_rect(atlas_uv_rect); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_GREATER); } else { glBindTexture(GL_TEXTURE_2D, shadow_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); @@ -3746,7 +3755,7 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES copy_effects->copy_to_rect(atlas_uv_rect); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GREATER); } } } @@ -3782,7 +3791,7 @@ void RasterizerSceneGLES3::_render_buffers_debug_draw(Ref<RenderSceneBuffersGLES glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_BLUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ALPHA); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GREATER); glBindTexture(GL_TEXTURE_2D, 0); } } diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 8da7d7dc80..efddbe9ad2 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -160,15 +160,18 @@ void main() { if (gl_VertexID % 3 == 0) { vertex = read_draw_data_point_a; uv = read_draw_data_uv_a; - color = vec4(unpackHalf2x16(read_draw_data_color_a_rg), unpackHalf2x16(read_draw_data_color_a_ba)); + color.xy = unpackHalf2x16(read_draw_data_color_a_rg); + color.zw = unpackHalf2x16(read_draw_data_color_a_ba); } else if (gl_VertexID % 3 == 1) { vertex = read_draw_data_point_b; uv = read_draw_data_uv_b; - color = vec4(unpackHalf2x16(read_draw_data_color_b_rg), unpackHalf2x16(read_draw_data_color_b_ba)); + color.xy = unpackHalf2x16(read_draw_data_color_b_rg); + color.zw = unpackHalf2x16(read_draw_data_color_b_ba); } else { vertex = read_draw_data_point_c; uv = read_draw_data_uv_c; - color = vec4(unpackHalf2x16(read_draw_data_color_c_rg), unpackHalf2x16(read_draw_data_color_c_ba)); + color.xy = unpackHalf2x16(read_draw_data_color_c_rg); + color.zw = unpackHalf2x16(read_draw_data_color_c_ba); } #elif defined(USE_ATTRIBUTES) @@ -178,11 +181,14 @@ void main() { #ifdef USE_INSTANCING if (bool(read_draw_data_flags & FLAGS_INSTANCING_HAS_COLORS)) { - vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y)); + vec4 instance_color; + instance_color.xy = unpackHalf2x16(uint(instance_color_custom_data.x)); + instance_color.zw = unpackHalf2x16(uint(instance_color_custom_data.y)); color *= instance_color; } if (bool(read_draw_data_flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { - instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w)); + instance_custom.xy = unpackHalf2x16(instance_color_custom_data.z); + instance_custom.zw = unpackHalf2x16(instance_color_custom_data.w); } #endif // !USE_INSTANCING diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl index 2384529a89..ec1982738a 100644 --- a/drivers/gles3/shaders/cube_to_dp.glsl +++ b/drivers/gles3/shaders/cube_to_dp.glsl @@ -95,6 +95,6 @@ void main() { float depth_fix = 1.0 / dot(normal, unorm); depth = 2.0 * depth - 1.0; - float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near)); - gl_FragDepth = (linear_depth * depth_fix + bias) / z_far; + float linear_depth = 2.0 * z_near * z_far / (z_far + z_near + depth * (z_far - z_near)); + gl_FragDepth = (z_far - (linear_depth * depth_fix + bias)) / z_far; } diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl index d95f7f4309..096f0a57ae 100644 --- a/drivers/gles3/shaders/particles.glsl +++ b/drivers/gles3/shaders/particles.glsl @@ -339,7 +339,8 @@ void main() { amount = max(0.0, 1.0 - d); } else if (attractors[i].type == ATTRACTOR_TYPE_VECTOR_FIELD) { } - amount = pow(amount, attractors[i].attenuation); + mediump float attractor_attenuation = attractors[i].attenuation; + amount = pow(amount, attractor_attenuation); dir = safe_normalize(mix(dir, attractors[i].transform[2].xyz, attractors[i].directionality)); attractor_force -= amount * dir * attractors[i].strength; } diff --git a/drivers/gles3/shaders/particles_copy.glsl b/drivers/gles3/shaders/particles_copy.glsl index 0bb8efc52d..55b5e6d7ce 100644 --- a/drivers/gles3/shaders/particles_copy.glsl +++ b/drivers/gles3/shaders/particles_copy.glsl @@ -57,45 +57,39 @@ void main() { txform = transpose(mat4(xform_1, xform_2, vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))); #endif - switch (align_mode) { - case TRANSFORM_ALIGN_DISABLED: { - } break; //nothing - case TRANSFORM_ALIGN_Z_BILLBOARD: { - mat3 local = mat3(normalize(cross(align_up, sort_direction)), align_up, sort_direction); - local = local * mat3(txform); - txform[0].xyz = local[0]; - txform[1].xyz = local[1]; - txform[2].xyz = local[2]; - - } break; - case TRANSFORM_ALIGN_Y_TO_VELOCITY: { - vec3 v = velocity_flags.xyz; - float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0; - if (length(v) > 0.0) { - txform[1].xyz = normalize(v); - } else { - txform[1].xyz = normalize(txform[1].xyz); - } - - txform[0].xyz = normalize(cross(txform[1].xyz, txform[2].xyz)); - txform[2].xyz = vec3(0.0, 0.0, 1.0) * s; - txform[0].xyz *= s; - txform[1].xyz *= s; - } break; - case TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY: { - vec3 sv = velocity_flags.xyz - sort_direction * dot(sort_direction, velocity_flags.xyz); //screen velocity - - if (length(sv) == 0.0) { - sv = align_up; - } - - sv = normalize(sv); - - txform[0].xyz = normalize(cross(sv, sort_direction)) * length(txform[0]); - txform[1].xyz = sv * length(txform[1]); - txform[2].xyz = sort_direction * length(txform[2]); - - } break; + if (align_mode == TRANSFORM_ALIGN_DISABLED) { + // nothing + } else if (align_mode == TRANSFORM_ALIGN_Z_BILLBOARD) { + mat3 local = mat3(normalize(cross(align_up, sort_direction)), align_up, sort_direction); + local = local * mat3(txform); + txform[0].xyz = local[0]; + txform[1].xyz = local[1]; + txform[2].xyz = local[2]; + } else if (align_mode == TRANSFORM_ALIGN_Y_TO_VELOCITY) { + vec3 v = velocity_flags.xyz; + float s = (length(txform[0]) + length(txform[1]) + length(txform[2])) / 3.0; + if (length(v) > 0.0) { + txform[1].xyz = normalize(v); + } else { + txform[1].xyz = normalize(txform[1].xyz); + } + + txform[0].xyz = normalize(cross(txform[1].xyz, txform[2].xyz)); + txform[2].xyz = vec3(0.0, 0.0, 1.0) * s; + txform[0].xyz *= s; + txform[1].xyz *= s; + } else if (align_mode == TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { + vec3 sv = velocity_flags.xyz - sort_direction * dot(sort_direction, velocity_flags.xyz); //screen velocity + + if (length(sv) == 0.0) { + sv = align_up; + } + + sv = normalize(sv); + + txform[0].xyz = normalize(cross(sv, sort_direction)) * length(txform[0]); + txform[1].xyz = sv * length(txform[1]); + txform[2].xyz = sort_direction * length(txform[2]); } txform[3].xyz += velocity_flags.xyz * frame_remainder; @@ -108,7 +102,10 @@ void main() { } txform = transpose(txform); - instance_color_custom_data = uvec4(packHalf2x16(color.xy), packHalf2x16(color.zw), packHalf2x16(custom.xy), packHalf2x16(custom.zw)); + instance_color_custom_data.x = packHalf2x16(color.xy); + instance_color_custom_data.y = packHalf2x16(color.zw); + instance_color_custom_data.z = packHalf2x16(custom.xy); + instance_color_custom_data.w = packHalf2x16(custom.zw); out_xform_1 = txform[0]; out_xform_2 = txform[1]; #ifdef MODE_3D diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index d73407d674..8bf844991d 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -366,7 +366,9 @@ void main() { #if defined(COLOR_USED) color_interp = color_attrib; #ifdef USE_INSTANCING - vec4 instance_color = vec4(unpackHalf2x16(instance_color_custom_data.x), unpackHalf2x16(instance_color_custom_data.y)); + vec4 instance_color; + instance_color.xy = unpackHalf2x16(instance_color_custom_data.x); + instance_color.zw = unpackHalf2x16(instance_color_custom_data.y); color_interp *= instance_color; #endif #endif @@ -403,7 +405,9 @@ void main() { #endif //USE_MULTIVIEW #ifdef USE_INSTANCING - vec4 instance_custom = vec4(unpackHalf2x16(instance_color_custom_data.z), unpackHalf2x16(instance_color_custom_data.w)); + vec4 instance_custom; + instance_custom.xy = unpackHalf2x16(instance_color_custom_data.z); + instance_custom.zw = unpackHalf2x16(instance_color_custom_data.w); #else vec4 instance_custom = vec4(0.0); #endif @@ -1710,7 +1714,7 @@ void main() { #ifdef MODE_RENDER_DEPTH #ifdef RENDER_SHADOWS_LINEAR // Linearize the depth buffer if rendering cubemap shadows. - gl_FragDepth = (length(vertex) + scene_data.shadow_bias) / scene_data.z_far; + gl_FragDepth = (scene_data.z_far - (length(vertex) + scene_data.shadow_bias)) / scene_data.z_far; #endif // Nothing happens, so a tree-ssa optimizer will result in no fragment shader :) @@ -1747,7 +1751,8 @@ void main() { #endif //!MODE_UNSHADED #ifndef FOG_DISABLED - fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba)); + fog.xy = unpackHalf2x16(fog_rg); + fog.zw = unpackHalf2x16(fog_ba); #ifndef DISABLE_FOG if (scene_data.fog_enabled) { @@ -1914,7 +1919,7 @@ void main() { float omni_shadow = 1.0f; #ifndef SHADOWS_DISABLED vec3 light_ray = ((positional_shadows[positional_shadow_index].shadow_matrix * vec4(shadow_coord.xyz, 1.0))).xyz; - omni_shadow = texture(omni_shadow_texture, vec4(light_ray, length(light_ray) * omni_lights[omni_light_index].inv_radius)); + omni_shadow = texture(omni_shadow_texture, vec4(light_ray, 1.0 - length(light_ray) * omni_lights[omni_light_index].inv_radius)); omni_shadow = mix(1.0, omni_shadow, omni_lights[omni_light_index].shadow_opacity); #endif // SHADOWS_DISABLED light_process_omni(omni_light_index, vertex, view, normal, f0, roughness, metallic, omni_shadow, albedo, alpha, @@ -1964,7 +1969,8 @@ void main() { vec3 additive_light_color = diffuse_light + specular_light; #ifndef FOG_DISABLED - fog = vec4(unpackHalf2x16(fog_rg), unpackHalf2x16(fog_ba)); + fog.xy = unpackHalf2x16(fog_rg); + fog.zw = unpackHalf2x16(fog_ba); #ifndef DISABLE_FOG if (scene_data.fog_enabled) { diff --git a/drivers/gles3/shaders/sky.glsl b/drivers/gles3/shaders/sky.glsl index b10ea12e6e..6c33bf7123 100644 --- a/drivers/gles3/shaders/sky.glsl +++ b/drivers/gles3/shaders/sky.glsl @@ -28,7 +28,7 @@ void main() { // We're doing clockwise culling so flip the order uv_interp = vec2(vertex_attrib.x, vertex_attrib.y * -1.0); #endif - gl_Position = vec4(uv_interp, 1.0, 1.0); + gl_Position = vec4(uv_interp, -1.0, 1.0); } /* clang-format off */ @@ -139,9 +139,11 @@ void main() { vec3 cube_normal; #ifdef USE_MULTIVIEW // In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject. - vec4 unproject = vec4(uv_interp.x, uv_interp.y, 1.0, 1.0); + vec4 unproject = vec4(uv_interp.xy, -1.0, 1.0); // unproject at the far plane vec4 unprojected = multiview_data.inv_projection_matrix_view[ViewIndex] * unproject; cube_normal = unprojected.xyz / unprojected.w; + + // Unproject will give us the position between the eyes, need to re-offset. cube_normal += multiview_data.eye_offset[ViewIndex].xyz; #else cube_normal.z = -1.0; diff --git a/drivers/gles3/shaders/stdlib_inc.glsl b/drivers/gles3/shaders/stdlib_inc.glsl index 92bf2d87e4..029084c34c 100644 --- a/drivers/gles3/shaders/stdlib_inc.glsl +++ b/drivers/gles3/shaders/stdlib_inc.glsl @@ -1,5 +1,12 @@ -#ifdef USE_GLES_OVER_GL +// Compatibility renames. These are exposed with the "godot_" prefix +// to work around two distinct Adreno bugs: +// 1. Some Adreno devices expose ES310 functions in ES300 shaders. +// Internally, we must use the "godot_" prefix, but user shaders +// will be mapped automatically. +// 2. Adreno 3XX devices have poor implementations of the other packing +// functions, so we just use our own everywhere to keep it simple. + // Floating point pack/unpack functions are part of the GLSL ES 300 specification used by web and mobile. uint float2half(uint f) { uint e = f & uint(0x7f800000); @@ -17,40 +24,34 @@ uint half2float(uint h) { return ((h & uint(0x8000)) << uint(16)) | uint((h_e >> uint(10)) != uint(0)) * (((h_e + uint(0x1c000)) << uint(13)) | ((h & uint(0x03ff)) << uint(13))); } -uint packHalf2x16(vec2 v) { +uint godot_packHalf2x16(vec2 v) { return float2half(floatBitsToUint(v.x)) | float2half(floatBitsToUint(v.y)) << uint(16); } -vec2 unpackHalf2x16(uint v) { +vec2 godot_unpackHalf2x16(uint v) { return vec2(uintBitsToFloat(half2float(v & uint(0xffff))), uintBitsToFloat(half2float(v >> uint(16)))); } -uint packUnorm2x16(vec2 v) { +uint godot_packUnorm2x16(vec2 v) { uvec2 uv = uvec2(round(clamp(v, vec2(0.0), vec2(1.0)) * 65535.0)); return uv.x | uv.y << uint(16); } -vec2 unpackUnorm2x16(uint p) { +vec2 godot_unpackUnorm2x16(uint p) { return vec2(float(p & uint(0xffff)), float(p >> uint(16))) * 0.000015259021; // 1.0 / 65535.0 optimization } -uint packSnorm2x16(vec2 v) { +uint godot_packSnorm2x16(vec2 v) { uvec2 uv = uvec2(round(clamp(v, vec2(-1.0), vec2(1.0)) * 32767.0) + 32767.0); return uv.x | uv.y << uint(16); } -vec2 unpackSnorm2x16(uint p) { +vec2 godot_unpackSnorm2x16(uint p) { vec2 v = vec2(float(p & uint(0xffff)), float(p >> uint(16))); return clamp((v - 32767.0) * vec2(0.00003051851), vec2(-1.0), vec2(1.0)); } -#endif - -// Compatibility renames. These are exposed with the "godot_" prefix -// to work around an Adreno bug which was exposing these ES310 functions -// in ES300 shaders. Internally, we must use the "godot_" prefix, but user shaders -// will be mapped automatically. uint godot_packUnorm4x8(vec4 v) { uvec4 uv = uvec4(round(clamp(v, vec4(0.0), vec4(1.0)) * 255.0)); return uv.x | (uv.y << uint(8)) | (uv.z << uint(16)) | (uv.w << uint(24)); @@ -74,3 +75,9 @@ vec4 godot_unpackSnorm4x8(uint p) { #define unpackUnorm4x8 godot_unpackUnorm4x8 #define packSnorm4x8 godot_packSnorm4x8 #define unpackSnorm4x8 godot_unpackSnorm4x8 +#define packHalf2x16 godot_packHalf2x16 +#define unpackHalf2x16 godot_unpackHalf2x16 +#define packUnorm2x16 godot_packUnorm2x16 +#define unpackUnorm2x16 godot_unpackUnorm2x16 +#define packSnorm2x16 godot_packSnorm2x16 +#define unpackSnorm2x16 godot_unpackSnorm2x16 diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp index f5d1f8dabd..d7d77c6b8f 100644 --- a/drivers/gles3/storage/light_storage.cpp +++ b/drivers/gles3/storage/light_storage.cpp @@ -1020,7 +1020,7 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_COMPARE_FUNC, GL_GREATER); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_CUBE_MAP_POSITIVE_X, texture_id, 0); @@ -1042,7 +1042,7 @@ bool LightStorage::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_i glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GREATER); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture_id, 0); @@ -1128,14 +1128,14 @@ void LightStorage::update_directional_shadow_atlas() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_GREATER); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); } glUseProgram(0); glDepthMask(GL_TRUE); glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); - RasterizerGLES3::clear_depth(1.0); + RasterizerGLES3::clear_depth(0.0); glClear(GL_DEPTH_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp index b72b4eaf8d..09878aaee4 100644 --- a/drivers/gles3/storage/particles_storage.cpp +++ b/drivers/gles3/storage/particles_storage.cpp @@ -31,6 +31,8 @@ #ifdef GLES3_ENABLED #include "particles_storage.h" + +#include "config.h" #include "material_storage.h" #include "mesh_storage.h" #include "texture_storage.h" @@ -120,6 +122,8 @@ void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_m } void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) { + ERR_FAIL_COND_MSG(GLES3::Config::get_singleton()->adreno_3xx_compatibility, "Due to driver bugs, GPUParticles are not supported on Adreno 3XX devices. Please use CPUParticles instead."); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL(particles); @@ -127,6 +131,10 @@ void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) } bool ParticlesStorage::particles_get_emitting(RID p_particles) { + if (GLES3::Config::get_singleton()->adreno_3xx_compatibility) { + return false; + } + ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, false); @@ -1003,6 +1011,12 @@ void ParticlesStorage::_particles_update_instance_buffer(Particles *particles, c } void ParticlesStorage::update_particles() { + if (!particle_update_list.first()) { + // Return early to avoid unnecessary state changes. + return; + } + + RENDER_TIMESTAMP("Update GPUParticles"); glEnable(GL_RASTERIZER_DISCARD); glBindFramebuffer(GL_FRAMEBUFFER, GLES3::TextureStorage::system_fbo); diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp index a032535827..6f32e4d49d 100644 --- a/drivers/gles3/storage/texture_storage.cpp +++ b/drivers/gles3/storage/texture_storage.cpp @@ -1077,7 +1077,7 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const { glDisable(GL_DEPTH_TEST); glDisable(GL_CULL_FACE); glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); + glDepthFunc(GL_GEQUAL); glColorMask(1, 1, 1, 1); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture->tex_id); @@ -2812,8 +2812,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) { } rt->process_size = size * scale / 100; - rt->process_size.x = MAX(rt->process_size.x, 1); - rt->process_size.y = MAX(rt->process_size.y, 1); + rt->process_size = rt->process_size.max(Size2i(1, 1)); glGenTextures(2, rt->sdf_texture_process); glBindTexture(GL_TEXTURE_2D, rt->sdf_texture_process[0]); diff --git a/drivers/png/resource_saver_png.h b/drivers/png/resource_saver_png.h index 2193b4a39b..2c24008074 100644 --- a/drivers/png/resource_saver_png.h +++ b/drivers/png/resource_saver_png.h @@ -39,9 +39,9 @@ public: static Error save_image(const String &p_path, const Ref<Image> &p_img); static Vector<uint8_t> save_image_to_buffer(const Ref<Image> &p_img); - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual bool recognize(const Ref<Resource> &p_resource) const; - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; ResourceSaverPNG(); }; diff --git a/drivers/unix/file_access_unix_pipe.cpp b/drivers/unix/file_access_unix_pipe.cpp new file mode 100644 index 0000000000..5d9a27ad05 --- /dev/null +++ b/drivers/unix/file_access_unix_pipe.cpp @@ -0,0 +1,185 @@ +/**************************************************************************/ +/* file_access_unix_pipe.cpp */ +/**************************************************************************/ +/* 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. */ +/**************************************************************************/ + +#include "file_access_unix_pipe.h" + +#if defined(UNIX_ENABLED) + +#include "core/os/os.h" +#include "core/string/print_string.h" + +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +Error FileAccessUnixPipe::open_existing(int p_rfd, int p_wfd) { + // Open pipe using handles created by pipe(fd) call in the OS.execute_with_pipe. + _close(); + + path_src = String(); + unlink_on_close = false; + ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use."); + fd[0] = p_rfd; + fd[1] = p_wfd; + + last_error = OK; + return OK; +} + +Error FileAccessUnixPipe::open_internal(const String &p_path, int p_mode_flags) { + _close(); + + path_src = p_path; + ERR_FAIL_COND_V_MSG(fd[0] >= 0 || fd[1] >= 0, ERR_ALREADY_IN_USE, "Pipe is already in use."); + + path = String("/tmp/") + p_path.replace("pipe://", "").replace("/", "_"); + struct stat st = {}; + int err = stat(path.utf8().get_data(), &st); + if (err) { + if (mkfifo(path.utf8().get_data(), 0666) != 0) { + last_error = ERR_FILE_CANT_OPEN; + return last_error; + } + unlink_on_close = true; + } else { + ERR_FAIL_COND_V_MSG(!S_ISFIFO(st.st_mode), ERR_ALREADY_IN_USE, "Pipe name is already used by file."); + } + + int f = ::open(path.utf8().get_data(), O_RDWR | O_CLOEXEC); + if (f < 0) { + switch (errno) { + case ENOENT: { + last_error = ERR_FILE_NOT_FOUND; + } break; + default: { + last_error = ERR_FILE_CANT_OPEN; + } break; + } + return last_error; + } + + // Set close on exec to avoid leaking it to subprocesses. + fd[0] = f; + fd[1] = f; + + last_error = OK; + return OK; +} + +void FileAccessUnixPipe::_close() { + if (fd[0] < 0) { + return; + } + + if (fd[1] != fd[0]) { + ::close(fd[1]); + } + ::close(fd[0]); + fd[0] = -1; + fd[1] = -1; + + if (unlink_on_close) { + ::unlink(path.utf8().ptr()); + } + unlink_on_close = false; +} + +bool FileAccessUnixPipe::is_open() const { + return (fd[0] >= 0 || fd[1] >= 0); +} + +String FileAccessUnixPipe::get_path() const { + return path_src; +} + +String FileAccessUnixPipe::get_path_absolute() const { + return path_src; +} + +uint8_t FileAccessUnixPipe::get_8() const { + ERR_FAIL_COND_V_MSG(fd[0] < 0, 0, "Pipe must be opened before use."); + + uint8_t b; + if (::read(fd[0], &b, 1) == 0) { + last_error = ERR_FILE_CANT_READ; + b = '\0'; + } else { + last_error = OK; + } + return b; +} + +uint64_t FileAccessUnixPipe::get_buffer(uint8_t *p_dst, uint64_t p_length) const { + ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); + ERR_FAIL_COND_V_MSG(fd[0] < 0, -1, "Pipe must be opened before use."); + + uint64_t read = ::read(fd[0], p_dst, p_length); + if (read == p_length) { + last_error = ERR_FILE_CANT_READ; + } else { + last_error = OK; + } + return read; +} + +Error FileAccessUnixPipe::get_error() const { + return last_error; +} + +void FileAccessUnixPipe::store_8(uint8_t p_src) { + ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use."); + if (::write(fd[1], &p_src, 1) != 1) { + last_error = ERR_FILE_CANT_WRITE; + } else { + last_error = OK; + } +} + +void FileAccessUnixPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use."); + ERR_FAIL_COND(!p_src && p_length > 0); + if (::write(fd[1], p_src, p_length) != (ssize_t)p_length) { + last_error = ERR_FILE_CANT_WRITE; + } else { + last_error = OK; + } +} + +void FileAccessUnixPipe::close() { + _close(); +} + +FileAccessUnixPipe::~FileAccessUnixPipe() { + _close(); +} + +#endif // UNIX_ENABLED diff --git a/drivers/unix/file_access_unix_pipe.h b/drivers/unix/file_access_unix_pipe.h new file mode 100644 index 0000000000..d14f897d8f --- /dev/null +++ b/drivers/unix/file_access_unix_pipe.h @@ -0,0 +1,96 @@ +/**************************************************************************/ +/* file_access_unix_pipe.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 FILE_ACCESS_UNIX_PIPE_H +#define FILE_ACCESS_UNIX_PIPE_H + +#include "core/io/file_access.h" +#include "core/os/memory.h" + +#include <stdio.h> + +#if defined(UNIX_ENABLED) + +class FileAccessUnixPipe : public FileAccess { + bool unlink_on_close = false; + + int fd[2] = { -1, -1 }; + + mutable Error last_error = OK; + String path; + String path_src; + + void _close(); + +public: + Error open_existing(int p_rfd, int p_wfd); + virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file + + virtual bool is_open() const override; ///< true when file is open + + virtual String get_path() const override; /// returns the path for the current open file + virtual String get_path_absolute() const override; /// returns the absolute path for the current open file + + virtual void seek(uint64_t p_position) override {} + virtual void seek_end(int64_t p_position = 0) override {} + virtual uint64_t get_position() const override { return 0; } + virtual uint64_t get_length() const override { return 0; } + + virtual bool eof_reached() const override { return false; } + + virtual uint8_t get_8() const override; ///< get a byte + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; + + virtual Error get_error() const override; ///< get last error + + virtual void flush() override {} + virtual void store_8(uint8_t p_src) override; ///< store a byte + virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes + + virtual bool file_exists(const String &p_path) override { return false; } + + virtual uint64_t _get_modified_time(const String &p_file) override { return 0; } + virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; } + virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return ERR_UNAVAILABLE; } + + virtual bool _get_hidden_attribute(const String &p_file) override { return false; } + virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; } + virtual bool _get_read_only_attribute(const String &p_file) override { return false; } + virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; } + + virtual void close() override; + + FileAccessUnixPipe() {} + virtual ~FileAccessUnixPipe(); +}; + +#endif // UNIX_ENABLED + +#endif // FILE_ACCESS_UNIX_PIPE_H diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 74b703b09e..597e41fd22 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -37,6 +37,7 @@ #include "core/debugger/script_debugger.h" #include "drivers/unix/dir_access_unix.h" #include "drivers/unix/file_access_unix.h" +#include "drivers/unix/file_access_unix_pipe.h" #include "drivers/unix/net_socket_posix.h" #include "drivers/unix/thread_posix.h" #include "servers/rendering_server.h" @@ -160,6 +161,7 @@ void OS_Unix::initialize_core() { FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM); + FileAccess::make_default<FileAccessUnixPipe>(FileAccess::ACCESS_PIPE); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_RESOURCES); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM); @@ -489,6 +491,106 @@ Dictionary OS_Unix::get_memory_info() const { return meminfo; } +Dictionary OS_Unix::execute_with_pipe(const String &p_path, const List<String> &p_arguments) { +#define CLEAN_PIPES \ + if (pipe_in[0] >= 0) { \ + ::close(pipe_in[0]); \ + } \ + if (pipe_in[1] >= 0) { \ + ::close(pipe_in[1]); \ + } \ + if (pipe_out[0] >= 0) { \ + ::close(pipe_out[0]); \ + } \ + if (pipe_out[1] >= 0) { \ + ::close(pipe_out[1]); \ + } \ + if (pipe_err[0] >= 0) { \ + ::close(pipe_err[0]); \ + } \ + if (pipe_err[1] >= 0) { \ + ::close(pipe_err[1]); \ + } + + Dictionary ret; +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_Web. + ERR_FAIL_V(ret); +#else + // Create pipes. + int pipe_in[2] = { -1, -1 }; + int pipe_out[2] = { -1, -1 }; + int pipe_err[2] = { -1, -1 }; + + ERR_FAIL_COND_V(pipe(pipe_in) != 0, ret); + if (pipe(pipe_out) != 0) { + CLEAN_PIPES + ERR_FAIL_V(ret); + } + if (pipe(pipe_err) != 0) { + CLEAN_PIPES + ERR_FAIL_V(ret); + } + + // Create process. + pid_t pid = fork(); + if (pid < 0) { + CLEAN_PIPES + ERR_FAIL_V(ret); + } + + if (pid == 0) { + // The child process. + Vector<CharString> cs; + cs.push_back(p_path.utf8()); + for (int i = 0; i < p_arguments.size(); i++) { + cs.push_back(p_arguments[i].utf8()); + } + + Vector<char *> args; + for (int i = 0; i < cs.size(); i++) { + args.push_back((char *)cs[i].get_data()); + } + args.push_back(0); + + ::close(STDIN_FILENO); + ::dup2(pipe_in[0], STDIN_FILENO); + + ::close(STDOUT_FILENO); + ::dup2(pipe_out[1], STDOUT_FILENO); + + ::close(STDERR_FILENO); + ::dup2(pipe_err[1], STDERR_FILENO); + + CLEAN_PIPES + + execvp(p_path.utf8().get_data(), &args[0]); + // The execvp() function only returns if an error occurs. + ERR_PRINT("Could not create child process: " + p_path); + raise(SIGKILL); + } + ::close(pipe_in[0]); + ::close(pipe_out[1]); + ::close(pipe_err[1]); + + Ref<FileAccessUnixPipe> main_pipe; + main_pipe.instantiate(); + main_pipe->open_existing(pipe_out[0], pipe_in[1]); + + Ref<FileAccessUnixPipe> err_pipe; + err_pipe.instantiate(); + err_pipe->open_existing(pipe_err[0], 0); + + ret["stdio"] = main_pipe; + ret["stderr"] = err_pipe; + ret["pid"] = pid; + +#undef CLEAN_PIPES + return ret; +#endif +} + Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { #ifdef __EMSCRIPTEN__ // Don't compile this code at all to avoid undefined references. diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index d3393c98ec..abbaf9b8cd 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -76,6 +76,7 @@ public: virtual Dictionary get_memory_info() const override; virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override; + virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) override; virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error kill(const ProcessID &p_pid) override; virtual int get_process_id() const override; diff --git a/drivers/vulkan/rendering_device_driver_vulkan.cpp b/drivers/vulkan/rendering_device_driver_vulkan.cpp index 297407da41..1906d168fe 100644 --- a/drivers/vulkan/rendering_device_driver_vulkan.cpp +++ b/drivers/vulkan/rendering_device_driver_vulkan.cpp @@ -760,8 +760,7 @@ Error RenderingDeviceDriverVulkan::_check_device_capabilities() { vrs_capabilities.max_texel_size.y = vrs_properties.maxFragmentShadingRateAttachmentTexelSize.height; // We'll attempt to default to a texel size of 16x16. - vrs_capabilities.texel_size.x = CLAMP(16, vrs_capabilities.min_texel_size.x, vrs_capabilities.max_texel_size.x); - vrs_capabilities.texel_size.y = CLAMP(16, vrs_capabilities.min_texel_size.y, vrs_capabilities.max_texel_size.y); + vrs_capabilities.texel_size = Vector2i(16, 16).clamp(vrs_capabilities.min_texel_size, vrs_capabilities.max_texel_size); print_verbose(String(" Attachment fragment shading rate") + String(", min texel size: (") + itos(vrs_capabilities.min_texel_size.x) + String(", ") + itos(vrs_capabilities.min_texel_size.y) + String(")") + String(", max texel size: (") + itos(vrs_capabilities.max_texel_size.x) + String(", ") + itos(vrs_capabilities.max_texel_size.y) + String(")")); } diff --git a/drivers/windows/file_access_windows_pipe.cpp b/drivers/windows/file_access_windows_pipe.cpp new file mode 100644 index 0000000000..7902c8e1d8 --- /dev/null +++ b/drivers/windows/file_access_windows_pipe.cpp @@ -0,0 +1,159 @@ +/**************************************************************************/ +/* file_access_windows_pipe.cpp */ +/**************************************************************************/ +/* 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. */ +/**************************************************************************/ + +#ifdef WINDOWS_ENABLED + +#include "file_access_windows_pipe.h" + +#include "core/os/os.h" +#include "core/string/print_string.h" + +Error FileAccessWindowsPipe::open_existing(HANDLE p_rfd, HANDLE p_wfd) { + // Open pipe using handles created by CreatePipe(rfd, wfd, NULL, 4096) call in the OS.execute_with_pipe. + _close(); + + path_src = String(); + ERR_FAIL_COND_V_MSG(fd[0] != 0 || fd[1] != 0, ERR_ALREADY_IN_USE, "Pipe is already in use."); + fd[0] = p_rfd; + fd[1] = p_wfd; + + last_error = OK; + return OK; +} + +Error FileAccessWindowsPipe::open_internal(const String &p_path, int p_mode_flags) { + _close(); + + path_src = p_path; + ERR_FAIL_COND_V_MSG(fd[0] != 0 || fd[1] != 0, ERR_ALREADY_IN_USE, "Pipe is already in use."); + + path = String("\\\\.\\pipe\\LOCAL\\") + p_path.replace("pipe://", "").replace("/", "_"); + + HANDLE h = CreateFileW((LPCWSTR)path.utf16().get_data(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + h = CreateNamedPipeW((LPCWSTR)path.utf16().get_data(), PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 4096, 4096, 0, nullptr); + if (h == INVALID_HANDLE_VALUE) { + last_error = ERR_FILE_CANT_OPEN; + return last_error; + } + ConnectNamedPipe(h, NULL); + } + fd[0] = h; + fd[1] = h; + + last_error = OK; + return OK; +} + +void FileAccessWindowsPipe::_close() { + if (fd[0] == 0) { + return; + } + if (fd[1] != fd[0]) { + CloseHandle(fd[1]); + } + CloseHandle(fd[0]); + fd[0] = 0; + fd[1] = 0; +} + +bool FileAccessWindowsPipe::is_open() const { + return (fd[0] != 0 || fd[1] != 0); +} + +String FileAccessWindowsPipe::get_path() const { + return path_src; +} + +String FileAccessWindowsPipe::get_path_absolute() const { + return path_src; +} + +uint8_t FileAccessWindowsPipe::get_8() const { + ERR_FAIL_COND_V_MSG(fd[0] == 0, 0, "Pipe must be opened before use."); + + uint8_t b; + if (!ReadFile(fd[0], &b, 1, nullptr, nullptr)) { + last_error = ERR_FILE_CANT_READ; + b = '\0'; + } else { + last_error = OK; + } + return b; +} + +uint64_t FileAccessWindowsPipe::get_buffer(uint8_t *p_dst, uint64_t p_length) const { + ERR_FAIL_COND_V(!p_dst && p_length > 0, -1); + ERR_FAIL_COND_V_MSG(fd[0] == 0, -1, "Pipe must be opened before use."); + + DWORD read = -1; + if (!ReadFile(fd[0], p_dst, p_length, &read, nullptr) || read != p_length) { + last_error = ERR_FILE_CANT_READ; + } else { + last_error = OK; + } + return read; +} + +Error FileAccessWindowsPipe::get_error() const { + return last_error; +} + +void FileAccessWindowsPipe::store_8(uint8_t p_src) { + ERR_FAIL_COND_MSG(fd[1] == 0, "Pipe must be opened before use."); + if (!WriteFile(fd[1], &p_src, 1, nullptr, nullptr)) { + last_error = ERR_FILE_CANT_WRITE; + } else { + last_error = OK; + } +} + +void FileAccessWindowsPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_MSG(fd[1] == 0, "Pipe must be opened before use."); + ERR_FAIL_COND(!p_src && p_length > 0); + + DWORD read = -1; + bool ok = WriteFile(fd[1], p_src, p_length, &read, nullptr); + if (!ok || read != p_length) { + last_error = ERR_FILE_CANT_WRITE; + } else { + last_error = OK; + } +} + +void FileAccessWindowsPipe::close() { + _close(); +} + +FileAccessWindowsPipe::~FileAccessWindowsPipe() { + _close(); +} + +#endif // WINDOWS_ENABLED diff --git a/drivers/windows/file_access_windows_pipe.h b/drivers/windows/file_access_windows_pipe.h new file mode 100644 index 0000000000..e6abe61fa3 --- /dev/null +++ b/drivers/windows/file_access_windows_pipe.h @@ -0,0 +1,95 @@ +/**************************************************************************/ +/* file_access_windows_pipe.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 FILE_ACCESS_WINDOWS_PIPE_H +#define FILE_ACCESS_WINDOWS_PIPE_H + +#ifdef WINDOWS_ENABLED + +#include "core/io/file_access.h" +#include "core/os/memory.h" + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +class FileAccessWindowsPipe : public FileAccess { + HANDLE fd[2] = { 0, 0 }; + + mutable Error last_error = OK; + + String path; + String path_src; + + void _close(); + +public: + Error open_existing(HANDLE p_rfd, HANDLE p_wfd); + + virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file + virtual bool is_open() const override; ///< true when file is open + + virtual String get_path() const override; /// returns the path for the current open file + virtual String get_path_absolute() const override; /// returns the absolute path for the current open file + + virtual void seek(uint64_t p_position) override {} + virtual void seek_end(int64_t p_position = 0) override {} + virtual uint64_t get_position() const override { return 0; } + virtual uint64_t get_length() const override { return 0; } + + virtual bool eof_reached() const override { return false; } + + virtual uint8_t get_8() const override; ///< get a byte + virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const override; + + virtual Error get_error() const override; ///< get last error + + virtual void flush() override {} + virtual void store_8(uint8_t p_src) override; ///< store a byte + virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes + + virtual bool file_exists(const String &p_name) override { return false; } + + uint64_t _get_modified_time(const String &p_file) override { return 0; } + virtual BitField<FileAccess::UnixPermissionFlags> _get_unix_permissions(const String &p_file) override { return 0; } + virtual Error _set_unix_permissions(const String &p_file, BitField<FileAccess::UnixPermissionFlags> p_permissions) override { return ERR_UNAVAILABLE; } + + virtual bool _get_hidden_attribute(const String &p_file) override { return false; } + virtual Error _set_hidden_attribute(const String &p_file, bool p_hidden) override { return ERR_UNAVAILABLE; } + virtual bool _get_read_only_attribute(const String &p_file) override { return false; } + virtual Error _set_read_only_attribute(const String &p_file, bool p_ro) override { return ERR_UNAVAILABLE; } + + virtual void close() override; + + FileAccessWindowsPipe() {} + virtual ~FileAccessWindowsPipe(); +}; + +#endif // WINDOWS_ENABLED + +#endif // FILE_ACCESS_WINDOWS_PIPE_H diff --git a/editor/SCsub b/editor/SCsub index f6d2f58d8e..e3b17b83f8 100644 --- a/editor/SCsub +++ b/editor/SCsub @@ -106,6 +106,7 @@ if env.editor_build: # Extractable translations tlist = glob.glob(env.Dir("#editor/translations/extractable").abspath + "/*.po") + tlist.extend(glob.glob(env.Dir("#editor/translations/extractable").abspath + "/extractable.pot")) env.Depends("#editor/extractable_translations.gen.h", tlist) env.CommandNoCache( "#editor/extractable_translations.gen.h", diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index fd06bf0533..a16446aea6 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -34,6 +34,7 @@ #include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/gui/editor_spin_slider.h" #include "editor/themes/editor_scale.h" #include "scene/gui/view_panner.h" #include "scene/resources/text_line.h" @@ -266,23 +267,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) { RBMap<String, Vector<int>> track_indices; int track_count = animation->get_track_count(); for (int i = 0; i < track_count; ++i) { - if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER) { + if (!_is_track_displayed(i)) { continue; } String base_path = animation->track_get_path(i); - if (is_filtered) { - if (root && root->has_node(base_path)) { - Node *node = root->get_node(base_path); - if (!node) { - continue; // No node, no filter. - } - if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) { - continue; // Skip track due to not selected. - } - } - } - int end = base_path.find(":"); if (end != -1) { base_path = base_path.substr(0, end + 1); @@ -520,28 +509,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) { float scale = timeline->get_zoom_scale(); for (int i = 0; i < track_count; ++i) { - if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i)) { - continue; - } - - if (hidden_tracks.has(i) || locked_tracks.has(i)) { + if (!_is_track_curves_displayed(i) || locked_tracks.has(i)) { continue; } int key_count = animation->track_get_key_count(i); - String path = animation->track_get_path(i); - - if (is_filtered) { - if (root && root->has_node(path)) { - Node *node = root->get_node(path); - if (!node) { - continue; // No node, no filter. - } - if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) { - continue; // Skip track due to not selected. - } - } - } for (int j = 0; j < key_count; ++j) { float offset = animation->track_get_key_time(i, j); @@ -648,6 +620,43 @@ void AnimationBezierTrackEdit::_notification(int p_what) { } } +// Check if a track is displayed in the bezier editor (track type = bezier and track not filtered). +bool AnimationBezierTrackEdit::_is_track_displayed(int p_track_index) { + if (animation->track_get_type(p_track_index) != Animation::TrackType::TYPE_BEZIER) { + return false; + } + + if (is_filtered) { + String path = animation->track_get_path(p_track_index); + if (root && root->has_node(path)) { + Node *node = root->get_node(path); + if (!node) { + return false; // No node, no filter. + } + if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) { + return false; // Skip track due to not selected. + } + } + } + + return true; +} + +// Check if the curves for a track are displayed in the editor (not hidden). Includes the check on the track visibility. +bool AnimationBezierTrackEdit::_is_track_curves_displayed(int p_track_index) { + //Is the track is visible in the editor? + if (!_is_track_displayed(p_track_index)) { + return false; + } + + //And curves visible? + if (hidden_tracks.has(p_track_index)) { + return false; + } + + return true; +} + Ref<Animation> AnimationBezierTrackEdit::get_animation() const { return animation; } @@ -741,6 +750,60 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) { queue_redraw(); } +void AnimationBezierTrackEdit::auto_fit_vertically() { + int track_count = animation->get_track_count(); + real_t minimum_value = INFINITY; + real_t maximum_value = -INFINITY; + + int nb_track_visible = 0; + for (int i = 0; i < track_count; ++i) { + if (!_is_track_curves_displayed(i) || locked_tracks.has(i)) { + continue; + } + + int key_count = animation->track_get_key_count(i); + + for (int j = 0; j < key_count; ++j) { + real_t value = animation->bezier_track_get_key_value(i, j); + + minimum_value = MIN(value, minimum_value); + maximum_value = MAX(value, maximum_value); + + // We also want to includes the handles... + Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j); + Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j); + + minimum_value = MIN(value + in_vec.y, minimum_value); + maximum_value = MAX(value + in_vec.y, maximum_value); + minimum_value = MIN(value + out_vec.y, minimum_value); + maximum_value = MAX(value + out_vec.y, maximum_value); + } + + nb_track_visible++; + } + + if (nb_track_visible == 0) { + // No visible track... we will not adjust the vertical zoom + return; + } + + if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) { + _zoom_vertically(minimum_value, maximum_value); + queue_redraw(); + } +} + +void AnimationBezierTrackEdit::_zoom_vertically(real_t p_minimum_value, real_t p_maximum_value) { + real_t target_height = p_maximum_value - p_minimum_value; + if (target_height <= CMP_EPSILON) { + timeline_v_scroll = p_maximum_value; + return; + } + + timeline_v_scroll = (p_maximum_value + p_minimum_value) / 2.0; + timeline_v_zoom = target_height / ((get_size().height - timeline->get_size().height) * 0.9); +} + void AnimationBezierTrackEdit::_zoom_changed() { queue_redraw(); play_position->queue_redraw(); @@ -838,7 +901,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (p_event->is_pressed()) { if (ED_IS_SHORTCUT("animation_editor/duplicate_selected_keys", p_event)) { if (!read_only) { - duplicate_selected_keys(-1.0); + duplicate_selected_keys(-1.0, false); } accept_event(); } @@ -856,7 +919,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } if (ED_IS_SHORTCUT("animation_editor/paste_keys", p_event)) { if (!read_only) { - paste_keys(-1.0); + paste_keys(-1.0, false); } accept_event(); } @@ -931,10 +994,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } if (Math::is_finite(minimum_value) && Math::is_finite(maximum_value)) { - timeline_v_scroll = (maximum_value + minimum_value) / 2.0; - if (maximum_value - minimum_value > CMP_EPSILON) { - timeline_v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9); - } + _zoom_vertically(minimum_value, maximum_value); } queue_redraw(); @@ -1179,6 +1239,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { moving_selection_attempt = true; moving_selection = false; + moving_selection_mouse_begin_x = mb->get_position().x; moving_selection_from_key = index; moving_selection_from_track = selected_track; moving_selection_offset = Vector2(); @@ -1260,7 +1321,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (!read_only) { - if (moving_selection && (abs(moving_selection_offset.x) > 0 || abs(moving_selection_offset.y) > 0)) { + if (moving_selection && (abs(moving_selection_offset.x) > CMP_EPSILON || abs(moving_selection_offset.y) > CMP_EPSILON)) { //combit it EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); @@ -1274,7 +1335,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { } // 2- remove overlapped keys for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + real_t newtime = animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x; int idx = animation->track_find_key(E->get().first, newtime, Animation::FIND_MODE_APPROX); if (idx == -1) { @@ -1298,7 +1359,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { // 3-move the keys (re insert them) for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + real_t newpos = animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x; Array key = animation->track_get_key_value(E->get().first, E->get().second); real_t h = key[0]; h += moving_selection_offset.y; @@ -1316,7 +1377,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { // 4-(undo) remove inserted keys for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + real_t newpos = animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x; undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos); } @@ -1358,7 +1419,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second); - real_t newpos = editor->snap_time(oldpos + moving_selection_offset.x); + real_t newpos = oldpos + moving_selection_offset.x; undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos); undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos); @@ -1366,14 +1427,15 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { undo_redo->commit_action(); - moving_selection = false; } else if (select_single_attempt != IntPair(-1, -1)) { selection.clear(); selection.insert(select_single_attempt); set_animation_and_track(animation, select_single_attempt.first, read_only); } + moving_selection = false; moving_selection_attempt = false; + moving_selection_mouse_begin_x = 0.0; queue_redraw(); } } @@ -1385,11 +1447,22 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) { select_single_attempt = IntPair(-1, -1); } - float y = (get_size().height / 2.0 - mm->get_position().y) * timeline_v_zoom + timeline_v_scroll; - float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value()); - if (!read_only) { - moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key)); + float y = (get_size().height / 2.0 - mm->get_position().y) * timeline_v_zoom + timeline_v_scroll; + float moving_selection_begin_time = ((moving_selection_mouse_begin_x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); + float new_time = ((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); + float moving_selection_pivot = animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key); + float time_delta = new_time - moving_selection_begin_time; + + float snapped_time = editor->snap_time(moving_selection_pivot + time_delta); + float time_offset = 0.0; + if (abs(moving_selection_offset.x) > CMP_EPSILON || (snapped_time > moving_selection_pivot && time_delta > CMP_EPSILON) || (snapped_time < moving_selection_pivot && time_delta < -CMP_EPSILON)) { + time_offset = snapped_time - moving_selection_pivot; + } + float moving_selection_begin_value = animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key); + float y_offset = y - moving_selection_begin_value; + + moving_selection_offset = Vector2(time_offset, y_offset); } additional_moving_handle_lefts.clear(); @@ -1503,17 +1576,18 @@ bool AnimationBezierTrackEdit::_try_select_at_ui_pos(const Point2 &p_pos, bool p moving_selection_attempt = true; moving_selection_from_key = pair.second; moving_selection_from_track = pair.first; + moving_selection_mouse_begin_x = p_pos.x; moving_selection_offset = Vector2(); moving_handle_track = pair.first; moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second); moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second); if (selection.has(pair)) { - select_single_attempt = pair; moving_selection = false; } else { moving_selection = true; } + select_single_attempt = pair; } set_animation_and_track(animation, pair.first, read_only); @@ -1583,25 +1657,28 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); - while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) { - time += 0.001; - } - switch (p_index) { case MENU_KEY_INSERT: { if (animation->get_track_count() > 0) { + if (editor->snap->is_pressed() && editor->step->get_value() != 0) { + time = editor->snap_time(time); + } + while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) { + time += 0.001; + } float h = (get_size().height / 2.0 - menu_insert_key.y) * timeline_v_zoom + timeline_v_scroll; Array new_point = make_default_bezier_key(h); EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Bezier Point")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time); undo_redo->commit_action(); queue_redraw(); } } break; case MENU_KEY_DUPLICATE: { - duplicate_selected_keys(time); + duplicate_selected_keys(time, true); } break; case MENU_KEY_DELETE: { delete_selection(); @@ -1613,7 +1690,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { copy_selected_keys(false); } break; case MENU_KEY_PASTE: { - paste_keys(time); + paste_keys(time, true); } break; case MENU_KEY_SET_HANDLE_FREE: { _change_selected_keys_handle_mode(Animation::HANDLE_MODE_FREE); @@ -1636,7 +1713,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) { } } -void AnimationBezierTrackEdit::duplicate_selected_keys(real_t p_ofs) { +void AnimationBezierTrackEdit::duplicate_selected_keys(real_t p_ofs, bool p_ofs_valid) { if (selection.size() == 0) { return; } @@ -1656,7 +1733,14 @@ void AnimationBezierTrackEdit::duplicate_selected_keys(real_t p_ofs) { for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { real_t t = animation->track_get_key_time(E->get().first, E->get().second); - real_t insert_pos = p_ofs >= 0 ? p_ofs : timeline->get_play_position(); + real_t insert_pos = p_ofs_valid ? p_ofs : timeline->get_play_position(); + + if (p_ofs_valid) { + if (editor->snap->is_pressed() && editor->step->get_value() != 0) { + insert_pos = editor->snap_time(insert_pos); + } + } + real_t dst_time = t + (insert_pos - top_time); int existing_idx = animation->track_find_key(E->get().first, dst_time, Animation::FIND_MODE_APPROX); @@ -1734,7 +1818,7 @@ void AnimationBezierTrackEdit::copy_selected_keys(bool p_cut) { } } -void AnimationBezierTrackEdit::paste_keys(real_t p_ofs) { +void AnimationBezierTrackEdit::paste_keys(real_t p_ofs, bool p_ofs_valid) { if (editor->is_key_clipboard_active() && animation.is_valid() && (selected_track >= 0 && selected_track < animation->get_track_count())) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Animation Paste Keys")); @@ -1765,7 +1849,12 @@ void AnimationBezierTrackEdit::paste_keys(real_t p_ofs) { for (int i = 0; i < editor->key_clipboard.keys.size(); i++) { const AnimationTrackEditor::KeyClipboard::Key key = editor->key_clipboard.keys[i]; - float insert_pos = p_ofs >= 0 ? p_ofs : timeline->get_play_position(); + float insert_pos = p_ofs_valid ? p_ofs : timeline->get_play_position(); + if (p_ofs_valid) { + if (editor->snap->is_pressed() && editor->step->get_value() != 0) { + insert_pos = editor->snap_time(insert_pos); + } + } float dst_time = key.time + insert_pos; int existing_idx = animation->track_find_key(selected_track, dst_time, Animation::FIND_MODE_APPROX); diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index ec2b52221e..ab667421f3 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -101,12 +101,15 @@ class AnimationBezierTrackEdit : public Control { void _menu_selected(int p_index); void _play_position_draw(); + bool _is_track_displayed(int p_track_index); + bool _is_track_curves_displayed(int p_track_index); Vector2 insert_at_pos; typedef Pair<int, int> IntPair; bool moving_selection_attempt = false; + float moving_selection_mouse_begin_x = 0.0; IntPair select_single_attempt; bool moving_selection = false; int moving_selection_from_key = 0; @@ -188,6 +191,7 @@ class AnimationBezierTrackEdit : public Control { void _draw_track(int p_track, const Color &p_color); float _bezier_h_to_pixel(float p_h); + void _zoom_vertically(real_t p_minimum_value, real_t p_maximum_value); protected: static void _bind_methods(); @@ -208,13 +212,14 @@ public: void set_editor(AnimationTrackEditor *p_editor); void set_root(Node *p_root); void set_filtered(bool p_filtered); + void auto_fit_vertically(); void set_play_position(real_t p_pos); void update_play_position(); - void duplicate_selected_keys(real_t p_ofs); + void duplicate_selected_keys(real_t p_ofs, bool p_ofs_valid); void copy_selected_keys(bool p_cut); - void paste_keys(real_t p_ofs); + void paste_keys(real_t p_ofs, bool p_ofs_valid); void delete_selection(); void _bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 6f1439a91f..bec95d40c6 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1305,7 +1305,11 @@ void AnimationTimelineEdit::_zoom_changed(double) { } float AnimationTimelineEdit::get_zoom_scale() const { - float zv = zoom->get_max() - zoom->get_value(); + return _get_zoom_scale(zoom->get_value()); +} + +float AnimationTimelineEdit::_get_zoom_scale(double p_zoom_value) const { + float zv = zoom->get_max() - p_zoom_value; if (zv < 1) { zv = 1.0 - zv; return Math::pow(1.0f + zv, 8.0f) * 100; @@ -1633,6 +1637,68 @@ void AnimationTimelineEdit::set_zoom(Range *p_zoom) { zoom->connect("value_changed", callable_mp(this, &AnimationTimelineEdit::_zoom_changed)); } +void AnimationTimelineEdit::auto_fit() { + if (!animation.is_valid()) { + return; + } + + float anim_end = animation->get_length(); + float anim_start = 0; + + // Search for keyframe outside animation boundaries to include keyframes before animation start and after animation length. + int track_count = animation->get_track_count(); + for (int track = 0; track < track_count; ++track) { + for (int i = 0; i < animation->track_get_key_count(track); i++) { + float key_time = animation->track_get_key_time(track, i); + if (key_time > anim_end) { + anim_end = key_time; + } + if (key_time < anim_start) { + anim_start = key_time; + } + } + } + + float anim_length = anim_end - anim_start; + int timeline_width_pixels = get_size().width - get_buttons_width() - get_name_limit(); + + // I want a little buffer at the end... (5% looks nice and we should keep some space for the bezier handles) + timeline_width_pixels *= 0.95; + + // The technique is to reuse the _get_zoom_scale function directly to be sure that the auto_fit is always calculated + // the same way as the zoom slider. It's a little bit more calculation then doing the inverse of get_zoom_scale but + // it's really easier to understand and should always be accurate. + float new_zoom = zoom->get_max(); + while (true) { + double test_zoom_scale = _get_zoom_scale(new_zoom); + + if (anim_length * test_zoom_scale <= timeline_width_pixels) { + // It fits... + break; + } + + new_zoom -= zoom->get_step(); + + if (new_zoom <= zoom->get_min()) { + new_zoom = zoom->get_min(); + break; + } + } + + // Horizontal scroll to get_min which should include keyframes that are before the animation start. + hscroll->set_value(hscroll->get_min()); + // Set the zoom value... the signal value_changed will be emitted and the timeline will be refreshed correctly! + zoom->set_value(new_zoom); + // The new zoom value must be applied correctly so the scrollbar are updated before we move the scrollbar to + // the beginning of the animation, hence the call deferred. + callable_mp(this, &AnimationTimelineEdit::_scroll_to_start).call_deferred(); +} + +void AnimationTimelineEdit::_scroll_to_start() { + // Horizontal scroll to get_min which should include keyframes that are before the animation start. + hscroll->set_value(hscroll->get_min()); +} + void AnimationTimelineEdit::set_track_edit(AnimationTrackEdit *p_track_edit) { track_edit = p_track_edit; } @@ -2001,13 +2067,13 @@ void AnimationTrackEdit::_notification(int p_what) { for (int i = 0; i < animation->track_get_key_count(track); i++) { float offset = animation->track_get_key_time(track, i) - timeline->get_value(); if (editor->is_key_selected(track, i) && editor->is_moving_selection()) { - offset = editor->snap_time(offset + editor->get_moving_selection_offset(), true); + offset = offset + editor->get_moving_selection_offset(); } offset = offset * scale + limit; if (i < animation->track_get_key_count(track) - 1) { float offset_n = animation->track_get_key_time(track, i + 1) - timeline->get_value(); if (editor->is_key_selected(track, i + 1) && editor->is_moving_selection()) { - offset_n = editor->snap_time(offset_n + editor->get_moving_selection_offset()); + offset_n = offset_n + editor->get_moving_selection_offset(); } offset_n = offset_n * scale + limit; @@ -2688,7 +2754,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (p_event->is_pressed()) { if (ED_IS_SHORTCUT("animation_editor/duplicate_selected_keys", p_event)) { if (!read_only) { - emit_signal(SNAME("duplicate_request"), -1.0); + emit_signal(SNAME("duplicate_request"), -1.0, false); } accept_event(); } @@ -2707,7 +2773,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (ED_IS_SHORTCUT("animation_editor/paste_keys", p_event)) { if (!read_only) { - emit_signal(SNAME("paste_request"), -1.0); + emit_signal(SNAME("paste_request"), -1.0, false); } accept_event(); } @@ -2908,8 +2974,10 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { if (mb.is_valid() && moving_selection_attempt) { if (!mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { moving_selection_attempt = false; - if (moving_selection) { - emit_signal(SNAME("move_selection_commit")); + if (moving_selection && moving_selection_effective) { + if (abs(editor->get_moving_selection_offset()) > CMP_EPSILON) { + emit_signal(SNAME("move_selection_commit")); + } } else if (select_single_attempt != -1) { emit_signal(SNAME("select_key"), select_single_attempt, true); } @@ -2982,8 +3050,18 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { emit_signal(SNAME("move_selection_begin")); } - float new_ofs = (mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale(); - emit_signal(SNAME("move_selection"), new_ofs - moving_selection_from_ofs); + float moving_begin_time = ((moving_selection_mouse_begin_x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value(); + float new_time = ((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value(); + float delta = new_time - moving_begin_time; + float snapped_time = editor->snap_time(moving_selection_pivot + delta); + + float offset = 0.0; + if (abs(editor->get_moving_selection_offset()) > CMP_EPSILON || (snapped_time > moving_selection_pivot && delta > CMP_EPSILON) || (snapped_time < moving_selection_pivot && delta < -CMP_EPSILON)) { + offset = snapped_time - moving_selection_pivot; + moving_selection_effective = true; + } + + emit_signal(SNAME("move_selection"), offset); } } @@ -3026,12 +3104,16 @@ bool AnimationTrackEdit::_try_select_at_ui_pos(const Point2 &p_pos, bool p_aggre if (editor->is_key_selected(track, key_idx)) { if (p_deselectable) { emit_signal(SNAME("deselect_key"), key_idx); + moving_selection_pivot = 0.0f; + moving_selection_mouse_begin_x = 0.0f; } } else { emit_signal(SNAME("select_key"), key_idx, false); moving_selection_attempt = true; + moving_selection_effective = false; select_single_attempt = -1; - moving_selection_from_ofs = (p_pos.x - limit) / timeline->get_zoom_scale(); + moving_selection_pivot = animation->track_get_key_time(track, key_idx); + moving_selection_mouse_begin_x = p_pos.x; } } else { if (!editor->is_key_selected(track, key_idx)) { @@ -3042,12 +3124,15 @@ bool AnimationTrackEdit::_try_select_at_ui_pos(const Point2 &p_pos, bool p_aggre } moving_selection_attempt = true; - moving_selection_from_ofs = (p_pos.x - limit) / timeline->get_zoom_scale(); + moving_selection_effective = false; + moving_selection_pivot = animation->track_get_key_time(track, key_idx); + moving_selection_mouse_begin_x = p_pos.x; } if (read_only) { moving_selection_attempt = false; - moving_selection_from_ofs = 0.0f; + moving_selection_pivot = 0.0f; + moving_selection_mouse_begin_x = 0.0f; } return true; } @@ -3182,7 +3267,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) { emit_signal(SNAME("insert_key"), insert_at_pos); } break; case MENU_KEY_DUPLICATE: { - emit_signal(SNAME("duplicate_request"), insert_at_pos); + emit_signal(SNAME("duplicate_request"), insert_at_pos, true); } break; case MENU_KEY_CUT: { emit_signal(SNAME("cut_request")); @@ -3191,7 +3276,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) { emit_signal(SNAME("copy_request")); } break; case MENU_KEY_PASTE: { - emit_signal(SNAME("paste_request"), insert_at_pos); + emit_signal(SNAME("paste_request"), insert_at_pos, true); } break; case MENU_KEY_ADD_RESET: { emit_signal(SNAME("create_reset_request")); @@ -3265,11 +3350,11 @@ void AnimationTrackEdit::_bind_methods() { ADD_SIGNAL(MethodInfo("move_selection_commit")); ADD_SIGNAL(MethodInfo("move_selection_cancel")); - ADD_SIGNAL(MethodInfo("duplicate_request", PropertyInfo(Variant::FLOAT, "offset"))); + ADD_SIGNAL(MethodInfo("duplicate_request", PropertyInfo(Variant::FLOAT, "offset"), PropertyInfo(Variant::BOOL, "is_offset_valid"))); ADD_SIGNAL(MethodInfo("create_reset_request")); ADD_SIGNAL(MethodInfo("copy_request")); ADD_SIGNAL(MethodInfo("cut_request")); - ADD_SIGNAL(MethodInfo("paste_request", PropertyInfo(Variant::FLOAT, "offset"))); + ADD_SIGNAL(MethodInfo("paste_request", PropertyInfo(Variant::FLOAT, "offset"), PropertyInfo(Variant::BOOL, "is_offset_valid"))); ADD_SIGNAL(MethodInfo("delete_request")); } @@ -3446,6 +3531,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re step->set_read_only(false); snap->set_disabled(false); snap_mode->set_disabled(false); + auto_fit->set_disabled(false); + auto_fit_bezier->set_disabled(false); imported_anim_warning->hide(); for (int i = 0; i < animation->get_track_count(); i++) { @@ -3466,6 +3553,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re snap->set_disabled(true); snap_mode->set_disabled(true); bezier_edit_icon->set_disabled(true); + auto_fit->set_disabled(true); + auto_fit_bezier->set_disabled(true); } } @@ -4763,6 +4852,8 @@ void AnimationTrackEditor::_notification(int p_what) { inactive_player_warning->set_icon(get_editor_theme_icon(SNAME("NodeWarning"))); main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("Tree"))); edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_editor_theme_icon(SNAME("Reload"))); + auto_fit->set_icon(get_editor_theme_icon(SNAME("AnimationAutoFit"))); + auto_fit_bezier->set_icon(get_editor_theme_icon(SNAME("AnimationAutoFitBezier"))); } break; case NOTIFICATION_READY: { @@ -4915,12 +5006,17 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { } void AnimationTrackEditor::_add_track(int p_type) { - if (!root) { + AnimationPlayer *ap = AnimationPlayerEditor::get_singleton()->get_player(); + if (!ap) { + ERR_FAIL_EDMSG("No AnimationPlayer is currently being edited."); + } + Node *root_node = ap->get_node_or_null(ap->get_root_node()); + if (!root_node) { EditorNode::get_singleton()->show_warning(TTR("Not possible to add a new track without a root")); return; } adding_track_type = p_type; - pick_track->popup_scenetree_dialog(); + pick_track->popup_scenetree_dialog(nullptr, root_node); pick_track->get_filter_line_edit()->clear(); pick_track->get_filter_line_edit()->grab_focus(); } @@ -5086,6 +5182,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { undo_redo->create_action(TTR("Add Position Key")); undo_redo->add_do_method(animation.ptr(), "position_track_insert_key", p_track, p_ofs, pos); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); undo_redo->commit_action(); @@ -5106,6 +5203,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { undo_redo->create_action(TTR("Add Rotation Key")); undo_redo->add_do_method(animation.ptr(), "rotation_track_insert_key", p_track, p_ofs, rot); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); undo_redo->commit_action(); @@ -5124,6 +5222,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { undo_redo->create_action(TTR("Add Scale Key")); undo_redo->add_do_method(animation.ptr(), "scale_track_insert_key", p_track, p_ofs, base->get_scale()); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); undo_redo->commit_action(); @@ -5169,6 +5268,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { undo_redo->create_action(TTR("Add Track Key")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, arr); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); undo_redo->commit_action(); @@ -5181,6 +5281,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { undo_redo->create_action(TTR("Add Track Key")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, ak); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); undo_redo->commit_action(); } break; @@ -5189,6 +5290,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) { undo_redo->create_action(TTR("Add Track Key")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, anim); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_track, p_ofs); undo_redo->commit_action(); } break; @@ -5229,6 +5331,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) { EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Add Method Track Key")); undo_redo->add_do_method(animation.ptr(), "track_insert_key", insert_key_from_track_call_track, insert_key_from_track_call_ofs, d); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", insert_key_from_track_call_track, insert_key_from_track_call_ofs); undo_redo->commit_action(); @@ -5427,7 +5530,7 @@ void AnimationTrackEditor::_move_selection_commit() { } // 2 - Remove overlapped keys. for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { - float newtime = snap_time(E->get().pos + motion); + float newtime = E->get().pos + motion; int idx = animation->track_find_key(E->key().track, newtime, Animation::FIND_MODE_APPROX); if (idx == -1) { continue; @@ -5452,13 +5555,13 @@ void AnimationTrackEditor::_move_selection_commit() { // 3 - Move the keys (Reinsert them). for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { - float newpos = snap_time(E->get().pos + motion); + float newpos = E->get().pos + motion; undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key)); } // 4 - (Undo) Remove inserted keys. for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { - float newpos = snap_time(E->get().pos + motion); + float newpos = E->get().pos + motion; undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos); } @@ -5478,7 +5581,7 @@ void AnimationTrackEditor::_move_selection_commit() { // 7 - Reselect. for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { float oldpos = E->get().pos; - float newpos = snap_time(oldpos + motion); + float newpos = oldpos + motion; undo_redo->add_do_method(this, "_select_at_anim", animation, E->key().track, newpos); undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos); @@ -5617,6 +5720,8 @@ void AnimationTrackEditor::_cancel_bezier_edit() { bezier_edit->hide(); scroll->show(); bezier_edit_icon->set_pressed(false); + auto_fit->show(); + auto_fit_bezier->hide(); } void AnimationTrackEditor::_bezier_edit(int p_for_track) { @@ -5625,6 +5730,8 @@ void AnimationTrackEditor::_bezier_edit(int p_for_track) { bezier_edit->set_animation_and_track(animation, p_for_track, read_only); scroll->hide(); bezier_edit->show(); + auto_fit->hide(); + auto_fit_bezier->show(); // Search everything within the track and curve - edit it. } @@ -5635,7 +5742,7 @@ void AnimationTrackEditor::_bezier_track_set_key_handle_mode(Animation *p_anim, p_anim->bezier_track_set_key_handle_mode(p_track, p_index, p_mode, p_set_mode); } -void AnimationTrackEditor::_anim_duplicate_keys(float p_ofs, int p_track) { +void AnimationTrackEditor::_anim_duplicate_keys(float p_ofs, bool p_ofs_valid, int p_track) { if (selection.size() && animation.is_valid()) { int top_track = 0x7FFFFFFF; float top_time = 1e10; @@ -5688,7 +5795,13 @@ void AnimationTrackEditor::_anim_duplicate_keys(float p_ofs, int p_track) { const SelectedKey &sk = E->key(); float t = animation->track_get_key_time(sk.track, sk.key); - float insert_pos = p_ofs >= 0 ? p_ofs : timeline->get_play_position(); + float insert_pos = p_ofs_valid ? p_ofs : timeline->get_play_position(); + + if (p_ofs_valid) { + if (snap->is_pressed() && step->get_value() != 0) { + insert_pos = snap_time(insert_pos); + } + } float dst_time = t + (insert_pos - top_time); int dst_track = sk.track + (start_track - top_track); @@ -5795,7 +5908,7 @@ void AnimationTrackEditor::_set_key_clipboard(int p_top_track, float p_top_time, } } -void AnimationTrackEditor::_anim_paste_keys(float p_ofs, int p_track) { +void AnimationTrackEditor::_anim_paste_keys(float p_ofs, bool p_ofs_valid, int p_track) { if (is_key_clipboard_active() && animation.is_valid()) { int start_track = p_track; if (p_track == -1) { // Pasting from shortcut or Edit menu. @@ -5830,7 +5943,13 @@ void AnimationTrackEditor::_anim_paste_keys(float p_ofs, int p_track) { for (int i = 0; i < key_clipboard.keys.size(); i++) { const KeyClipboard::Key key = key_clipboard.keys[i]; - float insert_pos = p_ofs >= 0 ? p_ofs : timeline->get_play_position(); + float insert_pos = p_ofs_valid ? p_ofs : timeline->get_play_position(); + + if (p_ofs_valid) { + if (snap->is_pressed() && step->get_value() != 0) { + insert_pos = snap_time(insert_pos); + } + } float dst_time = key.time + insert_pos; int dst_track = key.track + start_track; @@ -6427,10 +6546,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { case EDIT_DUPLICATE_SELECTED_KEYS: { if (bezier_edit->is_visible()) { - bezier_edit->duplicate_selected_keys(-1.0); + bezier_edit->duplicate_selected_keys(-1.0, false); break; } - _anim_duplicate_keys(-1.0, -1.0); + _anim_duplicate_keys(-1.0, false, -1.0); } break; case EDIT_CUT_KEYS: { if (bezier_edit->is_visible()) { @@ -6447,7 +6566,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { _anim_copy_keys(false); } break; case EDIT_PASTE_KEYS: { - _anim_paste_keys(-1.0, -1.0); + _anim_paste_keys(-1.0, false, -1.0); } break; case EDIT_MOVE_FIRST_SELECTED_KEY_TO_CURSOR: { if (moving_selection || selection.is_empty()) { @@ -6865,6 +6984,18 @@ bool AnimationTrackEditor::is_grouping_tracks() { return !view_group->is_pressed(); } +void AnimationTrackEditor::_auto_fit() { + timeline->auto_fit(); +} + +void AnimationTrackEditor::_auto_fit_bezier() { + timeline->auto_fit(); + + if (bezier_edit->is_visible()) { + bezier_edit->auto_fit_vertically(); + } +} + void AnimationTrackEditor::_selection_changed() { if (selected_filter->is_pressed()) { _update_tracks(); // Needs updatin. @@ -7179,6 +7310,19 @@ AnimationTrackEditor::AnimationTrackEditor() { bottom_hb->add_child(zoom); timeline->set_zoom(zoom); + auto_fit = memnew(Button); + auto_fit->set_flat(true); + auto_fit->connect("pressed", callable_mp(this, &AnimationTrackEditor::_auto_fit)); + auto_fit->set_shortcut(ED_SHORTCUT("animation_editor/auto_fit", TTR("Fit to panel"), KeyModifierMask::ALT | Key::F)); + bottom_hb->add_child(auto_fit); + + auto_fit_bezier = memnew(Button); + auto_fit_bezier->set_flat(true); + auto_fit_bezier->set_visible(false); + auto_fit_bezier->connect("pressed", callable_mp(this, &AnimationTrackEditor::_auto_fit_bezier)); + auto_fit_bezier->set_shortcut(ED_SHORTCUT("animation_editor/auto_fit", TTR("Fit to panel"), KeyModifierMask::ALT | Key::F)); + bottom_hb->add_child(auto_fit_bezier); + edit = memnew(MenuButton); edit->set_shortcut_context(this); edit->set_text(TTR("Edit")); @@ -7430,6 +7574,7 @@ AnimationTrackEditor::AnimationTrackEditor() { track_copy_vbox->add_child(select_all_button); track_copy_select = memnew(Tree); + track_copy_select->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); track_copy_select->set_h_size_flags(SIZE_EXPAND_FILL); track_copy_select->set_v_size_flags(SIZE_EXPAND_FILL); track_copy_select->set_hide_root(true); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index d0da7b0062..f449b51b81 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -182,6 +182,9 @@ class AnimationTimelineEdit : public Range { virtual void gui_input(const Ref<InputEvent> &p_event) override; void _track_added(int p_track); + float _get_zoom_scale(double p_zoom_value) const; + void _scroll_to_start(); + protected: static void _bind_methods(); void _notification(int p_what); @@ -197,6 +200,7 @@ public: void set_track_edit(AnimationTrackEdit *p_track_edit); void set_zoom(Range *p_zoom); Range *get_zoom() const { return zoom; } + void auto_fit(); void set_play_position(float p_pos); float get_play_position() const; @@ -286,9 +290,11 @@ class AnimationTrackEdit : public Control { mutable int dropping_at = 0; float insert_at_pos = 0.0f; bool moving_selection_attempt = false; + bool moving_selection_effective = false; + float moving_selection_pivot = 0.0f; + float moving_selection_mouse_begin_x = 0.0f; int select_single_attempt = -1; bool moving_selection = false; - float moving_selection_from_ofs = 0.0f; bool in_group = false; AnimationTrackEditor *editor = nullptr; @@ -404,6 +410,8 @@ class AnimationTrackEditor : public VBoxContainer { Button *snap = nullptr; Button *bezier_edit_icon = nullptr; OptionButton *snap_mode = nullptr; + Button *auto_fit = nullptr; + Button *auto_fit_bezier = nullptr; Button *imported_anim_warning = nullptr; void _show_imported_anim_warning(); @@ -579,18 +587,21 @@ class AnimationTrackEditor : public VBoxContainer { void _cleanup_animation(Ref<Animation> p_animation); - void _anim_duplicate_keys(float p_ofs, int p_track); + void _anim_duplicate_keys(float p_ofs, bool p_ofs_valid, int p_track); void _anim_copy_keys(bool p_cut); bool _is_track_compatible(int p_target_track_idx, Variant::Type p_source_value_type, Animation::TrackType p_source_track_type); - void _anim_paste_keys(float p_ofs, int p_track); + void _anim_paste_keys(float p_ofs, bool p_ofs_valid, int p_track); void _view_group_toggle(); Button *view_group = nullptr; Button *selected_filter = nullptr; + void _auto_fit(); + void _auto_fit_bezier(); + void _selection_changed(); ConfirmationDialog *track_copy_dialog = nullptr; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 6c16951186..bfad38d341 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -941,6 +941,10 @@ void CodeTextEditor::_complete_request() { font_color = completion_string_color; } else if (e.insert_text.begins_with("##") || e.insert_text.begins_with("///")) { font_color = completion_doc_comment_color; + } else if (e.insert_text.begins_with("&")) { + font_color = completion_string_name_color; + } else if (e.insert_text.begins_with("^")) { + font_color = completion_node_path_color; } else if (e.insert_text.begins_with("#") || e.insert_text.begins_with("//")) { font_color = completion_comment_color; } @@ -997,6 +1001,8 @@ void CodeTextEditor::update_editor_settings() { // Theme: Highlighting completion_font_color = EDITOR_GET("text_editor/theme/highlighting/completion_font_color"); completion_string_color = EDITOR_GET("text_editor/theme/highlighting/string_color"); + completion_string_name_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/string_name_color"); + completion_node_path_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_path_color"); completion_comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color"); completion_doc_comment_color = EDITOR_GET("text_editor/theme/highlighting/doc_comment_color"); @@ -1032,7 +1038,7 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_v_scroll_speed(EDITOR_GET("text_editor/behavior/navigation/v_scroll_speed")); text_editor->set_drag_and_drop_selection_enabled(EDITOR_GET("text_editor/behavior/navigation/drag_and_drop_selection")); - // Behavior: indent + // Behavior: Indent set_indent_using_spaces(EDITOR_GET("text_editor/behavior/indent/type")); text_editor->set_indent_size(EDITOR_GET("text_editor/behavior/indent/size")); text_editor->set_auto_indent_enabled(EDITOR_GET("text_editor/behavior/indent/auto_indent")); diff --git a/editor/code_editor.h b/editor/code_editor.h index c888619ac0..87031b672c 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -184,6 +184,8 @@ class CodeTextEditor : public VBoxContainer { Color completion_font_color; Color completion_string_color; + Color completion_string_name_color; + Color completion_node_path_color; Color completion_comment_color; Color completion_doc_comment_color; CodeTextEditorCodeCompleteFunc code_complete_func; diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index ed90b796f7..2db5b02d63 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -50,7 +50,6 @@ #include "scene/gui/option_button.h" #include "scene/gui/popup_menu.h" #include "scene/gui/spin_box.h" -#include "scene/resources/packed_scene.h" static Node *_find_first_script(Node *p_root, Node *p_node) { if (p_node != p_root && p_node->get_owner() != p_root) { @@ -617,7 +616,7 @@ void ConnectDialog::init(const ConnectionData &p_cd, const PackedStringArray &p_ signal_args = p_signal_args; tree->set_selected(nullptr); - tree->set_marked(source, true); + tree->set_marked(source); if (p_cd.target) { set_dst_node(static_cast<Node *>(p_cd.target)); @@ -751,6 +750,7 @@ ConnectDialog::ConnectDialog() { method_tree = memnew(Tree); method_vbc->add_child(method_tree); + method_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); method_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); method_tree->set_hide_root(true); method_tree->connect("item_selected", callable_mp(this, &ConnectDialog::_method_selected)); @@ -1561,6 +1561,7 @@ ConnectionsDock::ConnectionsDock() { vbc->add_child(search_box); tree = memnew(ConnectionsDockTree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_columns(1); tree->set_select_mode(Tree::SELECT_ROW); tree->set_hide_root(true); diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 603b3505d4..4c66068953 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -779,6 +779,7 @@ CreateDialog::CreateDialog() { vsc->add_child(fav_vb); favorites = memnew(Tree); + favorites->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); favorites->set_hide_root(true); favorites->set_hide_folding(true); favorites->set_allow_reselect(true); @@ -823,6 +824,7 @@ CreateDialog::CreateDialog() { vbc->add_margin_child(TTR("Search:"), search_hb); search_options = memnew(Tree); + search_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); search_options->connect("item_activated", callable_mp(this, &CreateDialog::_confirmed)); search_options->connect("cell_selected", callable_mp(this, &CreateDialog::_item_selected)); vbc->add_margin_child(TTR("Matches:"), search_options, true); diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index 7d3ea33fb5..17a23982a7 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -41,6 +41,7 @@ EditorDebuggerTree::EditorDebuggerTree() { set_v_size_flags(SIZE_EXPAND_FILL); set_allow_rmb_select(true); + set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // Popup item_menu = memnew(PopupMenu); diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp index ffff362a94..da75715b6d 100644 --- a/editor/debugger/editor_performance_profiler.cpp +++ b/editor/debugger/editor_performance_profiler.cpp @@ -84,7 +84,7 @@ String EditorPerformanceProfiler::_create_label(float p_value, Performance::Moni return String::humanize_size(p_value); } case Performance::MONITOR_TYPE_TIME: { - return TS->format_number(rtos(p_value * 1000).pad_decimals(2)) + " " + RTR("ms"); + return TS->format_number(rtos(p_value * 1000).pad_decimals(2)) + " " + TTR("ms"); } default: { return TS->format_number(rtos(p_value)); diff --git a/editor/debugger/editor_profiler.cpp b/editor/debugger/editor_profiler.cpp index 730160b331..ce08d40634 100644 --- a/editor/debugger/editor_profiler.cpp +++ b/editor/debugger/editor_profiler.cpp @@ -125,12 +125,12 @@ String EditorProfiler::_get_time_as_text(const Metric &m, float p_time, int p_ca const int dmode = display_mode->get_selected(); if (dmode == DISPLAY_FRAME_TIME) { - return TS->format_number(rtos(p_time * 1000).pad_decimals(2)) + " " + RTR("ms"); + return TS->format_number(rtos(p_time * 1000).pad_decimals(2)) + " " + TTR("ms"); } else if (dmode == DISPLAY_AVERAGE_TIME) { if (p_calls == 0) { - return TS->format_number("0.00") + " " + RTR("ms"); + return TS->format_number("0.00") + " " + TTR("ms"); } else { - return TS->format_number(rtos((p_time / p_calls) * 1000).pad_decimals(2)) + " " + RTR("ms"); + return TS->format_number(rtos((p_time / p_calls) * 1000).pad_decimals(2)) + " " + TTR("ms"); } } else if (dmode == DISPLAY_FRAME_PERCENT) { return _get_percent_txt(p_time, m.frame_time); @@ -670,6 +670,7 @@ EditorProfiler::EditorProfiler() { h_split->set_v_size_flags(SIZE_EXPAND_FILL); variables = memnew(Tree); + variables->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); variables->set_custom_minimum_size(Size2(320, 0) * EDSCALE); variables->set_hide_folding(true); h_split->add_child(variables); diff --git a/editor/debugger/editor_visual_profiler.cpp b/editor/debugger/editor_visual_profiler.cpp index 72f1060589..8a5c464c2f 100644 --- a/editor/debugger/editor_visual_profiler.cpp +++ b/editor/debugger/editor_visual_profiler.cpp @@ -116,7 +116,7 @@ String EditorVisualProfiler::_get_time_as_text(float p_time) { int dmode = display_mode->get_selected(); if (dmode == DISPLAY_FRAME_TIME) { - return TS->format_number(String::num(p_time, 2)) + " " + RTR("ms"); + return TS->format_number(String::num(p_time, 2)) + " " + TTR("ms"); } else if (dmode == DISPLAY_FRAME_PERCENT) { return TS->format_number(String::num(p_time * 100 / graph_limit, 2)) + " " + TS->percent_sign(); } diff --git a/editor/dependency_editor.cpp b/editor/dependency_editor.cpp index 5eccc7673a..8c3cad3e89 100644 --- a/editor/dependency_editor.cpp +++ b/editor/dependency_editor.cpp @@ -66,7 +66,7 @@ void DependencyEditor::_load_pressed(Object *p_item, int p_cell, int p_button, M List<String> ext; ResourceLoader::get_recognized_extensions_for_type(ti->get_metadata(0), &ext); for (const String &E : ext) { - search->add_filter("*" + E); + search->add_filter("*." + E); } search->popup_file_dialog(); } @@ -246,6 +246,7 @@ DependencyEditor::DependencyEditor() { add_child(vb); tree = memnew(Tree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_columns(2); tree->set_column_titles_visible(true); tree->set_column_title(0, TTR("Resource")); @@ -672,6 +673,7 @@ DependencyRemoveDialog::DependencyRemoveDialog() { vb->add_child(text); owners = memnew(Tree); + owners->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); owners->set_hide_root(true); vb->add_child(owners); owners->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -724,6 +726,7 @@ DependencyErrorDialog::DependencyErrorDialog() { add_child(vb); files = memnew(Tree); + files->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); files->set_hide_root(true); vb->add_margin_child(TTR("Load failed due to missing dependencies:"), files, true); files->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -879,6 +882,7 @@ OrphanResourcesDialog::OrphanResourcesDialog() { add_child(vbc); files = memnew(Tree); + files->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); files->set_columns(2); files->set_column_titles_visible(true); files->set_column_custom_minimum_width(1, 100 * EDSCALE); diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 52b0d485cf..db45478d21 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -76,241 +76,275 @@ static String _translate_doc_string(const String &p_text) { return translated.indent(indent); } -void DocTools::merge_from(const DocTools &p_data) { - for (KeyValue<String, DocData::ClassDoc> &E : class_list) { - DocData::ClassDoc &c = E.value; +// Comparator for constructors, based on `MetodDoc` operator. +struct ConstructorCompare { + _FORCE_INLINE_ bool operator()(const DocData::MethodDoc &p_lhs, const DocData::MethodDoc &p_rhs) const { + // Must be a constructor (i.e. assume named for the class) + // We want this arbitrary order for a class "Foo": + // - 1. Default constructor: Foo() + // - 2. Copy constructor: Foo(Foo) + // - 3+. Other constructors Foo(Bar, ...) based on first argument's name + if (p_lhs.arguments.is_empty() || p_rhs.arguments.is_empty()) { // 1. + return p_lhs.arguments.size() < p_rhs.arguments.size(); + } + if (p_lhs.arguments[0].type == p_lhs.return_type || p_rhs.arguments[0].type == p_lhs.return_type) { // 2. + return (p_lhs.arguments[0].type == p_lhs.return_type) || (p_rhs.arguments[0].type != p_lhs.return_type); + } + return p_lhs.arguments[0] < p_rhs.arguments[0]; + } +}; - if (!p_data.class_list.has(c.name)) { - continue; +// Comparator for operators, compares on name and type. +struct OperatorCompare { + _FORCE_INLINE_ bool operator()(const DocData::MethodDoc &p_lhs, const DocData::MethodDoc &p_rhs) const { + if (p_lhs.name == p_rhs.name) { + if (p_lhs.arguments.size() == p_rhs.arguments.size()) { + if (p_lhs.arguments.is_empty()) { + return false; + } + return p_lhs.arguments[0].type < p_rhs.arguments[0].type; + } + return p_lhs.arguments.size() < p_rhs.arguments.size(); } + return p_lhs.name.naturalcasecmp_to(p_rhs.name) < 0; + } +}; - const DocData::ClassDoc &cf = p_data.class_list[c.name]; +// Comparator for methods, compares on names. +struct MethodCompare { + _FORCE_INLINE_ bool operator()(const DocData::MethodDoc &p_lhs, const DocData::MethodDoc &p_rhs) const { + return p_lhs.name.naturalcasecmp_to(p_rhs.name) < 0; + } +}; - c.is_deprecated = cf.is_deprecated; - c.deprecated_message = cf.deprecated_message; - c.is_experimental = cf.is_experimental; - c.experimental_message = cf.experimental_message; - c.keywords = cf.keywords; +static void merge_constructors(Vector<DocData::MethodDoc> &p_to, const Vector<DocData::MethodDoc> &p_from) { + // Get data from `p_from`, to avoid mutation checks. + const DocData::MethodDoc *from_ptr = p_from.ptr(); + int64_t from_size = p_from.size(); - c.description = cf.description; - c.brief_description = cf.brief_description; - c.tutorials = cf.tutorials; + // TODO: Improve constructor merging. + for (DocData::MethodDoc &to : p_to) { + for (int64_t from_i = 0; from_i < from_size; ++from_i) { + const DocData::MethodDoc &from = from_ptr[from_i]; - for (int i = 0; i < c.constructors.size(); i++) { - DocData::MethodDoc &m = c.constructors.write[i]; + // Compare argument count first. + if (from.arguments.size() != to.arguments.size()) { + continue; + } - for (int j = 0; j < cf.constructors.size(); j++) { - if (cf.constructors[j].name != m.name) { - continue; - } + if (from.name != to.name) { + continue; + } - { - // Since constructors can repeat, we need to check the type of - // the arguments so we make sure they are different. - if (cf.constructors[j].arguments.size() != m.arguments.size()) { - continue; - } - int arg_count = cf.constructors[j].arguments.size(); - Vector<bool> arg_used; - arg_used.resize(arg_count); - for (int l = 0; l < arg_count; ++l) { - arg_used.write[l] = false; - } - // also there is no guarantee that argument ordering will match, so we - // have to check one by one so we make sure we have an exact match - for (int k = 0; k < arg_count; ++k) { - for (int l = 0; l < arg_count; ++l) { - if (cf.constructors[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) { - arg_used.write[l] = true; - break; - } - } - } - bool not_the_same = false; - for (int l = 0; l < arg_count; ++l) { - if (!arg_used[l]) { // at least one of the arguments was different - not_the_same = true; + { + // Since constructors can repeat, we need to check the type of + // the arguments so we make sure they are different. + int64_t arg_count = from.arguments.size(); + Vector<bool> arg_used; + arg_used.resize_zeroed(arg_count); + // Also there is no guarantee that argument ordering will match, + // so we have to check one by one so we make sure we have an exact match. + for (int64_t arg_i = 0; arg_i < arg_count; ++arg_i) { + for (int64_t arg_j = 0; arg_j < arg_count; ++arg_j) { + if (from.arguments[arg_i].type == to.arguments[arg_j].type && !arg_used[arg_j]) { + arg_used.write[arg_j] = true; + break; } } - if (not_the_same) { - continue; + } + bool not_the_same = false; + for (int64_t arg_i = 0; arg_i < arg_count; ++arg_i) { + if (!arg_used[arg_i]) { // At least one of the arguments was different. + not_the_same = true; + break; } } - - const DocData::MethodDoc &mf = cf.constructors[j]; - - m.description = mf.description; - m.is_deprecated = mf.is_deprecated; - m.deprecated_message = mf.deprecated_message; - m.is_experimental = mf.is_experimental; - m.experimental_message = mf.experimental_message; - break; + if (not_the_same) { + continue; + } } + + to.description = from.description; + to.is_deprecated = from.is_deprecated; + to.deprecated_message = from.deprecated_message; + to.is_experimental = from.is_experimental; + to.experimental_message = from.experimental_message; + break; } + } +} - for (int i = 0; i < c.methods.size(); i++) { - DocData::MethodDoc &m = c.methods.write[i]; +static void merge_methods(Vector<DocData::MethodDoc> &p_to, const Vector<DocData::MethodDoc> &p_from) { + // Get data from `p_to`, to avoid mutation checks. Searching will be done in the sorted `p_to` from the (potentially) unsorted `p_from`. + DocData::MethodDoc *to_ptrw = p_to.ptrw(); + int64_t to_size = p_to.size(); - for (int j = 0; j < cf.methods.size(); j++) { - if (cf.methods[j].name != m.name) { - continue; - } + SearchArray<DocData::MethodDoc, MethodCompare> search_array; - const DocData::MethodDoc &mf = cf.methods[j]; + for (const DocData::MethodDoc &from : p_from) { + int64_t found = search_array.bisect(to_ptrw, to_size, from, true); - m.description = mf.description; - m.is_deprecated = mf.is_deprecated; - m.deprecated_message = mf.deprecated_message; - m.is_experimental = mf.is_experimental; - m.experimental_message = mf.experimental_message; - m.keywords = mf.keywords; - break; - } + if (found >= to_size) { + continue; } - for (int i = 0; i < c.signals.size(); i++) { - DocData::MethodDoc &m = c.signals.write[i]; + DocData::MethodDoc &to = to_ptrw[found]; - for (int j = 0; j < cf.signals.size(); j++) { - if (cf.signals[j].name != m.name) { - continue; - } - const DocData::MethodDoc &mf = cf.signals[j]; - - m.description = mf.description; - m.is_deprecated = mf.is_deprecated; - m.deprecated_message = mf.deprecated_message; - m.is_experimental = mf.is_experimental; - m.experimental_message = mf.experimental_message; - m.keywords = mf.keywords; - break; - } + // Check found entry on name. + if (to.name == from.name) { + to.description = from.description; + to.is_deprecated = from.is_deprecated; + to.deprecated_message = from.deprecated_message; + to.is_experimental = from.is_experimental; + to.experimental_message = from.experimental_message; + to.keywords = from.keywords; } + } +} - for (int i = 0; i < c.constants.size(); i++) { - DocData::ConstantDoc &m = c.constants.write[i]; +static void merge_constants(Vector<DocData::ConstantDoc> &p_to, const Vector<DocData::ConstantDoc> &p_from) { + // Get data from `p_from`, to avoid mutation checks. Searching will be done in the sorted `p_from` from the unsorted `p_to`. + const DocData::ConstantDoc *from_ptr = p_from.ptr(); + int64_t from_size = p_from.size(); - for (int j = 0; j < cf.constants.size(); j++) { - if (cf.constants[j].name != m.name) { - continue; - } - const DocData::ConstantDoc &mf = cf.constants[j]; - - m.description = mf.description; - m.is_deprecated = mf.is_deprecated; - m.deprecated_message = mf.deprecated_message; - m.is_experimental = mf.is_experimental; - m.experimental_message = mf.experimental_message; - m.keywords = mf.keywords; - break; - } + SearchArray<DocData::ConstantDoc> search_array; + + for (DocData::ConstantDoc &to : p_to) { + int64_t found = search_array.bisect(from_ptr, from_size, to, true); + + if (found >= from_size) { + continue; } - for (int i = 0; i < c.annotations.size(); i++) { - DocData::MethodDoc &m = c.annotations.write[i]; + // Check found entry on name. + const DocData::ConstantDoc &from = from_ptr[found]; - for (int j = 0; j < cf.annotations.size(); j++) { - if (cf.annotations[j].name != m.name) { - continue; - } - const DocData::MethodDoc &mf = cf.annotations[j]; - - m.description = mf.description; - m.is_deprecated = mf.is_deprecated; - m.deprecated_message = mf.deprecated_message; - m.is_experimental = mf.is_experimental; - m.experimental_message = mf.experimental_message; - m.keywords = mf.keywords; - break; - } + if (from.name == to.name) { + to.description = from.description; + to.is_deprecated = from.is_deprecated; + to.deprecated_message = from.deprecated_message; + to.is_experimental = from.is_experimental; + to.experimental_message = from.experimental_message; + to.keywords = from.keywords; } + } +} - for (int i = 0; i < c.properties.size(); i++) { - DocData::PropertyDoc &p = c.properties.write[i]; +static void merge_properties(Vector<DocData::PropertyDoc> &p_to, const Vector<DocData::PropertyDoc> &p_from) { + // Get data from `p_to`, to avoid mutation checks. Searching will be done in the sorted `p_to` from the (potentially) unsorted `p_from`. + DocData::PropertyDoc *to_ptrw = p_to.ptrw(); + int64_t to_size = p_to.size(); - for (int j = 0; j < cf.properties.size(); j++) { - if (cf.properties[j].name != p.name) { - continue; - } - const DocData::PropertyDoc &pf = cf.properties[j]; - - p.description = pf.description; - p.is_deprecated = pf.is_deprecated; - p.deprecated_message = pf.deprecated_message; - p.is_experimental = pf.is_experimental; - p.experimental_message = pf.experimental_message; - p.keywords = pf.keywords; - break; - } + SearchArray<DocData::PropertyDoc> search_array; + + for (const DocData::PropertyDoc &from : p_from) { + int64_t found = search_array.bisect(to_ptrw, to_size, from, true); + + if (found >= to_size) { + continue; } - for (int i = 0; i < c.theme_properties.size(); i++) { - DocData::ThemeItemDoc &ti = c.theme_properties.write[i]; + DocData::PropertyDoc &to = to_ptrw[found]; - for (int j = 0; j < cf.theme_properties.size(); j++) { - if (cf.theme_properties[j].name != ti.name || cf.theme_properties[j].data_type != ti.data_type) { - continue; - } - const DocData::ThemeItemDoc &pf = cf.theme_properties[j]; + // Check found entry on name. + if (to.name == from.name) { + to.description = from.description; + to.is_deprecated = from.is_deprecated; + to.deprecated_message = from.deprecated_message; + to.is_experimental = from.is_experimental; + to.experimental_message = from.experimental_message; + to.keywords = from.keywords; + } + } +} - ti.description = pf.description; - ti.keywords = pf.keywords; - break; - } +static void merge_theme_properties(Vector<DocData::ThemeItemDoc> &p_to, const Vector<DocData::ThemeItemDoc> &p_from) { + // Get data from `p_to`, to avoid mutation checks. Searching will be done in the sorted `p_to` from the (potentially) unsorted `p_from`. + DocData::ThemeItemDoc *to_ptrw = p_to.ptrw(); + int64_t to_size = p_to.size(); + + SearchArray<DocData::ThemeItemDoc> search_array; + + for (const DocData::ThemeItemDoc &from : p_from) { + int64_t found = search_array.bisect(to_ptrw, to_size, from, true); + + if (found >= to_size) { + continue; } - for (int i = 0; i < c.operators.size(); i++) { - DocData::MethodDoc &m = c.operators.write[i]; + DocData::ThemeItemDoc &to = to_ptrw[found]; - for (int j = 0; j < cf.operators.size(); j++) { - if (cf.operators[j].name != m.name) { - continue; - } + // Check found entry on name and data type. + if (to.name == from.name && to.data_type == from.data_type) { + to.description = from.description; + to.keywords = from.keywords; + } + } +} - { - // Since operators can repeat, we need to check the type of - // the arguments so we make sure they are different. - if (cf.operators[j].arguments.size() != m.arguments.size()) { - continue; - } - int arg_count = cf.operators[j].arguments.size(); - Vector<bool> arg_used; - arg_used.resize(arg_count); - for (int l = 0; l < arg_count; ++l) { - arg_used.write[l] = false; - } - // also there is no guarantee that argument ordering will match, so we - // have to check one by one so we make sure we have an exact match - for (int k = 0; k < arg_count; ++k) { - for (int l = 0; l < arg_count; ++l) { - if (cf.operators[j].arguments[k].type == m.arguments[l].type && !arg_used[l]) { - arg_used.write[l] = true; - break; - } - } - } - bool not_the_same = false; - for (int l = 0; l < arg_count; ++l) { - if (!arg_used[l]) { // at least one of the arguments was different - not_the_same = true; - } - } - if (not_the_same) { - continue; - } - } +static void merge_operators(Vector<DocData::MethodDoc> &p_to, const Vector<DocData::MethodDoc> &p_from) { + // Get data from `p_to`, to avoid mutation checks. Searching will be done in the sorted `p_to` from the (potentially) unsorted `p_from`. + DocData::MethodDoc *to_ptrw = p_to.ptrw(); + int64_t to_size = p_to.size(); - const DocData::MethodDoc &mf = cf.operators[j]; + SearchArray<DocData::MethodDoc, OperatorCompare> search_array; - m.description = mf.description; - m.is_deprecated = mf.is_deprecated; - m.deprecated_message = mf.deprecated_message; - m.is_experimental = mf.is_experimental; - m.experimental_message = mf.experimental_message; - break; - } + for (const DocData::MethodDoc &from : p_from) { + int64_t found = search_array.bisect(to_ptrw, to_size, from, true); + + if (found >= to_size) { + continue; + } + + DocData::MethodDoc &to = to_ptrw[found]; + + // Check found entry on name and argument. + if (to.name == from.name && to.arguments.size() == from.arguments.size() && (to.arguments.is_empty() || to.arguments[0].type == from.arguments[0].type)) { + to.description = from.description; + to.is_deprecated = from.is_deprecated; + to.deprecated_message = from.deprecated_message; + to.is_experimental = from.is_experimental; + to.experimental_message = from.experimental_message; + } + } +} + +void DocTools::merge_from(const DocTools &p_data) { + for (KeyValue<String, DocData::ClassDoc> &E : class_list) { + DocData::ClassDoc &c = E.value; + + if (!p_data.class_list.has(c.name)) { + continue; } + const DocData::ClassDoc &cf = p_data.class_list[c.name]; + + c.is_deprecated = cf.is_deprecated; + c.deprecated_message = cf.deprecated_message; + c.is_experimental = cf.is_experimental; + c.experimental_message = cf.experimental_message; + c.keywords = cf.keywords; + + c.description = cf.description; + c.brief_description = cf.brief_description; + c.tutorials = cf.tutorials; + + merge_constructors(c.constructors, cf.constructors); + + merge_methods(c.methods, cf.methods); + + merge_methods(c.signals, cf.signals); + + merge_constants(c.constants, cf.constants); + + merge_methods(c.annotations, cf.annotations); + + merge_properties(c.properties, cf.properties); + + merge_theme_properties(c.theme_properties, cf.theme_properties); + + merge_operators(c.operators, cf.operators); + #ifndef MODULE_MONO_ENABLED // The Mono module defines some properties that we want to keep when // re-generating docs with a non-Mono build, to prevent pointless diffs @@ -323,6 +357,8 @@ void DocTools::merge_from(const DocTools &p_data) { for (int j = 0; j < cf.properties.size(); j++) { if (cf.properties[j].name == "GodotSharp") { c.properties.push_back(cf.properties[j]); + c.properties.sort(); + break; } } } @@ -620,7 +656,7 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) { c.methods.push_back(method); } - c.methods.sort(); + c.methods.sort_custom<MethodCompare>(); List<MethodInfo> signal_list; ClassDB::get_signal_list(name, &signal_list, true); @@ -639,6 +675,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) { c.signals.push_back(signal); } + + c.signals.sort_custom<MethodCompare>(); } List<String> constant_list; @@ -865,7 +903,9 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) { } } - c.methods.sort(); + c.constructors.sort_custom<ConstructorCompare>(); + c.operators.sort_custom<OperatorCompare>(); + c.methods.sort_custom<MethodCompare>(); List<PropertyInfo> properties; v.get_property_list(&properties); @@ -878,6 +918,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) { c.properties.push_back(property); } + c.properties.sort(); + List<StringName> constants; Variant::get_constants_for_type(Variant::Type(i), &constants); @@ -933,10 +975,11 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) { c.properties.push_back(pd); } + c.properties.sort(); + // Variant utility functions. List<StringName> utility_functions; Variant::get_utility_function_list(&utility_functions); - utility_functions.sort_custom<StringName::AlphCompare>(); for (const StringName &E : utility_functions) { DocData::MethodDoc md; md.name = E; @@ -971,6 +1014,8 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) { c.methods.push_back(md); } + + c.methods.sort_custom<MethodCompare>(); } // Add scripting language built-ins. @@ -1066,6 +1111,9 @@ void DocTools::generate(BitField<GenerateFlags> p_flags) { continue; } + c.methods.sort_custom<MethodCompare>(); + c.annotations.sort_custom<MethodCompare>(); + class_list[cname] = c; } } @@ -1468,6 +1516,9 @@ Error DocTools::_load(Ref<XMLParser> parser) { break; // End of <class>. } } + + // Sort loaded constants for merging. + c.constants.sort(); } return OK; @@ -1483,7 +1534,6 @@ static void _write_string(Ref<FileAccess> f, int p_tablevel, const String &p_str static void _write_method_doc(Ref<FileAccess> f, const String &p_name, Vector<DocData::MethodDoc> &p_method_docs) { if (!p_method_docs.is_empty()) { - p_method_docs.sort(); _write_string(f, 1, "<" + p_name + "s>"); for (int i = 0; i < p_method_docs.size(); i++) { const DocData::MethodDoc &m = p_method_docs[i]; @@ -1615,8 +1665,6 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String, if (!c.properties.is_empty()) { _write_string(f, 1, "<members>"); - c.properties.sort(); - for (int i = 0; i < c.properties.size(); i++) { String additional_attributes; if (!c.properties[i].enumeration.is_empty()) { @@ -1696,8 +1744,6 @@ Error DocTools::save_classes(const String &p_default_path, const HashMap<String, _write_method_doc(f, "annotation", c.annotations); if (!c.theme_properties.is_empty()) { - c.theme_properties.sort(); - _write_string(f, 1, "<theme_items>"); for (int i = 0; i < c.theme_properties.size(); i++) { const DocData::ThemeItemDoc &ti = c.theme_properties[i]; diff --git a/editor/editor_about.cpp b/editor/editor_about.cpp index e594d53d69..61c4eed669 100644 --- a/editor/editor_about.cpp +++ b/editor/editor_about.cpp @@ -304,6 +304,7 @@ EditorAbout::EditorAbout() { license_thirdparty->add_child(tpl_hbc); _tpl_tree = memnew(Tree); + _tpl_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); _tpl_tree->set_hide_root(true); TreeItem *root = _tpl_tree->create_item(); TreeItem *tpl_ti_all = _tpl_tree->create_item(root); diff --git a/editor/editor_asset_installer.cpp b/editor/editor_asset_installer.cpp index 3c42f07f82..742dec8d69 100644 --- a/editor/editor_asset_installer.cpp +++ b/editor/editor_asset_installer.cpp @@ -735,6 +735,7 @@ EditorAssetInstaller::EditorAssetInstaller() { source_tree_vb->add_child(source_tree_label); source_tree = memnew(Tree); + source_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); source_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); source_tree->connect("item_edited", callable_mp(this, &EditorAssetInstaller::_item_checked_cbk)); source_tree_vb->add_child(source_tree); @@ -749,6 +750,7 @@ EditorAssetInstaller::EditorAssetInstaller() { destination_tree_vb->add_child(destination_tree_label); destination_tree = memnew(Tree); + destination_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); destination_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); destination_tree->connect("item_edited", callable_mp(this, &EditorAssetInstaller::_item_checked_cbk)); destination_tree_vb->add_child(destination_tree); diff --git a/editor/editor_atlas_packer.cpp b/editor/editor_atlas_packer.cpp index 5de4869c88..a0f5f1bf11 100644 --- a/editor/editor_atlas_packer.cpp +++ b/editor/editor_atlas_packer.cpp @@ -72,8 +72,7 @@ void EditorAtlasPacker::chart_pack(Vector<Chart> &charts, int &r_width, int &r_h Vector2 vtx = chart.vertices[chart.faces[j].vertex[k]]; vtx -= aabb.position; vtx /= divide_by; - vtx.x = MIN(vtx.x, w - 1); - vtx.y = MIN(vtx.y, h - 1); + vtx = vtx.min(Vector2(w - 1, h - 1)); v[k] = vtx; } diff --git a/editor/editor_build_profile.cpp b/editor/editor_build_profile.cpp index 3d10b7949e..65bca1a935 100644 --- a/editor/editor_build_profile.cpp +++ b/editor/editor_build_profile.cpp @@ -854,6 +854,7 @@ EditorBuildProfileManager::EditorBuildProfileManager() { main_vbc->add_margin_child(TTR("Actions:"), profiles_hbc); class_list = memnew(Tree); + class_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); class_list->set_hide_root(true); class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); class_list->connect("cell_selected", callable_mp(this, &EditorBuildProfileManager::_class_list_item_selected)); diff --git a/editor/editor_builders.py b/editor/editor_builders.py index 68595047fe..a25f4949c4 100644 --- a/editor/editor_builders.py +++ b/editor/editor_builders.py @@ -61,7 +61,9 @@ def make_translations_header(target, source, env, category): xl_names = [] for i in range(len(sorted_paths)): - if msgfmt_available: + name = os.path.splitext(os.path.basename(sorted_paths[i]))[0] + # msgfmt erases non-translated messages, so avoid using it if exporting the POT. + if msgfmt_available and name != category: mo_path = os.path.join(tempfile.gettempdir(), uuid.uuid4().hex + ".mo") cmd = "msgfmt " + sorted_paths[i] + " --no-hash -o " + mo_path try: @@ -79,7 +81,7 @@ def make_translations_header(target, source, env, category): try: os.remove(mo_path) except OSError as e: - # Do not fail the entire build if it cannot delete a temporary file + # Do not fail the entire build if it cannot delete a temporary file. print( "WARNING: Could not delete temporary .mo file: path=%r; [%s] %s" % (mo_path, e.__class__.__name__, e) @@ -88,11 +90,13 @@ def make_translations_header(target, source, env, category): with open(sorted_paths[i], "rb") as f: buf = f.read() + if name == category: + name = "source" + decomp_size = len(buf) # Use maximum zlib compression level to further reduce file size # (at the cost of initial build times). buf = zlib.compress(buf, zlib.Z_BEST_COMPRESSION) - name = os.path.splitext(os.path.basename(sorted_paths[i]))[0] g.write("static const unsigned char _{}_translation_{}_compressed[] = {{\n".format(category, name)) for j in range(len(buf)): diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 47642c1592..6ab29c1850 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -721,12 +721,9 @@ bool EditorData::check_and_update_scene(int p_idx) { } new_scene->set_scene_file_path(edited_scene[p_idx].root->get_scene_file_path()); - - memdelete(edited_scene[p_idx].root); - edited_scene.write[p_idx].root = new_scene; - if (!new_scene->get_scene_file_path().is_empty()) { - edited_scene.write[p_idx].path = new_scene->get_scene_file_path(); - } + Node *old_root = edited_scene[p_idx].root; + old_root->replace_by(new_scene, false, false); + memdelete(old_root); edited_scene.write[p_idx].selection = new_selection; return true; diff --git a/editor/editor_dock_manager.cpp b/editor/editor_dock_manager.cpp index 08719d6bf0..b6250671ee 100644 --- a/editor/editor_dock_manager.cpp +++ b/editor/editor_dock_manager.cpp @@ -49,8 +49,6 @@ EditorDockManager *EditorDockManager::singleton = nullptr; -static const char *META_TOGGLE_SHORTCUT = "_toggle_shortcut"; - void DockSplitContainer::_update_visibility() { if (is_updating) { return; @@ -106,359 +104,257 @@ void DockSplitContainer::remove_child_notify(Node *p_child) { _update_visibility(); } -void EditorDockManager::_dock_select_popup_theme_changed() { - if (dock_float) { - dock_float->set_icon(dock_select_popup->get_editor_theme_icon(SNAME("MakeFloating"))); - } - if (dock_select_popup->is_layout_rtl()) { - dock_tab_move_left->set_icon(dock_select_popup->get_editor_theme_icon(SNAME("Forward"))); - dock_tab_move_right->set_icon(dock_select_popup->get_editor_theme_icon(SNAME("Back"))); - } else { - dock_tab_move_left->set_icon(dock_select_popup->get_editor_theme_icon(SNAME("Back"))); - dock_tab_move_right->set_icon(dock_select_popup->get_editor_theme_icon(SNAME("Forward"))); - } - - dock_to_bottom->set_icon(dock_select_popup->get_editor_theme_icon(SNAME("ControlAlignBottomWide"))); +void EditorDockManager::_dock_split_dragged(int p_offset) { + EditorNode::get_singleton()->save_editor_layout_delayed(); } -void EditorDockManager::_dock_popup_exit() { - dock_select_rect_over_idx = -1; - dock_select->queue_redraw(); -} +void EditorDockManager::_dock_container_gui_input(const Ref<InputEvent> &p_input, TabContainer *p_dock_container) { + Ref<InputEventMouseButton> mb = p_input; -void EditorDockManager::_dock_pre_popup(int p_dock_slot) { - dock_popup_selected_idx = p_dock_slot; - dock_bottom_selected_idx = -1; + if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { + int tab_id = p_dock_container->get_tab_bar()->get_hovered_tab(); + if (tab_id < 0) { + return; + } - if (bool(dock_slot[p_dock_slot]->get_current_tab_control()->call("_can_dock_horizontal"))) { - dock_to_bottom->show(); - } else { - dock_to_bottom->hide(); + // Right click context menu. + dock_context_popup->set_dock(p_dock_container->get_tab_control(tab_id)); + dock_context_popup->set_position(p_dock_container->get_screen_position() + mb->get_position()); + dock_context_popup->popup(); } +} + +void EditorDockManager::_bottom_dock_button_gui_input(const Ref<InputEvent> &p_input, Control *p_dock, Button *p_bottom_button) { + Ref<InputEventMouseButton> mb = p_input; - if (dock_float) { - dock_float->show(); + if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { + // Right click context menu. + dock_context_popup->set_dock(p_dock); + dock_context_popup->set_position(p_bottom_button->get_screen_position() + mb->get_position()); + dock_context_popup->popup(); } - dock_tab_move_right->show(); - dock_tab_move_left->show(); } -void EditorDockManager::_dock_move_left() { - if (dock_popup_selected_idx < 0 || dock_popup_selected_idx >= DOCK_SLOT_MAX) { - return; - } - Control *current_ctl = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab()); - Control *prev_ctl = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab() - 1); - if (!current_ctl || !prev_ctl) { +void EditorDockManager::_dock_container_update_visibility(TabContainer *p_dock_container) { + if (!docks_visible) { return; } - dock_slot[dock_popup_selected_idx]->move_child(current_ctl, prev_ctl->get_index(false)); - dock_select->queue_redraw(); - _edit_current(); - emit_signal(SNAME("layout_changed")); + // Hide the dock container if there are no tabs. + p_dock_container->set_visible(p_dock_container->get_tab_count() > 0); } -void EditorDockManager::_dock_move_right() { - if (dock_popup_selected_idx < 0 || dock_popup_selected_idx >= DOCK_SLOT_MAX) { - return; - } - Control *current_ctl = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab()); - Control *next_ctl = dock_slot[dock_popup_selected_idx]->get_tab_control(dock_slot[dock_popup_selected_idx]->get_current_tab() + 1); - if (!current_ctl || !next_ctl) { +void EditorDockManager::_update_layout() { + if (!dock_context_popup->is_inside_tree() || EditorNode::get_singleton()->is_exiting()) { return; } - dock_slot[dock_popup_selected_idx]->move_child(next_ctl, current_ctl->get_index(false)); - dock_select->queue_redraw(); - _edit_current(); - emit_signal(SNAME("layout_changed")); + EditorNode::get_singleton()->edit_current(); + dock_context_popup->docks_updated(); + _update_docks_menu(); + EditorNode::get_singleton()->save_editor_layout_delayed(); } -void EditorDockManager::_dock_select_input(const Ref<InputEvent> &p_input) { - Ref<InputEventMouse> me = p_input; +void EditorDockManager::_update_docks_menu() { + docks_menu->clear(); + docks_menu->reset_size(); - if (me.is_valid()) { - Vector2 point = me->get_position(); + const Ref<Texture2D> icon = docks_menu->get_editor_theme_icon(SNAME("Window")); + const Color closed_icon_color_mod = Color(1, 1, 1, 0.5); - int nrect = -1; - for (int i = 0; i < DOCK_SLOT_MAX; i++) { - if (dock_select_rect[i].has_point(point)) { - nrect = i; - break; - } - } - - if (nrect != dock_select_rect_over_idx) { - dock_select->queue_redraw(); - dock_select_rect_over_idx = nrect; + // Add docks. + docks_menu_docks.clear(); + int id = 0; + for (const KeyValue<Control *, DockInfo> &dock : all_docks) { + if (dock.value.shortcut.is_valid()) { + docks_menu->add_shortcut(dock.value.shortcut, id); + docks_menu->set_item_text(id, dock.value.title); + } else { + docks_menu->add_item(dock.value.title, id); } - - if (nrect == -1) { - return; + docks_menu->set_item_icon(id, icon); + if (!dock.value.open) { + docks_menu->set_item_icon_modulate(id, closed_icon_color_mod); } + docks_menu->set_item_disabled(id, !dock.value.enabled); + docks_menu_docks.push_back(dock.key); + id++; + } +} - Ref<InputEventMouseButton> mb = me; - - if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) { - if (dock_bottom_selected_idx != -1) { - EditorNode::get_bottom_panel()->remove_item(bottom_docks[dock_bottom_selected_idx]); - - bottom_docks[dock_bottom_selected_idx]->call("_set_dock_horizontal", false); - - dock_slot[nrect]->add_child(bottom_docks[dock_bottom_selected_idx]); - dock_slot[nrect]->show(); - bottom_docks.remove_at(dock_bottom_selected_idx); - dock_bottom_selected_idx = -1; - dock_popup_selected_idx = nrect; // Move to dock popup selected. - dock_select->queue_redraw(); - - update_dock_slots_visibility(true); - - _edit_current(); - emit_signal(SNAME("layout_changed")); - } - - if (dock_popup_selected_idx != nrect) { - dock_slot[nrect]->move_tab_from_tab_container(dock_slot[dock_popup_selected_idx], dock_slot[dock_popup_selected_idx]->get_current_tab(), dock_slot[nrect]->get_tab_count()); - - if (dock_slot[dock_popup_selected_idx]->get_tab_count() == 0) { - dock_slot[dock_popup_selected_idx]->hide(); - } else { - dock_slot[dock_popup_selected_idx]->set_current_tab(0); - } - - dock_popup_selected_idx = nrect; - dock_slot[nrect]->show(); - dock_select->queue_redraw(); +void EditorDockManager::_docks_menu_option(int p_id) { + focus_dock(docks_menu_docks[p_id]); +} - update_dock_slots_visibility(true); +void EditorDockManager::_window_close_request(WindowWrapper *p_wrapper) { + // Give the dock back to the original owner. + Control *dock = _close_window(p_wrapper); + ERR_FAIL_COND(!all_docks.has(dock)); - _edit_current(); - emit_signal(SNAME("layout_changed")); - } - } + if (all_docks[dock].previous_at_bottom || all_docks[dock].dock_slot_index != DOCK_SLOT_NONE) { + all_docks[dock].open = false; + open_dock(dock); + focus_dock(dock); + } else { + close_dock(dock); } } -void EditorDockManager::_dock_select_draw() { - Size2 s = dock_select->get_size(); - s.y /= 2.0; - s.x /= 6.0; +Control *EditorDockManager::_close_window(WindowWrapper *p_wrapper) { + p_wrapper->set_block_signals(true); + Control *dock = p_wrapper->release_wrapped_control(); + p_wrapper->set_block_signals(false); + ERR_FAIL_COND_V(!all_docks.has(dock), nullptr); - Color used = Color(0.6, 0.6, 0.6, 0.8); - Color used_selected = Color(0.8, 0.8, 0.8, 0.8); - Color tab_selected = dock_select->get_theme_color(SNAME("mono_color"), EditorStringName(Editor)); - Color unused = used; - unused.a = 0.4; - Color unusable = unused; - unusable.a = 0.1; + all_docks[dock].dock_window = nullptr; + dock_windows.erase(p_wrapper); + p_wrapper->queue_free(); + return dock; +} - Rect2 unr(s.x * 2, 0, s.x * 2, s.y * 2); - unr.position += Vector2(2, 5); - unr.size -= Vector2(4, 7); +void EditorDockManager::_open_dock_in_window(Control *p_dock, bool p_show_window, bool p_reset_size) { + ERR_FAIL_NULL(p_dock); - dock_select->draw_rect(unr, unusable); + Size2 borders = Size2(4, 4) * EDSCALE; + // Remember size and position before removing it from the main window. + Size2 dock_size = p_dock->get_size() + borders * 2; + Point2 dock_screen_pos = p_dock->get_screen_position(); - dock_tab_move_left->set_disabled(true); - dock_tab_move_right->set_disabled(true); + WindowWrapper *wrapper = memnew(WindowWrapper); + wrapper->set_window_title(vformat(TTR("%s - Godot Engine"), all_docks[p_dock].title)); + wrapper->set_margins_enabled(true); - if (dock_popup_selected_idx != -1 && dock_slot[dock_popup_selected_idx]->get_tab_count()) { - dock_tab_move_left->set_disabled(dock_slot[dock_popup_selected_idx]->get_current_tab() == 0); - dock_tab_move_right->set_disabled(dock_slot[dock_popup_selected_idx]->get_current_tab() >= dock_slot[dock_popup_selected_idx]->get_tab_count() - 1); - } + EditorNode::get_singleton()->get_gui_base()->add_child(wrapper); - for (int i = 0; i < DOCK_SLOT_MAX; i++) { - Vector2 ofs; - - switch (i) { - case DOCK_SLOT_LEFT_UL: { - } break; - case DOCK_SLOT_LEFT_BL: { - ofs.y += s.y; - } break; - case DOCK_SLOT_LEFT_UR: { - ofs.x += s.x; - } break; - case DOCK_SLOT_LEFT_BR: { - ofs += s; - } break; - case DOCK_SLOT_RIGHT_UL: { - ofs.x += s.x * 4; - } break; - case DOCK_SLOT_RIGHT_BL: { - ofs.x += s.x * 4; - ofs.y += s.y; - - } break; - case DOCK_SLOT_RIGHT_UR: { - ofs.x += s.x * 4; - ofs.x += s.x; - - } break; - case DOCK_SLOT_RIGHT_BR: { - ofs.x += s.x * 4; - ofs += s; - - } break; - } - - Rect2 r(ofs, s); - dock_select_rect[i] = r; - r.position += Vector2(2, 5); - r.size -= Vector2(4, 7); + _move_dock(p_dock, nullptr); + wrapper->set_wrapped_control(p_dock); - if (i == dock_select_rect_over_idx) { - dock_select->draw_rect(r, used_selected); - } else if (dock_slot[i]->get_tab_count() == 0) { - dock_select->draw_rect(r, unused); - } else { - dock_select->draw_rect(r, used); - } + all_docks[p_dock].dock_window = wrapper; + all_docks[p_dock].open = true; + p_dock->show(); - for (int j = 0; j < MIN(3, dock_slot[i]->get_tab_count()); j++) { - int xofs = (r.size.width / 3) * j; - Color c = used; - if (i == dock_popup_selected_idx && (dock_slot[i]->get_current_tab() > 3 || dock_slot[i]->get_current_tab() == j)) { - c = tab_selected; - } - dock_select->draw_rect(Rect2(2 + ofs.x + xofs, ofs.y, r.size.width / 3 - 1, 3), c); + wrapper->connect("window_close_requested", callable_mp(this, &EditorDockManager::_window_close_request).bind(wrapper)); + dock_windows.push_back(wrapper); + + if (p_show_window) { + wrapper->restore_window(Rect2i(dock_screen_pos, dock_size), EditorNode::get_singleton()->get_gui_base()->get_window()->get_current_screen()); + _update_layout(); + if (p_reset_size) { + // Use a default size of one third the current window size. + Size2i popup_size = EditorNode::get_singleton()->get_window()->get_size() / 3.0; + p_dock->get_window()->set_size(popup_size); + p_dock->get_window()->move_to_center(); } + p_dock->get_window()->grab_focus(); } } -void EditorDockManager::_dock_split_dragged(int p_offset) { - EditorNode::get_singleton()->save_editor_layout_delayed(); -} - -void EditorDockManager::_dock_tab_changed(int p_tab) { - // Update visibility but don't set current tab. - update_dock_slots_visibility(true); -} +void EditorDockManager::_restore_dock_to_saved_window(Control *p_dock, const Dictionary &p_window_dump) { + if (!all_docks[p_dock].dock_window) { + _open_dock_in_window(p_dock, false); + } -void EditorDockManager::_edit_current() { - EditorNode::get_singleton()->edit_current(); + all_docks[p_dock].dock_window->restore_window_from_saved_position( + p_window_dump.get("window_rect", Rect2i()), + p_window_dump.get("window_screen", -1), + p_window_dump.get("window_screen_rect", Rect2i())); } -void EditorDockManager::_dock_floating_close_request(WindowWrapper *p_wrapper) { - int dock_slot_num = p_wrapper->get_meta("dock_slot"); - int dock_slot_index = p_wrapper->get_meta("dock_index"); +void EditorDockManager::_dock_move_to_bottom(Control *p_dock) { + _move_dock(p_dock, nullptr); - // Give back the dock to the original owner. - Control *dock = p_wrapper->release_wrapped_control(); - - int target_index = MIN(dock_slot_index, dock_slot[dock_slot_num]->get_tab_count()); - dock_slot[dock_slot_num]->add_child(dock); - dock_slot[dock_slot_num]->move_child(dock, target_index); - dock_slot[dock_slot_num]->set_current_tab(target_index); + all_docks[p_dock].at_bottom = true; + all_docks[p_dock].previous_at_bottom = false; - floating_docks.erase(p_wrapper); - p_wrapper->queue_free(); + p_dock->call("_set_dock_horizontal", true); - update_dock_slots_visibility(true); - - _edit_current(); + // Force docks moved to the bottom to appear first in the list, and give them their associated shortcut to toggle their bottom panel. + Button *bottom_button = EditorNode::get_bottom_panel()->add_item(all_docks[p_dock].title, p_dock, all_docks[p_dock].shortcut, true); + bottom_button->connect("gui_input", callable_mp(this, &EditorDockManager::_bottom_dock_button_gui_input).bind(bottom_button).bind(p_dock)); + EditorNode::get_bottom_panel()->make_item_visible(p_dock); } -void EditorDockManager::_dock_make_selected_float() { - Control *dock = dock_slot[dock_popup_selected_idx]->get_current_tab_control(); - _dock_make_float(dock, dock_popup_selected_idx); +void EditorDockManager::_dock_remove_from_bottom(Control *p_dock) { + all_docks[p_dock].at_bottom = false; + all_docks[p_dock].previous_at_bottom = true; - dock_select_popup->hide(); - _edit_current(); + EditorNode::get_bottom_panel()->remove_item(p_dock); + p_dock->call("_set_dock_horizontal", false); } -void EditorDockManager::bottom_dock_show_placement_popup(const Rect2i &p_position, Control *p_dock) { - dock_bottom_selected_idx = bottom_docks.find(p_dock); - ERR_FAIL_COND(dock_bottom_selected_idx == -1); - dock_popup_selected_idx = -1; - dock_to_bottom->hide(); - - Vector2 popup_pos = p_position.position; - popup_pos.y += p_position.size.height; - - if (!EditorNode::get_singleton()->get_gui_base()->is_layout_rtl()) { - popup_pos.x -= dock_select_popup->get_size().width; - popup_pos.x += p_position.size.width; - } - dock_select_popup->set_position(popup_pos); - dock_select_popup->popup(); - if (dock_float) { - dock_float->hide(); - } - dock_tab_move_right->hide(); - dock_tab_move_left->hide(); +bool EditorDockManager::_is_dock_at_bottom(Control *p_dock) { + ERR_FAIL_COND_V(!all_docks.has(p_dock), false); + return all_docks[p_dock].at_bottom; } -void EditorDockManager::_dock_move_selected_to_bottom() { - Control *dock = dock_slot[dock_popup_selected_idx]->get_current_tab_control(); - dock_slot[dock_popup_selected_idx]->remove_child(dock); - - dock->call("_set_dock_horizontal", true); - - bottom_docks.push_back(dock); - - // Force docks moved to the bottom to appear first in the list, and give them their associated shortcut to toggle their bottom panel. - EditorNode::get_bottom_panel()->add_item(dock->get_name(), dock, dock->get_meta(META_TOGGLE_SHORTCUT), true); +void EditorDockManager::_move_dock_tab_index(Control *p_dock, int p_tab_index, bool p_set_current) { + TabContainer *dock_tab_container = Object::cast_to<TabContainer>(p_dock->get_parent()); + if (!dock_tab_container) { + return; + } - dock_select_popup->hide(); - update_dock_slots_visibility(true); - _edit_current(); - emit_signal(SNAME("layout_changed")); + dock_tab_container->set_block_signals(true); + int target_index = CLAMP(p_tab_index, 0, dock_tab_container->get_tab_count() - 1); + dock_tab_container->move_child(p_dock, dock_tab_container->get_tab_control(target_index)->get_index(false)); + all_docks[p_dock].previous_tab_index = target_index; - EditorNode::get_bottom_panel()->make_item_visible(dock); + if (p_set_current) { + dock_tab_container->set_current_tab(target_index); + } + dock_tab_container->set_block_signals(false); } -void EditorDockManager::_dock_make_float(Control *p_dock, int p_slot_index, bool p_show_window) { +void EditorDockManager::_move_dock(Control *p_dock, Control *p_target, int p_tab_index, bool p_set_current) { ERR_FAIL_NULL(p_dock); + ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot move unknown dock '%s'.", p_dock->get_name())); - Size2 borders = Size2(4, 4) * EDSCALE; - // Remember size and position before removing it from the main window. - Size2 dock_size = p_dock->get_size() + borders * 2; - Point2 dock_screen_pos = p_dock->get_screen_position(); - - int dock_index = p_dock->get_index() - 1; - dock_slot[p_slot_index]->remove_child(p_dock); - - WindowWrapper *wrapper = memnew(WindowWrapper); - wrapper->set_window_title(vformat(TTR("%s - Godot Engine"), p_dock->get_name())); - wrapper->set_margins_enabled(true); - - EditorNode::get_singleton()->get_gui_base()->add_child(wrapper); - - wrapper->set_wrapped_control(p_dock); - wrapper->set_meta("dock_slot", p_slot_index); - wrapper->set_meta("dock_index", dock_index); - wrapper->set_meta("dock_name", p_dock->get_name().operator String()); - p_dock->show(); - - wrapper->connect("window_close_requested", callable_mp(this, &EditorDockManager::_dock_floating_close_request).bind(wrapper)); - - dock_select_popup->hide(); - - if (p_show_window) { - wrapper->restore_window(Rect2i(dock_screen_pos, dock_size), EditorNode::get_singleton()->get_gui_base()->get_window()->get_current_screen()); + Node *parent = p_dock->get_parent(); + if (parent == p_target) { + if (p_tab_index >= 0 && parent) { + // Only change the tab index. + _move_dock_tab_index(p_dock, p_tab_index, p_set_current); + } + return; } - update_dock_slots_visibility(true); - - floating_docks.push_back(wrapper); - - _edit_current(); -} - -void EditorDockManager::_restore_floating_dock(const Dictionary &p_dock_dump, Control *p_dock, int p_slot_index) { - WindowWrapper *wrapper = Object::cast_to<WindowWrapper>(p_dock); - if (!wrapper) { - _dock_make_float(p_dock, p_slot_index, false); - wrapper = floating_docks[floating_docks.size() - 1]; + // Remove dock from its existing parent. + if (parent) { + if (all_docks[p_dock].dock_window) { + _close_window(all_docks[p_dock].dock_window); + } else if (all_docks[p_dock].at_bottom) { + _dock_remove_from_bottom(p_dock); + } else { + all_docks[p_dock].previous_at_bottom = false; + TabContainer *parent_tabs = Object::cast_to<TabContainer>(parent); + if (parent_tabs) { + all_docks[p_dock].previous_tab_index = parent_tabs->get_tab_idx_from_control(p_dock); + } + parent->set_block_signals(true); + parent->remove_child(p_dock); + parent->set_block_signals(false); + if (parent_tabs) { + _dock_container_update_visibility(parent_tabs); + } + } } - wrapper->restore_window_from_saved_position( - p_dock_dump.get("window_rect", Rect2i()), - p_dock_dump.get("window_screen", -1), - p_dock_dump.get("window_screen_rect", Rect2i())); + // Add dock to its new parent, at the given tab index. + if (!p_target) { + return; + } + p_target->set_block_signals(true); + p_target->add_child(p_dock); + p_target->set_block_signals(false); + TabContainer *dock_tab_container = Object::cast_to<TabContainer>(p_target); + if (dock_tab_container) { + dock_tab_container->set_tab_title(dock_tab_container->get_tab_idx_from_control(p_dock), all_docks[p_dock].title); + if (p_tab_index >= 0) { + _move_dock_tab_index(p_dock, p_tab_index, p_set_current); + } + _dock_container_update_visibility(dock_tab_container); + } } void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) const { + // Save docks by dock slot. for (int i = 0; i < DOCK_SLOT_MAX; i++) { String names; for (int j = 0; j < dock_slot[i]->get_tab_count(); j++) { @@ -484,23 +380,28 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str p_layout->set_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx", selected_tab_idx); } } + if (p_layout->has_section_key(p_section, "dock_0")) { + // Clear the keys where the dock has no slot so it is overridden. + p_layout->erase_section_key(p_section, "dock_0"); + } + // Save docks in windows. Dictionary floating_docks_dump; - - for (WindowWrapper *wrapper : floating_docks) { + for (WindowWrapper *wrapper : dock_windows) { Control *dock = wrapper->get_wrapped_control(); - Dictionary dock_dump; - dock_dump["window_rect"] = wrapper->get_window_rect(); + Dictionary window_dump; + window_dump["window_rect"] = wrapper->get_window_rect(); int screen = wrapper->get_window_screen(); - dock_dump["window_screen"] = wrapper->get_window_screen(); - dock_dump["window_screen_rect"] = DisplayServer::get_singleton()->screen_get_usable_rect(screen); + window_dump["window_screen"] = wrapper->get_window_screen(); + window_dump["window_screen_rect"] = DisplayServer::get_singleton()->screen_get_usable_rect(screen); String name = dock->get_name(); - floating_docks_dump[name] = dock_dump; + floating_docks_dump[name] = window_dump; - int dock_slot_id = wrapper->get_meta("dock_slot"); + // Append to regular dock section so we know where to restore it to. + int dock_slot_id = all_docks[dock].dock_slot_index; String config_key = "dock_" + itos(dock_slot_id + 1); String names = p_layout->get_value(p_section, config_key, ""); @@ -511,17 +412,39 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str } p_layout->set_value(p_section, config_key, names); } - p_layout->set_value(p_section, "dock_floating", floating_docks_dump); + // Save closed and bottom docks. Array bottom_docks_dump; + Array closed_docks_dump; + for (const KeyValue<Control *, DockInfo> &d : all_docks) { + if (!d.value.at_bottom && d.value.open && (!d.value.previous_at_bottom || !d.value.dock_window)) { + continue; + } + // Use the name of the Control since it isn't translated. + String name = d.key->get_name(); + if (d.value.at_bottom || (d.value.previous_at_bottom && d.value.dock_window)) { + bottom_docks_dump.push_back(name); + } + if (!d.value.open) { + closed_docks_dump.push_back(name); + } - for (Control *bdock : bottom_docks) { - bottom_docks_dump.push_back(bdock->get_name()); - } + int dock_slot_id = all_docks[d.key].dock_slot_index; + String config_key = "dock_" + itos(dock_slot_id + 1); + String names = p_layout->get_value(p_section, config_key, ""); + if (names.is_empty()) { + names = name; + } else { + names += "," + name; + } + p_layout->set_value(p_section, config_key, names); + } p_layout->set_value(p_section, "dock_bottom", bottom_docks_dump); + p_layout->set_value(p_section, "dock_closed", closed_docks_dump); + // Save SplitContainer offsets. for (int i = 0; i < vsplits.size(); i++) { if (vsplits[i]->is_visible_in_tree()) { p_layout->set_value(p_section, "dock_split_" + itos(i + 1), vsplits[i]->get_split_offset()); @@ -537,10 +460,19 @@ void EditorDockManager::save_docks_to_config(Ref<ConfigFile> p_layout, const Str void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const String &p_section) { Dictionary floating_docks_dump = p_layout->get_value(p_section, "dock_floating", Dictionary()); + Array dock_bottom = p_layout->get_value(p_section, "dock_bottom", Array()); + Array closed_docks = p_layout->get_value(p_section, "dock_closed", Array()); bool restore_window_on_load = EDITOR_GET("interface/multi_window/restore_windows_on_load"); - for (int i = 0; i < DOCK_SLOT_MAX; i++) { + // Store the docks by name for easy lookup. + HashMap<String, Control *> dock_map; + for (const KeyValue<Control *, DockInfo> &dock : all_docks) { + dock_map[dock.key->get_name()] = dock.key; + } + + // Load docks by slot. Index -1 is for docks that have no slot. + for (int i = -1; i < DOCK_SLOT_MAX; i++) { if (!p_layout->has_section_key(p_section, "dock_" + itos(i + 1))) { continue; } @@ -550,135 +482,57 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S for (int j = names.size() - 1; j >= 0; j--) { String name = names[j]; - // FIXME: Find it, in a horribly inefficient way. - int atidx = -1; - int bottom_idx = -1; - Control *node = nullptr; - for (int k = 0; k < DOCK_SLOT_MAX; k++) { - if (!dock_slot[k]->has_node(name)) { - continue; - } - node = Object::cast_to<Control>(dock_slot[k]->get_node(name)); - if (!node) { - continue; - } - atidx = k; - break; - } - - if (atidx == -1) { - // Try floating docks. - for (WindowWrapper *wrapper : floating_docks) { - if (wrapper->get_meta("dock_name") == name) { - if (restore_window_on_load && floating_docks_dump.has(name)) { - _restore_floating_dock(floating_docks_dump[name], wrapper, i); - } else { - atidx = wrapper->get_meta("dock_slot"); - node = wrapper->get_wrapped_control(); - wrapper->set_window_enabled(false); - } - break; - } - } - } - - if (atidx == -1) { - // Try bottom docks. - for (Control *bdock : bottom_docks) { - if (bdock->get_name() == name) { - node = bdock; - bottom_idx = bottom_docks.find(node); - break; - } - } + if (!dock_map.has(name)) { + continue; } + Control *dock = dock_map[name]; - if (!node) { - // Well, it's not anywhere. + if (!all_docks[dock].enabled) { + // Don't open disabled docks. continue; } - - if (atidx == i) { - dock_slot[i]->move_child(node, 0); - } else if (atidx != -1) { - dock_slot[i]->set_block_signals(true); - dock_slot[atidx]->set_block_signals(true); - dock_slot[i]->move_tab_from_tab_container(dock_slot[atidx], dock_slot[atidx]->get_tab_idx_from_control(node), 0); - dock_slot[i]->set_block_signals(false); - dock_slot[atidx]->set_block_signals(false); - } else if (bottom_idx != -1) { - bottom_docks.erase(node); - EditorNode::get_bottom_panel()->remove_item(node); - dock_slot[i]->add_child(node); - node->call("_set_dock_horizontal", false); + if (restore_window_on_load && floating_docks_dump.has(name)) { + all_docks[dock].previous_at_bottom = dock_bottom.has(name); + _restore_dock_to_saved_window(dock, floating_docks_dump[name]); + } else if (dock_bottom.has(name)) { + _dock_move_to_bottom(dock); + } else if (i >= 0) { + _move_dock(dock, dock_slot[i], 0); } - WindowWrapper *wrapper = Object::cast_to<WindowWrapper>(node); - if (restore_window_on_load && floating_docks_dump.has(name)) { - if (!dock_slot[i]->is_tab_hidden(dock_slot[i]->get_tab_idx_from_control(node))) { - _restore_floating_dock(floating_docks_dump[name], node, i); - } - } else if (wrapper) { - wrapper->set_window_enabled(false); + if (closed_docks.has(name)) { + _move_dock(dock, closed_dock_parent); + all_docks[dock].open = false; + dock->hide(); + } else { + // Make sure it is open. + all_docks[dock].open = true; + dock->show(); } + + all_docks[dock].dock_slot_index = i; + all_docks[dock].previous_tab_index = i >= 0 ? j : 0; } + } - if (!p_layout->has_section_key(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx")) { + // Set the selected tabs. + for (int i = 0; i < DOCK_SLOT_MAX; i++) { + if (dock_slot[i]->get_tab_count() == 0 || !p_layout->has_section_key(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx")) { continue; } - int selected_tab_idx = p_layout->get_value(p_section, "dock_" + itos(i + 1) + "_selected_tab_idx"); if (selected_tab_idx >= 0 && selected_tab_idx < dock_slot[i]->get_tab_count()) { - callable_mp(dock_slot[i], &TabContainer::set_current_tab).call_deferred(selected_tab_idx); - } - } - - Array dock_bottom = p_layout->get_value(p_section, "dock_bottom", Array()); - for (int i = 0; i < dock_bottom.size(); i++) { - const String &name = dock_bottom[i]; - // FIXME: Find it, in a horribly inefficient way. - int atidx = -1; - Control *node = nullptr; - for (int k = 0; k < DOCK_SLOT_MAX; k++) { - if (!dock_slot[k]->has_node(name)) { - continue; - } - node = Object::cast_to<Control>(dock_slot[k]->get_node(name)); - if (!node) { - continue; - } - atidx = k; - break; - } - - if (atidx == -1) { - // Try floating docks. - for (WindowWrapper *wrapper : floating_docks) { - if (wrapper->get_meta("dock_name") == name) { - atidx = wrapper->get_meta("dock_slot"); - node = wrapper->get_wrapped_control(); - wrapper->set_window_enabled(false); - break; - } - } - } - - if (node) { - dock_slot[atidx]->remove_child(node); - - node->call("_set_dock_horizontal", true); - - bottom_docks.push_back(node); - // Force docks moved to the bottom to appear first in the list, and give them their associated shortcut to toggle their bottom panel. - EditorNode::get_bottom_panel()->add_item(node->get_name(), node, node->get_meta(META_TOGGLE_SHORTCUT), true); + dock_slot[i]->set_block_signals(true); + dock_slot[i]->set_current_tab(selected_tab_idx); + dock_slot[i]->set_block_signals(false); } } + // Load SplitContainer offsets. for (int i = 0; i < vsplits.size(); i++) { if (!p_layout->has_section_key(p_section, "dock_split_" + itos(i + 1))) { continue; } - int ofs = p_layout->get_value(p_section, "dock_split_" + itos(i + 1)); vsplits[i]->set_split_offset(ofs); } @@ -691,87 +545,166 @@ void EditorDockManager::load_docks_from_config(Ref<ConfigFile> p_layout, const S hsplits[i]->set_split_offset(ofs); } - update_dock_slots_visibility(false); - FileSystemDock::get_singleton()->load_layout_from_config(p_layout, p_section); + + _update_docks_menu(); } -void EditorDockManager::update_dock_slots_visibility(bool p_keep_selected_tabs) { - if (!docks_visible) { - for (int i = 0; i < DOCK_SLOT_MAX; i++) { - dock_slot[i]->hide(); - } - } else { - for (int i = 0; i < DOCK_SLOT_MAX; i++) { - int first_tab_visible = -1; - for (int j = 0; j < dock_slot[i]->get_tab_count(); j++) { - if (!dock_slot[i]->is_tab_hidden(j)) { - first_tab_visible = j; - break; - } - } - if (first_tab_visible >= 0) { - dock_slot[i]->show(); - if (p_keep_selected_tabs) { - int current_tab = dock_slot[i]->get_current_tab(); - if (dock_slot[i]->is_tab_hidden(current_tab)) { - dock_slot[i]->set_block_signals(true); - dock_slot[i]->select_next_available(); - dock_slot[i]->set_block_signals(false); - } - } else { - dock_slot[i]->set_block_signals(true); - dock_slot[i]->set_current_tab(first_tab_visible); - dock_slot[i]->set_block_signals(false); - } - } else { - dock_slot[i]->hide(); - } - } +void EditorDockManager::bottom_dock_show_placement_popup(const Rect2i &p_position, Control *p_dock) { + ERR_FAIL_COND(!all_docks.has(p_dock)); + + dock_context_popup->set_dock(p_dock); + + Vector2 popup_pos = p_position.position; + popup_pos.y += p_position.size.height; + + if (!EditorNode::get_singleton()->get_gui_base()->is_layout_rtl()) { + popup_pos.x -= dock_context_popup->get_size().width; + popup_pos.x += p_position.size.width; } + dock_context_popup->set_position(popup_pos); + dock_context_popup->popup(); } -void EditorDockManager::close_all_floating_docks() { - for (WindowWrapper *wrapper : floating_docks) { - wrapper->set_window_enabled(false); +void EditorDockManager::set_dock_enabled(Control *p_dock, bool p_enabled) { + ERR_FAIL_NULL(p_dock); + ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot set enabled unknown dock '%s'.", p_dock->get_name())); + + if (all_docks[p_dock].enabled == p_enabled) { + return; + } + + all_docks[p_dock].enabled = p_enabled; + if (p_enabled) { + open_dock(p_dock, false); + } else { + close_dock(p_dock); } } -void EditorDockManager::add_control_to_dock(DockSlot p_slot, Control *p_control, const String &p_name, const Ref<Shortcut> &p_shortcut) { - ERR_FAIL_INDEX(p_slot, DOCK_SLOT_MAX); - p_control->set_meta(META_TOGGLE_SHORTCUT, p_shortcut); - dock_slot[p_slot]->add_child(p_control); - if (!p_name.is_empty()) { - dock_slot[p_slot]->set_tab_title(dock_slot[p_slot]->get_tab_idx_from_control(p_control), p_name); +void EditorDockManager::close_dock(Control *p_dock) { + ERR_FAIL_NULL(p_dock); + ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot close unknown dock '%s'.", p_dock->get_name())); + + if (!all_docks[p_dock].open) { + return; } + + _move_dock(p_dock, closed_dock_parent); + + all_docks[p_dock].open = false; + p_dock->hide(); + + _update_layout(); } -void EditorDockManager::remove_control_from_dock(Control *p_control) { - // If the dock is floating, close it first. - for (WindowWrapper *wrapper : floating_docks) { - if (p_control == wrapper->get_wrapped_control()) { - wrapper->set_window_enabled(false); - break; - } +void EditorDockManager::open_dock(Control *p_dock, bool p_set_current) { + ERR_FAIL_NULL(p_dock); + ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot open unknown dock '%s'.", p_dock->get_name())); + + if (all_docks[p_dock].open) { + return; } - Control *dock = nullptr; - for (int i = 0; i < DOCK_SLOT_MAX; i++) { - if (p_control->get_parent() == dock_slot[i]) { - dock = dock_slot[i]; - break; + all_docks[p_dock].open = true; + p_dock->show(); + + // Open dock to its previous location. + if (all_docks[p_dock].previous_at_bottom) { + _dock_move_to_bottom(p_dock); + } else if (all_docks[p_dock].dock_slot_index != DOCK_SLOT_NONE) { + TabContainer *slot = dock_slot[all_docks[p_dock].dock_slot_index]; + int tab_index = all_docks[p_dock].previous_tab_index; + if (tab_index < 0) { + tab_index = slot->get_tab_count(); } + _move_dock(p_dock, slot, tab_index, p_set_current); + } else { + _open_dock_in_window(p_dock, true, true); + return; + } + + _update_layout(); +} + +TabContainer *EditorDockManager::get_dock_tab_container(Control *p_dock) const { + return Object::cast_to<TabContainer>(p_dock->get_parent()); +} + +void EditorDockManager::focus_dock(Control *p_dock) { + ERR_FAIL_NULL(p_dock); + ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot focus unknown dock '%s'.", p_dock->get_name())); + + if (!all_docks[p_dock].enabled) { + return; + } + + if (!all_docks[p_dock].open) { + open_dock(p_dock); + } + + if (all_docks[p_dock].dock_window) { + p_dock->get_window()->grab_focus(); + return; + } + + if (all_docks[p_dock].at_bottom) { + EditorNode::get_bottom_panel()->make_item_visible(p_dock); + return; } - ERR_FAIL_NULL_MSG(dock, "Control is not in a dock."); + if (!docks_visible) { + return; + } + + TabContainer *tab_container = get_dock_tab_container(p_dock); + if (!tab_container) { + return; + } + int tab_index = tab_container->get_tab_idx_from_control(p_dock); + tab_container->get_tab_bar()->grab_focus(); + tab_container->set_current_tab(tab_index); +} + +void EditorDockManager::add_dock(Control *p_dock, const String &p_title, DockSlot p_slot, const Ref<Shortcut> &p_shortcut) { + ERR_FAIL_NULL(p_dock); + ERR_FAIL_COND_MSG(all_docks.has(p_dock), vformat("Cannot add dock '%s', already added.", p_dock->get_name())); + + DockInfo dock_info; + dock_info.title = !p_title.is_empty() ? p_title : String(p_dock->get_name()); + dock_info.dock_slot_index = p_slot; + dock_info.shortcut = p_shortcut; + all_docks[p_dock] = dock_info; + + if (p_slot != DOCK_SLOT_NONE) { + ERR_FAIL_INDEX(p_slot, DOCK_SLOT_MAX); + open_dock(p_dock, false); + } else { + closed_dock_parent->add_child(p_dock); + p_dock->hide(); + _update_layout(); + } +} + +void EditorDockManager::remove_dock(Control *p_dock) { + ERR_FAIL_NULL(p_dock); + ERR_FAIL_COND_MSG(!all_docks.has(p_dock), vformat("Cannot remove unknown dock '%s'.", p_dock->get_name())); + + _move_dock(p_dock, nullptr); - dock->remove_child(p_control); - update_dock_slots_visibility(); + all_docks.erase(p_dock); + _update_layout(); } void EditorDockManager::set_docks_visible(bool p_show) { + if (docks_visible == p_show) { + return; + } docks_visible = p_show; - update_dock_slots_visibility(true); + for (int i = 0; i < DOCK_SLOT_MAX; i++) { + dock_slot[i]->set_visible(docks_visible && dock_slot[i]->get_tab_count() > 0); + } + _update_layout(); } bool EditorDockManager::are_docks_visible() const { @@ -796,80 +729,329 @@ void EditorDockManager::register_dock_slot(DockSlot p_dock_slot, TabContainer *p p_tab_container->set_custom_minimum_size(Size2(170, 0) * EDSCALE); p_tab_container->set_v_size_flags(Control::SIZE_EXPAND_FILL); - p_tab_container->set_popup(dock_select_popup); - p_tab_container->connect("pre_popup_pressed", callable_mp(this, &EditorDockManager::_dock_pre_popup).bind(p_dock_slot)); + p_tab_container->set_popup(dock_context_popup); + p_tab_container->connect("pre_popup_pressed", callable_mp(dock_context_popup, &DockContextPopup::select_current_dock_in_dock_slot).bind(p_dock_slot)); p_tab_container->set_drag_to_rearrange_enabled(true); p_tab_container->set_tabs_rearrange_group(1); - p_tab_container->connect("tab_changed", callable_mp(this, &EditorDockManager::_dock_tab_changed)); + p_tab_container->connect("tab_changed", callable_mp(this, &EditorDockManager::_update_layout).unbind(1)); + p_tab_container->connect("active_tab_rearranged", callable_mp(this, &EditorDockManager::_update_layout).unbind(1)); + p_tab_container->connect("child_order_changed", callable_mp(this, &EditorDockManager::_dock_container_update_visibility).bind(p_tab_container)); p_tab_container->set_use_hidden_tabs_for_min_size(true); + p_tab_container->get_tab_bar()->connect("gui_input", callable_mp(this, &EditorDockManager::_dock_container_gui_input).bind(p_tab_container)); + p_tab_container->hide(); } int EditorDockManager::get_vsplit_count() const { return vsplits.size(); } -void EditorDockManager::_bind_methods() { - ADD_SIGNAL(MethodInfo("layout_changed")); +PopupMenu *EditorDockManager::get_docks_menu() { + return docks_menu; } EditorDockManager::EditorDockManager() { singleton = this; - dock_select_popup = memnew(PopupPanel); - EditorNode::get_singleton()->get_gui_base()->add_child(dock_select_popup); - VBoxContainer *dock_vb = memnew(VBoxContainer); - dock_select_popup->add_child(dock_vb); - dock_select_popup->connect("theme_changed", callable_mp(this, &EditorDockManager::_dock_select_popup_theme_changed)); - - HBoxContainer *dock_hb = memnew(HBoxContainer); - dock_tab_move_left = memnew(Button); - dock_tab_move_left->set_flat(true); - dock_tab_move_left->set_focus_mode(Control::FOCUS_NONE); - dock_tab_move_left->connect("pressed", callable_mp(this, &EditorDockManager::_dock_move_left)); - dock_hb->add_child(dock_tab_move_left); - - Label *dock_label = memnew(Label); - dock_label->set_text(TTR("Dock Position")); - dock_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); - dock_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - dock_hb->add_child(dock_label); - - dock_tab_move_right = memnew(Button); - dock_tab_move_right->set_flat(true); - dock_tab_move_right->set_focus_mode(Control::FOCUS_NONE); - dock_tab_move_right->connect("pressed", callable_mp(this, &EditorDockManager::_dock_move_right)); - - dock_hb->add_child(dock_tab_move_right); - dock_vb->add_child(dock_hb); + closed_dock_parent = EditorNode::get_singleton()->get_gui_base(); + + dock_context_popup = memnew(DockContextPopup); + EditorNode::get_singleton()->get_gui_base()->add_child(dock_context_popup); + + docks_menu = memnew(PopupMenu); + docks_menu->connect("id_pressed", callable_mp(this, &EditorDockManager::_docks_menu_option)); + EditorNode::get_singleton()->get_gui_base()->connect("theme_changed", callable_mp(this, &EditorDockManager::_update_docks_menu)); +} + +void DockContextPopup::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_THEME_CHANGED: { + if (make_float_button) { + make_float_button->set_icon(get_editor_theme_icon(SNAME("MakeFloating"))); + } + if (is_layout_rtl()) { + tab_move_left_button->set_icon(get_editor_theme_icon(SNAME("Forward"))); + tab_move_right_button->set_icon(get_editor_theme_icon(SNAME("Back"))); + tab_move_left_button->set_tooltip_text(TTR("Move this dock right one tab.")); + tab_move_right_button->set_tooltip_text(TTR("Move this dock left one tab.")); + } else { + tab_move_left_button->set_icon(get_editor_theme_icon(SNAME("Back"))); + tab_move_right_button->set_icon(get_editor_theme_icon(SNAME("Forward"))); + tab_move_left_button->set_tooltip_text(TTR("Move this dock left one tab.")); + tab_move_right_button->set_tooltip_text(TTR("Move this dock right one tab.")); + } + dock_to_bottom_button->set_icon(get_editor_theme_icon(SNAME("ControlAlignBottomWide"))); + close_button->set_icon(get_editor_theme_icon(SNAME("Close"))); + } break; + } +} + +void DockContextPopup::_tab_move_left() { + TabContainer *tab_container = dock_manager->get_dock_tab_container(context_dock); + if (!tab_container) { + return; + } + int new_index = tab_container->get_tab_idx_from_control(context_dock) - 1; + dock_manager->_move_dock(context_dock, tab_container, new_index); + dock_manager->_update_layout(); + dock_select->queue_redraw(); +} + +void DockContextPopup::_tab_move_right() { + TabContainer *tab_container = dock_manager->get_dock_tab_container(context_dock); + if (!tab_container) { + return; + } + int new_index = tab_container->get_tab_idx_from_control(context_dock) + 1; + dock_manager->_move_dock(context_dock, tab_container, new_index); + dock_manager->_update_layout(); + dock_select->queue_redraw(); +} + +void DockContextPopup::_close_dock() { + hide(); + dock_manager->close_dock(context_dock); +} + +void DockContextPopup::_float_dock() { + hide(); + dock_manager->_open_dock_in_window(context_dock); +} + +void DockContextPopup::_move_dock_to_bottom() { + hide(); + dock_manager->_dock_move_to_bottom(context_dock); + dock_manager->_update_layout(); +} + +void DockContextPopup::_dock_select_input(const Ref<InputEvent> &p_input) { + Ref<InputEventMouse> me = p_input; + + if (me.is_valid()) { + Vector2 point = me->get_position(); + + int over_dock_slot = -1; + for (int i = 0; i < EditorDockManager::DOCK_SLOT_MAX; i++) { + if (dock_select_rects[i].has_point(point)) { + over_dock_slot = i; + break; + } + } + + if (over_dock_slot != dock_select_rect_over_idx) { + dock_select->queue_redraw(); + dock_select_rect_over_idx = over_dock_slot; + } + + if (over_dock_slot == -1) { + return; + } + + Ref<InputEventMouseButton> mb = me; + TabContainer *target_tab_container = dock_manager->dock_slot[over_dock_slot]; + + if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) { + if (dock_manager->get_dock_tab_container(context_dock) != target_tab_container) { + dock_manager->_move_dock(context_dock, target_tab_container, target_tab_container->get_tab_count()); + dock_manager->all_docks[context_dock].dock_slot_index = over_dock_slot; + dock_manager->_update_layout(); + hide(); + } + } + } +} + +void DockContextPopup::_dock_select_mouse_exited() { + dock_select_rect_over_idx = -1; + dock_select->queue_redraw(); +} + +void DockContextPopup::_dock_select_draw() { + Color used_dock_color = Color(0.6, 0.6, 0.6, 0.8); + Color hovered_dock_color = Color(0.8, 0.8, 0.8, 0.8); + Color tab_selected_color = dock_select->get_theme_color(SNAME("mono_color"), EditorStringName(Editor)); + Color tab_unselected_color = used_dock_color; + Color unused_dock_color = used_dock_color; + unused_dock_color.a = 0.4; + Color unusable_dock_color = unused_dock_color; + unusable_dock_color.a = 0.1; + + // Update sizes. + Size2 dock_size = dock_select->get_size(); + dock_size.x /= 6.0; + dock_size.y /= 2.0; + + Size2 center_panel_size = dock_size * 2.0; + Rect2 center_panel_rect(center_panel_size.x, 0, center_panel_size.x, center_panel_size.y); + + if (dock_select->is_layout_rtl()) { + dock_select_rects[EditorDockManager::DOCK_SLOT_RIGHT_UR] = Rect2(Point2(), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_RIGHT_BR] = Rect2(Point2(0, dock_size.y), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_RIGHT_UL] = Rect2(Point2(dock_size.x, 0), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_RIGHT_BL] = Rect2(dock_size, dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_LEFT_UR] = Rect2(Point2(dock_size.x * 4, 0), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_LEFT_BR] = Rect2(Point2(dock_size.x * 4, dock_size.y), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_LEFT_UL] = Rect2(Point2(dock_size.x * 5, 0), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_LEFT_BL] = Rect2(Point2(dock_size.x * 5, dock_size.y), dock_size); + } else { + dock_select_rects[EditorDockManager::DOCK_SLOT_LEFT_UL] = Rect2(Point2(), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_LEFT_BL] = Rect2(Point2(0, dock_size.y), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_LEFT_UR] = Rect2(Point2(dock_size.x, 0), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_LEFT_BR] = Rect2(dock_size, dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_RIGHT_UL] = Rect2(Point2(dock_size.x * 4, 0), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_RIGHT_BL] = Rect2(Point2(dock_size.x * 4, dock_size.y), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_RIGHT_UR] = Rect2(Point2(dock_size.x * 5, 0), dock_size); + dock_select_rects[EditorDockManager::DOCK_SLOT_RIGHT_BR] = Rect2(Point2(dock_size.x * 5, dock_size.y), dock_size); + } + + int max_tabs = 3; + int rtl_dir = dock_select->is_layout_rtl() ? -1 : 1; + real_t tab_height = 3.0 * EDSCALE; + real_t tab_spacing = 1.0 * EDSCALE; + real_t dock_spacing = 2.0 * EDSCALE; + real_t dock_top_spacing = tab_height + dock_spacing; + + TabContainer *context_tab_container = dock_manager->get_dock_tab_container(context_dock); + int context_tab_index = -1; + if (context_tab_container && context_tab_container->get_tab_count() > 0) { + context_tab_index = context_tab_container->get_tab_idx_from_control(context_dock); + } + + // Draw center panel. + Rect2 center_panel_draw_rect = center_panel_rect.grow_individual(-dock_spacing, -dock_top_spacing, -dock_spacing, -dock_spacing); + dock_select->draw_rect(center_panel_draw_rect, unusable_dock_color); + + // Draw all dock slots. + for (int i = 0; i < EditorDockManager::DOCK_SLOT_MAX; i++) { + Rect2 dock_slot_draw_rect = dock_select_rects[i].grow_individual(-dock_spacing, -dock_top_spacing, -dock_spacing, -dock_spacing); + real_t tab_width = Math::round(dock_slot_draw_rect.size.width / max_tabs); + Rect2 tab_draw_rect = Rect2(dock_slot_draw_rect.position.x, dock_select_rects[i].position.y, tab_width - tab_spacing, tab_height); + if (dock_select->is_layout_rtl()) { + tab_draw_rect.position.x += dock_slot_draw_rect.size.x - tab_draw_rect.size.x; + } + bool is_context_dock = context_tab_container == dock_manager->dock_slot[i]; + int tabs_to_draw = MIN(max_tabs, dock_manager->dock_slot[i]->get_tab_count()); + + if (i == dock_select_rect_over_idx) { + dock_select->draw_rect(dock_slot_draw_rect, hovered_dock_color); + } else if (tabs_to_draw == 0) { + dock_select->draw_rect(dock_slot_draw_rect, unused_dock_color); + } else { + dock_select->draw_rect(dock_slot_draw_rect, used_dock_color); + } + + // Draw tabs above each used dock slot. + for (int j = 0; j < tabs_to_draw; j++) { + Color tab_color = tab_unselected_color; + if (is_context_dock && context_tab_index == j) { + tab_color = tab_selected_color; + } + Rect2 tabj_draw_rect = tab_draw_rect; + tabj_draw_rect.position.x += tab_width * j * rtl_dir; + dock_select->draw_rect(tabj_draw_rect, tab_color); + } + } +} + +void DockContextPopup::_update_buttons() { + TabContainer *context_tab_container = dock_manager->get_dock_tab_container(context_dock); + bool dock_at_bottom = dock_manager->_is_dock_at_bottom(context_dock); + + // Update tab move buttons. + tab_move_left_button->set_disabled(true); + tab_move_right_button->set_disabled(true); + if (!dock_at_bottom && context_tab_container && context_tab_container->get_tab_count() > 0) { + int context_tab_index = context_tab_container->get_tab_idx_from_control(context_dock); + tab_move_left_button->set_disabled(context_tab_index == 0); + tab_move_right_button->set_disabled(context_tab_index >= context_tab_container->get_tab_count() - 1); + } + + dock_to_bottom_button->set_visible(!dock_at_bottom && bool(context_dock->call("_can_dock_horizontal"))); + reset_size(); +} + +void DockContextPopup::select_current_dock_in_dock_slot(int p_dock_slot) { + context_dock = dock_manager->dock_slot[p_dock_slot]->get_current_tab_control(); + _update_buttons(); +} + +void DockContextPopup::set_dock(Control *p_dock) { + context_dock = p_dock; + _update_buttons(); +} + +Control *DockContextPopup::get_dock() const { + return context_dock; +} + +void DockContextPopup::docks_updated() { + if (!is_visible()) { + return; + } + _update_buttons(); +} + +DockContextPopup::DockContextPopup() { + dock_manager = EditorDockManager::get_singleton(); + + dock_select_popup_vb = memnew(VBoxContainer); + add_child(dock_select_popup_vb); + + HBoxContainer *header_hb = memnew(HBoxContainer); + tab_move_left_button = memnew(Button); + tab_move_left_button->set_flat(true); + tab_move_left_button->set_focus_mode(Control::FOCUS_NONE); + tab_move_left_button->connect("pressed", callable_mp(this, &DockContextPopup::_tab_move_left)); + header_hb->add_child(tab_move_left_button); + + Label *position_label = memnew(Label); + position_label->set_text(TTR("Dock Position")); + position_label->set_h_size_flags(Control::SIZE_EXPAND_FILL); + position_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + header_hb->add_child(position_label); + + tab_move_right_button = memnew(Button); + tab_move_right_button->set_flat(true); + tab_move_right_button->set_focus_mode(Control::FOCUS_NONE); + tab_move_right_button->connect("pressed", callable_mp(this, &DockContextPopup::_tab_move_right)); + + header_hb->add_child(tab_move_right_button); + dock_select_popup_vb->add_child(header_hb); dock_select = memnew(Control); dock_select->set_custom_minimum_size(Size2(128, 64) * EDSCALE); - dock_select->connect("gui_input", callable_mp(this, &EditorDockManager::_dock_select_input)); - dock_select->connect("draw", callable_mp(this, &EditorDockManager::_dock_select_draw)); - dock_select->connect("mouse_exited", callable_mp(this, &EditorDockManager::_dock_popup_exit)); + dock_select->connect("gui_input", callable_mp(this, &DockContextPopup::_dock_select_input)); + dock_select->connect("draw", callable_mp(this, &DockContextPopup::_dock_select_draw)); + dock_select->connect("mouse_exited", callable_mp(this, &DockContextPopup::_dock_select_mouse_exited)); dock_select->set_v_size_flags(Control::SIZE_EXPAND_FILL); - dock_vb->add_child(dock_select); + dock_select_popup_vb->add_child(dock_select); - dock_float = memnew(Button); - dock_float->set_text(TTR("Make Floating")); + make_float_button = memnew(Button); + make_float_button->set_text(TTR("Make Floating")); if (!EditorNode::get_singleton()->is_multi_window_enabled()) { - dock_float->set_disabled(true); - dock_float->set_tooltip_text(EditorNode::get_singleton()->get_multiwindow_support_tooltip_text()); + make_float_button->set_disabled(true); + make_float_button->set_tooltip_text(EditorNode::get_singleton()->get_multiwindow_support_tooltip_text()); } else { - dock_float->set_tooltip_text(TTR("Make this dock floating.")); - } - dock_float->set_focus_mode(Control::FOCUS_NONE); - dock_float->set_h_size_flags(Control::SIZE_EXPAND_FILL); - dock_float->connect("pressed", callable_mp(this, &EditorDockManager::_dock_make_selected_float)); - dock_vb->add_child(dock_float); - - dock_to_bottom = memnew(Button); - dock_to_bottom->set_text(TTR("Move to Bottom")); - dock_to_bottom->set_focus_mode(Control::FOCUS_NONE); - dock_to_bottom->set_h_size_flags(Control::SIZE_EXPAND_FILL); - dock_to_bottom->connect("pressed", callable_mp(this, &EditorDockManager::_dock_move_selected_to_bottom)); - dock_to_bottom->hide(); - dock_vb->add_child(dock_to_bottom); - - dock_select_popup->reset_size(); + make_float_button->set_tooltip_text(TTR("Make this dock floating.")); + } + make_float_button->set_focus_mode(Control::FOCUS_NONE); + make_float_button->set_h_size_flags(Control::SIZE_EXPAND_FILL); + make_float_button->connect("pressed", callable_mp(this, &DockContextPopup::_float_dock)); + dock_select_popup_vb->add_child(make_float_button); + + dock_to_bottom_button = memnew(Button); + dock_to_bottom_button->set_text(TTR("Move to Bottom")); + dock_to_bottom_button->set_tooltip_text(TTR("Move this dock to the bottom panel.")); + dock_to_bottom_button->set_focus_mode(Control::FOCUS_NONE); + dock_to_bottom_button->set_h_size_flags(Control::SIZE_EXPAND_FILL); + dock_to_bottom_button->connect("pressed", callable_mp(this, &DockContextPopup::_move_dock_to_bottom)); + dock_to_bottom_button->hide(); + dock_select_popup_vb->add_child(dock_to_bottom_button); + + close_button = memnew(Button); + close_button->set_text(TTR("Close")); + close_button->set_tooltip_text(TTR("Close this dock.")); + close_button->set_focus_mode(Control::FOCUS_NONE); + close_button->set_h_size_flags(Control::SIZE_EXPAND_FILL); + close_button->connect("pressed", callable_mp(this, &DockContextPopup::_close_dock)); + dock_select_popup_vb->add_child(close_button); } diff --git a/editor/editor_dock_manager.h b/editor/editor_dock_manager.h index 193ccd6541..cbb076c809 100644 --- a/editor/editor_dock_manager.h +++ b/editor/editor_dock_manager.h @@ -31,13 +31,15 @@ #ifndef EDITOR_DOCK_MANAGER_H #define EDITOR_DOCK_MANAGER_H +#include "scene/gui/popup.h" #include "scene/gui/split_container.h" class Button; class ConfigFile; class Control; -class PopupPanel; +class PopupMenu; class TabContainer; +class VBoxContainer; class WindowWrapper; class DockSplitContainer : public SplitContainer { @@ -53,11 +55,14 @@ protected: virtual void remove_child_notify(Node *p_child) override; }; +class DockContextPopup; + class EditorDockManager : public Object { GDCLASS(EditorDockManager, Object); public: enum DockSlot { + DOCK_SLOT_NONE = -1, DOCK_SLOT_LEFT_UL, DOCK_SLOT_LEFT_BL, DOCK_SLOT_LEFT_UR, @@ -70,49 +75,56 @@ public: }; private: + friend class DockContextPopup; + + struct DockInfo { + String title; + bool open = false; + bool enabled = true; + bool at_bottom = false; + int previous_tab_index = -1; + bool previous_at_bottom = false; + WindowWrapper *dock_window = nullptr; + int dock_slot_index = DOCK_SLOT_NONE; + Ref<Shortcut> shortcut; + }; + static EditorDockManager *singleton; // To access splits easily by index. Vector<DockSplitContainer *> vsplits; Vector<DockSplitContainer *> hsplits; - Vector<WindowWrapper *> floating_docks; - Vector<Control *> bottom_docks; + Vector<WindowWrapper *> dock_windows; TabContainer *dock_slot[DOCK_SLOT_MAX]; + HashMap<Control *, DockInfo> all_docks; bool docks_visible = true; - PopupPanel *dock_select_popup = nullptr; - Button *dock_float = nullptr; - Button *dock_to_bottom = nullptr; - Button *dock_tab_move_left = nullptr; - Button *dock_tab_move_right = nullptr; - Control *dock_select = nullptr; - Rect2 dock_select_rect[DOCK_SLOT_MAX]; - int dock_select_rect_over_idx = -1; - int dock_popup_selected_idx = -1; - int dock_bottom_selected_idx = -1; - - void _dock_select_popup_theme_changed(); - void _dock_popup_exit(); - void _dock_pre_popup(int p_dock_slot); - void _dock_move_left(); - void _dock_move_right(); - void _dock_select_input(const Ref<InputEvent> &p_input); - void _dock_select_draw(); + DockContextPopup *dock_context_popup = nullptr; + PopupMenu *docks_menu = nullptr; + Vector<Control *> docks_menu_docks; + Control *closed_dock_parent = nullptr; + void _dock_split_dragged(int p_offset); + void _dock_container_gui_input(const Ref<InputEvent> &p_input, TabContainer *p_dock_container); + void _bottom_dock_button_gui_input(const Ref<InputEvent> &p_input, Control *p_dock, Button *p_bottom_button); + void _dock_container_update_visibility(TabContainer *p_dock_container); + void _update_layout(); - void _dock_tab_changed(int p_tab); - void _edit_current(); + void _update_docks_menu(); + void _docks_menu_option(int p_id); - void _dock_floating_close_request(WindowWrapper *p_wrapper); - void _dock_make_selected_float(); - void _dock_make_float(Control *p_control, int p_slot_index, bool p_show_window = true); - void _restore_floating_dock(const Dictionary &p_dock_dump, Control *p_wrapper, int p_slot_index); + void _window_close_request(WindowWrapper *p_wrapper); + Control *_close_window(WindowWrapper *p_wrapper); + void _open_dock_in_window(Control *p_dock, bool p_show_window = true, bool p_reset_size = false); + void _restore_dock_to_saved_window(Control *p_dock, const Dictionary &p_window_dump); - void _dock_move_selected_to_bottom(); + void _dock_move_to_bottom(Control *p_dock); + void _dock_remove_from_bottom(Control *p_dock); + bool _is_dock_at_bottom(Control *p_dock); -protected: - static void _bind_methods(); + void _move_dock_tab_index(Control *p_dock, int p_tab_index, bool p_set_current); + void _move_dock(Control *p_dock, Control *p_target, int p_tab_index = -1, bool p_set_current = true); public: static EditorDockManager *get_singleton() { return singleton; } @@ -121,22 +133,70 @@ public: void add_hsplit(DockSplitContainer *p_split); void register_dock_slot(DockSlot p_dock_slot, TabContainer *p_tab_container); int get_vsplit_count() const; + PopupMenu *get_docks_menu(); void save_docks_to_config(Ref<ConfigFile> p_layout, const String &p_section) const; void load_docks_from_config(Ref<ConfigFile> p_layout, const String &p_section); - void update_dock_slots_visibility(bool p_keep_selected_tabs = false); - void bottom_dock_show_placement_popup(const Rect2i &p_position, Control *p_dock); + void set_dock_enabled(Control *p_dock, bool p_enabled); + void close_dock(Control *p_dock); + void open_dock(Control *p_dock, bool p_set_current = true); + void focus_dock(Control *p_dock); - void close_all_floating_docks(); + TabContainer *get_dock_tab_container(Control *p_dock) const; + + void bottom_dock_show_placement_popup(const Rect2i &p_position, Control *p_dock); void set_docks_visible(bool p_show); bool are_docks_visible() const; - void add_control_to_dock(DockSlot p_slot, Control *p_control, const String &p_name = "", const Ref<Shortcut> &p_shortcut = nullptr); - void remove_control_from_dock(Control *p_control); + void add_dock(Control *p_dock, const String &p_title = "", DockSlot p_slot = DOCK_SLOT_NONE, const Ref<Shortcut> &p_shortcut = nullptr); + void remove_dock(Control *p_dock); EditorDockManager(); }; +class DockContextPopup : public PopupPanel { + GDCLASS(DockContextPopup, PopupPanel); + + VBoxContainer *dock_select_popup_vb = nullptr; + + Button *make_float_button = nullptr; + Button *tab_move_left_button = nullptr; + Button *tab_move_right_button = nullptr; + Button *close_button = nullptr; + Button *dock_to_bottom_button = nullptr; + + Control *dock_select = nullptr; + Rect2 dock_select_rects[EditorDockManager::DOCK_SLOT_MAX]; + int dock_select_rect_over_idx = -1; + + Control *context_dock = nullptr; + + EditorDockManager *dock_manager = nullptr; + + void _tab_move_left(); + void _tab_move_right(); + void _close_dock(); + void _float_dock(); + void _move_dock_to_bottom(); + + void _dock_select_input(const Ref<InputEvent> &p_input); + void _dock_select_mouse_exited(); + void _dock_select_draw(); + + void _update_buttons(); + +protected: + void _notification(int p_what); + +public: + void select_current_dock_in_dock_slot(int p_dock_slot); + void set_dock(Control *p_dock); + Control *get_dock() const; + void docks_updated(); + + DockContextPopup(); +}; + #endif // EDITOR_DOCK_MANAGER_H diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index c08e99b2a4..541bcd5e02 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -619,8 +619,8 @@ void EditorFeatureProfileManager::_class_list_item_selected() { if (!(E.usage & PROPERTY_USAGE_EDITOR)) { continue; } - const String text = EditorPropertyNameProcessor::get_singleton()->process_name(name, text_style); - const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(name, tooltip_style); + const String text = EditorPropertyNameProcessor::get_singleton()->process_name(name, text_style, name, class_name); + const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(name, tooltip_style, name, class_name); TreeItem *property = property_list->create_item(properties); property->set_cell_mode(0, TreeItem::CELL_MODE_CHECK); @@ -976,6 +976,7 @@ EditorFeatureProfileManager::EditorFeatureProfileManager() { class_list_vbc->set_h_size_flags(Control::SIZE_EXPAND_FILL); class_list = memnew(Tree); + class_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); class_list_vbc->add_margin_child(TTR("Configure Selected Profile:"), class_list, true); class_list->set_hide_root(true); class_list->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index ff42b82435..516b8f3d74 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -50,10 +50,6 @@ EditorFileSystem *EditorFileSystem::singleton = nullptr; //the name is the version, to keep compatibility with different versions of Godot #define CACHE_FILE_NAME "filesystem_cache8" -void EditorFileSystemDirectory::sort_files() { - files.sort_custom<FileInfoSort>(); -} - int EditorFileSystemDirectory::find_file_index(const String &p_file) const { for (int i = 0; i < files.size(); i++) { if (files[i]->file == p_file) { @@ -578,7 +574,7 @@ bool EditorFileSystem::_update_scan_actions() { case ItemAction::ACTION_DIR_ADD: { int idx = 0; for (int i = 0; i < ia.dir->subdirs.size(); i++) { - if (ia.new_dir->name.naturalnocasecmp_to(ia.dir->subdirs[i]->name) < 0) { + if (ia.new_dir->name.filenocasecmp_to(ia.dir->subdirs[i]->name) < 0) { break; } idx++; @@ -600,7 +596,7 @@ bool EditorFileSystem::_update_scan_actions() { case ItemAction::ACTION_FILE_ADD: { int idx = 0; for (int i = 0; i < ia.dir->files.size(); i++) { - if (ia.new_file->file.naturalnocasecmp_to(ia.dir->files[i]->file) < 0) { + if (ia.new_file->file.filenocasecmp_to(ia.dir->files[i]->file) < 0) { break; } idx++; @@ -810,8 +806,8 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc da->list_dir_end(); - dirs.sort_custom<NaturalNoCaseComparator>(); - files.sort_custom<NaturalNoCaseComparator>(); + dirs.sort_custom<FileNoCaseComparator>(); + files.sort_custom<FileNoCaseComparator>(); int total = dirs.size() + files.size(); int idx = 0; @@ -832,7 +828,7 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc int idx2 = 0; for (int i = 0; i < p_dir->subdirs.size(); i++) { - if (efd->name.naturalnocasecmp_to(p_dir->subdirs[i]->name) < 0) { + if (efd->name.filenocasecmp_to(p_dir->subdirs[i]->name) < 0) { break; } idx2++; @@ -1409,7 +1405,7 @@ bool EditorFileSystem::_find_file(const String &p_file, EditorFileSystemDirector int idx2 = 0; for (int j = 0; j < fs->get_subdir_count(); j++) { - if (efsd->name.naturalnocasecmp_to(fs->get_subdir(j)->get_name()) < 0) { + if (efsd->name.filenocasecmp_to(fs->get_subdir(j)->get_name()) < 0) { break; } idx2++; @@ -1766,7 +1762,7 @@ void EditorFileSystem::update_file(const String &p_file) { String file_name = p_file.get_file(); for (int i = 0; i < fs->files.size(); i++) { - if (p_file.naturalnocasecmp_to(fs->files[i]->file) < 0) { + if (p_file.filenocasecmp_to(fs->files[i]->file) < 0) { break; } idx++; diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h index 818d725281..e45d6f8be3 100644 --- a/editor/editor_file_system.h +++ b/editor/editor_file_system.h @@ -68,14 +68,6 @@ class EditorFileSystemDirectory : public Object { String script_class_icon_path; }; - struct FileInfoSort { - bool operator()(const FileInfo *p_a, const FileInfo *p_b) const { - return p_a->file < p_b->file; - } - }; - - void sort_files(); - Vector<FileInfo *> files; static void _bind_methods(); diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 51df2716d7..ff381d68c0 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -356,6 +356,7 @@ EditorHelpSearch::EditorHelpSearch() { // Create the results tree. results_tree = memnew(Tree); + results_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); results_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); results_tree->set_columns(2); results_tree->set_column_title(0, TTR("Name")); diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index a14c6e8462..7919d61f26 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -57,7 +57,7 @@ bool EditorInspector::_property_path_matches(const String &p_property_path, cons const Vector<String> prop_sections = p_property_path.split("/"); for (int i = 0; i < prop_sections.size(); i++) { - if (p_filter.is_subsequence_ofn(EditorPropertyNameProcessor::get_singleton()->process_name(prop_sections[i], p_style))) { + if (p_filter.is_subsequence_ofn(EditorPropertyNameProcessor::get_singleton()->process_name(prop_sections[i], p_style, p_property_path))) { return true; } } @@ -86,8 +86,7 @@ Size2 EditorProperty::get_minimum_size() const { } Size2 minsize = c->get_combined_minimum_size(); - ms.width = MAX(ms.width, minsize.width); - ms.height = MAX(ms.height, minsize.height); + ms = ms.max(minsize); } if (keying) { @@ -1463,8 +1462,7 @@ Size2 EditorInspectorSection::get_minimum_size() const { continue; } Size2 minsize = c->get_combined_minimum_size(); - ms.width = MAX(ms.width, minsize.width); - ms.height = MAX(ms.height, minsize.height); + ms = ms.max(minsize); } Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Tree")); @@ -2806,6 +2804,9 @@ void EditorInspector::update_tree() { subgroup_base = ""; section_depth = 0; + vbox_per_path.clear(); + editor_inspector_array_per_prefix.clear(); + if (!show_categories) { continue; } @@ -3011,7 +3012,7 @@ void EditorInspector::update_tree() { if ((p.usage & PROPERTY_USAGE_SCRIPT_VARIABLE) && name_style == EditorPropertyNameProcessor::STYLE_LOCALIZED) { name_style = EditorPropertyNameProcessor::STYLE_CAPITALIZED; } - const String property_label_string = EditorPropertyNameProcessor::get_singleton()->process_name(name_override, name_style) + feature_tag; + const String property_label_string = EditorPropertyNameProcessor::get_singleton()->process_name(name_override, name_style, p.name, doc_name) + feature_tag; // Remove the property from the path. int idx = path.rfind("/"); @@ -3080,8 +3081,8 @@ void EditorInspector::update_tree() { tooltip = EditorPropertyNameProcessor::get_singleton()->translate_group_name(component); } } else { - label = EditorPropertyNameProcessor::get_singleton()->process_name(component, section_name_style); - tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(component, EditorPropertyNameProcessor::get_tooltip_style(section_name_style)); + label = EditorPropertyNameProcessor::get_singleton()->process_name(component, section_name_style, p.name, doc_name); + tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(component, EditorPropertyNameProcessor::get_tooltip_style(section_name_style), p.name, doc_name); } Color c = sscolor; @@ -3144,7 +3145,7 @@ void EditorInspector::update_tree() { editor_inspector_array = memnew(EditorInspectorArray(all_read_only)); String array_label = path.contains("/") ? path.substr(path.rfind("/") + 1) : path; - array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style); + array_label = EditorPropertyNameProcessor::get_singleton()->process_name(property_label_string, property_name_style, p.name, doc_name); int page = per_array_page.has(array_element_prefix) ? per_array_page[array_element_prefix] : 0; editor_inspector_array->setup_with_move_element_function(object, array_label, array_element_prefix, page, c, use_folding); editor_inspector_array->connect("page_change_request", callable_mp(this, &EditorInspector::_page_change_request).bind(array_element_prefix)); diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp index f1d82557fd..1318b59685 100644 --- a/editor/editor_locale_dialog.cpp +++ b/editor/editor_locale_dialog.cpp @@ -433,6 +433,7 @@ EditorLocaleDialog::EditorLocaleDialog() { } { lang_list = memnew(Tree); + lang_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); lang_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); lang_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected)); lang_list->set_columns(1); @@ -452,6 +453,7 @@ EditorLocaleDialog::EditorLocaleDialog() { } { script_list = memnew(Tree); + script_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); script_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); script_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected)); script_list->set_columns(1); @@ -470,6 +472,7 @@ EditorLocaleDialog::EditorLocaleDialog() { } { cnt_list = memnew(Tree); + cnt_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); cnt_list->set_v_size_flags(Control::SIZE_EXPAND_FILL); cnt_list->connect("cell_selected", callable_mp(this, &EditorLocaleDialog::_item_selected)); cnt_list->set_columns(1); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index c0c26bbfeb..667405ff10 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -435,8 +435,7 @@ EditorLog::EditorLog() { clear_button = memnew(Button); clear_button->set_theme_type_variation("FlatButton"); clear_button->set_focus_mode(FOCUS_NONE); - clear_button->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::K)); - clear_button->set_shortcut_context(this); + clear_button->set_shortcut(ED_SHORTCUT("editor/clear_output", TTR("Clear Output"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::ALT | Key::K)); clear_button->connect("pressed", callable_mp(this, &EditorLog::_clear_request)); hb_tools->add_child(clear_button); diff --git a/editor/editor_native_shader_source_visualizer.cpp b/editor/editor_native_shader_source_visualizer.cpp index 4a0fc235a5..0e3e44bb7e 100644 --- a/editor/editor_native_shader_source_visualizer.cpp +++ b/editor/editor_native_shader_source_visualizer.cpp @@ -30,7 +30,43 @@ #include "editor_native_shader_source_visualizer.h" +#include "editor/code_editor.h" +#include "editor/editor_settings.h" +#include "editor/themes/editor_scale.h" #include "scene/gui/text_edit.h" +#include "servers/rendering/shader_language.h" + +void EditorNativeShaderSourceVisualizer::_load_theme_settings() { + syntax_highlighter->set_number_color(EDITOR_GET("text_editor/theme/highlighting/number_color")); + syntax_highlighter->set_symbol_color(EDITOR_GET("text_editor/theme/highlighting/symbol_color")); + syntax_highlighter->set_function_color(EDITOR_GET("text_editor/theme/highlighting/function_color")); + syntax_highlighter->set_member_variable_color(EDITOR_GET("text_editor/theme/highlighting/member_variable_color")); + + syntax_highlighter->clear_keyword_colors(); + + List<String> keywords; + ShaderLanguage::get_keyword_list(&keywords); + const Color keyword_color = EDITOR_GET("text_editor/theme/highlighting/keyword_color"); + const Color control_flow_keyword_color = EDITOR_GET("text_editor/theme/highlighting/control_flow_keyword_color"); + + for (const String &keyword : keywords) { + if (ShaderLanguage::is_control_flow_keyword(keyword)) { + syntax_highlighter->add_keyword_color(keyword, control_flow_keyword_color); + } else { + syntax_highlighter->add_keyword_color(keyword, keyword_color); + } + } + + // Colorize comments. + const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color"); + syntax_highlighter->clear_color_regions(); + syntax_highlighter->add_color_region("/*", "*/", comment_color, false); + syntax_highlighter->add_color_region("//", "", comment_color, true); + + // Colorize preprocessor statements. + const Color user_type_color = EDITOR_GET("text_editor/theme/highlighting/user_type_color"); + syntax_highlighter->add_color_region("#", "", user_type_color, true); +} void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) { if (versions) { @@ -40,6 +76,8 @@ void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) { RS::ShaderNativeSourceCode nsc = RS::get_singleton()->shader_get_native_source_code(p_shader); + _load_theme_settings(); + versions = memnew(TabContainer); versions->set_tab_alignment(TabBar::ALIGNMENT_CENTER); versions->set_v_size_flags(Control::SIZE_EXPAND_FILL); @@ -52,13 +90,55 @@ void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) { vtab->set_h_size_flags(Control::SIZE_EXPAND_FILL); versions->add_child(vtab); for (int j = 0; j < nsc.versions[i].stages.size(); j++) { - TextEdit *vtext = memnew(TextEdit); - vtext->set_editable(false); - vtext->set_name(nsc.versions[i].stages[j].name); - vtext->set_text(nsc.versions[i].stages[j].code); - vtext->set_v_size_flags(Control::SIZE_EXPAND_FILL); - vtext->set_h_size_flags(Control::SIZE_EXPAND_FILL); - vtab->add_child(vtext); + CodeEdit *code_edit = memnew(CodeEdit); + code_edit->set_editable(false); + code_edit->set_syntax_highlighter(syntax_highlighter); + code_edit->add_theme_font_override("font", get_theme_font("source", "EditorFonts")); + code_edit->add_theme_font_size_override("font_size", get_theme_font_size("source_size", "EditorFonts")); + code_edit->add_theme_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 6)); + + // Appearance: Caret + code_edit->set_caret_type((TextEdit::CaretType)EDITOR_GET("text_editor/appearance/caret/type").operator int()); + code_edit->set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink")); + code_edit->set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval")); + code_edit->set_highlight_current_line(EDITOR_GET("text_editor/appearance/caret/highlight_current_line")); + code_edit->set_highlight_all_occurrences(EDITOR_GET("text_editor/appearance/caret/highlight_all_occurrences")); + + // Appearance: Gutters + code_edit->set_draw_line_numbers(EDITOR_GET("text_editor/appearance/gutters/show_line_numbers")); + code_edit->set_line_numbers_zero_padded(EDITOR_GET("text_editor/appearance/gutters/line_numbers_zero_padded")); + + // Appearance: Minimap + code_edit->set_draw_minimap(EDITOR_GET("text_editor/appearance/minimap/show_minimap")); + code_edit->set_minimap_width((int)EDITOR_GET("text_editor/appearance/minimap/minimap_width") * EDSCALE); + + // Appearance: Lines + code_edit->set_line_folding_enabled(EDITOR_GET("text_editor/appearance/lines/code_folding")); + code_edit->set_draw_fold_gutter(EDITOR_GET("text_editor/appearance/lines/code_folding")); + code_edit->set_line_wrapping_mode((TextEdit::LineWrappingMode)EDITOR_GET("text_editor/appearance/lines/word_wrap").operator int()); + code_edit->set_autowrap_mode((TextServer::AutowrapMode)EDITOR_GET("text_editor/appearance/lines/autowrap_mode").operator int()); + + // Appearance: Whitespace + code_edit->set_draw_tabs(EDITOR_GET("text_editor/appearance/whitespace/draw_tabs")); + code_edit->set_draw_spaces(EDITOR_GET("text_editor/appearance/whitespace/draw_spaces")); + code_edit->add_theme_constant_override("line_spacing", EDITOR_GET("text_editor/appearance/whitespace/line_spacing")); + + // Behavior: Navigation + code_edit->set_scroll_past_end_of_file_enabled(EDITOR_GET("text_editor/behavior/navigation/scroll_past_end_of_file")); + code_edit->set_smooth_scroll_enabled(EDITOR_GET("text_editor/behavior/navigation/smooth_scrolling")); + code_edit->set_v_scroll_speed(EDITOR_GET("text_editor/behavior/navigation/v_scroll_speed")); + code_edit->set_drag_and_drop_selection_enabled(EDITOR_GET("text_editor/behavior/navigation/drag_and_drop_selection")); + + // Behavior: Indent + code_edit->set_indent_size(EDITOR_GET("text_editor/behavior/indent/size")); + code_edit->set_auto_indent_enabled(EDITOR_GET("text_editor/behavior/indent/auto_indent")); + code_edit->set_indent_wrapped_lines(EDITOR_GET("text_editor/behavior/indent/indent_wrapped_lines")); + + code_edit->set_name(nsc.versions[i].stages[j].name); + code_edit->set_text(nsc.versions[i].stages[j].code); + code_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL); + code_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL); + vtab->add_child(code_edit); } } add_child(versions); @@ -68,7 +148,10 @@ void EditorNativeShaderSourceVisualizer::_inspect_shader(RID p_shader) { void EditorNativeShaderSourceVisualizer::_bind_methods() { ClassDB::bind_method("_inspect_shader", &EditorNativeShaderSourceVisualizer::_inspect_shader); } + EditorNativeShaderSourceVisualizer::EditorNativeShaderSourceVisualizer() { + syntax_highlighter.instantiate(); + add_to_group("_native_shader_source_visualizer"); set_title(TTR("Native Shader Source Inspector")); } diff --git a/editor/editor_native_shader_source_visualizer.h b/editor/editor_native_shader_source_visualizer.h index 00f314da7d..8ae942da7c 100644 --- a/editor/editor_native_shader_source_visualizer.h +++ b/editor/editor_native_shader_source_visualizer.h @@ -33,11 +33,14 @@ #include "scene/gui/dialogs.h" #include "scene/gui/tab_container.h" +#include "scene/resources/syntax_highlighter.h" class EditorNativeShaderSourceVisualizer : public AcceptDialog { GDCLASS(EditorNativeShaderSourceVisualizer, AcceptDialog) TabContainer *versions = nullptr; + Ref<CodeHighlighter> syntax_highlighter; + void _load_theme_settings(); void _inspect_shader(RID p_shader); protected: diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 3abf0582bc..5c1b14c203 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -2506,8 +2506,8 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update editable_info, info_is_warning); - Object *editor_owner = is_node ? (Object *)SceneTreeDock::get_singleton() : is_resource ? (Object *)InspectorDock::get_inspector_singleton() - : (Object *)this; + Object *editor_owner = (is_node || current_obj->is_class("MultiNodeEdit")) ? (Object *)SceneTreeDock::get_singleton() : is_resource ? (Object *)InspectorDock::get_inspector_singleton() + : (Object *)this; // Take care of the main editor plugin. @@ -3789,14 +3789,6 @@ void EditorNode::_set_current_scene_nocheck(int p_idx) { editor_folding.save_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx)); } - if (editor_data.check_and_update_scene(p_idx)) { - if (editor_data.get_scene_path(p_idx) != "") { - editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx)); - } - - EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_scene_history_id(p_idx)); - } - changing_scene = true; editor_data.save_edited_scene_state(editor_selection, &editor_history, _get_main_scene_state()); @@ -3826,6 +3818,14 @@ void EditorNode::_set_current_scene_nocheck(int p_idx) { } } + if (editor_data.check_and_update_scene(p_idx)) { + if (!editor_data.get_scene_path(p_idx).is_empty()) { + editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx)); + } + + EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_scene_history_id(p_idx)); + } + Dictionary state = editor_data.restore_edited_scene_state(editor_selection, &editor_history); _edit_current(true); @@ -6062,19 +6062,13 @@ void EditorNode::_resource_loaded(Ref<Resource> p_resource, const String &p_path void EditorNode::_feature_profile_changed() { Ref<EditorFeatureProfile> profile = feature_profile_manager->get_current_profile(); - // FIXME: Close all floating docks to avoid crash. - editor_dock_manager->close_all_floating_docks(); - TabContainer *import_tabs = cast_to<TabContainer>(ImportDock::get_singleton()->get_parent()); - TabContainer *node_tabs = cast_to<TabContainer>(NodeDock::get_singleton()->get_parent()); - TabContainer *fs_tabs = cast_to<TabContainer>(FileSystemDock::get_singleton()->get_parent()); - TabContainer *history_tabs = cast_to<TabContainer>(history_dock->get_parent()); if (profile.is_valid()) { - node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK)); + editor_dock_manager->set_dock_enabled(NodeDock::get_singleton(), !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK)); // The Import dock is useless without the FileSystem dock. Ensure the configuration is valid. bool fs_dock_disabled = profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK); - fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), fs_dock_disabled); - import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK)); - history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_HISTORY_DOCK)); + editor_dock_manager->set_dock_enabled(FileSystemDock::get_singleton(), !fs_dock_disabled); + editor_dock_manager->set_dock_enabled(ImportDock::get_singleton(), !fs_dock_disabled && !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK)); + editor_dock_manager->set_dock_enabled(history_dock, !profile->is_feature_disabled(EditorFeatureProfile::FEATURE_HISTORY_DOCK)); main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D)); main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT)); @@ -6087,18 +6081,16 @@ void EditorNode::_feature_profile_changed() { editor_select(EDITOR_2D); } } else { - import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), false); - node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), false); - fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), false); - history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), false); + editor_dock_manager->set_dock_enabled(ImportDock::get_singleton(), true); + editor_dock_manager->set_dock_enabled(NodeDock::get_singleton(), true); + editor_dock_manager->set_dock_enabled(FileSystemDock::get_singleton(), true); + editor_dock_manager->set_dock_enabled(history_dock, true); main_editor_buttons[EDITOR_3D]->set_visible(true); main_editor_buttons[EDITOR_SCRIPT]->set_visible(true); if (AssetLibraryEditorPlugin::is_available()) { main_editor_buttons[EDITOR_ASSETLIB]->set_visible(true); } } - - editor_dock_manager->update_dock_slots_visibility(); } void EditorNode::_bind_methods() { @@ -6557,7 +6549,6 @@ EditorNode::EditorNode() { right_r_vsplit->add_child(dock_slot[EditorDockManager::DOCK_SLOT_RIGHT_BR]); editor_dock_manager = memnew(EditorDockManager); - editor_dock_manager->connect("layout_changed", callable_mp(this, &EditorNode::_save_editor_layout)); // Save the splits for easier access. editor_dock_manager->add_vsplit(left_l_vsplit); @@ -6754,7 +6745,7 @@ EditorNode::EditorNode() { ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings...")); ED_SHORTCUT_OVERRIDE("editor/editor_settings", "macos", KeyModifierMask::META + Key::COMMA); #ifdef MACOS_ENABLED - if (global_menu) { + if (global_menu && NativeMenu::get_singleton()->has_system_menu(NativeMenu::APPLICATION_MENU_ID)) { apple_menu = memnew(PopupMenu); apple_menu->set_system_menu(NativeMenu::APPLICATION_MENU_ID); main_menu->add_child(apple_menu); @@ -6838,6 +6829,8 @@ EditorNode::EditorNode() { settings_menu->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE); settings_menu->add_separator(); + settings_menu->add_submenu_node_item(TTR("Editor Docks"), editor_dock_manager->get_docks_menu()); + editor_layouts = memnew(PopupMenu); editor_layouts->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); settings_menu->add_submenu_node_item(TTR("Editor Layout"), editor_layouts); @@ -6879,7 +6872,9 @@ EditorNode::EditorNode() { help_menu = memnew(PopupMenu); help_menu->set_name(TTR("Help")); - help_menu->set_system_menu(NativeMenu::HELP_MENU_ID); + if (global_menu && NativeMenu::get_singleton()->has_system_menu(NativeMenu::HELP_MENU_ID)) { + help_menu->set_system_menu(NativeMenu::HELP_MENU_ID); + } main_menu->add_child(help_menu); help_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); @@ -7005,22 +7000,22 @@ EditorNode::EditorNode() { history_dock = memnew(HistoryDock); // Scene: Top left. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_LEFT_UR, SceneTreeDock::get_singleton(), TTR("Scene")); + editor_dock_manager->add_dock(SceneTreeDock::get_singleton(), TTR("Scene"), EditorDockManager::DOCK_SLOT_LEFT_UR); // Import: Top left, behind Scene. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_LEFT_UR, ImportDock::get_singleton(), TTR("Import")); + editor_dock_manager->add_dock(ImportDock::get_singleton(), TTR("Import"), EditorDockManager::DOCK_SLOT_LEFT_UR); // FileSystem: Bottom left. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_LEFT_BR, FileSystemDock::get_singleton(), TTR("FileSystem"), ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_filesystem_bottom_panel", TTR("Toggle FileSystem Bottom Panel"), KeyModifierMask::ALT | Key::F)); + editor_dock_manager->add_dock(FileSystemDock::get_singleton(), TTR("FileSystem"), EditorDockManager::DOCK_SLOT_LEFT_BR, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_filesystem_bottom_panel", TTR("Toggle FileSystem Bottom Panel"), KeyModifierMask::ALT | Key::F)); // Inspector: Full height right. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_RIGHT_UL, InspectorDock::get_singleton(), TTR("Inspector")); + editor_dock_manager->add_dock(InspectorDock::get_singleton(), TTR("Inspector"), EditorDockManager::DOCK_SLOT_RIGHT_UL); // Node: Full height right, behind Inspector. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_RIGHT_UL, NodeDock::get_singleton(), TTR("Node")); + editor_dock_manager->add_dock(NodeDock::get_singleton(), TTR("Node"), EditorDockManager::DOCK_SLOT_RIGHT_UL); // History: Full height right, behind Node. - editor_dock_manager->add_control_to_dock(EditorDockManager::DOCK_SLOT_RIGHT_UL, history_dock, TTR("History")); + editor_dock_manager->add_dock(history_dock, TTR("History"), EditorDockManager::DOCK_SLOT_RIGHT_UL); // Add some offsets to left_r and main hsplits to make LEFT_R and RIGHT_L docks wider than minsize. left_r_hsplit->set_split_offset(270 * EDSCALE); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 67fe0c2e28..f42a1555a2 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -87,12 +87,12 @@ Button *EditorPlugin::add_control_to_bottom_panel(Control *p_control, const Stri void EditorPlugin::add_control_to_dock(DockSlot p_slot, Control *p_control, const Ref<Shortcut> &p_shortcut) { ERR_FAIL_NULL(p_control); - EditorDockManager::get_singleton()->add_control_to_dock(EditorDockManager::DockSlot(p_slot), p_control, String(), p_shortcut); + EditorDockManager::get_singleton()->add_dock(p_control, String(), EditorDockManager::DockSlot(p_slot), p_shortcut); } void EditorPlugin::remove_control_from_docks(Control *p_control) { ERR_FAIL_NULL(p_control); - EditorDockManager::get_singleton()->remove_control_from_dock(p_control); + EditorDockManager::get_singleton()->remove_dock(p_control); } void EditorPlugin::remove_control_from_bottom_panel(Control *p_control) { diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 0e3b408996..c6a6163a4e 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -2630,16 +2630,22 @@ void EditorPropertyColor::_set_read_only(bool p_read_only) { } void EditorPropertyColor::_color_changed(const Color &p_color) { + if (!live_changes_enabled) { + return; + } + // Cancel the color change if the current color is identical to the new one. - if (get_edited_property_value() == p_color) { + if (((Color)get_edited_property_value()).is_equal_approx(p_color)) { return; } - emit_changed(get_edited_property(), p_color, "", true); + // Preview color change, bypassing undo/redo. + get_edited_object()->set(get_edited_property(), p_color); } void EditorPropertyColor::_popup_closed() { - if (picker->get_pick_color() != last_color) { + get_edited_object()->set(get_edited_property(), last_color); + if (!picker->get_pick_color().is_equal_approx(last_color)) { emit_changed(get_edited_property(), picker->get_pick_color(), "", false); } } @@ -2682,6 +2688,10 @@ void EditorPropertyColor::setup(bool p_show_alpha) { picker->set_edit_alpha(p_show_alpha); } +void EditorPropertyColor::set_live_changes_enabled(bool p_enabled) { + live_changes_enabled = p_enabled; +} + EditorPropertyColor::EditorPropertyColor() { picker = memnew(ColorPickerButton); add_child(picker); @@ -2741,7 +2751,15 @@ void EditorPropertyNodePath::_node_assign() { add_child(scene_tree); scene_tree->connect("selected", callable_mp(this, &EditorPropertyNodePath::_node_selected)); } - scene_tree->popup_scenetree_dialog(); + + Variant val = get_edited_property_value(); + Node *n = nullptr; + if (val.get_type() == Variant::Type::NODE_PATH) { + n = get_base_node()->get_node_or_null(val); + } else { + n = Object::cast_to<Node>(val); + } + scene_tree->popup_scenetree_dialog(n, get_base_node()); } void EditorPropertyNodePath::_update_menu() { @@ -3174,7 +3192,6 @@ void EditorPropertyResource::_resource_changed(const Ref<Resource> &p_resource) add_child(scene_tree); scene_tree->connect("selected", callable_mp(this, &EditorPropertyResource::_viewport_selected)); } - scene_tree->popup_scenetree_dialog(); } } diff --git a/editor/editor_properties.h b/editor/editor_properties.h index fa759d5d19..ce164733fe 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -621,10 +621,10 @@ class EditorPropertyColor : public EditorProperty { ColorPickerButton *picker = nullptr; void _color_changed(const Color &p_color); void _popup_closed(); - void _picker_created(); void _picker_opening(); Color last_color; + bool live_changes_enabled = true; protected: virtual void _set_read_only(bool p_read_only) override; @@ -633,6 +633,7 @@ protected: public: virtual void update_property() override; void setup(bool p_show_alpha); + void set_live_changes_enabled(bool p_enabled); EditorPropertyColor(); }; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 8a15f4912a..a6c7d6b617 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -111,6 +111,7 @@ bool EditorPropertyDictionaryObject::_set(const StringName &p_name, const Varian } if (name.begins_with("indices")) { + dict = dict.duplicate(); int index = name.get_slicec('/', 1).to_int(); Variant key = dict.get_key_at_index(index); dict[key] = p_value; @@ -171,6 +172,31 @@ Variant EditorPropertyDictionaryObject::get_new_item_value() { return new_item_value; } +String EditorPropertyDictionaryObject::get_property_name_for_index(int p_index) { + switch (p_index) { + case NEW_KEY_INDEX: + return "new_item_key"; + case NEW_VALUE_INDEX: + return "new_item_value"; + default: + return "indices/" + itos(p_index); + } +} + +String EditorPropertyDictionaryObject::get_label_for_index(int p_index) { + switch (p_index) { + case NEW_KEY_INDEX: + return TTR("New Key:"); + break; + case NEW_VALUE_INDEX: + return TTR("New Value:"); + break; + default: + return dict.get_key_at_index(p_index).get_construct_string(); + break; + } +} + EditorPropertyDictionaryObject::EditorPropertyDictionaryObject() { } @@ -230,15 +256,14 @@ void EditorPropertyArray::_change_type_menu(int p_index) { Variant array = object->get_array().duplicate(); array.set(slots[changing_type_index].index, value); - emit_changed(get_edited_property(), array, "", true); - update_property(); + emit_changed(get_edited_property(), array); } void EditorPropertyArray::_object_id_selected(const StringName &p_property, ObjectID p_id) { emit_signal(SNAME("object_id_selected"), p_property, p_id); } -void EditorPropertyArray::create_new_property_slot() { +void EditorPropertyArray::_create_new_property_slot() { int idx = slots.size(); HBoxContainer *hbox = memnew(HBoxContainer); @@ -365,7 +390,7 @@ void EditorPropertyArray::update_property() { vbox->add_child(paginator); for (int i = 0; i < page_length; i++) { - create_new_property_slot(); + _create_new_property_slot(); } } @@ -434,8 +459,7 @@ void EditorPropertyArray::_remove_pressed(int p_slot_index) { Variant array = object->get_array().duplicate(); array.call("remove_at", slots[p_slot_index].index); - emit_changed(get_edited_property(), array, "", false); - update_property(); + emit_changed(get_edited_property(), array); } void EditorPropertyArray::_button_draw() { @@ -514,8 +538,7 @@ void EditorPropertyArray::drop_data_fw(const Point2 &p_point, const Variant &p_d } } - emit_changed(get_edited_property(), array, "", false); - update_property(); + emit_changed(get_edited_property(), array); } } @@ -607,8 +630,7 @@ void EditorPropertyArray::_length_changed(double p_page) { Variant array = object->get_array().duplicate(); array.call("resize", int(p_page)); - emit_changed(get_edited_property(), array, "", false); - update_property(); + emit_changed(get_edited_property(), array); } void EditorPropertyArray::_add_element() { @@ -700,8 +722,7 @@ void EditorPropertyArray::_reorder_button_up() { array.call("remove_at", reorder_slot.index); array.call("insert", reorder_to_index, value_to_move); - reorder_slot.index = reorder_slot.index % page_length + page_index * page_length; - emit_changed(get_edited_property(), array, "", false); + emit_changed(get_edited_property(), array); } Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); @@ -748,31 +769,19 @@ void EditorPropertyDictionary::_property_changed(const String &p_property, Varia p_value = Variant(); // `EditorResourcePicker` resets to `Ref<Resource>()`. See GH-82716. } - if (p_property == "new_item_key") { - object->set_new_item_key(p_value); - } else if (p_property == "new_item_value") { - object->set_new_item_value(p_value); - } else if (p_property.begins_with("indices")) { - int index = p_property.get_slice("/", 1).to_int(); - - Dictionary dict = object->get_dict().duplicate(); - Variant key = dict.get_key_at_index(index); - dict[key] = p_value; - - object->set_dict(dict); - emit_changed(get_edited_property(), dict, "", true); - } + object->set(p_property, p_value); + emit_changed(get_edited_property(), object->get_dict(), p_name, p_changing); } -void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) { +void EditorPropertyDictionary::_change_type(Object *p_button, int p_slot_index) { Button *button = Object::cast_to<Button>(p_button); - + int index = slots[p_slot_index].index; Rect2 rect = button->get_screen_rect(); - change_type->set_item_disabled(change_type->get_item_index(Variant::VARIANT_MAX), p_index < 0); + change_type->set_item_disabled(change_type->get_item_index(Variant::VARIANT_MAX), index < 0); change_type->reset_size(); change_type->set_position(rect.get_end() - Vector2(change_type->get_contents_minimum_size().x, 0)); change_type->popup(); - changing_type_index = p_index; + changing_type_index = index; } void EditorPropertyDictionary::_add_key_value() { @@ -796,36 +805,59 @@ void EditorPropertyDictionary::_add_key_value() { VariantInternal::initialize(&new_value, type); object->set_new_item_value(new_value); - emit_changed(get_edited_property(), dict, "", false); - update_property(); + emit_changed(get_edited_property(), dict); } -void EditorPropertyDictionary::_change_type_menu(int p_index) { - if (changing_type_index < 0) { - Variant value; - VariantInternal::initialize(&value, Variant::Type(p_index)); - if (changing_type_index == -1) { - object->set_new_item_key(value); - } else { - object->set_new_item_value(value); - } - update_property(); - return; - } +void EditorPropertyDictionary::_create_new_property_slot(int p_idx) { + HBoxContainer *hbox = memnew(HBoxContainer); + EditorProperty *prop = memnew(EditorPropertyNil); + hbox->add_child(prop); - Dictionary dict = object->get_dict().duplicate(); - if (p_index < Variant::VARIANT_MAX) { - Variant value; - VariantInternal::initialize(&value, Variant::Type(p_index)); - Variant key = dict.get_key_at_index(changing_type_index); - dict[key] = value; + Button *edit_btn = memnew(Button); + edit_btn->set_icon(get_editor_theme_icon(SNAME("Edit"))); + edit_btn->set_disabled(is_read_only()); + edit_btn->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit_btn, slots.size())); + hbox->add_child(edit_btn); + if (add_panel) { + add_panel->get_child(0)->add_child(hbox); } else { - Variant key = dict.get_key_at_index(changing_type_index); - dict.erase(key); + property_vbox->add_child(hbox); } + Slot slot; + slot.prop = prop; + slot.object = object; + slot.container = hbox; + int index = p_idx + (p_idx >= 0 ? page_index * page_length : 0); + slot.set_index(index); + slots.push_back(slot); +} - emit_changed(get_edited_property(), dict, "", false); - update_property(); +void EditorPropertyDictionary::_change_type_menu(int p_index) { + Variant value; + switch (changing_type_index) { + case EditorPropertyDictionaryObject::NEW_KEY_INDEX: + case EditorPropertyDictionaryObject::NEW_VALUE_INDEX: + VariantInternal::initialize(&value, Variant::Type(p_index)); + if (changing_type_index == EditorPropertyDictionaryObject::NEW_KEY_INDEX) { + object->set_new_item_key(value); + } else { + object->set_new_item_value(value); + } + update_property(); + break; + + default: + Dictionary dict = object->get_dict().duplicate(); + Variant key = dict.get_key_at_index(changing_type_index); + if (p_index < Variant::VARIANT_MAX) { + VariantInternal::initialize(&value, Variant::Type(p_index)); + dict[key] = value; + } else { + dict.erase(key); + } + + emit_changed(get_edited_property(), dict); + } } void EditorPropertyDictionary::setup(PropertyHint p_hint) { @@ -877,331 +909,72 @@ void EditorPropertyDictionary::update_property() { paginator = memnew(EditorPaginator); paginator->connect("page_changed", callable_mp(this, &EditorPropertyDictionary::_page_changed)); vbox->add_child(paginator); - } else { - // Queue children for deletion, deleting immediately might cause errors. - for (int i = property_vbox->get_child_count() - 1; i >= 0; i--) { - property_vbox->get_child(i)->queue_free(); + + for (int i = 0; i < page_length; i++) { + _create_new_property_slot(slots.size()); } + + add_panel = memnew(PanelContainer); + property_vbox->add_child(add_panel); + add_panel->add_theme_style_override(SNAME("panel"), get_theme_stylebox(SNAME("DictionaryAddItem"), EditorStringName(EditorStyles))); + VBoxContainer *add_vbox = memnew(VBoxContainer); + add_panel->add_child(add_vbox); + + _create_new_property_slot(EditorPropertyDictionaryObject::NEW_KEY_INDEX); + _create_new_property_slot(EditorPropertyDictionaryObject::NEW_VALUE_INDEX); + + button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair")); + button_add_item->set_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons))); + button_add_item->set_disabled(is_read_only()); + button_add_item->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_add_key_value)); + add_vbox->add_child(button_add_item); } int size = dict.size(); int max_page = MAX(0, size - 1) / page_length; - page_index = MIN(page_index, max_page); + if (page_index > max_page) { + _page_changed(max_page); + } paginator->update(page_index, max_page); paginator->set_visible(max_page > 0); - int offset = page_index * page_length; - - int amount = MIN(size - offset, page_length); - int total_amount = page_index == max_page ? amount + 2 : amount; // For the "Add Key/Value Pair" box on last page. - - VBoxContainer *add_vbox = nullptr; - double default_float_step = EDITOR_GET("interface/inspector/default_float_step"); - - for (int i = 0; i < total_amount; i++) { - String prop_name; - Variant key; - Variant value; + add_panel->set_visible(page_index == max_page); - if (i < amount) { - prop_name = "indices/" + itos(i + offset); - key = dict.get_key_at_index(i + offset); - value = dict.get_value_at_index(i + offset); - } else if (i == amount) { - prop_name = "new_item_key"; - value = object->get_new_item_key(); - } else if (i == amount + 1) { - prop_name = "new_item_value"; - value = object->get_new_item_value(); + for (Slot &slot : slots) { + bool slot_visible = slot.index < size; + slot.container->set_visible(slot_visible); + // If not visible no need to update it. + if (!slot_visible) { + continue; } + Variant value = object->get(slot.prop_name); + Variant::Type value_type = value.get_type(); - EditorProperty *prop = nullptr; - - switch (value.get_type()) { - case Variant::NIL: { - prop = memnew(EditorPropertyNil); - - } break; - - // Atomic types. - case Variant::BOOL: { - prop = memnew(EditorPropertyCheck); - - } break; - case Variant::INT: { - EditorPropertyInteger *editor = memnew(EditorPropertyInteger); - editor->setup(-100000, 100000, 1, false, true, true); - prop = editor; - - } break; - case Variant::FLOAT: { - EditorPropertyFloat *editor = memnew(EditorPropertyFloat); - editor->setup(-100000, 100000, default_float_step, true, false, true, true); - prop = editor; - } break; - case Variant::STRING: { - if (i != amount && property_hint == PROPERTY_HINT_MULTILINE_TEXT) { - // If this is NOT the new key field and there's a multiline hint, - // show the field as multiline - prop = memnew(EditorPropertyMultilineText); - } else { - prop = memnew(EditorPropertyText); - } - - } break; - - // Math types. - case Variant::VECTOR2: { - EditorPropertyVector2 *editor = memnew(EditorPropertyVector2); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::VECTOR2I: { - EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i); - editor->setup(-100000, 100000); - prop = editor; - - } break; - case Variant::RECT2: { - EditorPropertyRect2 *editor = memnew(EditorPropertyRect2); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::RECT2I: { - EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i); - editor->setup(-100000, 100000); - prop = editor; - - } break; - case Variant::VECTOR3: { - EditorPropertyVector3 *editor = memnew(EditorPropertyVector3); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::VECTOR3I: { - EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i); - editor->setup(-100000, 100000); - prop = editor; - - } break; - case Variant::VECTOR4: { - EditorPropertyVector4 *editor = memnew(EditorPropertyVector4); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::VECTOR4I: { - EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i); - editor->setup(-100000, 100000); - prop = editor; - - } break; - case Variant::TRANSFORM2D: { - EditorPropertyTransform2D *editor = memnew(EditorPropertyTransform2D); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::PLANE: { - EditorPropertyPlane *editor = memnew(EditorPropertyPlane); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::QUATERNION: { - EditorPropertyQuaternion *editor = memnew(EditorPropertyQuaternion); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::AABB: { - EditorPropertyAABB *editor = memnew(EditorPropertyAABB); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::BASIS: { - EditorPropertyBasis *editor = memnew(EditorPropertyBasis); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::TRANSFORM3D: { - EditorPropertyTransform3D *editor = memnew(EditorPropertyTransform3D); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - case Variant::PROJECTION: { - EditorPropertyProjection *editor = memnew(EditorPropertyProjection); - editor->setup(-100000, 100000, default_float_step, true); - prop = editor; - - } break; - - // Miscellaneous types. - case Variant::COLOR: { - prop = memnew(EditorPropertyColor); - - } break; - case Variant::STRING_NAME: { - EditorPropertyText *ept = memnew(EditorPropertyText); - ept->set_string_name(true); - prop = ept; - - } break; - case Variant::NODE_PATH: { - prop = memnew(EditorPropertyNodePath); - - } break; - case Variant::RID: { - prop = memnew(EditorPropertyRID); - - } break; - case Variant::SIGNAL: { - prop = memnew(EditorPropertySignal); - - } break; - case Variant::CALLABLE: { - prop = memnew(EditorPropertyCallable); - - } break; - case Variant::OBJECT: { - if (Object::cast_to<EncodedObjectAsID>(value)) { - EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); - editor->setup("Object"); - prop = editor; - - } else { - EditorPropertyResource *editor = memnew(EditorPropertyResource); - editor->setup(object.ptr(), prop_name, "Resource"); - editor->set_use_folding(is_using_folding()); - prop = editor; - } - - } break; - case Variant::DICTIONARY: { - prop = memnew(EditorPropertyDictionary); - - } break; - case Variant::ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::ARRAY); - prop = editor; - } break; - - // Arrays. - case Variant::PACKED_BYTE_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_BYTE_ARRAY); - prop = editor; - } break; - case Variant::PACKED_INT32_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_INT32_ARRAY); - prop = editor; - } break; - case Variant::PACKED_FLOAT32_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_FLOAT32_ARRAY); - prop = editor; - } break; - case Variant::PACKED_INT64_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_INT64_ARRAY); - prop = editor; - } break; - case Variant::PACKED_FLOAT64_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_FLOAT64_ARRAY); - prop = editor; - } break; - case Variant::PACKED_STRING_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_STRING_ARRAY); - prop = editor; - } break; - case Variant::PACKED_VECTOR2_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_VECTOR2_ARRAY); - prop = editor; - } break; - case Variant::PACKED_VECTOR3_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_VECTOR3_ARRAY); - prop = editor; - } break; - case Variant::PACKED_COLOR_ARRAY: { - EditorPropertyArray *editor = memnew(EditorPropertyArray); - editor->setup(Variant::PACKED_COLOR_ARRAY); - prop = editor; - } break; - default: { + // Check if the editor property needs to be updated. + bool value_as_id = Object::cast_to<EncodedObjectAsID>(value); + if (value_type != slot.type || (value_type == Variant::OBJECT && value_as_id != slot.as_id)) { + slot.as_id = value_as_id; + slot.type = value_type; + EditorProperty *new_prop = nullptr; + if (value_type == Variant::OBJECT && value_as_id) { + EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID); + editor->setup("Object"); + new_prop = editor; + } else { + new_prop = EditorInspector::instantiate_property_editor(nullptr, value_type, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE); } + new_prop->set_selectable(false); + new_prop->set_use_folding(is_using_folding()); + new_prop->connect(SNAME("property_changed"), callable_mp(this, &EditorPropertyDictionary::_property_changed)); + new_prop->connect(SNAME("object_id_selected"), callable_mp(this, &EditorPropertyDictionary::_object_id_selected)); + new_prop->set_h_size_flags(SIZE_EXPAND_FILL); + new_prop->set_read_only(is_read_only()); + slot.set_prop(new_prop); } - - ERR_FAIL_NULL(prop); - - prop->set_read_only(is_read_only()); - - if (i == amount) { - PanelContainer *pc = memnew(PanelContainer); - property_vbox->add_child(pc); - pc->add_theme_style_override(SNAME("panel"), get_theme_stylebox(SNAME("DictionaryAddItem"), EditorStringName(EditorStyles))); - - add_vbox = memnew(VBoxContainer); - pc->add_child(add_vbox); - } - prop->set_object_and_property(object.ptr(), prop_name); - int change_index = 0; - - if (i < amount) { - String cs = key.get_construct_string(); - prop->set_label(key.get_construct_string()); - prop->set_tooltip_text(cs); - change_index = i + offset; - } else if (i == amount) { - prop->set_label(TTR("New Key:")); - change_index = -1; - } else if (i == amount + 1) { - prop->set_label(TTR("New Value:")); - change_index = -2; - } - - prop->set_selectable(false); - prop->connect("property_changed", callable_mp(this, &EditorPropertyDictionary::_property_changed)); - prop->connect("object_id_selected", callable_mp(this, &EditorPropertyDictionary::_object_id_selected)); - - HBoxContainer *hbox = memnew(HBoxContainer); - if (add_vbox) { - add_vbox->add_child(hbox); - } else { - property_vbox->add_child(hbox); - } - hbox->add_child(prop); - prop->set_h_size_flags(SIZE_EXPAND_FILL); - Button *edit_btn = memnew(Button); - edit_btn->set_icon(get_editor_theme_icon(SNAME("Edit"))); - edit_btn->set_disabled(is_read_only()); - hbox->add_child(edit_btn); - edit_btn->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_change_type).bind(edit_btn, change_index)); - - prop->update_property(); - - if (i == amount + 1) { - button_add_item = EditorInspector::create_inspector_action_button(TTR("Add Key/Value Pair")); - button_add_item->set_icon(get_editor_theme_icon(SNAME("Add"))); - button_add_item->set_disabled(is_read_only()); - button_add_item->connect("pressed", callable_mp(this, &EditorPropertyDictionary::_add_key_value)); - add_vbox->add_child(button_add_item); - } + slot.prop->update_property(); } - updating = false; } else { @@ -1210,6 +983,8 @@ void EditorPropertyDictionary::update_property() { memdelete(container); button_add_item = nullptr; container = nullptr; + add_panel = nullptr; + slots.clear(); } } } @@ -1254,10 +1029,17 @@ void EditorPropertyDictionary::_edit_pressed() { } void EditorPropertyDictionary::_page_changed(int p_page) { + page_index = p_page; + int i = p_page * page_length; + for (Slot &slot : slots) { + if (slot.index > -1) { + slot.set_index(i); + i++; + } + } if (updating) { return; } - page_index = p_page; update_property(); } diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h index 0e81a0fae3..b1bf45f1b7 100644 --- a/editor/editor_properties_array_dict.h +++ b/editor/editor_properties_array_dict.h @@ -66,6 +66,11 @@ protected: bool _get(const StringName &p_name, Variant &r_ret) const; public: + enum { + NEW_KEY_INDEX = -2, + NEW_VALUE_INDEX, + }; + void set_dict(const Dictionary &p_dict); Dictionary get_dict(); @@ -75,6 +80,9 @@ public: void set_new_item_value(const Variant &p_new_item); Variant get_new_item_value(); + String get_label_for_index(int p_index); + String get_property_name_for_index(int p_index); + EditorPropertyDictionaryObject(); }; @@ -125,7 +133,7 @@ class EditorPropertyArray : public EditorProperty { void _reorder_button_gui_input(const Ref<InputEvent> &p_event); void _reorder_button_down(int p_index); void _reorder_button_up(); - void create_new_property_slot(); + void _create_new_property_slot(); protected: Ref<EditorPropertyArrayObject> object; @@ -160,6 +168,34 @@ public: class EditorPropertyDictionary : public EditorProperty { GDCLASS(EditorPropertyDictionary, EditorProperty); + struct Slot { + Ref<EditorPropertyDictionaryObject> object; + HBoxContainer *container = nullptr; + int index = -1; + Variant::Type type = Variant::VARIANT_MAX; + bool as_id = false; + EditorProperty *prop = nullptr; + String prop_name; + + void set_index(int p_idx) { + index = p_idx; + prop_name = object->get_property_name_for_index(p_idx); + update_prop_or_index(); + } + + void set_prop(EditorProperty *p_prop) { + prop->add_sibling(p_prop); + prop->queue_free(); + prop = p_prop; + update_prop_or_index(); + } + + void update_prop_or_index() { + prop->set_object_and_property(object.ptr(), prop_name); + prop->set_label(object->get_label_for_index(index)); + } + }; + PopupMenu *change_type = nullptr; bool updating = false; @@ -170,15 +206,18 @@ class EditorPropertyDictionary : public EditorProperty { Button *edit = nullptr; MarginContainer *container = nullptr; VBoxContainer *property_vbox = nullptr; + PanelContainer *add_panel = nullptr; EditorSpinSlider *size_sliderv = nullptr; Button *button_add_item = nullptr; EditorPaginator *paginator = nullptr; PropertyHint property_hint; + LocalVector<Slot> slots; + void _create_new_property_slot(int p_idx); void _page_changed(int p_page); void _edit_pressed(); void _property_changed(const String &p_property, Variant p_value, const String &p_name = "", bool p_changing = false); - void _change_type(Object *p_button, int p_index); + void _change_type(Object *p_button, int p_slot_index); void _change_type_menu(int p_index); void _add_key_value(); diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index a892ea0f85..1318b84d60 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -91,7 +91,27 @@ String EditorPropertyNameProcessor::_capitalize_name(const String &p_name) const return capitalized; } -String EditorPropertyNameProcessor::process_name(const String &p_name, Style p_style) const { +StringName EditorPropertyNameProcessor::_get_context(const String &p_name, const String &p_property, const StringName &p_class) const { + if (p_property.is_empty() && p_class == StringName()) { + return StringName(); + } + const HashMap<String, StringName> *context_map = translation_contexts.getptr(p_name); + if (context_map == nullptr) { + return StringName(); + } + // It's expected that full property path is enough to distinguish between usages. + // In case a class name is needed, all usages should be prefixed with the class name. + const StringName *context = context_map->getptr(p_property); + if (context == nullptr && p_class != StringName()) { + context = context_map->getptr(String(p_class) + "::" + p_property); + } + if (context == nullptr) { + return StringName(); + } + return *context; +} + +String EditorPropertyNameProcessor::process_name(const String &p_name, Style p_style, const String &p_property, const StringName &p_class) const { switch (p_style) { case STYLE_RAW: { return p_name; @@ -104,7 +124,7 @@ String EditorPropertyNameProcessor::process_name(const String &p_name, Style p_s case STYLE_LOCALIZED: { const String capitalized = _capitalize_name(p_name); if (TranslationServer::get_singleton()) { - return TranslationServer::get_singleton()->property_translate(capitalized); + return TranslationServer::get_singleton()->property_translate(capitalized, _get_context(p_name, p_property, p_class)); } return capitalized; } break; @@ -320,6 +340,25 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { "then", "to", }); + + // Translation context associated with a name. + // The second key is either: + // - `full/property/path` + // - `Class::full/property/path` + // In case a class name is needed to distinguish between usages, all usages should use the second format. + // + // The following initialization is parsed in `editor/translations/scripts/common.py` with a regex. + // The map name and value definition format should be kept synced with the regex. + translation_contexts["force"]["constant_force"] = "Physics"; + translation_contexts["force"]["force/8_bit"] = "Enforce"; + translation_contexts["force"]["force/mono"] = "Enforce"; + translation_contexts["force"]["force/max_rate"] = "Enforce"; + translation_contexts["force"]["force/max_rate_hz"] = "Enforce"; + translation_contexts["normal"]["theme_override_styles/normal"] = "Ordinary"; + translation_contexts["normal"]["TextureButton::texture_normal"] = "Ordinary"; + translation_contexts["normal"]["Decal::texture_normal"] = "Geometry"; + translation_contexts["normal"]["detail_normal"] = "Geometry"; + translation_contexts["normal"]["normal"] = "Geometry"; } EditorPropertyNameProcessor::~EditorPropertyNameProcessor() { diff --git a/editor/editor_property_name_processor.h b/editor/editor_property_name_processor.h index 8e3cecb45b..2c68423c84 100644 --- a/editor/editor_property_name_processor.h +++ b/editor/editor_property_name_processor.h @@ -42,9 +42,14 @@ class EditorPropertyNameProcessor : public Node { HashMap<String, String> capitalize_string_remaps; LocalVector<String> stop_words; // Exceptions that shouldn't be capitalized. + HashMap<String, HashMap<String, StringName>> translation_contexts; + // Capitalizes property path segments. String _capitalize_name(const String &p_name) const; + // Returns the translation context for the given name. + StringName _get_context(const String &p_name, const String &p_property, const StringName &p_class) const; + public: // Matches `interface/inspector/capitalize_properties` editor setting. enum Style { @@ -62,7 +67,8 @@ public: static bool is_localization_available(); // Turns property path segment into the given style. - String process_name(const String &p_name, Style p_style) const; + // `p_class` and `p_property` are only used for `STYLE_LOCALIZED`, associating the name with a translation context. + String process_name(const String &p_name, Style p_style, const String &p_property = "", const StringName &p_class = "") const; // Translate plain text group names. String translate_group_name(const String &p_name) const; diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp index f39872ba2c..6fd1fd687b 100644 --- a/editor/editor_quick_open.cpp +++ b/editor/editor_quick_open.cpp @@ -275,6 +275,7 @@ EditorQuickOpen::EditorQuickOpen() { register_text_enter(search_box); search_options = memnew(Tree); + search_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); search_options->connect("item_activated", callable_mp(this, &EditorQuickOpen::_confirmed)); search_options->create_item(); search_options->set_hide_root(true); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index a9225a3057..1cb71aa933 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -112,7 +112,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const preview_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); int thumbnail_size = EDITOR_GET("filesystem/file_dialog/thumbnail_size"); thumbnail_size *= EDSCALE; - assign_button->set_custom_minimum_size(Size2(MAX(1, assign_button_min_size.x), MAX(thumbnail_size, assign_button_min_size.y))); + assign_button->set_custom_minimum_size(assign_button_min_size.max(Size2(1, thumbnail_size))); } preview_rect->set_texture(p_preview); @@ -382,6 +382,7 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) { vb->add_child(label); duplicate_resources_tree = memnew(Tree); + duplicate_resources_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); vb->add_child(duplicate_resources_tree); duplicate_resources_tree->set_columns(2); duplicate_resources_tree->set_v_size_flags(SIZE_EXPAND_FILL); diff --git a/editor/editor_sectioned_inspector.cpp b/editor/editor_sectioned_inspector.cpp index 8d1f97f6b1..f13af8e4ca 100644 --- a/editor/editor_sectioned_inspector.cpp +++ b/editor/editor_sectioned_inspector.cpp @@ -42,7 +42,7 @@ static bool _property_path_matches(const String &p_property_path, const String & const Vector<String> sections = p_property_path.split("/"); for (int i = 0; i < sections.size(); i++) { - if (p_filter.is_subsequence_ofn(EditorPropertyNameProcessor::get_singleton()->process_name(sections[i], p_style))) { + if (p_filter.is_subsequence_ofn(EditorPropertyNameProcessor::get_singleton()->process_name(sections[i], p_style, p_property_path))) { return true; } } @@ -278,8 +278,8 @@ void SectionedInspector::update_category_list() { TreeItem *ms = sections->create_item(parent); section_map[metasection] = ms; - const String text = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], name_style); - const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], tooltip_style); + const String text = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], name_style, pi.name); + const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(sectionarr[i], tooltip_style, pi.name); ms->set_text(0, text); ms->set_tooltip_text(0, tooltip); @@ -331,6 +331,7 @@ SectionedInspector::SectionedInspector() : left_vb->set_custom_minimum_size(Size2(190, 0) * EDSCALE); add_child(left_vb); + sections->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); sections->set_v_size_flags(SIZE_EXPAND_FILL); sections->set_hide_root(true); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 7436cd8629..89580b83b0 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -653,6 +653,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("text_editor/completion/put_callhint_tooltip_below_current_line", true); _initial_set("text_editor/completion/complete_file_paths", true); _initial_set("text_editor/completion/add_type_hints", true); + _initial_set("text_editor/completion/add_string_name_literals", false); + _initial_set("text_editor/completion/add_node_path_literals", false); _initial_set("text_editor/completion/use_single_quotes", false); _initial_set("text_editor/completion/colorize_suggestions", true); @@ -753,6 +755,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { // Tiles editor _initial_set("editors/tiles_editor/display_grid", true); + _initial_set("editors/tiles_editor/highlight_selected_layer", true); _initial_set("editors/tiles_editor/grid_color", Color(1.0, 0.5, 0.2, 0.5)); // Polygon editor diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index c339bbf365..7faab03a35 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -452,8 +452,8 @@ void EditorSettingsDialog::_update_shortcuts() { TreeItem *section = shortcuts->create_item(root); - const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style); - const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style); + const String item_name = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, name_style, E); + const String tooltip = EditorPropertyNameProcessor::get_singleton()->process_name(section_name, tooltip_style, E); section->set_text(0, item_name); section->set_tooltip_text(0, tooltip); @@ -789,6 +789,7 @@ EditorSettingsDialog::EditorSettingsDialog() { top_hbox->add_child(clear_all_search); shortcuts = memnew(Tree); + shortcuts->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); shortcuts->set_v_size_flags(Control::SIZE_EXPAND_FILL); shortcuts->set_columns(2); shortcuts->set_hide_root(true); diff --git a/editor/editor_translation.cpp b/editor/editor_translation.cpp index 302a81669d..194d78326d 100644 --- a/editor/editor_translation.cpp +++ b/editor/editor_translation.cpp @@ -160,20 +160,22 @@ List<StringName> get_extractable_message_list() { ExtractableTranslationList *etl = _extractable_translations; List<StringName> msgids; while (etl->data) { - Vector<uint8_t> data; - data.resize(etl->uncomp_size); - int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); - ERR_FAIL_COND_V_MSG(ret == -1, msgids, "Compressed file is corrupt."); + if (!strcmp(etl->lang, "source")) { + Vector<uint8_t> data; + data.resize(etl->uncomp_size); + int ret = Compression::decompress(data.ptrw(), etl->uncomp_size, etl->data, etl->comp_size, Compression::MODE_DEFLATE); + ERR_FAIL_COND_V_MSG(ret == -1, msgids, "Compressed file is corrupt."); - Ref<FileAccessMemory> fa; - fa.instantiate(); - fa->open_custom(data.ptr(), data.size()); + Ref<FileAccessMemory> fa; + fa.instantiate(); + fa->open_custom(data.ptr(), data.size()); - Ref<Translation> tr = TranslationLoaderPO::load_translation(fa); + Ref<Translation> tr = TranslationLoaderPO::load_translation(fa); - if (tr.is_valid()) { - tr->get_message_list(&msgids); - break; + if (tr.is_valid()) { + tr->get_message_list(&msgids); + break; + } } etl++; diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp index 3738521491..9fad872a3b 100644 --- a/editor/export/export_template_manager.cpp +++ b/editor/export/export_template_manager.cpp @@ -1040,6 +1040,7 @@ ExportTemplateManager::ExportTemplateManager() { installed_versions_hb->add_child(installed_label); installed_table = memnew(Tree); + installed_table->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); installed_table->set_hide_root(true); installed_table->set_custom_minimum_size(Size2(0, 100) * EDSCALE); installed_table->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index cae814e77d..536e7a0f04 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -1321,6 +1321,7 @@ ProjectExportDialog::ProjectExportDialog() { include_files = memnew(Tree); include_margin->add_child(include_files); + include_files->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); include_files->connect("item_edited", callable_mp(this, &ProjectExportDialog::_tree_changed)); include_files->connect("check_propagated_to_item", callable_mp(this, &ProjectExportDialog::_check_propagated_to_item)); include_files->connect("custom_popup_edited", callable_mp(this, &ProjectExportDialog::_tree_popup_edited)); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 0f83e109fa..4521f4d3ff 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -453,7 +453,7 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo int index; EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->find_file(favorite, &index); if (dir) { - icon = _get_tree_item_icon(dir->get_file_import_is_valid(index), dir->get_file_path(index), dir->get_file_type(index)); + icon = _get_tree_item_icon(dir->get_file_import_is_valid(index), dir->get_file_type(index), _get_entry_script_icon(dir, index)); } else { icon = get_editor_theme_icon(SNAME("File")); } @@ -776,12 +776,7 @@ void FileSystemDock::navigate_to_path(const String &p_path) { _navigate_to_path(p_path); // Ensure that the FileSystem dock is visible. - if (get_window() == get_tree()->get_root()) { - TabContainer *tab_container = (TabContainer *)get_parent_control(); - tab_container->set_current_tab(tab_container->get_tab_idx_from_control((Control *)this)); - } else { - get_window()->grab_focus(); - } + EditorDockManager::get_singleton()->focus_dock(this); } void FileSystemDock::_file_list_thumbnail_done(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, const Variant &p_udata) { @@ -885,7 +880,7 @@ void FileSystemDock::_search(EditorFileSystemDirectory *p_path, List<FileInfo> * struct FileSystemDock::FileInfoTypeComparator { bool operator()(const FileInfo &p_a, const FileInfo &p_b) const { - return NaturalNoCaseComparator()(p_a.name.get_extension() + p_a.type + p_a.name.get_basename(), p_b.name.get_extension() + p_b.type + p_b.name.get_basename()); + return FileNoCaseComparator()(p_a.name.get_extension() + p_a.type + p_a.name.get_basename(), p_b.name.get_extension() + p_b.type + p_b.name.get_basename()); } }; @@ -1009,6 +1004,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { fi.path = favorite; if (efd) { fi.type = efd->get_file_type(index); + fi.icon_path = _get_entry_script_icon(efd, index); fi.import_broken = !efd->get_file_import_is_valid(index); fi.modified_time = efd->get_file_modified_time(index); } else { @@ -1101,6 +1097,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { fi.name = efd->get_file(i); fi.path = directory.path_join(fi.name); fi.type = efd->get_file_type(i); + fi.icon_path = _get_entry_script_icon(efd, i); fi.import_broken = !efd->get_file_import_is_valid(i); fi.modified_time = efd->get_file_modified_time(i); @@ -1118,7 +1115,6 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { FileInfo *finfo = &(E); String fname = finfo->name; String fpath = finfo->path; - String ftype = finfo->type; Ref<Texture2D> type_icon; Ref<Texture2D> big_icon; @@ -1126,11 +1122,10 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { String tooltip = fpath; // Select the icons. + type_icon = _get_tree_item_icon(!finfo->import_broken, finfo->type, finfo->icon_path); if (!finfo->import_broken) { - type_icon = (has_theme_icon(ftype, EditorStringName(EditorIcons))) ? get_editor_theme_icon(ftype) : get_editor_theme_icon(SNAME("Object")); big_icon = file_thumbnail; } else { - type_icon = get_editor_theme_icon(SNAME("ImportFail")); big_icon = file_thumbnail_broken; tooltip += "\n" + TTR("Status: Import of file failed. Please fix file and reimport manually."); } @@ -2043,7 +2038,7 @@ Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion, bo Vector<String> FileSystemDock::_remove_self_included_paths(Vector<String> selected_strings) { // Remove paths or files that are included into another. if (selected_strings.size() > 1) { - selected_strings.sort_custom<NaturalNoCaseComparator>(); + selected_strings.sort_custom<FileNoCaseComparator>(); String last_path = ""; for (int i = 0; i < selected_strings.size(); i++) { if (!last_path.is_empty() && selected_strings[i].begins_with(last_path)) { @@ -3325,6 +3320,7 @@ void FileSystemDock::_file_list_empty_clicked(const Vector2 &p_pos, MouseButton file_list_popup->add_icon_item(get_editor_theme_icon(SNAME("TextFile")), TTR("New TextFile..."), FILE_NEW_TEXTFILE); file_list_popup->add_separator(); file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER); + file_list_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL); file_list_popup->set_position(files->get_screen_position() + p_pos); file_list_popup->reset_size(); @@ -3905,7 +3901,9 @@ FileSystemDock::FileSystemDock() { add_child(split_box); tree = memnew(FileSystemTree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_hide_root(true); SET_DRAG_FORWARDING_GCD(tree, FileSystemDock); tree->set_allow_rmb_select(true); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 15a43dc6f2..b950075928 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -332,7 +332,7 @@ private: uint64_t modified_time = 0; bool operator<(const FileInfo &fi) const { - return NaturalNoCaseComparator()(name, fi.name); + return FileNoCaseComparator()(name, fi.name); } }; diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 965cb39df3..3bddc91b81 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -566,6 +566,7 @@ void FindInFilesDialog::_bind_methods() { //----------------------------------------------------------------------------- const char *FindInFilesPanel::SIGNAL_RESULT_SELECTED = "result_selected"; const char *FindInFilesPanel::SIGNAL_FILES_MODIFIED = "files_modified"; +const char *FindInFilesPanel::SIGNAL_CLOSE_BUTTON_CLICKED = "close_button_clicked"; FindInFilesPanel::FindInFilesPanel() { _finder = memnew(FindInFiles); @@ -611,10 +612,16 @@ FindInFilesPanel::FindInFilesPanel() { _cancel_button->hide(); hbc->add_child(_cancel_button); + _close_button = memnew(Button); + _close_button->set_text(TTR("Close")); + _close_button->connect("pressed", callable_mp(this, &FindInFilesPanel::_on_close_button_clicked)); + hbc->add_child(_close_button); + vbc->add_child(hbc); } _results_display = memnew(Tree); + _results_display->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); _results_display->set_v_size_flags(SIZE_EXPAND_FILL); _results_display->connect("item_selected", callable_mp(this, &FindInFilesPanel::_on_result_selected)); _results_display->connect("item_edited", callable_mp(this, &FindInFilesPanel::_on_item_edited)); @@ -842,6 +849,10 @@ void FindInFilesPanel::_on_cancel_button_clicked() { stop_search(); } +void FindInFilesPanel::_on_close_button_clicked() { + emit_signal(SNAME(SIGNAL_CLOSE_BUTTON_CLICKED)); +} + void FindInFilesPanel::_on_result_selected() { TreeItem *item = _results_display->get_selected(); HashMap<TreeItem *, Result>::Iterator E = _result_items.find(item); @@ -1009,4 +1020,6 @@ void FindInFilesPanel::_bind_methods() { PropertyInfo(Variant::INT, "end"))); ADD_SIGNAL(MethodInfo(SIGNAL_FILES_MODIFIED, PropertyInfo(Variant::STRING, "paths"))); + + ADD_SIGNAL(MethodInfo(SIGNAL_CLOSE_BUTTON_CLICKED)); } diff --git a/editor/find_in_files.h b/editor/find_in_files.h index 7885931514..ac336b4e35 100644 --- a/editor/find_in_files.h +++ b/editor/find_in_files.h @@ -159,6 +159,7 @@ class FindInFilesPanel : public Control { public: static const char *SIGNAL_RESULT_SELECTED; static const char *SIGNAL_FILES_MODIFIED; + static const char *SIGNAL_CLOSE_BUTTON_CLICKED; FindInFilesPanel(); @@ -180,6 +181,7 @@ private: void _on_finished(); void _on_refresh_button_clicked(); void _on_cancel_button_clicked(); + void _on_close_button_clicked(); void _on_result_selected(); void _on_item_edited(); void _on_replace_text_changed(const String &text); @@ -207,6 +209,7 @@ private: Label *_status_label = nullptr; Button *_refresh_button = nullptr; Button *_cancel_button = nullptr; + Button *_close_button = nullptr; ProgressBar *_progress_bar = nullptr; HashMap<String, TreeItem *> _file_items; HashMap<TreeItem *, Result> _result_items; diff --git a/editor/group_settings_editor.cpp b/editor/group_settings_editor.cpp index da169b36b2..45da907d8a 100644 --- a/editor/group_settings_editor.cpp +++ b/editor/group_settings_editor.cpp @@ -31,7 +31,6 @@ #include "group_settings_editor.h" #include "core/config/project_settings.h" -#include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" @@ -521,6 +520,7 @@ GroupSettingsEditor::GroupSettingsEditor() { hbc->add_child(add_button); tree = memnew(Tree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_hide_root(true); tree->set_select_mode(Tree::SELECT_SINGLE); tree->set_allow_reselect(true); diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index ba7b627207..902e166fd9 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -842,6 +842,7 @@ GroupsEditor::GroupsEditor() { hbc->add_child(filter); tree = memnew(Tree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_hide_root(true); tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->set_allow_rmb_select(true); diff --git a/editor/gui/editor_file_dialog.cpp b/editor/gui/editor_file_dialog.cpp index fe86ac442b..df1f026f78 100644 --- a/editor/gui/editor_file_dialog.cpp +++ b/editor/gui/editor_file_dialog.cpp @@ -874,8 +874,8 @@ void EditorFileDialog::update_file_list() { item = dir_access->get_next(); } - dirs.sort_custom<NaturalNoCaseComparator>(); - files.sort_custom<NaturalNoCaseComparator>(); + dirs.sort_custom<FileNoCaseComparator>(); + files.sort_custom<FileNoCaseComparator>(); while (!dirs.is_empty()) { const String &dir_name = dirs.front()->get(); diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp index fab5784f16..c0a704105c 100644 --- a/editor/gui/editor_spin_slider.cpp +++ b/editor/gui/editor_spin_slider.cpp @@ -238,28 +238,28 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) { void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventKey> k = p_event; if (k.is_valid() && k->is_pressed() && !is_read_only()) { - double step = get_step(); - if (step < 1) { - double divisor = 1.0 / get_step(); - - if (trunc(divisor) == divisor) { - step = 1.0; - } - } - - if (k->is_command_or_control_pressed()) { - step *= 100.0; - } else if (k->is_shift_pressed()) { - step *= 10.0; - } else if (k->is_alt_pressed()) { - step *= 0.1; - } - Key code = k->get_keycode(); switch (code) { case Key::UP: case Key::DOWN: { + double step = get_step(); + if (step < 1) { + double divisor = 1.0 / step; + + if (trunc(divisor) == divisor) { + step = 1.0; + } + } + + if (k->is_command_or_control_pressed()) { + step *= 100.0; + } else if (k->is_shift_pressed()) { + step *= 10.0; + } else if (k->is_alt_pressed()) { + step *= 0.1; + } + _evaluate_input_text(); double last_value = get_value(); @@ -267,12 +267,6 @@ void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) { step *= -1; } set_value(last_value + step); - double new_value = get_value(); - - double clamp_value = CLAMP(new_value, get_min(), get_max()); - if (new_value != clamp_value) { - set_value(clamp_value); - } value_input_dirty = true; set_process_internal(true); diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp index 248678662c..0dd75ea033 100644 --- a/editor/gui/scene_tree_editor.cpp +++ b/editor/gui/scene_tree_editor.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/object/script_language.h" +#include "editor/editor_dock_manager.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" @@ -44,7 +45,6 @@ #include "editor/themes/editor_scale.h" #include "scene/gui/flow_container.h" #include "scene/gui/label.h" -#include "scene/gui/tab_container.h" #include "scene/gui/texture_rect.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" @@ -163,18 +163,15 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i set_selected(n); - TabContainer *tab_container = Object::cast_to<TabContainer>(NodeDock::get_singleton()->get_parent()); - NodeDock::get_singleton()->get_parent()->call("set_current_tab", tab_container->get_tab_idx_from_control(NodeDock::get_singleton())); + EditorDockManager::get_singleton()->focus_dock(NodeDock::get_singleton()); NodeDock::get_singleton()->show_connections(); - } else if (p_id == BUTTON_GROUPS) { editor_selection->clear(); editor_selection->add_node(n); set_selected(n); - TabContainer *tab_container = Object::cast_to<TabContainer>(NodeDock::get_singleton()->get_parent()); - NodeDock::get_singleton()->get_parent()->call("set_current_tab", tab_container->get_tab_idx_from_control(NodeDock::get_singleton())); + EditorDockManager::get_singleton()->focus_dock(NodeDock::get_singleton()); NodeDock::get_singleton()->show_groups(); } else if (p_id == BUTTON_UNIQUE) { undo_redo->create_action(TTR("Disable Scene Unique Name")); @@ -928,6 +925,27 @@ void SceneTreeEditor::_notification(int p_what) { _update_tree(); } break; + + case NOTIFICATION_VISIBILITY_CHANGED: { + if (is_visible()) { + TreeItem *item = nullptr; + if (selected) { + // Scroll to selected node. + item = _find(tree->get_root(), selected->get_path()); + } else if (marked.size() == 1) { + // Scroll to a single marked node. + Node *marked_node = *marked.begin(); + if (marked_node) { + item = _find(tree->get_root(), marked_node->get_path()); + } + } + + if (item) { + // Must wait until tree is properly sized before scrolling. + callable_mp(tree, &Tree::scroll_to_item).call_deferred(item, true); + } + } + } break; } } @@ -1515,6 +1533,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope } tree = memnew(Tree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_anchor(SIDE_RIGHT, ANCHOR_END); tree->set_anchor(SIDE_BOTTOM, ANCHOR_END); tree->set_begin(Point2(0, p_label ? 18 : 0)); @@ -1569,7 +1588,9 @@ SceneTreeEditor::~SceneTreeEditor() { /******** DIALOG *********/ -void SceneTreeDialog::popup_scenetree_dialog() { +void SceneTreeDialog::popup_scenetree_dialog(Node *p_selected_node, Node *p_marked_node, bool p_marked_node_selectable, bool p_marked_node_children_selectable) { + get_scene_tree()->set_marked(p_marked_node, p_marked_node_selectable, p_marked_node_children_selectable); + get_scene_tree()->set_selected(p_selected_node); popup_centered_clamped(Size2(350, 700) * EDSCALE); } diff --git a/editor/gui/scene_tree_editor.h b/editor/gui/scene_tree_editor.h index a869e867b8..c1abdcef8b 100644 --- a/editor/gui/scene_tree_editor.h +++ b/editor/gui/scene_tree_editor.h @@ -157,8 +157,8 @@ public: void set_as_scene_tree_dock(); void set_display_foreign_nodes(bool p_display); - void set_marked(const HashSet<Node *> &p_marked, bool p_selectable = false, bool p_children_selectable = true); - void set_marked(Node *p_marked, bool p_selectable = false, bool p_children_selectable = true); + void set_marked(const HashSet<Node *> &p_marked, bool p_selectable = true, bool p_children_selectable = true); + void set_marked(Node *p_marked, bool p_selectable = true, bool p_children_selectable = true); void set_selected(Node *p_node, bool p_emit_selected = true); Node *get_selected(); void set_can_rename(bool p_can_rename) { can_rename = p_can_rename; } @@ -201,7 +201,7 @@ protected: static void _bind_methods(); public: - void popup_scenetree_dialog(); + void popup_scenetree_dialog(Node *p_selected_node = nullptr, Node *p_marked_node = nullptr, bool p_marked_node_selectable = true, bool p_marked_node_children_selectable = true); void set_valid_types(const Vector<StringName> &p_valid); SceneTreeEditor *get_scene_tree() { return tree; } diff --git a/editor/icons/AnimationAutoFit.svg b/editor/icons/AnimationAutoFit.svg new file mode 100644 index 0000000000..fdde20d464 --- /dev/null +++ b/editor/icons/AnimationAutoFit.svg @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m15.477 0.99862v14h-2.1017v-14zm-14.954 14.003v-14h2.1017v14zm11.946-6.823-3.5-3v6zm-8.9343 0.023985 3.5 3v-2h2.1464l0.00376-2h-2.1501v-2zm4.6005-7.0028c8.9077 15.09 8.9077 15.09 0 0zm-0.23085 14.003c-8.9077-15.09-8.9077-15.09 0 0z" fill="#e0e0e0" stroke-width="1.0251"/></svg> diff --git a/editor/icons/AnimationAutoFitBezier.svg b/editor/icons/AnimationAutoFitBezier.svg new file mode 100644 index 0000000000..1a79255c19 --- /dev/null +++ b/editor/icons/AnimationAutoFitBezier.svg @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="m12.469 8.1784-3.5-3v6zm-8.9343 0.023985 3.5 3v-2h2.1464l0.00376-2h-2.1501v-2zm9.4532 0.53338c-10.763 8.9077-10.763 8.9077 0 0zm0 7h-9.9859v-2h9.9859zm-9.9806-8.5564c10.763-8.9077 10.763-8.9077 0 0zm0-7h9.9859v2h-9.9859zm5.4684 2.8277c8.9077 10.763 8.9077 10.763 0 0zm7 0v9.9859h-2v-9.9859zm-7.8862 9.9859c-8.9077-10.763-8.9077-10.763 0 0zm-7 0v-9.9859h2v9.9859z" fill="#e0e0e0"/></svg> diff --git a/editor/icons/DefaultProjectIcon.svg b/editor/icons/DefaultProjectIcon.svg index b370ceb727..3fe4f4ae8c 100644 --- a/editor/icons/DefaultProjectIcon.svg +++ b/editor/icons/DefaultProjectIcon.svg @@ -1 +1 @@ -<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg> +<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg> diff --git a/editor/icons/Godot.svg b/editor/icons/Godot.svg index 96f4943659..588b7e612a 100644 --- a/editor/icons/Godot.svg +++ b/editor/icons/Godot.svg @@ -1 +1 @@ -<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g transform="scale(.015625)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg> +<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g transform="scale(.015625)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg> diff --git a/editor/icons/GodotFile.svg b/editor/icons/GodotFile.svg index ef9d541c39..13a364ece2 100644 --- a/editor/icons/GodotFile.svg +++ b/editor/icons/GodotFile.svg @@ -1 +1 @@ -<svg height="64" viewBox="0 0 64 64" width="64" xmlns="http://www.w3.org/2000/svg"><g transform="scale(.03) translate(555 725)"><path d="M105 673v33q407 354 814 0v-33z" fill="#fff"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z" fill="#fff"/><g fill="#fefefe"><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g><path d="M14 5a4 4 0 0 0-4 4v46a4 4 0 0 0 4 4h36a4 4 0 0 0 4-4V22a1 1 0 0 0-.285-.707l-16-16A1 1 0 0 0 37 5zm0 2h22v12a4 4 0 0 0 4 4h12v32a2 2 0 0 1-2 2H14a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2z" fill="#fff" fill-opacity=".6"/></svg> +<svg height="64" viewBox="0 0 64 64" width="64" xmlns="http://www.w3.org/2000/svg"><g transform="scale(.03) translate(555 725)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g><path d="M14 5a4 4 0 0 0-4 4v46a4 4 0 0 0 4 4h36a4 4 0 0 0 4-4V22a1 1 0 0 0-.285-.707l-16-16A1 1 0 0 0 37 5zm0 2h22v12a4 4 0 0 0 4 4h12v32a2 2 0 0 1-2 2H14a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2z" fill="#fff" fill-opacity=".6"/></svg> diff --git a/editor/icons/GodotMonochrome.svg b/editor/icons/GodotMonochrome.svg index aa46eb8542..a8e2d38986 100644 --- a/editor/icons/GodotMonochrome.svg +++ b/editor/icons/GodotMonochrome.svg @@ -1 +1 @@ -<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" transform="scale(.01563)"><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69zm378-192c3-34 55-34 58 0v86c-3 34-55 34-58 0zm152 12a90 90 0 0 1 180 0 90 90 0 0 1-180 0zm-426 0a90 90 0 0 1 180 0 90 90 0 0 1-180 0"/><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg> +<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="#fff" transform="scale(.01563)"><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69zM725 436a90 90 0 0 1 0 180 90 90 0 0 1 0-180zM299 436a90 90 0 0 1 0 180 90 90 0 0 1 0-180zM483 514c0-34 58-34 58 0v86c0 34-58 34-58 0z"/><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg> diff --git a/editor/icons/Logo.svg b/editor/icons/Logo.svg index a32a8f71c2..647262559f 100644 --- a/editor/icons/Logo.svg +++ b/editor/icons/Logo.svg @@ -1 +1 @@ -<svg height="69" viewBox="0 0 187 69" width="187" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M96.116 30.781c-1.847-.029-3.96.356-3.96.356v3.605h2.125l-.024 1.606c0 .595-.59.894-1.767.894-1.178 0-2.218-.499-3.12-1.493-.906-.997-1.356-2.453-1.356-4.372 0-1.923.44-3.34 1.32-4.255.88-.914 2.03-1.372 3.448-1.372a6.32 6.32 0 0 1 1.852.292c.64.194 1.069.376 1.287.546.217.176.422.258.618.258.194 0 .507-.226.94-.685.436-.457.826-1.15 1.169-2.074.342-.929.514-1.64.514-2.145 0-.501-.011-.847-.034-1.029-.48-.526-1.366-.942-2.66-1.252-1.29-.31-2.737-.463-4.338-.463-3.522 0-6.276 1.11-8.265 3.327-1.991 2.219-2.985 5.099-2.985 8.644 0 4.163 1.017 7.318 3.051 9.467 2.037 2.15 4.712 3.223 8.028 3.223 1.783 0 3.366-.154 4.75-.463 1.384-.307 2.304-.623 2.762-.943l.137-10.734c0-.623-1.646-.906-3.492-.938zm17.018-5.01c-1.098 0-2.016.504-2.762 1.509-.742 1.006-1.114 2.417-1.114 4.234 0 1.82.354 3.215 1.064 4.186.709.974 1.64 1.46 2.795 1.46 1.154 0 2.092-.492 2.812-1.478.72-.982 1.082-2.388 1.082-4.218s-.373-3.237-1.116-4.22c-.742-.982-1.663-1.473-2.761-1.473m-.017 18.074c-3.212 0-5.832-1.05-7.856-3.153-2.022-2.104-3.033-5.174-3.033-9.21 0-4.038 1.022-7.096 3.068-9.178 2.047-2.079 4.688-3.12 7.924-3.12 3.235 0 5.849 1.022 7.837 3.072 1.991 2.045 2.985 5.146 2.985 9.294 0 4.15-1.017 7.237-3.053 9.263-2.036 2.021-4.659 3.032-7.872 3.032M133.71 26.01v10.26c0 .478.035.78.104.907.068.126.274.189.616.189 1.26 0 2.213-.47 2.865-1.408.653-.936.976-2.496.976-4.68 0-2.185-.338-3.609-1.01-4.27-.675-.663-1.745-.998-3.208-.998zm-6.585 15.917V21.348c0-.573.142-1.024.43-1.359.285-.33.656-.497 1.114-.497h5.728c3.635 0 6.397.917 8.281 2.747 1.888 1.829 2.832 4.708 2.832 8.642 0 8.415-3.59 12.622-10.772 12.622h-5.864c-1.165 0-1.75-.524-1.75-1.577m31.623-16.155c-1.098 0-2.02.504-2.763 1.509-.742 1.006-1.113 2.417-1.113 4.234 0 1.82.355 3.215 1.063 4.186.708.974 1.64 1.46 2.795 1.46s2.093-.492 2.813-1.478c.72-.982 1.081-2.388 1.081-4.218s-.372-3.237-1.115-4.22c-.743-.982-1.663-1.473-2.761-1.473m-.018 18.074c-3.213 0-5.83-1.05-7.854-3.153-2.024-2.104-3.036-5.174-3.036-9.21 0-4.038 1.023-7.096 3.069-9.178 2.048-2.079 4.688-3.12 7.925-3.12 3.236 0 5.847 1.022 7.837 3.072 1.99 2.045 2.984 5.146 2.984 9.294 0 4.15-1.017 7.237-3.053 9.263-2.035 2.021-4.66 3.032-7.872 3.032m23.773-.842c0 .454-1.13.685-3.395.685-2.263 0-3.397-.23-3.397-.685v-17.22h-4.115c-.39 0-.663-.525-.823-1.58a11.366 11.366 0 0 1-.101-1.542c0-.524.032-1.04.1-1.543.16-1.05.435-1.58.824-1.58h14.92c.39 0 .663.529.825 1.58a11.642 11.642 0 0 1 0 3.086c-.162 1.054-.435 1.579-.824 1.579h-4.014z"/><path fill="#e0e0e0" d="M88.866 57.973c-.19.39-.538.746-1.048 1.069-.51.324-1.156.486-1.942.486-1.036 0-1.87-.327-2.503-.987-.63-.655-.947-1.6-.947-2.833v-3.073c0-1.206.298-2.13.895-2.776.596-.64 1.395-.966 2.392-.966.974 0 1.73.257 2.265.764.533.51.813 1.22.837 2.128l-.013.04h-.796c-.028-.695-.23-1.232-.61-1.612-.378-.376-.94-.566-1.683-.566-.751 0-1.347.254-1.782.765-.435.508-.651 1.246-.651 2.215v3.091c0 1.005.234 1.771.702 2.3.468.523 1.098.785 1.894.785.581 0 1.049-.103 1.398-.313.351-.208.595-.462.732-.763v-2.692h-2.144v-.748h3.004zm3.95.789c.472 0 .892-.134 1.26-.406.367-.274.625-.62.777-1.04v-1.661H93.49c-.58 0-1.045.164-1.393.493a1.604 1.604 0 0 0-.522 1.22c0 .41.108.746.327 1.006.218.26.523.388.915.388m2.165.62a20.049 20.049 0 0 1-.097-.652 4.392 4.392 0 0 1-.03-.518 3.003 3.003 0 0 1-.906.945c-.37.25-.783.373-1.238.373-.636 0-1.124-.197-1.47-.591-.344-.396-.518-.93-.518-1.603 0-.712.25-1.283.751-1.707.501-.424 1.182-.636 2.038-.636h1.342v-.943c0-.543-.138-.97-.41-1.28-.278-.304-.66-.459-1.152-.459-.458 0-.836.146-1.133.441a1.457 1.457 0 0 0-.442 1.078l-.797-.007-.014-.042c-.022-.578.197-1.09.659-1.544.46-.452 1.051-.677 1.77-.677.71 0 1.282.216 1.719.646.433.435.651 1.055.651 1.86v3.767c0 .274.013.54.037.795a5.02 5.02 0 0 0 .127.753zm3.415-7.698.072 1.191a2.46 2.46 0 0 1 .808-.989c.336-.23.732-.345 1.186-.345.464 0 .855.135 1.17.408.316.272.55.684.697 1.237.19-.51.457-.914.805-1.207.348-.292.77-.438 1.259-.438.673 0 1.196.272 1.566.818.372.546.557 1.385.557 2.518v4.485h-.857v-4.5c0-.942-.13-1.605-.384-1.987-.255-.381-.62-.574-1.093-.574-.497 0-.885.21-1.165.637-.278.427-.449.96-.511 1.605v4.82h-.853v-4.497c0-.92-.13-1.578-.393-1.97a1.246 1.246 0 0 0-1.096-.59c-.449 0-.811.138-1.083.409-.273.272-.467.645-.585 1.119v5.528h-.853v-7.679zm12.414.61c-.534 0-.973.243-1.317.73s-.522 1.089-.536 1.805h3.542v-.328c0-.634-.148-1.162-.446-1.58-.3-.42-.713-.627-1.243-.627m.12 7.218c-.827 0-1.504-.311-2.03-.933-.525-.621-.787-1.415-.787-2.382V54.92c0-.969.263-1.777.79-2.42.528-.64 1.163-.959 1.907-.959.804 0 1.428.286 1.872.858.447.573.67 1.343.67 2.31v.842h-4.395v.639c0 .743.178 1.362.532 1.856.355.495.837.74 1.442.74.42 0 .785-.073 1.09-.22a2.246 2.246 0 0 0 .783-.632l.349.604a2.51 2.51 0 0 1-.9.708c-.365.175-.807.265-1.322.265m9.375-7.218c-.536 0-.976.243-1.32.73-.341.487-.52 1.089-.535 1.805h3.543V54.5c0-.634-.148-1.162-.447-1.58-.298-.42-.711-.627-1.241-.627m.12 7.218c-.829 0-1.505-.311-2.03-.933-.526-.621-.79-1.415-.79-2.382V54.92c0-.969.265-1.777.79-2.42.53-.64 1.166-.959 1.91-.959.803 0 1.428.286 1.872.858.445.573.668 1.343.668 2.31v.842h-4.395v.639c0 .743.179 1.362.535 1.856.353.495.833.74 1.44.74.42 0 .785-.073 1.088-.22a2.268 2.268 0 0 0 .787-.632l.347.604a2.51 2.51 0 0 1-.9.708c-.365.175-.807.265-1.322.265m4.684-7.828.07 1.269c.204-.45.475-.8.814-1.044a1.972 1.972 0 0 1 1.19-.368c.685 0 1.211.254 1.576.763.369.51.551 1.3.551 2.374v4.684h-.858v-4.677c0-.877-.128-1.49-.384-1.845-.254-.356-.627-.533-1.113-.533-.436 0-.802.142-1.095.43-.294.285-.514.665-.66 1.144v5.481h-.852v-7.678zm6.72 4.523c0 .78.148 1.4.447 1.86.296.466.747.696 1.348.696.412 0 .759-.11 1.044-.335.283-.225.507-.538.673-.935V53.69c-.16-.41-.378-.74-.655-.994-.276-.25-.626-.377-1.047-.377-.6 0-1.054.262-1.355.786-.304.526-.455 1.211-.455 2.053zm-.86-1.05c0-1.087.22-1.961.66-2.62.439-.656 1.048-.984 1.825-.984.43 0 .81.105 1.132.316.324.207.592.51.807.895l.083-1.068h.723v7.686c0 .983-.228 1.746-.686 2.286-.46.537-1.111.81-1.953.81-.303 0-.628-.048-.976-.14a3.95 3.95 0 0 1-.927-.365l.236-.748a2.85 2.85 0 0 0 .774.347 3.066 3.066 0 0 0 .879.124c.61 0 1.063-.196 1.355-.587.293-.396.44-.969.44-1.727v-.93a2.325 2.325 0 0 1-.802.795 2.15 2.15 0 0 1-1.1.276c-.771 0-1.376-.302-1.813-.906-.438-.603-.658-1.407-.658-2.41zm8.12 4.226h-.862v-7.7h.862zm0-9.892h-.862v-1.213h.862zm2.782 2.193.07 1.269c.205-.45.475-.8.813-1.044a1.982 1.982 0 0 1 1.19-.368c.686 0 1.214.254 1.58.763.368.51.549 1.3.549 2.374v4.684h-.858v-4.677c0-.877-.129-1.49-.384-1.845-.256-.356-.626-.533-1.114-.533-.436 0-.8.142-1.093.43-.294.285-.514.665-.66 1.144v5.481h-.853v-7.678zm8.499.61c-.536 0-.975.243-1.317.73-.343.487-.522 1.089-.537 1.805h3.543V54.5c0-.634-.148-1.162-.446-1.58-.298-.42-.712-.627-1.243-.627m.122 7.218c-.83 0-1.506-.311-2.03-.933-.526-.621-.788-1.415-.788-2.382V54.92c0-.969.263-1.777.79-2.42.528-.64 1.163-.959 1.906-.959.804 0 1.43.286 1.875.858.444.573.667 1.343.667 2.31v.842h-4.396v.639c0 .743.18 1.362.534 1.856.354.495.835.74 1.442.74.42 0 .783-.073 1.087-.22a2.254 2.254 0 0 0 .787-.632l.348.604a2.53 2.53 0 0 1-.9.708c-.365.175-.807.265-1.322.265"/><g fill="#fefefe"><path d="M4.901 46.266v2.4q29.597 25.743 59.194 0v-2.4z"/><path fill="#478cbf" d="m4.901 46.266 11.054 1.018q.872.073 1.09 1.018l.291 4.872 9.6.728.581-4.436q.146-.8 1.091-1.091h11.78q.946.29 1.091 1.09l.582 4.437 9.6-.728.29-4.872q.218-.945 1.091-1.018l11.053-1.018V28.377q2.182-2.836 4.073-5.89-2.545-4.29-6.036-7.854-3.127 1.454-5.963 3.418-2.909-2.69-6.4-4.654.51-3.71.582-7.418-4.29-2.036-8.944-3.054-1.891 3.127-3.345 6.472-3.564-.509-7.127 0-1.454-3.345-3.345-6.472-4.654 1.018-8.945 3.054.073 3.709.582 7.418-3.49 1.963-6.4 4.654-2.835-1.964-5.962-3.418-3.49 3.563-6.036 7.854 1.89 3.054 4.072 5.89zm0 2.4v2.836c0 20.07 59.122 20.07 59.122 0v-2.836l-9.745.872-.363 5.018q-.146.727-1.018.946l-11.781.8q-.873 0-1.164-.8l-.727-4.727h-9.453l-.728 4.727q-.29.8-1.163.8l-11.78-.8q-.873-.219-1.019-.946l-.363-5.018z"/><path d="M32.39 40.958c.218 2.472 4 2.472 4.217 0v-6.254c-.218-2.473-4-2.473-4.218 0z"/><circle cx="49.988" cy="35.576" r="6.545"/><circle cx="18.988" cy="35.576" r="6.545"/></g><g fill="#414042"><circle cx="19.591" cy="36.013" r="4.363"/><circle cx="49.406" cy="36.013" r="4.363"/></g></svg> +<svg height="69" viewBox="0 0 187 69" width="187" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M96.116 30.781c-1.847-.029-3.96.356-3.96.356v3.605h2.125l-.024 1.606q0 .893-1.767.894-1.767-.001-3.12-1.493-1.358-1.495-1.356-4.372 0-2.884 1.32-4.255 1.32-1.372 3.448-1.372a6.3 6.3 0 0 1 1.852.292q.96.291 1.287.546c.217.176.422.258.618.258q.29.002.94-.685.654-.687 1.169-2.074c.342-.929.514-1.64.514-2.145 0-.501-.011-.847-.034-1.029q-.72-.788-2.66-1.252-1.936-.464-4.338-.463-5.282 0-8.265 3.327-2.986 3.328-2.985 8.644 0 6.244 3.051 9.467 3.055 3.224 8.028 3.223 2.674 0 4.75-.463 2.075-.462 2.762-.943l.137-10.734c0-.623-1.646-.906-3.492-.938m17.018-5.01q-1.645 0-2.762 1.509-1.114 1.509-1.114 4.234 0 2.73 1.064 4.186 1.063 1.46 2.795 1.46t2.812-1.478q1.081-1.473 1.082-4.218c.001-2.745-.373-3.237-1.116-4.22q-1.114-1.473-2.761-1.473m-.017 18.074q-4.819 0-7.856-3.153-3.033-3.156-3.033-9.21 0-6.056 3.068-9.178 3.07-3.12 7.924-3.12 4.854-.002 7.837 3.072c1.991 2.045 2.985 5.146 2.985 9.294q0 6.224-3.053 9.263-3.053 3.032-7.872 3.032M133.71 26.01v10.26q0 .717.104.907.103.189.616.189 1.888 0 2.865-1.408.978-1.404.976-4.68-.001-3.278-1.01-4.27-1.013-.996-3.208-.998zm-6.585 15.917V21.348q-.001-.858.43-1.359.427-.496 1.114-.497h5.728q5.454.001 8.281 2.747 2.832 2.742 2.832 8.642 0 12.622-10.772 12.622h-5.864q-1.749.001-1.75-1.577m31.623-16.155q-1.648 0-2.763 1.509-1.113 1.509-1.113 4.234 0 2.73 1.063 4.186 1.062 1.46 2.795 1.46c1.733 0 2.093-.492 2.813-1.478q1.08-1.473 1.081-4.218c.001-2.745-.372-3.237-1.115-4.22q-1.114-1.473-2.761-1.473m-.018 18.074q-4.819 0-7.854-3.153-3.036-3.156-3.036-9.21 0-6.056 3.069-9.178 3.07-3.12 7.925-3.12 4.853-.002 7.837 3.072c1.99 2.045 2.984 5.146 2.984 9.294q0 6.224-3.053 9.263-3.053 3.032-7.872 3.032m23.773-.842c0 .454-1.13.685-3.395.685q-3.396-.001-3.397-.685v-17.22h-4.115q-.584.001-.823-1.58a11 11 0 0 1-.101-1.542q-.001-.787.1-1.543c.16-1.05.435-1.58.824-1.58h14.92q.584.002.825 1.58a11.6 11.6 0 0 1 0 3.086q-.242 1.58-.824 1.579h-4.014z"/><path fill="#e0e0e0" d="M88.866 57.973q-.284.585-1.048 1.069-.764.486-1.942.486-1.554.002-2.503-.987-.946-.983-.947-2.833v-3.073q0-1.808.895-2.776c.596-.64 1.395-.966 2.392-.966q1.462.002 2.265.764.8.765.837 2.128l-.013.04h-.796q-.041-1.042-.61-1.612-.568-.565-1.683-.566-1.128 0-1.782.765-.652.762-.651 2.215v3.091q0 1.507.702 2.3.701.785 1.894.785.873.001 1.398-.313.526-.312.732-.763v-2.692h-2.144v-.748h3.004zm3.95.789q.708.001 1.26-.406.55-.41.777-1.04v-1.661H93.49q-.87 0-1.393.493a1.6 1.6 0 0 0-.522 1.22q0 .616.327 1.006.327.389.915.388m2.165.62a20 20 0 0 1-.097-.652 4 4 0 0 1-.03-.518 3 3 0 0 1-.906.945q-.555.374-1.238.373-.952 0-1.47-.591-.517-.594-.518-1.603 0-1.07.751-1.707.753-.636 2.038-.636h1.342v-.943q-.001-.815-.41-1.28-.415-.457-1.152-.459-.687 0-1.133.441a1.46 1.46 0 0 0-.442 1.078l-.797-.007-.014-.042q-.033-.865.659-1.544.69-.678 1.77-.677 1.064 0 1.719.646.65.653.651 1.86v3.767q0 .412.037.795a5 5 0 0 0 .127.753zm3.415-7.698.072 1.191a2.46 2.46 0 0 1 .808-.989q.505-.345 1.186-.345.697 0 1.17.408.475.408.697 1.237.284-.766.805-1.207.524-.438 1.259-.438 1.01 0 1.566.818.557.819.557 2.518v4.485h-.857v-4.5q-.001-1.413-.384-1.987-.383-.573-1.093-.574-.745-.002-1.165.637-.417.639-.511 1.605v4.82h-.853v-4.497q0-1.381-.393-1.97a1.25 1.25 0 0 0-1.096-.59q-.674.001-1.083.409t-.585 1.119v5.528h-.853v-7.679zm12.414.61q-.801 0-1.317.73c-.516.73-.522 1.089-.536 1.805h3.542v-.328q0-.952-.446-1.58-.449-.628-1.243-.627m.12 7.218q-1.24 0-2.03-.933-.787-.931-.787-2.382V54.92q0-1.454.79-2.42.792-.96 1.907-.959 1.206 0 1.872.858.67.86.67 2.31v.842h-4.395v.639q0 1.115.532 1.856.534.741 1.442.74.631 0 1.09-.22a2.25 2.25 0 0 0 .783-.632l.349.604a2.5 2.5 0 0 1-.9.708q-.548.264-1.322.265m9.375-7.218q-.804 0-1.32.73-.512.73-.535 1.805h3.543V54.5q0-.952-.447-1.58-.446-.629-1.241-.627m.12 7.218q-1.243 0-2.03-.933-.79-.932-.79-2.382V54.92q.001-1.454.79-2.42.794-.96 1.91-.959 1.205 0 1.872.858.668.86.668 2.31v.842h-4.395v.639q0 1.115.535 1.856.53.741 1.44.74.632 0 1.088-.22a2.3 2.3 0 0 0 .787-.632l.347.604a2.5 2.5 0 0 1-.9.708q-.548.264-1.322.265m4.684-7.828.07 1.269q.306-.677.814-1.044a1.97 1.97 0 0 1 1.19-.368q1.028 0 1.576.763.552.764.551 2.374v4.684h-.858v-4.677q0-1.314-.384-1.845-.382-.534-1.113-.533-.655-.001-1.095.43-.441.426-.66 1.144v5.481h-.852v-7.678zm6.72 4.523q0 1.17.447 1.86.445.697 1.348.696.617.001 1.044-.335.424-.338.673-.935V53.69q-.24-.614-.655-.994-.415-.376-1.047-.377-.902 0-1.355.786-.456.79-.455 2.053zm-.86-1.05q0-1.631.66-2.62.659-.984 1.825-.984c.43 0 .81.105 1.132.316.324.207.592.51.807.895l.083-1.068h.723v7.686q0 1.475-.686 2.286c-.46.537-1.111.81-1.953.81q-.454-.001-.976-.14a4 4 0 0 1-.927-.365l.236-.748a2.9 2.9 0 0 0 .774.347 3 3 0 0 0 .879.124q.916 0 1.355-.587.44-.592.44-1.727v-.93a2.3 2.3 0 0 1-.802.795 2.15 2.15 0 0 1-1.1.276q-1.157 0-1.813-.906-.657-.905-.658-2.41zm8.12 4.226h-.862v-7.7h.862zm0-9.892h-.862v-1.213h.862zm2.782 2.193.07 1.269q.307-.677.813-1.044a2 2 0 0 1 1.19-.368q1.03 0 1.58.763.55.764.549 2.374v4.684h-.858v-4.677q0-1.314-.384-1.845-.383-.534-1.114-.533-.654-.001-1.093.43-.441.426-.66 1.144v5.481h-.853v-7.678zm8.499.61q-.804 0-1.317.73-.514.73-.537 1.805h3.543V54.5q0-.952-.446-1.58-.447-.629-1.243-.627m.122 7.218q-1.245 0-2.03-.933-.789-.932-.788-2.382V54.92q0-1.454.79-2.42.792-.96 1.906-.959 1.207 0 1.875.858.666.86.667 2.31v.842h-4.396v.639q.002 1.115.534 1.856.531.741 1.442.74.63 0 1.087-.22a2.25 2.25 0 0 0 .787-.632l.348.604a2.5 2.5 0 0 1-.9.708q-.548.264-1.322.265"/><g transform="scale(.0727) translate(-37-37)"><g fill="#fefefe"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg> diff --git a/editor/icons/TileMapLayer.svg b/editor/icons/TileMapLayer.svg index 1903a87e3b..90664dee03 100644 --- a/editor/icons/TileMapLayer.svg +++ b/editor/icons/TileMapLayer.svg @@ -1 +1 @@ -<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 7v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2zm3 0v2h2v-2z" fill="#8da5f3"/></svg>
\ No newline at end of file +<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2 6.25 3.375 8 4.75l1.75-1.375zm2.624 2.062-1.75 1.375 1.75 1.375 1.75-1.375Zm2.626 2.063L11.5 7.5l1.75 1.375L15 7.5ZM5.376 4.062l-1.75 1.375 1.75 1.375 1.75-1.375zM8 6.124 6.25 7.499 8 8.874l1.75-1.375zm2.626 2.063-1.75 1.375 1.75 1.375 1.75-1.375ZM2.75 6.125 1 7.5l1.75 1.375L4.5 7.5Zm2.624 2.062-1.75 1.375 1.75 1.375 1.75-1.375ZM8 10.25l-1.75 1.375L8 13l1.75-1.375z" fill="#8da5f3"/></svg>
\ No newline at end of file diff --git a/editor/icons/TitleBarLogo.svg b/editor/icons/TitleBarLogo.svg index 65bb367c61..82124de1f4 100644 --- a/editor/icons/TitleBarLogo.svg +++ b/editor/icons/TitleBarLogo.svg @@ -1 +1 @@ -<svg clip-rule="evenodd" fill-rule="evenodd" stroke-linejoin="round" viewBox="0 0 100 24" xmlns="http://www.w3.org/2000/svg"><path d="m40.122 11.514c-1.211-.019-2.597.234-2.597.234v2.364h1.393l-.015 1.052c0 .391-.387.587-1.159.587s-1.454-.328-2.045-.979c-.594-.654-.889-1.609-.889-2.867 0-1.261.288-2.19.865-2.79.577-.599 1.331-.899 2.261-.899.411.003.821.067 1.214.191.42.128.701.247.844.358.142.116.276.17.405.17.127 0 .332-.149.616-.45.286-.299.542-.754.767-1.359.224-.61.337-1.076.337-1.407 0-.328-.007-.555-.023-.674-.314-.345-.895-.618-1.744-.821-.845-.204-1.794-.304-2.844-.304-2.309 0-4.115.728-5.419 2.181-1.305 1.455-1.957 3.344-1.957 5.668 0 2.729.667 4.798 2.001 6.207 1.335 1.41 3.089 2.113 5.263 2.113 1.169 0 2.207-.101 3.114-.303.908-.202 1.511-.409 1.811-.619l.09-7.038c0-.408-1.079-.594-2.289-.615zm11.157-3.284c-.719 0-1.321.33-1.81.989-.487.66-.731 1.585-.731 2.776 0 1.193.232 2.108.698 2.745.465.638 1.075.957 1.832.957s1.372-.323 1.844-.969c.472-.644.709-1.566.709-2.766s-.244-2.122-.731-2.767c-.487-.643-1.091-.965-1.811-.965m-.011 11.85c-2.106 0-3.823-.689-5.15-2.067-1.326-1.38-1.989-3.393-1.989-6.039 0-2.647.67-4.652 2.011-6.017 1.343-1.364 3.074-2.046 5.196-2.046 2.121 0 3.835.67 5.138 2.014 1.306 1.341 1.957 3.374 1.957 6.094 0 2.721-.666 4.745-2.001 6.073-1.335 1.325-3.055 1.988-5.162 1.988m13.502-11.694v6.727c0 .314.023.512.068.595s.18.124.404.124c.826 0 1.451-.308 1.879-.923.428-.614.64-1.637.64-3.069s-.222-2.366-.663-2.799c-.442-.435-1.144-.655-2.103-.655zm-4.317 10.436v-13.492c0-.376.093-.672.282-.891.186-.217.43-.326.73-.326h3.756c2.383 0 4.194.601 5.429 1.801 1.238 1.199 1.857 3.087 1.857 5.666 0 5.517-2.354 8.276-7.063 8.276h-3.845c-.763 0-1.147-.344-1.147-1.034m20.734-10.592c-.72 0-1.325.33-1.812.989-.486.66-.73 1.585-.73 2.776 0 1.193.233 2.108.697 2.745.464.638 1.076.957 1.833.957s1.372-.323 1.844-.969c.472-.644.709-1.566.709-2.766s-.244-2.122-.731-2.767c-.487-.643-1.09-.965-1.81-.965m-.012 11.85c-2.107 0-3.823-.689-5.15-2.067-1.327-1.38-1.99-3.393-1.99-6.039 0-2.647.671-4.652 2.012-6.017 1.343-1.364 3.074-2.046 5.196-2.046s3.834.67 5.138 2.014c1.305 1.341 1.957 3.374 1.957 6.094 0 2.721-.667 4.745-2.002 6.073-1.334 1.325-3.055 1.988-5.161 1.988m15.587-.552c0 .298-.741.449-2.226.449-1.484 0-2.228-.151-2.228-.449v-11.29h-2.698c-.255 0-.434-.345-.539-1.036-.045-.335-.067-.673-.066-1.011 0-.344.021-.682.065-1.012.105-.688.285-1.036.54-1.036h9.783c.255 0 .434.347.541 1.036.089.671.089 1.352 0 2.023-.107.691-.286 1.036-.541 1.036h-2.631z" fill="#fff" fill-rule="nonzero"/><path d="m2.644 9.821v7.76c0 6.683 19.71 6.611 19.71-.072v-7.628c.485-.629.937-1.283 1.356-1.961-.565-.952-1.235-1.824-2.009-2.615-.695.323-1.356.702-1.986 1.138-.646-.597-1.356-1.114-2.131-1.55.113-.823.178-1.647.194-2.47-.952-.451-1.945-.79-2.978-1.017-.42.695-.791 1.413-1.114 2.155-.791-.112-1.582-.112-2.373 0-.323-.742-.694-1.46-1.114-2.155-1.033.227-2.026.566-2.979 1.017.017.824.081 1.647.194 2.47-.775.436-1.485.953-2.131 1.55-.629-.436-1.291-.815-1.985-1.138-.775.791-1.445 1.662-2.01 2.615.42.678.872 1.271 1.356 1.901z" fill="none" stroke="#fff" stroke-width="2"/><g fill="#fff" fill-rule="nonzero"><path d="m2.644 15.838 3.681.339c.193.016.315.129.363.339l.097 1.622 3.196.243.194-1.478c.032-.177.153-.298.363-.363h3.923c.21.064.331.186.363.363l.194 1.478 3.196-.243.097-1.622c.048-.21.169-.323.363-.339l3.68-.339-.024.799-3.244.29-.121 1.671c-.033.162-.146.267-.339.315l-3.923.267c-.194 0-.323-.089-.388-.267l-.242-1.574h-3.147l-.243 1.574c-.064.178-.193.267-.387.267l-3.922-.267c-.194-.048-.307-.153-.34-.315l-.121-1.671-3.269-.29z" stroke="#fff" stroke-linejoin="miter"/><path d="m11.801 13.556-.001-2.082c.073-.824 1.332-.824 1.405 0v2.082c-.072.823-1.332.823-1.404 0zm-4.463-3.735c1.203 0 2.18.976 2.18 2.179s-.977 2.179-2.18 2.179-2.179-.976-2.179-2.179.976-2.179 2.179-2.179zm10.322 0c1.203 0 2.18.976 2.18 2.179s-.977 2.179-2.18 2.179c-1.202 0-2.179-.976-2.179-2.179s.977-2.179 2.179-2.179z"/></g></svg> +<svg width="100" height="24" viewBox="0 0 100 24" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><path d="M40.122 11.514c-1.211-.019-2.597.234-2.597.234v2.364h1.393l-.015 1.052q0 .587-1.159.587c-1.159 0-1.454-.328-2.045-.979q-.89-.98-.889-2.867 0-1.89.865-2.79.866-.899 2.261-.899c.411.003.821.067 1.214.191q.63.192.844.358.212.172.405.17.19 0 .616-.45.43-.45.767-1.359c.224-.61.337-1.076.337-1.407a6 6 0 0 0-.023-.674q-.47-.517-1.744-.821-1.268-.305-2.844-.304-3.463 0-5.419 2.181-1.957 2.182-1.957 5.668 0 4.094 2.001 6.207 2.002 2.114 5.263 2.113 1.754 0 3.114-.303 1.361-.303 1.811-.619l.09-7.038c0-.408-1.079-.594-2.289-.615M51.279 8.23q-1.078 0-1.81.989-.73.99-.731 2.776 0 1.79.698 2.745.697.957 1.832.957c1.135 0 1.372-.323 1.844-.969q.709-.966.709-2.766c0-1.8-.244-2.122-.731-2.767q-.73-.965-1.811-.965m-.011 11.85q-3.16 0-5.15-2.067-1.989-2.07-1.989-6.039 0-3.97 2.011-6.017 2.014-2.046 5.196-2.046 3.183-.001 5.138 2.014 1.958 2.013 1.957 6.094t-2.001 6.073q-2.002 1.988-5.162 1.988M64.77 8.386v6.727q0 .47.068.595c.068.125.18.124.404.124q1.238 0 1.879-.923.641-.921.64-3.069c-.001-2.148-.222-2.366-.663-2.799q-.664-.654-2.103-.655zm-4.317 10.436V5.33q0-.563.282-.891a.92.92 0 0 1 .73-.326h3.756q3.575 0 5.429 1.801 1.857 1.798 1.857 5.666 0 8.276-7.063 8.276h-3.845q-1.146 0-1.147-1.034M81.186 8.23q-1.08 0-1.812.989-.73.99-.73 2.776 0 1.79.697 2.745.697.957 1.833.957c1.136 0 1.372-.323 1.844-.969q.709-.966.709-2.766c0-1.8-.244-2.122-.731-2.767q-.73-.965-1.81-.965m-.012 11.85q-3.16 0-5.15-2.067-1.99-2.07-1.99-6.039 0-3.97 2.012-6.017 2.014-2.046 5.196-2.046c3.182 0 3.834.67 5.138 2.014q1.957 2.013 1.957 6.094t-2.002 6.073q-2.001 1.988-5.161 1.988m15.587-.552q0 .448-2.226.449-2.227-.001-2.228-.449V8.238h-2.698q-.382 0-.539-1.036a7 7 0 0 1-.066-1.011q0-.517.065-1.012c.105-.688.285-1.036.54-1.036h9.783q.382.001.541 1.036a7.7 7.7 0 0 1 0 2.023q-.16 1.036-.541 1.036h-2.631z" fill="#e0e0e0"/><path d="M2.644 9.821v7.76c0 6.683 19.71 6.611 19.71-.072V9.881q.727-.944 1.356-1.961a13.8 13.8 0 0 0-2.009-2.615q-1.042.484-1.986 1.138a11.3 11.3 0 0 0-2.131-1.55q.17-1.235.194-2.47A14 14 0 0 0 14.8 1.406q-.63 1.042-1.114 2.155a8.4 8.4 0 0 0-2.373 0 18 18 0 0 0-1.114-2.155A14 14 0 0 0 7.22 2.423q.025 1.236.194 2.47a11.3 11.3 0 0 0-2.131 1.55 13.4 13.4 0 0 0-1.985-1.138 13.7 13.7 0 0 0-2.01 2.615c.42.678.872 1.271 1.356 1.901z" fill="none" stroke="#e0e0e0" stroke-width="2"/><g fill="#e0e0e0"><path d="m2.644 15.838 3.681.339q.29.024.363.339l.097 1.622 3.196.243.194-1.478q.048-.265.363-.363h3.923q.315.097.363.363l.194 1.478 3.196-.243.097-1.622q.072-.315.363-.339l3.68-.339v.799l-3.244.29-.121 1.671q-.05.243-.339.315l-3.923.267q-.29 0-.388-.267l-.242-1.574H10.95l-.243 1.574q-.096.267-.387.267l-3.922-.267q-.29-.072-.34-.315l-.121-1.671-3.269-.29z" stroke="#e0e0e0"/><path d="m11.801 13.556-.001-2.082c0-.824 1.404-.824 1.404 0v2.082c0 .824-1.404.824-1.404 0M7.338 9.821a2.18 2.18 0 0 1 0 4.359 2.18 2.18 0 0 1 0-4.359m10.322 0a2.18 2.18 0 0 1 0 4.359 2.18 2.18 0 0 1 0-4.359"/></g></svg> diff --git a/editor/import/3d/resource_importer_scene.cpp b/editor/import/3d/resource_importer_scene.cpp index ca128968de..8f06af7bdb 100644 --- a/editor/import/3d/resource_importer_scene.cpp +++ b/editor/import/3d/resource_importer_scene.cpp @@ -53,6 +53,7 @@ #include "scene/resources/3d/sphere_shape_3d.h" #include "scene/resources/3d/world_boundary_shape_3d.h" #include "scene/resources/animation.h" +#include "scene/resources/bone_map.h" #include "scene/resources/packed_scene.h" #include "scene/resources/resource_format_text.h" #include "scene/resources/surface_tool.h" @@ -312,6 +313,71 @@ String ResourceImporterScene::get_preset_name(int p_idx) const { return String(); } +void ResourceImporterScene::_pre_fix_global(Node *p_scene, const HashMap<StringName, Variant> &p_options) const { + if (p_options.has("animation/import_rest_as_RESET") && (bool)p_options["animation/import_rest_as_RESET"]) { + TypedArray<Node> anim_players = p_scene->find_children("*", "AnimationPlayer"); + if (anim_players.is_empty()) { + AnimationPlayer *anim_player = memnew(AnimationPlayer); + anim_player->set_name("AnimationPlayer"); + p_scene->add_child(anim_player); + anim_player->set_owner(p_scene); + anim_players.append(anim_player); + } + Ref<Animation> reset_anim; + for (int i = 0; i < anim_players.size(); i++) { + AnimationPlayer *player = cast_to<AnimationPlayer>(anim_players[i]); + if (player->has_animation(SNAME("RESET"))) { + reset_anim = player->get_animation(SNAME("RESET")); + break; + } + } + if (reset_anim.is_null()) { + AnimationPlayer *anim_player = cast_to<AnimationPlayer>(anim_players[0]); + reset_anim.instantiate(); + Ref<AnimationLibrary> anim_library; + if (anim_player->has_animation_library(StringName())) { + anim_library = anim_player->get_animation_library(StringName()); + } else { + anim_library.instantiate(); + anim_player->add_animation_library(StringName(), anim_library); + } + anim_library->add_animation(SNAME("RESET"), reset_anim); + } + TypedArray<Node> skeletons = p_scene->find_children("*", "Skeleton3D"); + for (int i = 0; i < skeletons.size(); i++) { + Skeleton3D *skeleton = cast_to<Skeleton3D>(skeletons[i]); + NodePath skeleton_path = p_scene->get_path_to(skeleton); + + HashSet<NodePath> existing_pos_tracks; + HashSet<NodePath> existing_rot_tracks; + for (int trk_i = 0; trk_i < reset_anim->get_track_count(); trk_i++) { + NodePath np = reset_anim->track_get_path(trk_i); + if (reset_anim->track_get_type(trk_i) == Animation::TYPE_POSITION_3D) { + existing_pos_tracks.insert(np); + } + if (reset_anim->track_get_type(trk_i) == Animation::TYPE_ROTATION_3D) { + existing_rot_tracks.insert(np); + } + } + for (int bone_i = 0; bone_i < skeleton->get_bone_count(); bone_i++) { + NodePath bone_path(skeleton_path.get_names(), Vector<StringName>{ skeleton->get_bone_name(bone_i) }, false); + if (!existing_pos_tracks.has(bone_path)) { + int pos_t = reset_anim->add_track(Animation::TYPE_POSITION_3D); + reset_anim->track_set_path(pos_t, bone_path); + reset_anim->position_track_insert_key(pos_t, 0.0, skeleton->get_bone_rest(bone_i).origin); + reset_anim->track_set_imported(pos_t, true); + } + if (!existing_rot_tracks.has(bone_path)) { + int rot_t = reset_anim->add_track(Animation::TYPE_ROTATION_3D); + reset_anim->track_set_path(rot_t, bone_path); + reset_anim->rotation_track_insert_key(rot_t, 0.0, skeleton->get_bone_rest(bone_i).basis.get_rotation_quaternion()); + reset_anim->track_set_imported(rot_t, true); + } + } + } + } +} + static bool _teststr(const String &p_what, const String &p_str) { String what = p_what; @@ -1157,6 +1223,74 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, HashMap< } if (Object::cast_to<Skeleton3D>(p_node)) { + Ref<Animation> rest_animation; + float rest_animation_timestamp = 0.0; + Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_node); + if (skeleton != nullptr && int(node_settings.get("rest_pose/load_pose", 0)) != 0) { + String selected_animation_name = node_settings.get("rest_pose/selected_animation", String()); + if (int(node_settings["rest_pose/load_pose"]) == 1) { + TypedArray<Node> children = p_root->find_children("*", "AnimationPlayer", true, false); + for (int node_i = 0; node_i < children.size(); node_i++) { + AnimationPlayer *anim_player = cast_to<AnimationPlayer>(children[node_i]); + ERR_CONTINUE(anim_player == nullptr); + List<StringName> anim_list; + anim_player->get_animation_list(&anim_list); + if (anim_list.size() == 1) { + selected_animation_name = anim_list[0]; + } + rest_animation = anim_player->get_animation(selected_animation_name); + if (rest_animation.is_valid()) { + break; + } + } + } else if (int(node_settings["rest_pose/load_pose"]) == 2) { + Object *external_object = node_settings.get("rest_pose/external_animation_library", Variant()); + rest_animation = external_object; + if (rest_animation.is_null()) { + Ref<AnimationLibrary> library(external_object); + if (library.is_valid()) { + List<StringName> anim_list; + library->get_animation_list(&anim_list); + if (anim_list.size() == 1) { + selected_animation_name = String(anim_list[0]); + } + rest_animation = library->get_animation(selected_animation_name); + } + } + } + rest_animation_timestamp = double(node_settings.get("rest_pose/selected_timestamp", 0.0)); + if (rest_animation.is_valid()) { + for (int track_i = 0; track_i < rest_animation->get_track_count(); track_i++) { + NodePath path = rest_animation->track_get_path(track_i); + StringName node_path = path.get_concatenated_names(); + if (String(node_path).begins_with("%")) { + continue; // Unique node names are commonly used with retargeted animations, which we do not want to use. + } + StringName skeleton_bone = path.get_concatenated_subnames(); + if (skeleton_bone == StringName()) { + continue; + } + int bone_idx = skeleton->find_bone(skeleton_bone); + if (bone_idx == -1) { + continue; + } + switch (rest_animation->track_get_type(track_i)) { + case Animation::TYPE_POSITION_3D: { + Vector3 bone_position = rest_animation->position_track_interpolate(track_i, rest_animation_timestamp); + skeleton->set_bone_rest(bone_idx, Transform3D(skeleton->get_bone_rest(bone_idx).basis, bone_position)); + } break; + case Animation::TYPE_ROTATION_3D: { + Quaternion bone_rotation = rest_animation->rotation_track_interpolate(track_i, rest_animation_timestamp); + Transform3D current_rest = skeleton->get_bone_rest(bone_idx); + skeleton->set_bone_rest(bone_idx, Transform3D(Basis(bone_rotation).scaled(current_rest.basis.get_scale()), current_rest.origin)); + } break; + default: + break; + } + } + } + } + ObjectID node_id = p_node->get_instance_id(); for (int i = 0; i < post_importer_plugins.size(); i++) { post_importer_plugins.write[i]->internal_process(EditorScenePostImportPlugin::INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE, p_root, p_node, Ref<Resource>(), node_settings); @@ -1745,6 +1879,34 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p } break; case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: { r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "import/skip_import", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false)); + r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "rest_pose/load_pose", PROPERTY_HINT_ENUM, "Default Pose,Use AnimationPlayer,Load External Animation", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), 0)); + r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "rest_pose/external_animation_library", PROPERTY_HINT_RESOURCE_TYPE, "Animation,AnimationLibrary", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Variant())); + r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "rest_pose/selected_animation", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "")); + r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "rest_pose/selected_timestamp", PROPERTY_HINT_RANGE, "0,1,0.001,or_greater,suffix:s", PROPERTY_USAGE_DEFAULT), 0.0f)); + String mismatched_or_empty_profile_warning = String( + "The external rest animation is missing some bones. " + "Consider disabling Remove Immutable Tracks on the other file."); // TODO: translate. + r_options->push_back(ImportOption( + PropertyInfo( + Variant::STRING, U"rest_pose/\u26A0_validation_warning/mismatched_or_empty_profile", + PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY), + Variant(mismatched_or_empty_profile_warning))); + String profile_must_not_be_retargeted_warning = String( + "This external rest animation appears to have been imported with a BoneMap. " + "Disable the bone map when exporting a rest animation from the reference model."); // TODO: translate. + r_options->push_back(ImportOption( + PropertyInfo( + Variant::STRING, U"rest_pose/\u26A0_validation_warning/profile_must_not_be_retargeted", + PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY), + Variant(profile_must_not_be_retargeted_warning))); + String no_animation_warning = String( + "Select an animation: Find a FBX or glTF in a compatible rest pose " + "and export a compatible animation from its import settings."); // TODO: translate. + r_options->push_back(ImportOption( + PropertyInfo( + Variant::STRING, U"rest_pose//no_animation_chosen", + PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY), + Variant(no_animation_warning))); r_options->push_back(ImportOption(PropertyInfo(Variant::OBJECT, "retarget/bone_map", PROPERTY_HINT_RESOURCE_TYPE, "BoneMap", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), Variant())); } break; default: { @@ -1859,9 +2021,90 @@ bool ResourceImporterScene::get_internal_option_visibility(InternalImportCategor } } break; case INTERNAL_IMPORT_CATEGORY_SKELETON_3D_NODE: { - const bool use_retarget = p_options["retarget/bone_map"].get_validated_object() != nullptr; - if (p_option != "retarget/bone_map" && p_option.begins_with("retarget/")) { - return use_retarget; + const bool use_retarget = Object::cast_to<BoneMap>(p_options["retarget/bone_map"].get_validated_object()) != nullptr; + if (!use_retarget && p_option != "retarget/bone_map" && p_option.begins_with("retarget/")) { + return false; + } + int rest_warning = 0; + if (p_option.begins_with("rest_pose/")) { + if (!p_options.has("rest_pose/load_pose") || int(p_options["rest_pose/load_pose"]) == 0) { + if (p_option != "rest_pose/load_pose") { + return false; + } + } else if (int(p_options["rest_pose/load_pose"]) == 1) { + if (p_option == "rest_pose/external_animation_library") { + return false; + } + } else if (int(p_options["rest_pose/load_pose"]) == 2) { + Object *res = p_options["rest_pose/external_animation_library"]; + Ref<Animation> anim(res); + if (anim.is_valid() && p_option == "rest_pose/selected_animation") { + return false; + } + Ref<AnimationLibrary> library(res); + String selected_animation_name = p_options["rest_pose/selected_animation"]; + if (library.is_valid()) { + List<StringName> anim_list; + library->get_animation_list(&anim_list); + if (anim_list.size() == 1) { + selected_animation_name = String(anim_list[0]); + } + if (library->has_animation(selected_animation_name)) { + anim = library->get_animation(selected_animation_name); + } + } + int found_bone_count = 0; + Ref<BoneMap> bone_map; + Ref<SkeletonProfile> prof; + if (p_options.has("retarget/bone_map")) { + bone_map = p_options["retarget/bone_map"]; + } + if (bone_map.is_valid()) { + prof = bone_map->get_profile(); + } + if (anim.is_valid()) { + HashSet<StringName> target_bones; + if (bone_map.is_valid() && prof.is_valid()) { + for (int target_i = 0; target_i < prof->get_bone_size(); target_i++) { + StringName skeleton_bone_name = bone_map->get_skeleton_bone_name(prof->get_bone_name(target_i)); + if (skeleton_bone_name) { + target_bones.insert(skeleton_bone_name); + } + } + } + for (int track_i = 0; track_i < anim->get_track_count(); track_i++) { + if (anim->track_get_type(track_i) != Animation::TYPE_POSITION_3D && anim->track_get_type(track_i) != Animation::TYPE_ROTATION_3D) { + continue; + } + NodePath path = anim->track_get_path(track_i); + StringName node_path = path.get_concatenated_names(); + StringName skeleton_bone = path.get_concatenated_subnames(); + if (skeleton_bone) { + if (String(node_path).begins_with("%")) { + rest_warning = 1; + } + if (target_bones.has(skeleton_bone)) { + target_bones.erase(skeleton_bone); + } + found_bone_count++; + } + } + if ((found_bone_count < 15 || !target_bones.is_empty()) && rest_warning != 1) { + rest_warning = 2; // heuristic: animation targeted too few bones. + } + } else { + rest_warning = 3; + } + } + if (p_option.begins_with("rest_pose/") && p_option.ends_with("profile_must_not_be_retargeted")) { + return rest_warning == 1; + } + if (p_option.begins_with("rest_pose/") && p_option.ends_with("mismatched_or_empty_profile")) { + return rest_warning == 2; + } + if (p_option.begins_with("rest_pose/") && p_option.ends_with("no_animation_chosen")) { + return rest_warning == 3; + } } } break; default: { @@ -1945,6 +2188,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/trimming"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/remove_immutable_tracks"), true)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import_rest_as_RESET"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), "")); r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Dictionary())); @@ -2079,8 +2323,8 @@ Node *ResourceImporterScene::_generate_meshes(Node *p_node, const Dictionary &p_ merge_angle = mesh_settings["lods/normal_merge_angle"]; } - if (mesh_settings.has("save_to_file/enabled") && bool(mesh_settings["save_to_file/enabled"]) && mesh_settings.has("save_to_file/path")) { - save_to_file = mesh_settings["save_to_file/path"]; + if (bool(mesh_settings.get("save_to_file/enabled", false))) { + save_to_file = mesh_settings.get("save_to_file/path", String()); if (!save_to_file.is_resource_file()) { save_to_file = ""; } @@ -2387,6 +2631,8 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM return nullptr; } + _pre_fix_global(scene, p_options); + HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map; List<Pair<NodePath, Node *>> node_renames; _pre_fix_node(scene, scene, collision_map, nullptr, node_renames); @@ -2521,6 +2767,8 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p } } + _pre_fix_global(scene, p_options); + HashSet<Ref<ImporterMesh>> scanned_meshes; HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> collision_map; Pair<PackedVector3Array, PackedInt32Array> occluder_arrays; diff --git a/editor/import/3d/resource_importer_scene.h b/editor/import/3d/resource_importer_scene.h index 17fa9ef0e2..4e15471d17 100644 --- a/editor/import/3d/resource_importer_scene.h +++ b/editor/import/3d/resource_importer_scene.h @@ -282,6 +282,7 @@ public: // Import scenes *after* everything else (such as textures). virtual int get_import_order() const override { return ResourceImporter::IMPORT_ORDER_SCENE; } + void _pre_fix_global(Node *p_scene, const HashMap<StringName, Variant> &p_options) const; Node *_pre_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &r_collision_map, Pair<PackedVector3Array, PackedInt32Array> *r_occluder_arrays, List<Pair<NodePath, Node *>> &r_node_renames); Node *_pre_fix_animations(Node *p_node, Node *p_root, const Dictionary &p_node_data, const Dictionary &p_animation_data, float p_animation_fps); Node *_post_fix_node(Node *p_node, Node *p_root, HashMap<Ref<ImporterMesh>, Vector<Ref<Shape3D>>> &collision_map, Pair<PackedVector3Array, PackedInt32Array> &r_occluder_arrays, HashSet<Ref<ImporterMesh>> &r_scanned_meshes, const Dictionary &p_node_data, const Dictionary &p_material_data, const Dictionary &p_animation_data, float p_animation_fps, float p_applied_root_scale); diff --git a/editor/import/3d/scene_import_settings.cpp b/editor/import/3d/scene_import_settings.cpp index 721eccdfdd..e4f1da55a5 100644 --- a/editor/import/3d/scene_import_settings.cpp +++ b/editor/import/3d/scene_import_settings.cpp @@ -50,6 +50,8 @@ class SceneImportSettingsData : public Object { HashMap<StringName, Variant> current; HashMap<StringName, Variant> defaults; List<ResourceImporter::ImportOption> options; + Vector<String> animation_list; + bool hide_options = false; String path; @@ -96,6 +98,7 @@ class SceneImportSettingsData : public Object { } return false; } + bool _get(const StringName &p_name, Variant &r_ret) const { if (settings) { if (settings->has(p_name)) { @@ -109,29 +112,81 @@ class SceneImportSettingsData : public Object { } return false; } - void _get_property_list(List<PropertyInfo> *p_list) const { + + void handle_special_properties(PropertyInfo &r_option) const { + ERR_FAIL_NULL(settings); + if (r_option.name == "rest_pose/load_pose") { + if (!settings->has("rest_pose/load_pose") || int((*settings)["rest_pose/load_pose"]) != 2) { + (*settings)["rest_pose/external_animation_library"] = Variant(); + } + } + if (r_option.name == "rest_pose/selected_animation") { + if (!settings->has("rest_pose/load_pose")) { + return; + } + String hint_string; + + switch (int((*settings)["rest_pose/load_pose"])) { + case 1: { + hint_string = String(",").join(animation_list); + if (animation_list.size() == 1) { + (*settings)["rest_pose/selected_animation"] = animation_list[0]; + } + } break; + case 2: { + Object *res = (*settings)["rest_pose/external_animation_library"]; + Ref<Animation> anim(res); + Ref<AnimationLibrary> library(res); + if (anim.is_valid()) { + hint_string = anim->get_name(); + } + if (library.is_valid()) { + List<StringName> anim_names; + library->get_animation_list(&anim_names); + if (anim_names.size() == 1) { + (*settings)["rest_pose/selected_animation"] = String(anim_names[0]); + } + for (StringName anim_name : anim_names) { + hint_string += "," + anim_name; // Include preceding, as a catch-all. + } + } + } break; + default: + break; + } + r_option.hint = PROPERTY_HINT_ENUM; + r_option.hint_string = hint_string; + } + } + + void _get_property_list(List<PropertyInfo> *r_list) const { if (hide_options) { return; } for (const ResourceImporter::ImportOption &E : options) { + PropertyInfo option = E.option; if (SceneImportSettingsDialog::get_singleton()->is_editing_animation()) { if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { if (ResourceImporterScene::get_animation_singleton()->get_option_visibility(path, E.option.name, current)) { - p_list->push_back(E.option); + handle_special_properties(option); + r_list->push_back(option); } } else { if (ResourceImporterScene::get_animation_singleton()->get_internal_option_visibility(category, E.option.name, current)) { - p_list->push_back(E.option); + handle_special_properties(option); + r_list->push_back(option); } } } else { if (category == ResourceImporterScene::INTERNAL_IMPORT_CATEGORY_MAX) { if (ResourceImporterScene::get_scene_singleton()->get_option_visibility(path, E.option.name, current)) { - p_list->push_back(E.option); + handle_special_properties(option); + r_list->push_back(option); } } else { if (ResourceImporterScene::get_scene_singleton()->get_internal_option_visibility(category, E.option.name, current)) { - p_list->push_back(E.option); + handle_special_properties(option); + r_list->push_back(option); } } } @@ -376,10 +431,15 @@ void SceneImportSettingsDialog::_fill_scene(Node *p_node, TreeItem *p_parent_ite AnimationPlayer *anim_node = Object::cast_to<AnimationPlayer>(p_node); if (anim_node) { + Vector<String> animation_list; List<StringName> animations; anim_node->get_animation_list(&animations); for (const StringName &E : animations) { _fill_animation(scene_tree, anim_node->get_animation(E), E, item); + animation_list.append(E); + } + if (scene_import_settings_data != nullptr) { + scene_import_settings_data->animation_list = animation_list; } } @@ -433,13 +493,20 @@ void SceneImportSettingsDialog::_update_view_gizmos() { return; } const HashMap<StringName, Variant> &main_settings = scene_import_settings_data->current; + bool reshow_settings = false; if (main_settings.has("nodes/import_as_skeleton_bones")) { bool new_import_as_skeleton = main_settings["nodes/import_as_skeleton_bones"]; - if (new_import_as_skeleton != previous_import_as_skeleton) { - previous_import_as_skeleton = new_import_as_skeleton; - _re_import(); - open_settings(base_path); - } + reshow_settings = reshow_settings || (new_import_as_skeleton != previous_import_as_skeleton); + previous_import_as_skeleton = new_import_as_skeleton; + } + if (main_settings.has("animation/import_rest_as_RESET")) { + bool new_rest_as_reset = main_settings["animation/import_rest_as_RESET"]; + reshow_settings = reshow_settings || (new_rest_as_reset != previous_rest_as_reset); + previous_rest_as_reset = new_rest_as_reset; + } + if (reshow_settings) { + _re_import(); + open_settings(base_path); return; } for (const KeyValue<String, NodeData> &e : node_map) { @@ -688,6 +755,9 @@ void SceneImportSettingsDialog::open_settings(const String &p_path, bool p_for_a if (main_settings.has("nodes/import_as_skeleton_bones")) { previous_import_as_skeleton = main_settings["nodes/import_as_skeleton_bones"]; } + if (main_settings.has("animation/import_rest_as_RESET")) { + previous_rest_as_reset = main_settings["animation/import_rest_as_RESET"]; + } popup_centered_ratio(); _update_view_gizmos(); _update_camera(); @@ -1503,17 +1573,20 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() { scene_tree = memnew(Tree); scene_tree->set_name(TTR("Scene")); + scene_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); data_mode->add_child(scene_tree); scene_tree->connect("cell_selected", callable_mp(this, &SceneImportSettingsDialog::_scene_tree_selected)); mesh_tree = memnew(Tree); mesh_tree->set_name(TTR("Meshes")); + mesh_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); data_mode->add_child(mesh_tree); mesh_tree->set_hide_root(true); mesh_tree->connect("cell_selected", callable_mp(this, &SceneImportSettingsDialog::_mesh_tree_selected)); material_tree = memnew(Tree); material_tree->set_name(TTR("Materials")); + material_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); data_mode->add_child(material_tree); material_tree->connect("cell_selected", callable_mp(this, &SceneImportSettingsDialog::_material_tree_selected)); @@ -1649,6 +1722,7 @@ SceneImportSettingsDialog::SceneImportSettingsDialog() { external_paths->add_child(external_path_tree); external_path_tree->connect("button_clicked", callable_mp(this, &SceneImportSettingsDialog::_browse_save_callback)); external_paths->connect("confirmed", callable_mp(this, &SceneImportSettingsDialog::_save_dir_confirm)); + external_path_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); external_path_tree->set_columns(3); external_path_tree->set_column_titles_visible(true); external_path_tree->set_column_expand(0, true); diff --git a/editor/import/3d/scene_import_settings.h b/editor/import/3d/scene_import_settings.h index e1183dc5b0..f4954c41db 100644 --- a/editor/import/3d/scene_import_settings.h +++ b/editor/import/3d/scene_import_settings.h @@ -97,6 +97,7 @@ class SceneImportSettingsDialog : public ConfirmationDialog { Animation::LoopMode animation_loop_mode = Animation::LOOP_NONE; bool animation_pingpong = false; bool previous_import_as_skeleton = false; + bool previous_rest_as_reset = false; Ref<StandardMaterial3D> collider_mat; diff --git a/editor/import/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index b892324ba4..f2096c362e 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -1375,6 +1375,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { add_var->connect("pressed", callable_mp(this, &DynamicFontImportSettingsDialog::_variation_add)); vars_list = memnew(Tree); + vars_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); vars_list->set_custom_minimum_size(Size2(300 * EDSCALE, 0)); vars_list->set_hide_root(true); vars_list->set_columns(2); @@ -1427,6 +1428,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { page2_0_vb->add_child(page2_0_description); locale_tree = memnew(Tree); + locale_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); locale_tree->set_columns(1); locale_tree->set_hide_root(true); locale_tree->set_column_expand(0, true); @@ -1502,6 +1504,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { page2_2_vb->add_child(glyphs_split); glyph_table = memnew(Tree); + glyph_table->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); glyph_table->set_custom_minimum_size(Size2((30 * 16 + 100) * EDSCALE, 0)); glyph_table->set_columns(17); glyph_table->set_column_expand(0, false); @@ -1521,6 +1524,7 @@ DynamicFontImportSettingsDialog::DynamicFontImportSettingsDialog() { glyph_table->connect("item_activated", callable_mp(this, &DynamicFontImportSettingsDialog::_glyph_selected)); glyph_tree = memnew(Tree); + glyph_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); glyph_tree->set_custom_minimum_size(Size2(300 * EDSCALE, 0)); glyph_tree->set_columns(2); glyph_tree->set_hide_root(true); diff --git a/editor/input_event_configuration_dialog.cpp b/editor/input_event_configuration_dialog.cpp index 451829163c..e2aac6c75d 100644 --- a/editor/input_event_configuration_dialog.cpp +++ b/editor/input_event_configuration_dialog.cpp @@ -668,6 +668,7 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() { manual_vbox->add_child(input_list_search); input_list_tree = memnew(Tree); + input_list_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); input_list_tree->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); // Min height for tree input_list_tree->connect("item_selected", callable_mp(this, &InputEventConfigurationDialog::_input_list_item_selected)); input_list_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 78ceb2ef6d..55fc52e1db 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -702,6 +702,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { forward_button->connect("pressed", callable_mp(this, &InspectorDock::_edit_forward)); history_menu = memnew(MenuButton); + history_menu->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); history_menu->set_flat(false); history_menu->set_theme_type_variation("FlatMenuButton"); history_menu->set_tooltip_text(TTR("History of recently edited objects.")); @@ -762,6 +763,7 @@ InspectorDock::InspectorDock(EditorData &p_editor_data) { container->add_child(unique_resources_label); unique_resources_list_tree = memnew(Tree); + unique_resources_list_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); unique_resources_list_tree->set_hide_root(true); unique_resources_list_tree->set_columns(1); unique_resources_list_tree->set_column_title(0, TTR("Property")); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 0412141775..e75bb454ae 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -256,10 +256,6 @@ void AnimationNodeBlendTreeEditor::update_graph() { options.push_back(F); } - if (tree->has_animation(anim->get_animation())) { - pb->set_max(tree->get_animation(anim->get_animation())->get_length()); - } - pb->set_show_percentage(false); pb->set_custom_minimum_size(Vector2(0, 14) * EDSCALE); animations[E] = pb; @@ -994,9 +990,10 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { if (tree->has_animation(an->get_animation())) { Ref<Animation> anim = tree->get_animation(an->get_animation()); if (anim.is_valid()) { - E.value->set_max(anim->get_length()); //StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node; - StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/time"; + StringName length_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/current_length"; + StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/current_position"; + E.value->set_max(tree->get(length_path)); E.value->set_value(tree->get(time_path)); } } @@ -1255,6 +1252,7 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() { filters = memnew(Tree); filter_vbox->add_child(filters); + filters->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); filters->set_v_size_flags(SIZE_EXPAND_FILL); filters->set_hide_root(true); filters->connect("item_edited", callable_mp(this, &AnimationNodeBlendTreeEditor::_filter_edited)); diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index 2af3811863..9a7974acef 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -821,6 +821,7 @@ AnimationLibraryEditor::AnimationLibraryEditor() { tree = memnew(Tree); vb->add_child(tree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_columns(2); tree->set_column_titles_visible(true); tree->set_column_title(0, TTR("Resource")); diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index c03dc7efde..bfac9c8cf9 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -73,6 +73,8 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) { _update_player(); _ensure_dummy_player(); + + pin->set_pressed(false); } } @@ -2056,6 +2058,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug blend_editor.dialog->add_child(blend_vb); blend_editor.tree = memnew(Tree); + blend_editor.tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); blend_editor.tree->set_hide_root(true); blend_editor.tree->set_columns(2); blend_editor.tree->set_column_expand_ratio(0, 10); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index dbfb143b22..f24747d903 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -337,10 +337,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && tool_select->is_pressed()) { box_selecting = true; box_selecting_from = box_selecting_to = state_machine_draw->get_local_mouse_position(); - box_selecting_rect = Rect2(MIN(box_selecting_from.x, box_selecting_to.x), - MIN(box_selecting_from.y, box_selecting_to.y), - ABS(box_selecting_from.x - box_selecting_to.x), - ABS(box_selecting_from.y - box_selecting_to.y)); + box_selecting_rect = Rect2(box_selecting_from.min(box_selecting_to), (box_selecting_from - box_selecting_to).abs()); if (mb->is_command_or_control_pressed() || mb->is_shift_pressed()) { previous_selected = selected_nodes; @@ -423,10 +420,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv if (mm.is_valid() && box_selecting) { box_selecting_to = state_machine_draw->get_local_mouse_position(); - box_selecting_rect = Rect2(MIN(box_selecting_from.x, box_selecting_to.x), - MIN(box_selecting_from.y, box_selecting_to.y), - ABS(box_selecting_from.x - box_selecting_to.x), - ABS(box_selecting_from.y - box_selecting_to.y)); + box_selecting_rect = Rect2(box_selecting_from.min(box_selecting_to), (box_selecting_from - box_selecting_to).abs()); for (int i = 0; i < node_rects.size(); i++) { bool in_box = node_rects[i].node.intersects(box_selecting_rect); @@ -1247,14 +1241,14 @@ void AnimationNodeStateMachineEditor::_state_machine_pos_draw_all() { { float len = MAX(0.0001, current_length); float pos = CLAMP(current_play_pos, 0, len); - float c = current_length == HUGE_LENGTH ? 1 : (pos / len); + float c = pos / len; _state_machine_pos_draw_individual(playback->get_current_node(), c); } { float len = MAX(0.0001, fade_from_length); float pos = CLAMP(fade_from_current_play_pos, 0, len); - float c = fade_from_length == HUGE_LENGTH ? 1 : (pos / len); + float c = pos / len; _state_machine_pos_draw_individual(playback->get_fading_from_node(), c); } } @@ -1815,6 +1809,7 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { add_child(delete_window); delete_tree = memnew(Tree); + delete_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); delete_tree->set_hide_root(true); delete_tree->connect("draw", callable_mp(this, &AnimationNodeStateMachineEditor::_delete_tree_draw)); delete_window->add_child(delete_tree); diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 074fea49bd..c7f132bec1 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -34,25 +34,15 @@ #include "animation_blend_space_2d_editor.h" #include "animation_blend_tree_editor_plugin.h" #include "animation_state_machine_editor.h" -#include "core/config/project_settings.h" -#include "core/input/input.h" -#include "core/io/resource_loader.h" -#include "core/math/delaunay_2d.h" -#include "core/os/keyboard.h" #include "editor/editor_command_palette.h" #include "editor/editor_node.h" #include "editor/gui/editor_bottom_panel.h" -#include "editor/gui/editor_file_dialog.h" #include "editor/themes/editor_scale.h" #include "scene/animation/animation_blend_tree.h" -#include "scene/animation/animation_player.h" #include "scene/gui/button.h" #include "scene/gui/margin_container.h" -#include "scene/gui/menu_button.h" -#include "scene/gui/panel.h" #include "scene/gui/scroll_container.h" #include "scene/gui/separator.h" -#include "scene/main/window.h" #include "scene/scene_string_names.h" void AnimationTreeEditor::edit(AnimationTree *p_tree) { @@ -115,6 +105,7 @@ void AnimationTreeEditor::_update_path() { path_hb->add_child(b); for (int i = 0; i < button_path.size(); i++) { b = memnew(Button); + b->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); b->set_text(button_path[i]); b->set_toggle_mode(true); b->set_button_group(group); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 13bdc366bf..184241e6db 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -55,7 +55,9 @@ static inline void setup_http_request(HTTPRequest *request) { } void EditorAssetLibraryItem::configure(const String &p_title, int p_asset_id, const String &p_category, int p_category_id, const String &p_author, int p_author_id, const String &p_cost) { - title->set_text(p_title); + title_text = p_title; + title->set_text(title_text); + title->set_tooltip_text(title_text); asset_id = p_asset_id; category->set_text(p_category); category_id = p_category_id; @@ -66,16 +68,15 @@ void EditorAssetLibraryItem::configure(const String &p_title, int p_asset_id, co // TODO: Refactor this method to use the TextServer. void EditorAssetLibraryItem::clamp_width(int p_max_width) { - int text_pixel_width = title->get_button_font().ptr()->get_string_size(title->get_text()).x * EDSCALE; - - String full_text = title->get_text(); - title->set_tooltip_text(full_text); + int text_pixel_width = title->get_button_font()->get_string_size(title_text).x * EDSCALE; if (text_pixel_width > p_max_width) { // Truncate title text to within the current column width. - int max_length = p_max_width / (text_pixel_width / full_text.length()); - String truncated_text = full_text.left(max_length - 3) + "..."; + int max_length = p_max_width / (text_pixel_width / title_text.length()); + String truncated_text = title_text.left(max_length - 3) + "..."; title->set_text(truncated_text); + } else { + title->set_text(title_text); } } @@ -1525,7 +1526,15 @@ void EditorAssetLibrary::_update_asset_items_columns() { asset_items->set_columns(new_columns); } - asset_items_column_width = (get_size().x / new_columns) - (100 * EDSCALE); + asset_items_column_width = (get_size().x / new_columns) - (120 * EDSCALE); + + for (int i = 0; i < asset_items->get_child_count(); i++) { + EditorAssetLibraryItem *item = Object::cast_to<EditorAssetLibraryItem>(asset_items->get_child(i)); + if (!item || !item->is_visible()) { + continue; + } + item->clamp_width(asset_items_column_width); + } } void EditorAssetLibrary::_set_library_message(const String &p_message) { diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h index d4a1411c18..16b784d629 100644 --- a/editor/plugins/asset_library_editor_plugin.h +++ b/editor/plugins/asset_library_editor_plugin.h @@ -62,6 +62,7 @@ class EditorAssetLibraryItem : public PanelContainer { LinkButton *author = nullptr; Label *price = nullptr; + String title_text; int asset_id = 0; int category_id = 0; int author_id = 0; diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index d8c020eb29..e80f299f42 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -173,6 +173,7 @@ void BonePicker::create_editors() { add_child(vbox); bones = memnew(Tree); + bones->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); bones->set_select_mode(Tree::SELECT_SINGLE); bones->set_v_size_flags(Control::SIZE_EXPAND_FILL); bones->set_hide_root(true); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 894eef74ec..41e5eee486 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2643,6 +2643,7 @@ void CanvasItemEditor::_update_cursor() { void CanvasItemEditor::_update_lock_and_group_button() { bool all_locked = true; bool all_group = true; + bool has_canvas_item = false; List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.is_empty()) { all_locked = false; @@ -2657,6 +2658,7 @@ void CanvasItemEditor::_update_lock_and_group_button() { if (all_group && !item->has_meta("_edit_group_")) { all_group = false; } + has_canvas_item = true; } if (!all_locked && !all_group) { break; @@ -2664,12 +2666,17 @@ void CanvasItemEditor::_update_lock_and_group_button() { } } + all_locked = all_locked && has_canvas_item; + all_group = all_group && has_canvas_item; + lock_button->set_visible(!all_locked); - lock_button->set_disabled(selection.is_empty()); + lock_button->set_disabled(!has_canvas_item); unlock_button->set_visible(all_locked); + unlock_button->set_disabled(!has_canvas_item); group_button->set_visible(!all_group); - group_button->set_disabled(selection.is_empty()); + group_button->set_disabled(!has_canvas_item); ungroup_button->set_visible(all_group); + ungroup_button->set_disabled(!has_canvas_item); } Control::CursorShape CanvasItemEditor::get_cursor_shape(const Point2 &p_pos) const { @@ -4011,6 +4018,9 @@ void CanvasItemEditor::_notification(int p_what) { AnimationPlayerEditor::get_singleton()->connect("animation_selected", callable_mp(this, &CanvasItemEditor::_keying_changed).unbind(1)); _keying_changed(); _update_editor_settings(); + + connect("item_lock_status_changed", callable_mp(this, &CanvasItemEditor::_update_lock_and_group_button)); + connect("item_group_status_changed", callable_mp(this, &CanvasItemEditor::_update_lock_and_group_button)); } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { diff --git a/editor/plugins/cpu_particles_3d_editor_plugin.cpp b/editor/plugins/cpu_particles_3d_editor_plugin.cpp index bf427f733b..b5e3f102cf 100644 --- a/editor/plugins/cpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_3d_editor_plugin.cpp @@ -56,7 +56,6 @@ void CPUParticles3DEditor::_menu_option(int p_option) { switch (p_option) { case MENU_OPTION_CREATE_EMISSION_VOLUME_FROM_NODE: { emission_tree_dialog->popup_scenetree_dialog(); - } break; case MENU_OPTION_RESTART: { diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp index 2dc43098f7..edd0ddbdad 100644 --- a/editor/plugins/debugger_editor_plugin.cpp +++ b/editor/plugins/debugger_editor_plugin.cpp @@ -77,10 +77,10 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) { TTR("When this option is enabled, curve resources used by path nodes will be visible in the running project.")); debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_navigation", TTR("Visible Navigation")), RUN_DEBUG_NAVIGATION); debug_menu->set_item_tooltip(-1, - TTR("When this option is enabled, navigation meshes and polygons will be visible in the running project.")); + TTR("When this option is enabled, navigation meshes, and polygons will be visible in the running project.")); debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_avoidance", TTR("Visible Avoidance")), RUN_DEBUG_AVOIDANCE); debug_menu->set_item_tooltip(-1, - TTR("When this option is enabled, avoidance objects shapes, radius and velocities will be visible in the running project.")); + TTR("When this option is enabled, avoidance object shapes, radiuses, and velocities will be visible in the running project.")); debug_menu->add_separator(); debug_menu->add_check_shortcut(ED_SHORTCUT("editor/visible_canvas_redraw", TTR("Debug CanvasItem Redraws")), RUN_DEBUG_CANVAS_REDRAW); debug_menu->set_item_tooltip(-1, diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index e8804fdf12..70213b280c 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -130,7 +130,7 @@ Ref<Texture2D> EditorTexturePreviewPlugin::generate(const Ref<Resource> &p_from, if (new_size.y > p_size.y) { new_size = Vector2(new_size.x * p_size.y / new_size.y, p_size.y); } - Vector2i new_size_i(MAX(1, (int)new_size.x), MAX(1, (int)new_size.y)); + Vector2i new_size_i = Vector2i(new_size).max(Vector2i(1, 1)); img->resize(new_size_i.x, new_size_i.y, Image::INTERPOLATE_CUBIC); post_process_preview(img); diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index 4011d36456..be7ff6ba3e 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -383,14 +383,6 @@ EditorPropertyFontMetaOverride::EditorPropertyFontMetaOverride(bool p_script) { /* EditorPropertyOTVariation */ /*************************************************************************/ -void EditorPropertyOTVariation::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_ENTER_TREE: - case NOTIFICATION_THEME_CHANGED: { - } break; - } -} - void EditorPropertyOTVariation::_property_changed(const String &p_property, const Variant &p_value, const String &p_name, bool p_changing) { if (p_property.begins_with("keys")) { Dictionary dict = object->get_dict(); @@ -724,7 +716,7 @@ void EditorPropertyOTFeatures::update_property() { } for (int i = 0; i < FGRP_MAX; i++) { if (have_sub[i]) { - menu->add_submenu_node_item(RTR(group_names[i]), menu_sub[i]); + menu->add_submenu_node_item(TTRGET(group_names[i]), menu_sub[i]); } } @@ -856,15 +848,15 @@ EditorPropertyOTFeatures::EditorPropertyOTFeatures() { menu_sub[i]->connect("id_pressed", callable_mp(this, &EditorPropertyOTFeatures::_add_feature)); } - group_names[FGRP_STYLISTIC_SET] = "Stylistic Sets"; - group_names[FGRP_CHARACTER_VARIANT] = "Character Variants"; - group_names[FGRP_CAPITLS] = "Capitals"; - group_names[FGRP_LIGATURES] = "Ligatures"; - group_names[FGRP_ALTERNATES] = "Alternates"; - group_names[FGRP_EAL] = "East Asian Language"; - group_names[FGRP_EAW] = "East Asian Widths"; - group_names[FGRP_NUMAL] = "Numeral Alignment"; - group_names[FGRP_CUSTOM] = "Custom"; + group_names[FGRP_STYLISTIC_SET] = TTRC("Stylistic Sets"); + group_names[FGRP_CHARACTER_VARIANT] = TTRC("Character Variants"); + group_names[FGRP_CAPITLS] = TTRC("Capitals"); + group_names[FGRP_LIGATURES] = TTRC("Ligatures"); + group_names[FGRP_ALTERNATES] = TTRC("Alternates"); + group_names[FGRP_EAL] = TTRC("East Asian Language"); + group_names[FGRP_EAW] = TTRC("East Asian Widths"); + group_names[FGRP_NUMAL] = TTRC("Numeral Alignment"); + group_names[FGRP_CUSTOM] = TTRC("Custom"); } /*************************************************************************/ diff --git a/editor/plugins/font_config_plugin.h b/editor/plugins/font_config_plugin.h index dc17a7717e..1adb578950 100644 --- a/editor/plugins/font_config_plugin.h +++ b/editor/plugins/font_config_plugin.h @@ -139,7 +139,6 @@ class EditorPropertyOTVariation : public EditorProperty { EditorPaginator *paginator = nullptr; protected: - void _notification(int p_what); static void _bind_methods(){}; void _edit_pressed(); diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index 086abc0859..9fec263af3 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -255,13 +255,15 @@ void MultiMeshEditor::edit(MultiMeshInstance3D *p_multimesh) { void MultiMeshEditor::_browse(bool p_source) { browsing_source = p_source; - std->get_scene_tree()->set_marked(node, false); - std->popup_scenetree_dialog(); + Node *browsed_node = nullptr; if (p_source) { + browsed_node = node->get_node_or_null(mesh_source->get_text()); std->set_title(TTR("Select a Source Mesh:")); } else { + browsed_node = node->get_node_or_null(surface_source->get_text()); std->set_title(TTR("Select a Target Surface:")); } + std->popup_scenetree_dialog(browsed_node); } void MultiMeshEditor::_bind_methods() { diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index f38d42f681..468d7fb051 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -691,11 +691,11 @@ Vector3 Node3DEditorViewport::_get_camera_position() const { return _get_camera_transform().origin; } -Point2 Node3DEditorViewport::_point_to_screen(const Vector3 &p_point) { +Point2 Node3DEditorViewport::point_to_screen(const Vector3 &p_point) { return camera->unproject_position(p_point) * subviewport_container->get_stretch_shrink(); } -Vector3 Node3DEditorViewport::_get_ray_pos(const Vector2 &p_pos) const { +Vector3 Node3DEditorViewport::get_ray_pos(const Vector2 &p_pos) const { return camera->project_ray_origin(p_pos / subviewport_container->get_stretch_shrink()); } @@ -703,7 +703,7 @@ Vector3 Node3DEditorViewport::_get_camera_normal() const { return -_get_camera_transform().basis.get_column(2); } -Vector3 Node3DEditorViewport::_get_ray(const Vector2 &p_pos) const { +Vector3 Node3DEditorViewport::get_ray(const Vector2 &p_pos) const { return camera->project_ray_normal(p_pos / subviewport_container->get_stretch_shrink()); } @@ -769,8 +769,8 @@ void Node3DEditorViewport::_select_clicked(bool p_allow_locked) { } ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const { - Vector3 ray = _get_ray(p_pos); - Vector3 pos = _get_ray_pos(p_pos); + Vector3 ray = get_ray(p_pos); + Vector3 pos = get_ray_pos(p_pos); Vector2 shrinked_pos = p_pos / subviewport_container->get_stretch_shrink(); if (viewport->get_debug_draw() == Viewport::DEBUG_DRAW_SDFGI_PROBES) { @@ -837,8 +837,8 @@ ObjectID Node3DEditorViewport::_select_ray(const Point2 &p_pos) const { } void Node3DEditorViewport::_find_items_at_pos(const Point2 &p_pos, Vector<_RayResult> &r_results, bool p_include_locked_nodes) { - Vector3 ray = _get_ray(p_pos); - Vector3 pos = _get_ray_pos(p_pos); + Vector3 ray = get_ray(p_pos); + Vector3 pos = get_ray_pos(p_pos); Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_ray(pos, pos + ray * camera->get_far(), get_tree()->get_root()->get_world_3d()->get_scenario()); HashSet<Node3D *> found_nodes; @@ -1153,8 +1153,8 @@ void Node3DEditorViewport::_update_name() { void Node3DEditorViewport::_compute_edit(const Point2 &p_point) { _edit.original_local = spatial_editor->are_local_coords_enabled(); - _edit.click_ray = _get_ray(p_point); - _edit.click_ray_pos = _get_ray_pos(p_point); + _edit.click_ray = get_ray(p_point); + _edit.click_ray_pos = get_ray_pos(p_point); _edit.plane = TRANSFORM_VIEW; spatial_editor->update_transform_gizmo(); _edit.center = spatial_editor->get_gizmo_transform().origin; @@ -1233,8 +1233,8 @@ bool Node3DEditorViewport::_transform_gizmo_select(const Vector2 &p_screenpos, b return false; } - Vector3 ray_pos = _get_ray_pos(p_screenpos); - Vector3 ray = _get_ray(p_screenpos); + Vector3 ray_pos = get_ray_pos(p_screenpos); + Vector3 ray = get_ray(p_screenpos); Transform3D gt = spatial_editor->get_gizmo_transform(); @@ -3115,7 +3115,7 @@ void Node3DEditorViewport::_draw() { } if (_edit.mode == TRANSFORM_ROTATE && _edit.show_rotation_line) { - Point2 center = _point_to_screen(_edit.center); + Point2 center = point_to_screen(_edit.center); Color handle_color; switch (_edit.plane) { @@ -4087,8 +4087,8 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const const float MAX_DISTANCE = 50.0; const float FALLBACK_DISTANCE = 5.0; - Vector3 world_ray = _get_ray(p_pos); - Vector3 world_pos = _get_ray_pos(p_pos); + Vector3 world_ray = get_ray(p_pos); + Vector3 world_pos = get_ray_pos(p_pos); PhysicsDirectSpaceState3D *ss = get_tree()->get_root()->get_world_3d()->get_direct_space_state(); @@ -4250,8 +4250,8 @@ bool Node3DEditorViewport::_apply_preview_material(ObjectID p_target, const Poin Ref<Mesh> mesh = mesh_instance->get_mesh(); int surface_count = mesh->get_surface_count(); - Vector3 world_ray = _get_ray(p_point); - Vector3 world_pos = _get_ray_pos(p_point); + Vector3 world_ray = get_ray(p_point); + Vector3 world_pos = get_ray_pos(p_point); int closest_surface = -1; float closest_dist = 1e20; @@ -4698,8 +4698,8 @@ void Node3DEditorViewport::apply_transform(Vector3 p_motion, double p_snap) { // Update the current transform operation in response to an input. void Node3DEditorViewport::update_transform(bool p_shift) { - Vector3 ray_pos = _get_ray_pos(_edit.mouse_pos); - Vector3 ray = _get_ray(_edit.mouse_pos); + Vector3 ray_pos = get_ray_pos(_edit.mouse_pos); + Vector3 ray = get_ray(_edit.mouse_pos); double snap = EDITOR_GET("interface/inspector/default_float_step"); int snap_step_decimals = Math::range_step_decimals(snap); @@ -7376,6 +7376,7 @@ void Node3DEditor::_selection_changed() { void Node3DEditor::_refresh_menu_icons() { bool all_locked = true; bool all_grouped = true; + bool has_node3d_item = false; List<Node *> &selection = editor_selection->get_selected_node_list(); @@ -7384,26 +7385,34 @@ void Node3DEditor::_refresh_menu_icons() { all_grouped = false; } else { for (Node *E : selection) { - if (Object::cast_to<Node3D>(E) && !Object::cast_to<Node3D>(E)->has_meta("_edit_lock_")) { - all_locked = false; - break; + Node3D *node = Object::cast_to<Node3D>(E); + if (node) { + if (all_locked && !node->has_meta("_edit_lock_")) { + all_locked = false; + } + if (all_grouped && !node->has_meta("_edit_group_")) { + all_grouped = false; + } + has_node3d_item = true; } - } - for (Node *E : selection) { - if (Object::cast_to<Node3D>(E) && !Object::cast_to<Node3D>(E)->has_meta("_edit_group_")) { - all_grouped = false; + if (!all_locked && !all_grouped) { break; } } } + all_locked = all_locked && has_node3d_item; + all_grouped = all_grouped && has_node3d_item; + tool_button[TOOL_LOCK_SELECTED]->set_visible(!all_locked); - tool_button[TOOL_LOCK_SELECTED]->set_disabled(selection.is_empty()); + tool_button[TOOL_LOCK_SELECTED]->set_disabled(!has_node3d_item); tool_button[TOOL_UNLOCK_SELECTED]->set_visible(all_locked); + tool_button[TOOL_UNLOCK_SELECTED]->set_disabled(!has_node3d_item); tool_button[TOOL_GROUP_SELECTED]->set_visible(!all_grouped); - tool_button[TOOL_GROUP_SELECTED]->set_disabled(selection.is_empty()); + tool_button[TOOL_GROUP_SELECTED]->set_disabled(!has_node3d_item); tool_button[TOOL_UNGROUP_SELECTED]->set_visible(all_grouped); + tool_button[TOOL_UNGROUP_SELECTED]->set_disabled(!has_node3d_item); } template <typename T> diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index 091432b35a..7ddbb74006 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -271,9 +271,7 @@ private: void _select_clicked(bool p_allow_locked); ObjectID _select_ray(const Point2 &p_pos) const; void _find_items_at_pos(const Point2 &p_pos, Vector<_RayResult> &r_results, bool p_include_locked); - Vector3 _get_ray_pos(const Vector2 &p_pos) const; - Vector3 _get_ray(const Vector2 &p_pos) const; - Point2 _point_to_screen(const Vector3 &p_point); + Transform3D _get_camera_transform() const; int get_selected_count() const; void cancel_transform(); @@ -481,6 +479,10 @@ public: void reset(); bool is_freelook_active() const { return freelook_active; } + Vector3 get_ray_pos(const Vector2 &p_pos) const; + Vector3 get_ray(const Vector2 &p_pos) const; + Point2 point_to_screen(const Vector3 &p_point); + void focus_selection(); void assign_pending_data_pointers( diff --git a/editor/plugins/packed_scene_translation_parser_plugin.cpp b/editor/plugins/packed_scene_translation_parser_plugin.cpp index 86df57c469..e266a3241b 100644 --- a/editor/plugins/packed_scene_translation_parser_plugin.cpp +++ b/editor/plugins/packed_scene_translation_parser_plugin.cpp @@ -136,6 +136,10 @@ Error PackedSceneEditorTranslationParserPlugin::parse_file(const String &p_path, if (property_name == "script" && property_value.get_type() == Variant::OBJECT && !property_value.is_null()) { // Parse built-in script. Ref<Script> s = Object::cast_to<Script>(property_value); + if (!s->is_built_in()) { + continue; + } + String extension = s->get_language()->get_extension(); if (EditorTranslationParser::get_singleton()->can_parse(extension)) { Vector<String> temp; diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index ffdc06ceee..e4522f5a03 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -473,6 +473,17 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p if (mb.is_valid()) { Point2 mbpos(mb->get_position().x, mb->get_position().y); + Node3DEditorViewport *viewport = nullptr; + for (uint32_t i = 0; i < Node3DEditor::VIEWPORTS_COUNT; i++) { + Node3DEditorViewport *vp = Node3DEditor::get_singleton()->get_editor_viewport(i); + if (vp->get_camera_3d() == p_camera) { + viewport = vp; + break; + } + } + + ERR_FAIL_NULL_V(viewport, EditorPlugin::AFTER_GUI_INPUT_PASS); + if (!mb->is_pressed()) { set_handle_clicked(false); } @@ -489,14 +500,14 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p const Vector3 *r = v3a.ptr(); float closest_d = 1e20; - if (p_camera->unproject_position(gt.xform(c->get_point_position(0))).distance_to(mbpos) < click_dist) { + if (viewport->point_to_screen(gt.xform(c->get_point_position(0))).distance_to(mbpos) < click_dist) { return EditorPlugin::AFTER_GUI_INPUT_PASS; //nope, existing } for (int i = 0; i < c->get_point_count() - 1; i++) { //find the offset and point index of the place to break up int j = idx; - if (p_camera->unproject_position(gt.xform(c->get_point_position(i + 1))).distance_to(mbpos) < click_dist) { + if (viewport->point_to_screen(gt.xform(c->get_point_position(i + 1))).distance_to(mbpos) < click_dist) { return EditorPlugin::AFTER_GUI_INPUT_PASS; //nope, existing } @@ -508,16 +519,16 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p to = gt.xform(to); if (cdist > 0) { Vector2 s[2]; - s[0] = p_camera->unproject_position(from); - s[1] = p_camera->unproject_position(to); + s[0] = viewport->point_to_screen(from); + s[1] = viewport->point_to_screen(to); Vector2 inters = Geometry2D::get_closest_point_to_segment(mbpos, s); float d = inters.distance_to(mbpos); if (d < 10 && d < closest_d) { closest_d = d; closest_seg = i; - Vector3 ray_from = p_camera->project_ray_origin(mbpos); - Vector3 ray_dir = p_camera->project_ray_normal(mbpos); + Vector3 ray_from = viewport->get_ray_pos(mbpos); + Vector3 ray_dir = viewport->get_ray(mbpos); Vector3 ra, rb; Geometry3D::get_closest_points_between_segments(ray_from, ray_from + ray_dir * 4096, from, to, ra, rb); @@ -557,8 +568,8 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p origin = gt.xform(c->get_point_position(c->get_point_count() - 1)); } Plane p(p_camera->get_transform().basis.get_column(2), origin); - Vector3 ray_from = p_camera->project_ray_origin(mbpos); - Vector3 ray_dir = p_camera->project_ray_normal(mbpos); + Vector3 ray_from = viewport->get_ray_pos(mbpos); + Vector3 ray_dir = viewport->get_ray(mbpos); Vector3 inters; if (p.intersects_ray(ray_from, ray_dir, &inters)) { @@ -574,10 +585,10 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p } else if (mb->is_pressed() && ((mb->get_button_index() == MouseButton::LEFT && curve_del->is_pressed()) || (mb->get_button_index() == MouseButton::RIGHT && curve_edit->is_pressed()))) { for (int i = 0; i < c->get_point_count(); i++) { - real_t dist_to_p = p_camera->unproject_position(gt.xform(c->get_point_position(i))).distance_to(mbpos); - real_t dist_to_p_out = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_out(i))).distance_to(mbpos); - real_t dist_to_p_in = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_in(i))).distance_to(mbpos); - real_t dist_to_p_up = p_camera->unproject_position(gt.xform(c->get_point_position(i) + c->get_point_baked_posture(i, true).get_column(1) * disk_size)).distance_to(mbpos); + real_t dist_to_p = viewport->point_to_screen(gt.xform(c->get_point_position(i))).distance_to(mbpos); + real_t dist_to_p_out = viewport->point_to_screen(gt.xform(c->get_point_position(i) + c->get_point_out(i))).distance_to(mbpos); + real_t dist_to_p_in = viewport->point_to_screen(gt.xform(c->get_point_position(i) + c->get_point_in(i))).distance_to(mbpos); + real_t dist_to_p_up = viewport->point_to_screen(gt.xform(c->get_point_position(i) + c->get_point_baked_posture(i, true).get_column(1) * disk_size)).distance_to(mbpos); // Find the offset and point index of the place to break up. // Also check for the control points. diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp index a624c47e3e..2e0a9c7272 100644 --- a/editor/plugins/resource_preloader_editor_plugin.cpp +++ b/editor/plugins/resource_preloader_editor_plugin.cpp @@ -369,6 +369,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() { tree = memnew(Tree); tree->connect("button_clicked", callable_mp(this, &ResourcePreloaderEditor::_cell_button_pressed)); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_columns(2); tree->set_column_expand_ratio(0, 2); tree->set_column_clip_content(0, true); diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index 13928710bb..30fb731fc8 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -216,6 +216,7 @@ EditorPropertyRootMotion::EditorPropertyRootMotion() { filters = memnew(Tree); filter_dialog->add_child(filters); + filters->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); filters->set_v_size_flags(SIZE_EXPAND_FILL); filters->set_hide_root(true); filters->connect("item_activated", callable_mp(this, &EditorPropertyRootMotion::_confirmed)); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index edec4af094..6f1eef62de 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -423,6 +423,7 @@ ScriptEditorQuickOpen::ScriptEditorQuickOpen() { register_text_enter(search_box); set_hide_on_ok(false); search_options->connect("item_activated", callable_mp(this, &ScriptEditorQuickOpen::_confirmed)); + search_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); search_options->set_hide_root(true); search_options->set_hide_folding(true); search_options->add_theme_constant_override("draw_guides", 1); @@ -1715,18 +1716,6 @@ void ScriptEditor::_notification(int p_what) { _test_script_times_on_disk(); _update_modified_scripts_for_external_editor(); } break; - - case CanvasItem::NOTIFICATION_VISIBILITY_CHANGED: { - if (is_visible()) { - find_in_files_button->show(); - } else { - if (find_in_files->is_visible_in_tree()) { - EditorNode::get_bottom_panel()->hide_bottom_panel(); - } - find_in_files_button->hide(); - } - - } break; } } @@ -1892,7 +1881,7 @@ struct _ScriptEditorItemData { if (sort_key == id.sort_key) { return index < id.index; } else { - return sort_key.naturalnocasecmp_to(id.sort_key) < 0; + return sort_key.filenocasecmp_to(id.sort_key) < 0; } } else { return category < id.category; @@ -3775,6 +3764,7 @@ void ScriptEditor::_on_find_in_files_result_selected(const String &fpath, int li ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor()); if (ste) { + EditorInterface::get_singleton()->set_main_screen_editor("Script"); ste->goto_line_selection(line_number, begin, end); } } @@ -3789,6 +3779,7 @@ void ScriptEditor::_on_find_in_files_result_selected(const String &fpath, int li ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(_get_current_editor()); if (ste) { + EditorInterface::get_singleton()->set_main_screen_editor("Script"); ste->goto_line_selection(line_number - 1, begin, end); } return; @@ -3822,6 +3813,13 @@ void ScriptEditor::_start_find_in_files(bool with_replace) { find_in_files->set_replace_text(find_in_files_dialog->get_replace_text()); find_in_files->start_search(); + if (find_in_files_button->get_index() != find_in_files_button->get_parent()->get_child_count()) { + find_in_files_button->get_parent()->move_child(find_in_files_button, -1); + } + if (!find_in_files_button->is_visible()) { + find_in_files_button->show(); + } + EditorNode::get_bottom_panel()->make_item_visible(find_in_files); } @@ -3848,6 +3846,11 @@ void ScriptEditor::_set_zoom_factor(float p_zoom_factor) { } } +void ScriptEditor::_on_find_in_files_close_button_clicked() { + EditorNode::get_bottom_panel()->hide_bottom_panel(); + find_in_files_button->hide(); +} + void ScriptEditor::_window_changed(bool p_visible) { make_floating->set_visible(!p_visible); is_floating = p_visible; @@ -4167,6 +4170,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { disk_changed_list = memnew(Tree); vbc->add_child(disk_changed_list); + disk_changed_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL); disk_changed->connect("confirmed", callable_mp(this, &ScriptEditor::reload_scripts).bind(false)); @@ -4201,6 +4205,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) { find_in_files->set_custom_minimum_size(Size2(0, 200) * EDSCALE); find_in_files->connect(FindInFilesPanel::SIGNAL_RESULT_SELECTED, callable_mp(this, &ScriptEditor::_on_find_in_files_result_selected)); find_in_files->connect(FindInFilesPanel::SIGNAL_FILES_MODIFIED, callable_mp(this, &ScriptEditor::_on_find_in_files_modified_files)); + find_in_files->connect(FindInFilesPanel::SIGNAL_CLOSE_BUTTON_CLICKED, callable_mp(this, &ScriptEditor::_on_find_in_files_close_button_clicked)); find_in_files->hide(); find_in_files_button->hide(); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index d5c33c73b4..4fff724866 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -496,6 +496,7 @@ class ScriptEditor : public PanelContainer { void _on_find_in_files_result_selected(const String &fpath, int line_number, int begin, int end); void _start_find_in_files(bool with_replace); void _on_find_in_files_modified_files(const PackedStringArray &paths); + void _on_find_in_files_close_button_clicked(); void _set_zoom_factor(float p_zoom_factor); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 13b1c4b6ac..0a6eacf11d 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -99,6 +99,7 @@ ConnectionInfoDialog::ConnectionInfoDialog() { vbc->add_child(method); tree = memnew(Tree); + tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); tree->set_columns(3); tree->set_hide_root(true); tree->set_column_titles_visible(true); @@ -598,8 +599,7 @@ void ScriptTextEditor::_update_warnings() { warnings_panel->push_cell(); warnings_panel->push_meta(w.start_line - 1); warnings_panel->push_color(warnings_panel->get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); - warnings_panel->add_text(TTR("Line") + " " + itos(w.start_line)); - warnings_panel->add_text(" (" + w.string_code + "):"); + warnings_panel->add_text(vformat(TTR("Line %d (%s):"), w.start_line, w.string_code)); warnings_panel->pop(); // Color. warnings_panel->pop(); // Meta goto. warnings_panel->pop(); // Cell. @@ -625,7 +625,7 @@ void ScriptTextEditor::_update_errors() { errors_panel->push_cell(); errors_panel->push_meta(err.line - 1); errors_panel->push_color(warnings_panel->get_theme_color(SNAME("error_color"), EditorStringName(Editor))); - errors_panel->add_text(TTR("Line") + " " + itos(err.line) + ":"); + errors_panel->add_text(vformat(TTR("Line %d:"), err.line)); errors_panel->pop(); // Color. errors_panel->pop(); // Meta goto. errors_panel->pop(); // Cell. @@ -659,7 +659,7 @@ void ScriptTextEditor::_update_errors() { errors_panel->push_cell(); errors_panel->push_meta(click_meta); errors_panel->push_color(errors_panel->get_theme_color(SNAME("error_color"), EditorStringName(Editor))); - errors_panel->add_text(TTR("Line") + " " + itos(err.line) + ":"); + errors_panel->add_text(vformat(TTR("Line %d:"), err.line)); errors_panel->pop(); // Color. errors_panel->pop(); // Meta goto. errors_panel->pop(); // Cell. @@ -1164,11 +1164,19 @@ void ScriptTextEditor::_update_connected_methods() { // Add override icons to methods. methods_found.clear(); for (int i = 0; i < functions.size(); i++) { - StringName name = StringName(functions[i].get_slice(":", 0)); + String raw_name = functions[i].get_slice(":", 0); + StringName name = StringName(raw_name); if (methods_found.has(name)) { continue; } + // Account for inner classes by stripping the class names from the method, + // starting from the right since our inner class might be inside of another inner class. + int pos = raw_name.rfind("."); + if (pos != -1) { + name = raw_name.substr(pos + 1); + } + String found_base_class; StringName base_class = script->get_instance_base_type(); Ref<Script> inherited_script = script->get_base_script(); @@ -1217,7 +1225,7 @@ void ScriptTextEditor::_update_connected_methods() { text_edit->set_line_gutter_icon(line, connection_gutter, get_parent_control()->get_editor_theme_icon(SNAME("MethodOverrideAndSlot"))); } - methods_found.insert(name); + methods_found.insert(StringName(raw_name)); } } } @@ -1946,9 +1954,12 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data if (d.has("type") && String(d["type"]) == "obj_property") { te->remove_secondary_carets(); + + bool add_literal = EDITOR_GET("text_editor/completion/add_node_path_literals"); + String text_to_drop = add_literal ? "^" : ""; // It is unclear whether properties may contain single or double quotes. // Assume here that double-quotes may not exist. We are escaping single-quotes if necessary. - const String text_to_drop = _quote_drop_data(String(d["property"])); + text_to_drop += _quote_drop_data(String(d["property"])); te->set_caret_line(row); te->set_caret_column(col); diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index ffc59a3429..e0c5f9e596 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -505,10 +505,8 @@ void Skeleton3DEditor::_file_selected(const String &p_file) { position_max = Vector2(grest.origin.x, grest.origin.y); position_min = Vector2(grest.origin.x, grest.origin.y); } else { - position_max.x = MAX(grest.origin.x, position_max.x); - position_max.y = MAX(grest.origin.y, position_max.y); - position_min.x = MIN(grest.origin.x, position_min.x); - position_min.y = MIN(grest.origin.y, position_min.y); + position_max = position_max.max(Vector2(grest.origin.x, grest.origin.y)); + position_min = position_min.min(Vector2(grest.origin.x, grest.origin.y)); } } @@ -811,6 +809,7 @@ void Skeleton3DEditor::create_editors() { bones_section->get_vbox()->add_child(s_con); joint_tree = memnew(Tree); + joint_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); joint_tree->set_columns(1); joint_tree->set_focus_mode(Control::FOCUS_NONE); joint_tree->set_select_mode(Tree::SELECT_SINGLE); diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp index 5a1fe833d6..6e786c1d94 100644 --- a/editor/plugins/text_shader_editor.cpp +++ b/editor/plugins/text_shader_editor.cpp @@ -598,8 +598,7 @@ void ShaderTextEditor::_update_warning_panel() { warnings_panel->push_color(warnings_panel->get_theme_color(SNAME("warning_color"), EditorStringName(Editor))); if (line != -1) { warnings_panel->push_meta(line - 1); - warnings_panel->add_text(TTR("Line") + " " + itos(line)); - warnings_panel->add_text(" (" + w.get_name() + "):"); + warnings_panel->add_text(vformat(TTR("Line %d (%s):"), line, w.get_name())); warnings_panel->pop(); // Meta goto. } else { warnings_panel->add_text(w.get_name() + ":"); diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 8ed00cf542..0db752e771 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -918,6 +918,7 @@ ThemeItemImportTree::ThemeItemImportTree() { add_child(import_main_hb); import_items_tree = memnew(Tree); + import_items_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); import_items_tree->set_hide_root(true); import_items_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL); import_main_hb->add_child(import_items_tree); @@ -1928,6 +1929,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito edit_dialog_side_vb->add_child(edit_type_label); edit_type_list = memnew(Tree); + edit_type_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); edit_type_list->set_hide_root(true); edit_type_list->set_hide_folding(true); edit_type_list->set_columns(1); @@ -2031,6 +2033,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito edit_items_remove_all->connect("pressed", callable_mp(this, &ThemeItemEditorDialog::_remove_all_items)); edit_items_tree = memnew(Tree); + edit_items_tree->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); edit_items_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL); edit_items_tree->set_hide_root(true); edit_items_tree->set_columns(1); diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp index 8c2cb68413..c3900b8235 100644 --- a/editor/plugins/tiles/tile_atlas_view.cpp +++ b/editor/plugins/tiles/tile_atlas_view.cpp @@ -501,8 +501,7 @@ Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p // Clamp. if (p_clamp) { Vector2i size = tile_set_atlas_source->get_atlas_grid_size(); - ret.x = CLAMP(ret.x, 0, size.x - 1); - ret.y = CLAMP(ret.y, 0, size.y - 1); + ret = ret.clamp(Vector2i(), size - Vector2i(1, 1)); } return ret; diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index 597fd7393f..f047e4ff16 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -1280,7 +1280,7 @@ void TileDataDefaultEditor::setup_property_editor(Variant::Type p_type, const St property_editor = EditorInspectorDefaultPlugin::get_editor_for_property(dummy_object, p_type, p_property, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT); property_editor->set_object_and_property(dummy_object, p_property); if (p_label.is_empty()) { - property_editor->set_label(EditorPropertyNameProcessor::get_singleton()->process_name(p_property, EditorPropertyNameProcessor::get_default_inspector_style())); + property_editor->set_label(EditorPropertyNameProcessor::get_singleton()->process_name(p_property, EditorPropertyNameProcessor::get_default_inspector_style(), p_property)); } else { property_editor->set_label(p_label); } diff --git a/editor/plugins/tiles/tile_map_layer_editor.cpp b/editor/plugins/tiles/tile_map_layer_editor.cpp index ccadc0643b..ac4708aa06 100644 --- a/editor/plugins/tiles/tile_map_layer_editor.cpp +++ b/editor/plugins/tiles/tile_map_layer_editor.cpp @@ -36,9 +36,9 @@ #include "editor/editor_resource_preview.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/multi_node_edit.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/themes/editor_scale.h" - #include "scene/2d/camera_2d.h" #include "scene/2d/tile_map_layer.h" #include "scene/gui/center_container.h" @@ -107,7 +107,7 @@ void TileMapLayerEditorTilesPlugin::_update_transform_buttons() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null() || selection_pattern.is_null()) { return; } @@ -171,7 +171,7 @@ void TileMapLayerEditorTilesPlugin::_update_tile_set_sources_list() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -256,7 +256,7 @@ void TileMapLayerEditorTilesPlugin::_update_source_display() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -302,7 +302,7 @@ void TileMapLayerEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<Inpu return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -348,7 +348,7 @@ void TileMapLayerEditorTilesPlugin::_update_patterns_list() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -380,7 +380,7 @@ void TileMapLayerEditorTilesPlugin::_update_atlas_view() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -401,7 +401,7 @@ void TileMapLayerEditorTilesPlugin::_update_scenes_collection_view() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -459,7 +459,7 @@ void TileMapLayerEditorTilesPlugin::_scenes_list_multi_selected(int p_index, boo return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -538,7 +538,7 @@ bool TileMapLayerEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEven return false; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return false; } @@ -784,7 +784,7 @@ void TileMapLayerEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -1021,7 +1021,7 @@ TileMapCell TileMapLayerEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> return TileMapCell(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return TileMapCell(); } @@ -1073,7 +1073,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_line(Vector2 return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -1122,7 +1122,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_rect(Vector2 return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -1181,7 +1181,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTilesPlugin::_draw_bucket_fill( return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -1293,7 +1293,7 @@ void TileMapLayerEditorTilesPlugin::_stop_dragging() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -1601,7 +1601,7 @@ void TileMapLayerEditorTilesPlugin::_update_fix_selected_and_hovered() { selection_pattern.instantiate(); return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { hovered_tile.source_id = TileSet::INVALID_SOURCE; hovered_tile.set_atlas_coords(TileSetSource::INVALID_ATLAS_COORDS); @@ -1688,7 +1688,7 @@ void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tilemap_selec return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -1709,7 +1709,7 @@ void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -1783,7 +1783,7 @@ void TileMapLayerEditorTilesPlugin::_update_selection_pattern_from_tileset_patte return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -1822,7 +1822,7 @@ void TileMapLayerEditorTilesPlugin::_tile_atlas_control_draw() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -1901,7 +1901,7 @@ void TileMapLayerEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<Inpu return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -2007,7 +2007,7 @@ void TileMapLayerEditorTilesPlugin::_tile_alternatives_control_draw() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -2059,7 +2059,7 @@ void TileMapLayerEditorTilesPlugin::_tile_alternatives_control_gui_input(const R return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -2157,16 +2157,21 @@ void TileMapLayerEditorTilesPlugin::edit(ObjectID p_tile_map_layer_id) { // Disable sort button if the tileset is read-only TileMapLayer *edited_layer = _get_edited_layer(); + Ref<TileSet> tile_set; if (edited_layer) { - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + tile_set = edited_layer->get_tile_set(); if (tile_set.is_valid()) { source_sort_button->set_disabled(EditorNode::get_singleton()->is_resource_read_only(tile_set)); } } - if (edited_tile_map_layer_id != p_tile_map_layer_id) { - edited_tile_map_layer_id = p_tile_map_layer_id; + TileMapLayer *new_tile_map_layer = Object::cast_to<TileMapLayer>(ObjectDB::get_instance(edited_tile_map_layer_id)); + Ref<TileSet> new_tile_set; + if (new_tile_map_layer) { + new_tile_set = new_tile_map_layer->get_tile_set(); + } + if (tile_set.is_valid() && tile_set != new_tile_set) { // Clear the selection. tile_set_selection.clear(); patterns_item_list->deselect_all(); @@ -2531,7 +2536,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_terrain_p return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -2583,7 +2588,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_terrain_p return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -2630,7 +2635,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_line(Vect return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -2654,7 +2659,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_rect(Vect return HashMap<Vector2i, TileMapCell>(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -2688,7 +2693,7 @@ RBSet<Vector2i> TileMapLayerEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vec return RBSet<Vector2i>(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return RBSet<Vector2i>(); } @@ -2799,7 +2804,7 @@ HashMap<Vector2i, TileMapCell> TileMapLayerEditorTerrainsPlugin::_draw_bucket_fi return HashMap<Vector2i, TileMapCell>(); } - const Ref<TileSet> &tile_set = edited_layer->get_effective_tile_set(); + const Ref<TileSet> &tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return HashMap<Vector2i, TileMapCell>(); } @@ -2827,7 +2832,7 @@ void TileMapLayerEditorTerrainsPlugin::_stop_dragging() { return; } - const Ref<TileSet> &tile_set = edited_layer->get_effective_tile_set(); + const Ref<TileSet> &tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -2961,7 +2966,7 @@ void TileMapLayerEditorTerrainsPlugin::_update_selection() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -3013,7 +3018,7 @@ bool TileMapLayerEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputE return false; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return false; } @@ -3150,7 +3155,7 @@ void TileMapLayerEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -3275,7 +3280,7 @@ void TileMapLayerEditorTerrainsPlugin::_update_terrains_cache() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -3342,7 +3347,7 @@ void TileMapLayerEditorTerrainsPlugin::_update_terrains_tree() { const TileMapLayer *edited_layer = _get_edited_layer(); ERR_FAIL_NULL(edited_layer); - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -3389,7 +3394,7 @@ void TileMapLayerEditorTerrainsPlugin::_update_tiles_list() { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -3627,57 +3632,258 @@ TileMapLayer *TileMapLayerEditor::_get_edited_layer() const { return Object::cast_to<TileMapLayer>(ObjectDB::get_instance(edited_tile_map_layer_id)); } +void TileMapLayerEditor::_find_tile_map_layers_in_scene(Node *p_current, const Node *p_owner, Vector<TileMapLayer *> &r_list) const { + ERR_FAIL_COND(!p_current || !p_owner); + if (p_current != p_owner && p_current->get_owner() != p_owner) { + return; + } + TileMapLayer *layer = Object::cast_to<TileMapLayer>(p_current); + if (layer) { + r_list.append(layer); + } + for (int i = 0; i < p_current->get_child_count(); i++) { + Node *child = p_current->get_child(i); + _find_tile_map_layers_in_scene(child, p_owner, r_list); + } +} + +void TileMapLayerEditor::_update_tile_map_layers_in_scene_list_cache() { + if (!layers_in_scene_list_cache_needs_update) { + return; + } + EditorNode *en = EditorNode::get_singleton(); + Node *edited_scene_root = en->get_edited_scene(); + if (!edited_scene_root) { + return; + } + + tile_map_layers_in_scene_cache.clear(); + _find_tile_map_layers_in_scene(edited_scene_root, edited_scene_root, tile_map_layers_in_scene_cache); + layers_in_scene_list_cache_needs_update = false; +} + +void TileMapLayerEditor::_node_change(Node *p_node) { + if (!layers_in_scene_list_cache_needs_update && p_node->is_part_of_edited_scene() && Object::cast_to<TileMapLayer>(p_node)) { + layers_in_scene_list_cache_needs_update = true; + } +} + void TileMapLayerEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_READY: { + get_tree()->connect("node_added", callable_mp(this, &TileMapLayerEditor::_node_change)); + get_tree()->connect("node_removed", callable_mp(this, &TileMapLayerEditor::_node_change)); + } break; case NOTIFICATION_THEME_CHANGED: { missing_tile_texture = get_editor_theme_icon(SNAME("StatusWarning")); warning_pattern_texture = get_editor_theme_icon(SNAME("WarningPattern")); advanced_menu_button->set_icon(get_editor_theme_icon(SNAME("Tools"))); + select_previous_layer->set_icon(get_editor_theme_icon(SNAME("MoveUp"))); + select_next_layer->set_icon(get_editor_theme_icon(SNAME("MoveDown"))); + select_all_layers->set_icon(get_editor_theme_icon(SNAME("FileList"))); toggle_grid_button->set_icon(get_editor_theme_icon(SNAME("Grid"))); - toggle_grid_button->set_pressed(EDITOR_GET("editors/tiles_editor/display_grid")); toggle_highlight_selected_layer_button->set_icon(get_editor_theme_icon(SNAME("TileMapHighlightSelected"))); } break; case NOTIFICATION_INTERNAL_PROCESS: { - if (is_visible_in_tree() && tileset_changed_needs_update) { + if (is_visible_in_tree() && tile_map_layer_changed_needs_update) { _update_bottom_panel(); - update_layers_selector(); - _update_highlighting_toggle(); + _update_layers_selector(); tabs_plugins[tabs_bar->get_current_tab()]->tile_set_changed(); CanvasItemEditor::get_singleton()->update_viewport(); - tileset_changed_needs_update = false; + tile_map_layer_changed_needs_update = false; } } break; case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { if (EditorSettings::get_singleton()->check_changed_settings_in_group("editors/tiles_editor")) { toggle_grid_button->set_pressed_no_signal(EDITOR_GET("editors/tiles_editor/display_grid")); + toggle_highlight_selected_layer_button->set_pressed_no_signal(EDITOR_GET("editors/tiles_editor/highlight_selected_layer")); } } break; } } -void TileMapLayerEditor::_bind_methods() { - ADD_SIGNAL(MethodInfo("change_selected_layer_request", PropertyInfo(Variant::STRING_NAME, "layer_name"))); -} - void TileMapLayerEditor::_on_grid_toggled(bool p_pressed) { EditorSettings::get_singleton()->set("editors/tiles_editor/display_grid", p_pressed); CanvasItemEditor::get_singleton()->update_viewport(); } -void TileMapLayerEditor::_layers_selection_item_selected(int p_index) { - emit_signal("change_selected_layer_request", layers_selection_button->get_item_metadata(p_index)); +void TileMapLayerEditor::_select_previous_layer_pressed() { + _layers_select_next_or_previous(false); } -void TileMapLayerEditor::_highlight_selected_layer_button_toggled(bool p_pressed) { +void TileMapLayerEditor::_select_next_layer_pressed() { + _layers_select_next_or_previous(true); +} + +void TileMapLayerEditor::_select_all_layers_pressed() { + EditorNode *en = EditorNode::get_singleton(); + Node *edited_scene_root = en->get_edited_scene(); + ERR_FAIL_NULL(edited_scene_root); + + en->get_editor_selection()->clear(); + if (tile_map_layers_in_scene_cache.size() == 1) { + en->edit_node(tile_map_layers_in_scene_cache[0]); + en->get_editor_selection()->add_node(tile_map_layers_in_scene_cache[0]); + } else { + _update_tile_map_layers_in_scene_list_cache(); + Ref<MultiNodeEdit> multi_node_edit = memnew(MultiNodeEdit); + for (TileMapLayer *layer : tile_map_layers_in_scene_cache) { + multi_node_edit->add_node(edited_scene_root->get_path_to(layer)); + en->get_editor_selection()->add_node(layer); + } + en->push_item(multi_node_edit.ptr()); + } +} + +void TileMapLayerEditor::_layers_selection_item_selected(int p_index) { TileMapLayer *edited_layer = _get_edited_layer(); ERR_FAIL_NULL(edited_layer); - TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); - ERR_FAIL_NULL(tile_map_layer_group); + TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent()); + ERR_FAIL_NULL(tile_map); + + TileMapLayer *new_edited = Object::cast_to<TileMapLayer>(tile_map->get_child(p_index)); + edit(new_edited); +} + +void TileMapLayerEditor::_update_layers_selector() { + const TileMapLayer *edited_layer = _get_edited_layer(); + + // Update the selector. + layers_selection_button->clear(); + layers_selection_button->hide(); + select_all_layers->show(); + select_next_layer->set_disabled(false); + select_previous_layer->set_disabled(false); + advanced_menu_button->get_popup()->set_item_disabled(ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS, true); + if (edited_layer) { + TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent()); + if (tile_map && edited_layer->get_index_in_tile_map() >= 0) { + // Build the list of layers. + for (int i = 0; i < tile_map->get_layers_count(); i++) { + const TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map->get_child(i)); + if (layer) { + int index = layers_selection_button->get_item_count(); + layers_selection_button->add_item(layer->get_name()); + layers_selection_button->set_item_metadata(index, layer->get_name()); + if (edited_layer == layer) { + layers_selection_button->select(index); + } + } + } + + // Disable selector if there's no layer to select. + layers_selection_button->set_disabled(false); + if (layers_selection_button->get_item_count() == 0) { + layers_selection_button->set_disabled(true); + layers_selection_button->set_text(TTR("No Layers")); + } + + // Disable next/previous if there's one or less layers. + if (layers_selection_button->get_item_count() <= 1) { + select_next_layer->set_disabled(true); + select_previous_layer->set_disabled(true); + } + layers_selection_button->show(); + select_all_layers->hide(); + + // Enable the "extract as TileMapLayer" option only if we are editing a TleMap. + advanced_menu_button->get_popup()->set_item_disabled(ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS, false); + } + } else { + select_all_layers->hide(); + select_next_layer->set_disabled(true); + select_previous_layer->set_disabled(true); + } +} + +void TileMapLayerEditor::_clear_all_layers_highlighting() { + // Note: This function might be removed if we remove the TileMap node at some point. + // All processing could be done in _update_all_layers_highlighting otherwise. + TileMapLayer *edited_layer = _get_edited_layer(); + + // Use default mode. + if (edited_layer && edited_layer->get_index_in_tile_map() >= 0) { + // For the TileMap node. + TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent()); + if (tile_map) { + for (int i = 0; i < tile_map->get_layers_count(); i++) { + TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map->get_child(i)); + layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_DEFAULT); + } + } + } else { + // For other TileMapLayer nodes. + _update_tile_map_layers_in_scene_list_cache(); + for (TileMapLayer *layer : tile_map_layers_in_scene_cache) { + layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_DEFAULT); + } + } +} + +void TileMapLayerEditor::_update_all_layers_highlighting() { + EditorNode *en = EditorNode::get_singleton(); + Node *edited_scene_root = en->get_edited_scene(); + if (!edited_scene_root) { + return; + } + + // Get selected layer. + TileMapLayer *edited_layer = _get_edited_layer(); + + bool highlight_selected_layer = EDITOR_GET("editors/tiles_editor/highlight_selected_layer"); + if (edited_layer && highlight_selected_layer) { + int edited_z_index = edited_layer->get_z_index(); + + if (edited_layer->get_index_in_tile_map() >= 0) { + // For the TileMap node. + TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent()); + ERR_FAIL_NULL(tile_map); + + bool passed = false; + for (int i = 0; i < tile_map->get_layers_count(); i++) { + TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map->get_child(i)); + if (layer == edited_layer) { + passed = true; + layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_DEFAULT); + } else { + if (passed || layer->get_z_index() > edited_z_index) { + layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_ABOVE); + } else { + layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_BELOW); + } + } + } + } else { + // Update highlight mode for independent layers. + _update_tile_map_layers_in_scene_list_cache(); + bool passed = false; + for (TileMapLayer *layer : tile_map_layers_in_scene_cache) { + if (layer == edited_layer) { + passed = true; + layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_DEFAULT); + } else { + if (passed || layer->get_z_index() > edited_z_index) { + layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_ABOVE); + } else { + layer->set_highlight_mode(TileMapLayer::HIGHLIGHT_MODE_BELOW); + } + } + } + } + } +} + +void TileMapLayerEditor::_highlight_selected_layer_button_toggled(bool p_pressed) { + TileMapLayer *edited_layer = _get_edited_layer(); + if (!edited_layer) { + return; + } - tile_map_layer_group->set_highlight_selected_layer(p_pressed); + EditorSettings::get_singleton()->set("editors/tiles_editor/highlight_selected_layer", p_pressed); + _update_all_layers_highlighting(); } void TileMapLayerEditor::_advanced_menu_button_id_pressed(int p_id) { @@ -3686,12 +3892,12 @@ void TileMapLayerEditor::_advanced_menu_button_id_pressed(int p_id) { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } - if (p_id == 0) { // Replace Tile Proxies + if (p_id == ADVANCED_MENU_REPLACE_WITH_PROXIES) { // Replace Tile Proxies EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); undo_redo->create_action(TTR("Replace Tiles with Proxies")); TypedArray<Vector2i> used_cells = edited_layer->get_used_cells(); @@ -3710,31 +3916,74 @@ void TileMapLayerEditor::_advanced_menu_button_id_pressed(int p_id) { } undo_redo->commit_action(); + } else if (p_id == ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS) { // Transform internal TileMap layers into TileMapLayers. + ERR_FAIL_COND(edited_layer->get_index_in_tile_map() < 0); + + EditorNode *en = EditorNode::get_singleton(); + Node *edited_scene_root = en->get_edited_scene(); + ERR_FAIL_NULL(edited_scene_root); + + EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); + undo_redo->create_action(TTR("Extract TileMap layers as individual TileMapLayer nodes")); + + TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent()); + for (int i = 0; i < tile_map->get_layers_count(); i++) { + undo_redo->add_do_method(tile_map, "remove_layer", 0); + } + + for (int i = 0; i < tile_map->get_layers_count(); i++) { + TileMapLayer *new_layer = tile_map->duplicate_layer_from_internal(i); + undo_redo->add_do_method(tile_map, "add_child", new_layer); + undo_redo->add_do_method(new_layer, "set_owner", edited_scene_root); + undo_redo->add_do_property(new_layer, "tile_set", tile_map->get_tileset()); // Workaround for a bug: #89947. + undo_redo->add_undo_method(tile_map, "remove_child", new_layer); + undo_redo->add_do_reference(new_layer); + } + + List<PropertyInfo> prop_list; + tile_map->get_property_list(&prop_list); + for (PropertyInfo &prop : prop_list) { + undo_redo->add_undo_property(tile_map, prop.name, tile_map->get(prop.name)); + } + undo_redo->commit_action(); } } void TileMapLayerEditor::_update_bottom_panel() { const TileMapLayer *edited_layer = _get_edited_layer(); - if (!edited_layer) { - return; + Ref<TileSet> tile_set; + if (edited_layer) { + tile_set = edited_layer->get_tile_set(); + } + + // Update state labels. + if (is_multi_node_edit) { + cant_edit_label->set_text(TTR("Can't edit multiple layers at once.")); + cant_edit_label->show(); + } else if (!edited_layer) { + cant_edit_label->set_text(TTR("The selected TileMap has no layer to edit.")); + cant_edit_label->show(); + } else if (!edited_layer->is_enabled() || !edited_layer->is_visible_in_tree()) { + cant_edit_label->set_text(TTR("The edited layer is disabled or invisible")); + cant_edit_label->show(); + } else if (tile_set.is_null()) { + cant_edit_label->set_text(TTR("The edited TileMap or TileMapLayer node has no TileSet resource.\nCreate or load a TileSet resource in the Tile Set property in the inspector.")); + cant_edit_label->show(); + } else { + cant_edit_label->hide(); } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); - - // Update the visibility of controls. - missing_tileset_label->set_visible(tile_set.is_null()); + // Update tabs visibility. for (TileMapLayerSubEditorPlugin::TabData &tab_data : tabs_data) { tab_data.panel->hide(); } - if (tile_set.is_valid()) { - tabs_data[tabs_bar->get_current_tab()].panel->show(); - } + tabs_data[tabs_bar->get_current_tab()].panel->set_visible(!cant_edit_label->is_visible()); } Vector<Vector2i> TileMapLayerEditor::get_line(const TileMapLayer *p_tile_map_layer, Vector2i p_from_cell, Vector2i p_to_cell) { ERR_FAIL_NULL_V(p_tile_map_layer, Vector<Vector2i>()); - Ref<TileSet> tile_set = p_tile_map_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = p_tile_map_layer->get_tile_set(); ERR_FAIL_COND_V(tile_set.is_null(), Vector<Vector2i>()); if (tile_set->get_tile_shape() == TileSet::TILE_SHAPE_SQUARE) { @@ -3805,7 +4054,7 @@ Vector<Vector2i> TileMapLayerEditor::get_line(const TileMapLayer *p_tile_map_lay } void TileMapLayerEditor::_tile_map_layer_changed() { - tileset_changed_needs_update = true; + tile_map_layer_changed_needs_update = true; } void TileMapLayerEditor::_tab_changed(int p_tab_id) { @@ -3825,7 +4074,7 @@ void TileMapLayerEditor::_tab_changed(int p_tab_id) { TileMapLayer *tile_map_layer = _get_edited_layer(); if (tile_map_layer) { - if (tile_map_layer->get_effective_tile_set().is_valid()) { + if (tile_map_layer->get_tile_set().is_valid()) { tabs_data[tabs_bar->get_current_tab()].panel->show(); } } @@ -3841,36 +4090,38 @@ void TileMapLayerEditor::_layers_select_next_or_previous(bool p_next) { return; } - TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); - if (!tile_map_layer_group) { - return; - } + EditorNode *en = EditorNode::get_singleton(); + Node *edited_scene_root = en->get_edited_scene(); + ERR_FAIL_NULL(edited_scene_root); + TileMapLayer *new_selected_layer = nullptr; int inc = p_next ? 1 : -1; - int index = Math::posmod(edited_layer->get_index() + inc, tile_map_layer_group->get_child_count()); - const TileMapLayer *new_selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(index)); - while (new_selected_layer != edited_layer) { - if (new_selected_layer && new_selected_layer->is_enabled()) { - break; + if (edited_layer->get_index_in_tile_map() >= 0) { + // Part of a TileMap. + TileMap *tile_map = Object::cast_to<TileMap>(edited_layer->get_parent()); + new_selected_layer = Object::cast_to<TileMapLayer>(tile_map->get_child(Math::posmod(edited_layer->get_index_in_tile_map() + inc, tile_map->get_layers_count()))); + } else { + // Individual layer. + _update_tile_map_layers_in_scene_list_cache(); + int edited_index = -1; + for (int i = 0; i < tile_map_layers_in_scene_cache.size(); i++) { + if (tile_map_layers_in_scene_cache[i] == edited_layer) { + edited_index = i; + break; + } } - index = Math::posmod((index + inc), tile_map_layer_group->get_child_count()); - new_selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(index)); + new_selected_layer = tile_map_layers_in_scene_cache[Math::posmod(edited_index + inc, tile_map_layers_in_scene_cache.size())]; } - if (new_selected_layer != edited_layer) { - emit_signal("change_selected_layer_request", new_selected_layer->get_name()); - } -} + ERR_FAIL_NULL(new_selected_layer); -void TileMapLayerEditor::_update_highlighting_toggle() { - const TileMapLayer *edited_layer = _get_edited_layer(); - if (!edited_layer) { - return; - } - - TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); - if (tile_map_layer_group) { - toggle_highlight_selected_layer_button->set_pressed(tile_map_layer_group->is_highlighting_selected_layer()); + if (edited_layer->get_index_in_tile_map() < 0) { + // Only if not part of a TileMap. + en->edit_node(new_selected_layer); + en->get_editor_selection()->clear(); + en->get_editor_selection()->add_node(new_selected_layer); + } else { + edit(new_selected_layer); } } @@ -3966,7 +4217,7 @@ void TileMapLayerEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { return; } - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_null()) { return; } @@ -3994,29 +4245,25 @@ void TileMapLayerEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { } if (!source || !source->has_tile(tile_atlas_coords) || !source->has_alternative_tile(tile_atlas_coords, tile_alternative_tile)) { - // Generate a random color from the hashed values of the tiles. - Array a = tile_set->map_tile_proxy(tile_source_id, tile_atlas_coords, tile_alternative_tile); - if (int(a[0]) == tile_source_id && Vector2i(a[1]) == tile_atlas_coords && int(a[2]) == tile_alternative_tile) { - // Only display the pattern if we have no proxy tile. - Array to_hash; - to_hash.push_back(tile_source_id); - to_hash.push_back(tile_atlas_coords); - to_hash.push_back(tile_alternative_tile); - uint32_t hash = RandomPCG(to_hash.hash()).rand(); - - Color color; - color = color.from_hsv( - (float)((hash >> 24) & 0xFF) / 256.0, - Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), - Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), - 0.8); - - // Draw the scaled tile. - Transform2D tile_xform; - tile_xform.set_origin(tile_set->map_to_local(coords)); - tile_xform.set_scale(tile_shape_size); - tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture); - } + // Generate a random color from the hashed identifier of the tiles. + Array to_hash; + to_hash.push_back(tile_source_id); + to_hash.push_back(tile_atlas_coords); + to_hash.push_back(tile_alternative_tile); + uint32_t hash = RandomPCG(to_hash.hash()).rand(); + + Color color; + color = color.from_hsv( + (float)((hash >> 24) & 0xFF) / 256.0, + Math::lerp(0.5, 1.0, (float)((hash >> 16) & 0xFF) / 256.0), + Math::lerp(0.5, 1.0, (float)((hash >> 8) & 0xFF) / 256.0), + 0.8); + + // Display the warning pattern. + Transform2D tile_xform; + tile_xform.set_origin(tile_set->map_to_local(coords)); + tile_xform.set_scale(tile_shape_size); + tile_set->draw_tile_shape(p_overlay, xform * tile_xform, color, true, warning_pattern_texture); // Draw the warning icon. Vector2::Axis min_axis = missing_tile_texture->get_size().min_axis_index(); @@ -4092,75 +4339,50 @@ void TileMapLayerEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { tabs_plugins[tabs_bar->get_current_tab()]->forward_canvas_draw_over_viewport(p_overlay); } -void TileMapLayerEditor::edit(TileMapLayer *p_tile_map_layer) { - if (p_tile_map_layer && p_tile_map_layer->get_instance_id() == edited_tile_map_layer_id) { +void TileMapLayerEditor::edit(Object *p_edited) { + if (p_edited && p_edited->get_instance_id() == edited_tile_map_layer_id) { return; } + _clear_all_layers_highlighting(); + // Disconnect to changes. TileMapLayer *tile_map_layer = _get_edited_layer(); if (tile_map_layer) { tile_map_layer->disconnect("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed)); + tile_map_layer->disconnect("visibility_changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed)); } // Update the edited layer. - if (p_tile_map_layer) { + TileMapLayer *new_layer = Object::cast_to<TileMapLayer>(p_edited); + if (new_layer) { // Change the edited object. - edited_tile_map_layer_id = p_tile_map_layer->get_instance_id(); + edited_tile_map_layer_id = new_layer->get_instance_id(); tile_map_layer = _get_edited_layer(); // Connect to changes. if (!tile_map_layer->is_connected("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed))) { tile_map_layer->connect("changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed)); + tile_map_layer->connect("visibility_changed", callable_mp(this, &TileMapLayerEditor::_tile_map_layer_changed)); } } else { edited_tile_map_layer_id = ObjectID(); } - update_layers_selector(); - _update_highlighting_toggle(); + // Check if we are trying to use a MultiNodeEdit. + is_multi_node_edit = Object::cast_to<MultiNodeEdit>(p_edited); - // Call the plugins. + // Call the plugins and update everything. tabs_plugins[tabs_bar->get_current_tab()]->edit(edited_tile_map_layer_id); + _update_layers_selector(); + _update_all_layers_highlighting(); _tile_map_layer_changed(); } -void TileMapLayerEditor::update_layers_selector() { - const TileMapLayer *edited_layer = _get_edited_layer(); - if (!edited_layer) { - return; - } - - TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); - if (tile_map_layer_group) { - // Update the selector - layers_selection_button->show(); - layers_selection_button->clear(); - - // Build the list of layers. - for (int i = 0; i < tile_map_layer_group->get_child_count(); i++) { - const TileMapLayer *layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_child(i)); - if (layer) { - int index = layers_selection_button->get_item_count(); - layers_selection_button->add_item(layer->get_name()); - layers_selection_button->set_item_disabled(index, !layer->is_enabled()); - layers_selection_button->set_item_metadata(index, layer->get_name()); - if (edited_layer == layer) { - layers_selection_button->select(index); - } - } - } - - // Disable the button if there's no layer to select. - layers_selection_button->set_disabled(false); - if (layers_selection_button->get_item_count() == 0) { - layers_selection_button->set_disabled(true); - layers_selection_button->set_text(TTR("No Layers")); - } - } else { - layers_selection_button->hide(); - } +void TileMapLayerEditor::set_show_layer_selector(bool p_show_layer_selector) { + show_layers_selector = p_show_layer_selector; + _update_layers_selector(); } TileMapLayerEditor::TileMapLayerEditor() { @@ -4210,13 +4432,36 @@ TileMapLayerEditor::TileMapLayerEditor() { tile_map_toolbar->add_child(c); // Layer selector. + layer_selection_hbox = memnew(HBoxContainer); + tile_map_toolbar->add_child(layer_selection_hbox); + layers_selection_button = memnew(OptionButton); layers_selection_button->set_custom_minimum_size(Size2(200, 0)); layers_selection_button->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS); layers_selection_button->set_tooltip_text(TTR("TileMap Layers")); layers_selection_button->connect("item_selected", callable_mp(this, &TileMapLayerEditor::_layers_selection_item_selected)); - tile_map_toolbar->add_child(layers_selection_button); - + layer_selection_hbox->add_child(layers_selection_button); + + select_previous_layer = memnew(Button); + select_previous_layer->set_theme_type_variation("FlatButton"); + select_previous_layer->set_tooltip_text(TTR("Select previous layer")); + select_previous_layer->connect("pressed", callable_mp(this, &TileMapLayerEditor::_select_previous_layer_pressed)); + layer_selection_hbox->add_child(select_previous_layer); + + select_next_layer = memnew(Button); + select_next_layer->set_theme_type_variation("FlatButton"); + select_next_layer->set_tooltip_text(TTR("Select next layer")); + select_next_layer->connect("pressed", callable_mp(this, &TileMapLayerEditor::_select_next_layer_pressed)); + layer_selection_hbox->add_child(select_next_layer); + + select_all_layers = memnew(Button); + select_all_layers->set_theme_type_variation("FlatButton"); + select_all_layers->set_text(TTR("Select all layers")); + select_all_layers->connect("pressed", callable_mp(this, &TileMapLayerEditor::_select_all_layers_pressed)); + select_all_layers->set_tooltip_text(TTR("Select all TileMapLayers in scene")); + layer_selection_hbox->add_child(select_all_layers); + + // Highlighting selected layer. toggle_highlight_selected_layer_button = memnew(Button); toggle_highlight_selected_layer_button->set_theme_type_variation("FlatButton"); toggle_highlight_selected_layer_button->set_toggle_mode(true); @@ -4239,18 +4484,19 @@ TileMapLayerEditor::TileMapLayerEditor() { advanced_menu_button = memnew(MenuButton); advanced_menu_button->set_flat(false); advanced_menu_button->set_theme_type_variation("FlatButton"); - advanced_menu_button->get_popup()->add_item(TTR("Automatically Replace Tiles with Proxies")); + advanced_menu_button->get_popup()->add_item(TTR("Automatically Replace Tiles with Proxies"), ADVANCED_MENU_REPLACE_WITH_PROXIES); + advanced_menu_button->get_popup()->add_item(TTR("Extract TileMap layers as individual TileMapLayer nodes"), ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS); advanced_menu_button->get_popup()->connect("id_pressed", callable_mp(this, &TileMapLayerEditor::_advanced_menu_button_id_pressed)); tile_map_toolbar->add_child(advanced_menu_button); - missing_tileset_label = memnew(Label); - missing_tileset_label->set_text(TTR("The edited TileMap node has no TileSet resource.\nCreate or load a TileSet resource in the Tile Set property in the inspector.")); - missing_tileset_label->set_h_size_flags(SIZE_EXPAND_FILL); - missing_tileset_label->set_v_size_flags(SIZE_EXPAND_FILL); - missing_tileset_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - missing_tileset_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - missing_tileset_label->hide(); - add_child(missing_tileset_label); + // A label for editing errors. + cant_edit_label = memnew(Label); + cant_edit_label->set_h_size_flags(SIZE_EXPAND_FILL); + cant_edit_label->set_v_size_flags(SIZE_EXPAND_FILL); + cant_edit_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); + cant_edit_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); + cant_edit_label->hide(); + add_child(cant_edit_label); for (unsigned int tab_index = 0; tab_index < tabs_data.size(); tab_index++) { add_child(tabs_data[tab_index].panel); diff --git a/editor/plugins/tiles/tile_map_layer_editor.h b/editor/plugins/tiles/tile_map_layer_editor.h index a7fea2abcf..2603261449 100644 --- a/editor/plugins/tiles/tile_map_layer_editor.h +++ b/editor/plugins/tiles/tile_map_layer_editor.h @@ -339,10 +339,16 @@ class TileMapLayerEditor : public VBoxContainer { GDCLASS(TileMapLayerEditor, VBoxContainer); private: - bool tileset_changed_needs_update = false; + bool tile_map_layer_changed_needs_update = false; ObjectID edited_tile_map_layer_id; + bool is_multi_node_edit = false; + Vector<TileMapLayer *> tile_map_layers_in_scene_cache; + bool layers_in_scene_list_cache_needs_update = false; TileMapLayer *_get_edited_layer() const; + void _find_tile_map_layers_in_scene(Node *p_current, const Node *p_owner, Vector<TileMapLayer *> &r_list) const; + void _update_tile_map_layers_in_scene_list_cache(); + void _node_change(Node *p_node); // Vector to keep plugins. Vector<TileMapLayerSubEditorPlugin *> tile_map_editor_plugins; @@ -350,20 +356,36 @@ private: // Toolbar. HFlowContainer *tile_map_toolbar = nullptr; + bool show_layers_selector = false; + + HBoxContainer *layer_selection_hbox = nullptr; + Button *select_previous_layer = nullptr; + void _select_previous_layer_pressed(); + Button *select_next_layer = nullptr; + void _select_next_layer_pressed(); + Button *select_all_layers = nullptr; + void _select_all_layers_pressed(); OptionButton *layers_selection_button = nullptr; void _layers_selection_item_selected(int p_index); + void _update_layers_selector(); Button *toggle_highlight_selected_layer_button = nullptr; + void _clear_all_layers_highlighting(); + void _update_all_layers_highlighting(); void _highlight_selected_layer_button_toggled(bool p_pressed); Button *toggle_grid_button = nullptr; void _on_grid_toggled(bool p_pressed); + enum { + ADVANCED_MENU_REPLACE_WITH_PROXIES, + ADVANCED_MENU_EXTRACT_TILE_MAP_LAYERS, + }; MenuButton *advanced_menu_button = nullptr; void _advanced_menu_button_id_pressed(int p_id); // Bottom panel. - Label *missing_tileset_label = nullptr; + Label *cant_edit_label = nullptr; TabBar *tabs_bar = nullptr; LocalVector<TileMapLayerSubEditorPlugin::TabData> tabs_data; LocalVector<TileMapLayerSubEditorPlugin *> tabs_plugins; @@ -379,22 +401,20 @@ private: // Updates. void _layers_select_next_or_previous(bool p_next); - void _update_highlighting_toggle(); // Inspector undo/redo callback. void _move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, const String &p_array_prefix, int p_from_index, int p_to_pos); protected: void _notification(int p_what); - static void _bind_methods(); void _draw_shape(Control *p_control, Rect2 p_region, TileSet::TileShape p_shape, TileSet::TileOffsetAxis p_offset_axis, Color p_color); public: bool forward_canvas_gui_input(const Ref<InputEvent> &p_event); void forward_canvas_draw_over_viewport(Control *p_overlay); - void edit(TileMapLayer *p_tile_map_layer); - void update_layers_selector(); + void edit(Object *p_tile_map_layer); + void set_show_layer_selector(bool p_show_layer_selector); TileMapLayerEditor(); ~TileMapLayerEditor(); diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index ed21a29487..c3141beb1a 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/gui/editor_bottom_panel.h" +#include "editor/multi_node_edit.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/themes/editor_scale.h" #include "scene/2d/tile_map.h" @@ -336,7 +337,7 @@ void TileMapEditorPlugin::_tile_map_layer_removed() { void TileMapEditorPlugin::_update_tile_map() { TileMapLayer *edited_layer = Object::cast_to<TileMapLayer>(ObjectDB::get_instance(tile_map_layer_id)); if (edited_layer) { - Ref<TileSet> tile_set = edited_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = edited_layer->get_tile_set(); if (tile_set.is_valid() && tile_set_id != tile_set->get_instance_id()) { tile_set_plugin_singleton->edit(tile_set.ptr()); tile_set_plugin_singleton->make_visible(true); @@ -355,38 +356,25 @@ void TileMapEditorPlugin::_select_layer(const StringName &p_name) { ERR_FAIL_NULL(edited_layer); Node *parent = edited_layer->get_parent(); - ERR_FAIL_NULL(parent); - - TileMapLayer *new_layer = Object::cast_to<TileMapLayer>(parent->get_node_or_null(String(p_name))); - edit(new_layer); + if (parent) { + TileMapLayer *new_layer = Object::cast_to<TileMapLayer>(parent->get_node_or_null(String(p_name))); + edit(new_layer); + } } -void TileMapEditorPlugin::_edit_tile_map_layer(TileMapLayer *p_tile_map_layer) { +void TileMapEditorPlugin::_edit_tile_map_layer(TileMapLayer *p_tile_map_layer, bool p_show_layer_selector) { ERR_FAIL_NULL(p_tile_map_layer); editor->edit(p_tile_map_layer); - - // Update the selected layers in the TileMapLayerGroup parent node. - TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(p_tile_map_layer->get_parent()); - if (tile_map_layer_group) { - Vector<StringName> selected; - selected.push_back(p_tile_map_layer->get_name()); - tile_map_layer_group->set_selected_layers(selected); - } + editor->set_show_layer_selector(p_show_layer_selector); // Update the object IDs. tile_map_layer_id = p_tile_map_layer->get_instance_id(); p_tile_map_layer->connect("changed", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_changed)); p_tile_map_layer->connect("tree_exited", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_removed)); - if (tile_map_layer_group) { - tile_map_group_id = tile_map_layer_group->get_instance_id(); - tile_map_layer_group->connect("child_entered_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1)); - tile_map_layer_group->connect("child_exiting_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1)); - tile_map_layer_group->connect("child_order_changed", callable_mp(editor, &TileMapLayerEditor::update_layers_selector)); - } // Update the edited tileset. - Ref<TileSet> tile_set = p_tile_map_layer->get_effective_tile_set(); + Ref<TileSet> tile_set = p_tile_map_layer->get_tile_set(); if (tile_set.is_valid()) { tile_set_plugin_singleton->edit(tile_set.ptr()); tile_set_plugin_singleton->make_visible(true); @@ -397,30 +385,15 @@ void TileMapEditorPlugin::_edit_tile_map_layer(TileMapLayer *p_tile_map_layer) { } } -void TileMapEditorPlugin::_edit_tile_map_layer_group(TileMapLayerGroup *p_tile_map_layer_group) { - ERR_FAIL_NULL(p_tile_map_layer_group); - - Vector<StringName> selected_layers = p_tile_map_layer_group->get_selected_layers(); - - TileMapLayer *selected_layer = nullptr; - if (selected_layers.size() > 0) { - // Edit the selected layer. - selected_layer = Object::cast_to<TileMapLayer>(p_tile_map_layer_group->get_node_or_null(String(selected_layers[0]))); - } - if (!selected_layer) { - // Edit the first layer found. - for (int i = 0; i < p_tile_map_layer_group->get_child_count(); i++) { - selected_layer = Object::cast_to<TileMapLayer>(p_tile_map_layer_group->get_child(i)); - if (selected_layer) { - break; - } - } - } +void TileMapEditorPlugin::_edit_tile_map(TileMap *p_tile_map) { + ERR_FAIL_NULL(p_tile_map); - if (selected_layer) { - _edit_tile_map_layer(selected_layer); + if (p_tile_map->get_layers_count() > 0) { + TileMapLayer *selected_layer = Object::cast_to<TileMapLayer>(p_tile_map->get_child(0)); + _edit_tile_map_layer(selected_layer, true); } else { editor->edit(nullptr); + editor->set_show_layer_selector(false); } } @@ -437,36 +410,38 @@ void TileMapEditorPlugin::edit(Object *p_object) { edited_layer->disconnect("tree_exited", callable_mp(this, &TileMapEditorPlugin::_tile_map_layer_removed)); } - TileMapLayerGroup *tile_map_group = Object::cast_to<TileMapLayerGroup>(ObjectDB::get_instance(tile_map_group_id)); - if (tile_map_group) { - tile_map_group->disconnect("child_entered_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1)); - tile_map_group->disconnect("child_exiting_tree", callable_mp(editor, &TileMapLayerEditor::update_layers_selector).unbind(1)); - tile_map_group->disconnect("child_order_changed", callable_mp(editor, &TileMapLayerEditor::update_layers_selector)); - } - tile_map_group_id = ObjectID(); tile_map_layer_id = ObjectID(); tile_set_id = ObjectID(); - TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMap>(p_object); + TileMap *tile_map = Object::cast_to<TileMap>(p_object); TileMapLayer *tile_map_layer = Object::cast_to<TileMapLayer>(p_object); - if (tile_map_layer_group) { - _edit_tile_map_layer_group(tile_map_layer_group); + MultiNodeEdit *multi_node_edit = Object::cast_to<MultiNodeEdit>(p_object); + if (tile_map) { + _edit_tile_map(tile_map); } else if (tile_map_layer) { - _edit_tile_map_layer(tile_map_layer); + _edit_tile_map_layer(tile_map_layer, false); + } else if (multi_node_edit) { + editor->edit(multi_node_edit); } else { - // Deselect the layer in the group. - if (edited_layer) { - tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(edited_layer->get_parent()); - if (tile_map_layer_group) { - tile_map_layer_group->set_selected_layers(Vector<StringName>()); - } - } + editor->edit(nullptr); } } bool TileMapEditorPlugin::handles(Object *p_object) const { - return Object::cast_to<TileMapLayer>(p_object) != nullptr || Object::cast_to<TileMapLayerGroup>(p_object) != nullptr; + MultiNodeEdit *multi_node_edit = Object::cast_to<MultiNodeEdit>(p_object); + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + if (multi_node_edit && edited_scene) { + bool only_tile_map_layers = true; + for (int i = 0; i < multi_node_edit->get_node_count(); i++) { + if (!Object::cast_to<TileMapLayer>(edited_scene->get_node(multi_node_edit->get_node(i)))) { + only_tile_map_layers = false; + break; + } + } + return only_tile_map_layers; + } + return Object::cast_to<TileMapLayer>(p_object) != nullptr || Object::cast_to<TileMap>(p_object) != nullptr; } void TileMapEditorPlugin::make_visible(bool p_visible) { @@ -509,7 +484,6 @@ TileMapEditorPlugin::TileMapEditorPlugin() { editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); - editor->connect("change_selected_layer_request", callable_mp(this, &TileMapEditorPlugin::_select_layer)); editor->hide(); button = EditorNode::get_bottom_panel()->add_item(TTR("TileMap"), editor, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_tile_map_bottom_panel", TTR("Toggle TileMap Bottom Panel"))); diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h index ac3e8986d6..23a6a52a5c 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.h +++ b/editor/plugins/tiles/tiles_editor_plugin.h @@ -126,8 +126,8 @@ class TileMapEditorPlugin : public EditorPlugin { void _update_tile_map(); void _select_layer(const StringName &p_name); - void _edit_tile_map_layer(TileMapLayer *p_tile_map_layer); - void _edit_tile_map_layer_group(TileMapLayerGroup *p_tile_map_layer_group); + void _edit_tile_map_layer(TileMapLayer *p_tile_map_layer, bool p_show_layer_selector); + void _edit_tile_map(TileMap *p_tile_map); protected: void _notification(int p_notification); diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 9460f9fef2..9173838471 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -93,8 +93,7 @@ void VersionControlEditorPlugin::popup_vcs_set_up_dialog(const Control *p_gui_ba if (!available_plugins.is_empty()) { Size2 popup_size = Size2(400, 100); Size2 window_size = p_gui_base->get_viewport_rect().size; - popup_size.x = MIN(window_size.x * 0.5, popup_size.x); - popup_size.y = MIN(window_size.y * 0.5, popup_size.y); + popup_size = popup_size.min(window_size * 0.5); _populate_available_vcs_names(); @@ -912,7 +911,7 @@ void VersionControlEditorPlugin::fetch_available_vcs_plugin_names() { } void VersionControlEditorPlugin::register_editor() { - EditorDockManager::get_singleton()->add_control_to_dock(EditorDockManager::DOCK_SLOT_RIGHT_UL, version_commit_dock); + EditorDockManager::get_singleton()->add_dock(version_commit_dock, "", EditorDockManager::DOCK_SLOT_RIGHT_UL); version_control_dock_button = EditorNode::get_bottom_panel()->add_item(TTR("Version Control"), version_control_dock, ED_SHORTCUT_AND_COMMAND("bottom_panels/toggle_version_control_bottom_panel", TTR("Toggle Version Control Bottom Panel"))); @@ -932,7 +931,7 @@ void VersionControlEditorPlugin::shut_down() { memdelete(EditorVCSInterface::get_singleton()); EditorVCSInterface::set_singleton(nullptr); - EditorDockManager::get_singleton()->remove_control_from_dock(version_commit_dock); + EditorDockManager::get_singleton()->remove_dock(version_commit_dock); EditorNode::get_bottom_panel()->remove_item(version_control_dock); _set_vcs_ui_state(false); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index b6a4a14117..c83c47577d 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -5716,6 +5716,7 @@ VisualShaderEditor::VisualShaderEditor() { members = memnew(Tree); members_vb->add_child(members); SET_DRAG_FORWARDING_GCD(members, VisualShaderEditor); + members->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); // TODO: Implement proper translation switch. members->set_h_size_flags(SIZE_EXPAND_FILL); members->set_v_size_flags(SIZE_EXPAND_FILL); members->set_hide_root(true); @@ -5818,6 +5819,7 @@ VisualShaderEditor::VisualShaderEditor() { varyings = memnew(Tree); vb->add_child(varyings); + varyings->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); varyings->set_h_size_flags(SIZE_EXPAND_FILL); varyings->set_v_size_flags(SIZE_EXPAND_FILL); varyings->set_hide_root(true); @@ -6920,6 +6922,8 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par } else if (Object::cast_to<EditorPropertyEnum>(prop)) { prop->set_custom_minimum_size(Size2(100 * EDSCALE, 0)); Object::cast_to<EditorPropertyEnum>(prop)->set_option_button_clip(false); + } else if (Object::cast_to<EditorPropertyColor>(prop)) { + Object::cast_to<EditorPropertyColor>(prop)->set_live_changes_enabled(false); } editors.push_back(prop); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index b951e9453e..86c59ec99e 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -44,6 +44,7 @@ #include "editor/editor_settings.h" #include "editor/editor_string_names.h" #include "editor/gui/editor_file_dialog.h" +#include "editor/gui/editor_title_bar.h" #include "editor/plugins/asset_library_editor_plugin.h" #include "editor/project_manager/project_dialog.h" #include "editor/project_manager/project_list.h" @@ -80,6 +81,12 @@ void ProjectManager::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { Engine::get_singleton()->set_editor_hint(false); + Window *main_window = get_window(); + if (main_window) { + // Handle macOS fullscreen and extend-to-title changes. + main_window->connect("titlebar_changed", callable_mp(this, &ProjectManager::_titlebar_resized)); + } + // Theme has already been created in the constructor, so we can skip that step. _update_theme(true); } break; @@ -91,6 +98,7 @@ void ProjectManager::_notification(int p_what) { _select_main_view(MAIN_VIEW_PROJECTS); _update_list_placeholder(); + _titlebar_resized(); } break; case NOTIFICATION_VISIBILITY_CHANGED: { @@ -1007,6 +1015,24 @@ void ProjectManager::_files_dropped(PackedStringArray p_files) { project_list->find_projects_multiple(folders); } +void ProjectManager::_titlebar_resized() { + DisplayServer::get_singleton()->window_set_window_buttons_offset(Vector2i(title_bar->get_global_position().y + title_bar->get_size().y / 2, title_bar->get_global_position().y + title_bar->get_size().y / 2), DisplayServer::MAIN_WINDOW_ID); + const Vector3i &margin = DisplayServer::get_singleton()->window_get_safe_title_margins(DisplayServer::MAIN_WINDOW_ID); + if (left_menu_spacer) { + int w = (root_container->is_layout_rtl()) ? margin.y : margin.x; + left_menu_spacer->set_custom_minimum_size(Size2(w, 0)); + right_spacer->set_custom_minimum_size(Size2(w, 0)); + } + if (right_menu_spacer) { + int w = (root_container->is_layout_rtl()) ? margin.x : margin.y; + right_menu_spacer->set_custom_minimum_size(Size2(w, 0)); + left_spacer->set_custom_minimum_size(Size2(w, 0)); + } + if (title_bar) { + title_bar->set_custom_minimum_size(Size2(0, margin.z - title_bar->get_global_position().y)); + } +} + // Object methods. ProjectManager::ProjectManager() { @@ -1102,10 +1128,19 @@ ProjectManager::ProjectManager() { root_container->add_child(main_vbox); // Title bar. + bool can_expand = bool(EDITOR_GET("interface/editor/expand_to_title")) && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_EXTEND_TO_TITLE); + { - title_bar = memnew(HBoxContainer); + title_bar = memnew(EditorTitleBar); main_vbox->add_child(title_bar); + if (can_expand) { + // Add spacer to avoid other controls under window minimize/maximize/close buttons (left side). + left_menu_spacer = memnew(Control); + left_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS); + title_bar->add_child(left_menu_spacer); + } + HBoxContainer *left_hbox = memnew(HBoxContainer); left_hbox->set_alignment(BoxContainer::ALIGNMENT_BEGIN); left_hbox->set_h_size_flags(Control::SIZE_EXPAND_FILL); @@ -1117,12 +1152,26 @@ ProjectManager::ProjectManager() { left_hbox->add_child(title_bar_logo); title_bar_logo->connect("pressed", callable_mp(this, &ProjectManager::_show_about)); + if (can_expand) { + // Spacer to center main toggles. + left_spacer = memnew(Control); + left_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS); + title_bar->add_child(left_spacer); + } + main_view_toggles = memnew(HBoxContainer); main_view_toggles->set_alignment(BoxContainer::ALIGNMENT_CENTER); main_view_toggles->set_h_size_flags(Control::SIZE_EXPAND_FILL); main_view_toggles->set_stretch_ratio(2.0); title_bar->add_child(main_view_toggles); + if (can_expand) { + // Spacer to center main toggles. + right_spacer = memnew(Control); + right_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS); + title_bar->add_child(right_spacer); + } + main_view_toggles_group.instantiate(); HBoxContainer *right_hbox = memnew(HBoxContainer); @@ -1136,6 +1185,13 @@ ProjectManager::ProjectManager() { quick_settings_button->set_text(TTR("Settings")); right_hbox->add_child(quick_settings_button); quick_settings_button->connect("pressed", callable_mp(this, &ProjectManager::_show_quick_settings)); + + if (can_expand) { + // Add spacer to avoid other controls under the window minimize/maximize/close buttons (right side). + right_menu_spacer = memnew(Control); + right_menu_spacer->set_mouse_filter(Control::MOUSE_FILTER_PASS); + title_bar->add_child(right_menu_spacer); + } } main_view_container = memnew(PanelContainer); @@ -1537,6 +1593,14 @@ ProjectManager::ProjectManager() { } } + // Extend menu bar to window title. + if (can_expand) { + DisplayServer::get_singleton()->process_events(); + DisplayServer::get_singleton()->window_set_flag(DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE, true, DisplayServer::MAIN_WINDOW_ID); + title_bar->set_can_move_window(true); + title_bar->connect("item_rect_changed", callable_mp(this, &ProjectManager::_titlebar_resized)); + } + _update_size_limits(); } diff --git a/editor/project_manager.h b/editor/project_manager.h index 1c829e971d..d472666d1a 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -38,6 +38,7 @@ class CheckBox; class EditorAbout; class EditorAssetLibrary; class EditorFileDialog; +class EditorTitleBar; class HFlowContainer; class LineEdit; class LinkButton; @@ -71,12 +72,17 @@ class ProjectManager : public Control { void _update_size_limits(); void _update_theme(bool p_skip_creation = false); + void _titlebar_resized(); MarginContainer *root_container = nullptr; Panel *background_panel = nullptr; VBoxContainer *main_vbox = nullptr; - HBoxContainer *title_bar = nullptr; + EditorTitleBar *title_bar = nullptr; + Control *left_menu_spacer = nullptr; + Control *left_spacer = nullptr; + Control *right_menu_spacer = nullptr; + Control *right_spacer = nullptr; Button *title_bar_logo = nullptr; HBoxContainer *main_view_toggles = nullptr; Button *quick_settings_button = nullptr; diff --git a/editor/property_selector.cpp b/editor/property_selector.cpp index be5f309704..ac175d01a6 100644 --- a/editor/property_selector.cpp +++ b/editor/property_selector.cpp @@ -557,6 +557,7 @@ PropertySelector::PropertySelector() { search_box->connect("text_changed", callable_mp(this, &PropertySelector::_text_changed)); search_box->connect("gui_input", callable_mp(this, &PropertySelector::_sbox_input)); search_options = memnew(Tree); + search_options->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); vbc->add_margin_child(TTR("Matches:"), search_options, true); set_ok_button_text(TTR("Open")); get_ok_button()->set_disabled(true); diff --git a/editor/reparent_dialog.cpp b/editor/reparent_dialog.cpp index ec5208b549..a139d180f0 100644 --- a/editor/reparent_dialog.cpp +++ b/editor/reparent_dialog.cpp @@ -60,7 +60,7 @@ void ReparentDialog::_reparent() { void ReparentDialog::set_current(const HashSet<Node *> &p_selection) { tree->set_marked(p_selection, false, false); - //tree->set_selected(p_node->get_parent()); + tree->set_selected(nullptr); } void ReparentDialog::_bind_methods() { @@ -74,7 +74,6 @@ ReparentDialog::ReparentDialog() { VBoxContainer *vbc = memnew(VBoxContainer); add_child(vbc); - //set_child_rect(vbc); tree = memnew(SceneTreeEditor(false)); tree->set_show_enabled_subscene(true); @@ -86,10 +85,6 @@ ReparentDialog::ReparentDialog() { keep_transform->set_pressed(true); vbc->add_child(keep_transform); - //vbc->add_margin_child("Options:",node_only); - - //cancel->connect("pressed", this,"_cancel"); - set_ok_button_text(TTR("Reparent")); } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index c6e122dde8..26ddec6603 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -3156,7 +3156,7 @@ void SceneTreeDock::_files_dropped(const Vector<String> &p_files, NodePath p_to, const EditorPropertyNameProcessor::Style style = InspectorDock::get_singleton()->get_property_name_style(); menu_properties->clear(); for (const String &p : valid_properties) { - menu_properties->add_item(EditorPropertyNameProcessor::get_singleton()->process_name(p, style)); + menu_properties->add_item(EditorPropertyNameProcessor::get_singleton()->process_name(p, style, p, node->get_class_name())); menu_properties->set_item_metadata(-1, p); } @@ -3511,6 +3511,7 @@ void SceneTreeDock::_update_tree_menu() { tree_menu->set_item_tooltip(tree_menu->get_item_index(TOOL_CENTER_PARENT), TTR("If enabled, Reparent to New Node will create the new node in the center of the selected nodes, if possible.")); PopupMenu *resource_list = memnew(PopupMenu); + resource_list->set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED); resource_list->connect("about_to_popup", callable_mp(this, &SceneTreeDock::_list_all_subresources).bind(resource_list)); resource_list->connect("index_pressed", callable_mp(this, &SceneTreeDock::_edit_subresource).bind(resource_list)); tree_menu->add_submenu_node_item(TTR("All Scene Sub-Resources"), resource_list); diff --git a/gles3_builders.py b/gles3_builders.py index 985e9d547c..cf7c74f32d 100644 --- a/gles3_builders.py +++ b/gles3_builders.py @@ -31,7 +31,7 @@ class GLES3HeaderStruct: def include_file_in_gles3_header(filename: str, header_data: GLES3HeaderStruct, depth: int): - with open(filename, "r") as fs: + with open(filename, "r", encoding="utf-8") as fs: line = fs.readline() while line: diff --git a/glsl_builders.py b/glsl_builders.py index fd90e9a6c0..5a17e3ca7f 100644 --- a/glsl_builders.py +++ b/glsl_builders.py @@ -38,7 +38,7 @@ class RDHeaderStruct: def include_file_in_rd_header(filename: str, header_data: RDHeaderStruct, depth: int) -> RDHeaderStruct: - with open(filename, "r") as fs: + with open(filename, "r", encoding="utf-8") as fs: line = fs.readline() while line: @@ -172,7 +172,7 @@ class RAWHeaderStruct: def include_file_in_raw_header(filename: str, header_data: RAWHeaderStruct, depth: int) -> None: - with open(filename, "r") as fs: + with open(filename, "r", encoding="utf-8") as fs: line = fs.readline() while line: @@ -1 +1 @@ -<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg> +<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg> diff --git a/icon_outlined.svg b/icon_outlined.svg index 6b31d44e9a..43cc110fea 100644 --- a/icon_outlined.svg +++ b/icon_outlined.svg @@ -1 +1 @@ -<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="M105 745c0 276 813 276 813 0V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81v318z" fill="none" stroke="#fff" stroke-width="64" stroke-linejoin="round"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg> +<svg width="1024" height="1024" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="M105 745c0 276 813 276 814 0V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81v318z" fill="none" stroke="#fff" stroke-width="64" stroke-linejoin="round"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg>
\ No newline at end of file @@ -1 +1 @@ -<svg width="1024" height="414" viewBox="0 0 1024 414" xmlns="http://www.w3.org/2000/svg"><path fill="#414042" d="M523.82 188.382c-9.142-.142-19.603 1.764-19.603 1.764v17.842h10.52l-.117 7.953c0 2.946-2.92 4.427-8.747 4.427-5.831 0-10.982-2.47-15.45-7.395-4.48-4.932-6.708-12.141-6.708-21.64 0-9.519 2.176-16.537 6.536-21.065 4.35-4.524 10.05-6.794 17.064-6.794 2.946 0 5.996.476 9.168 1.445 3.174.962 5.293 1.863 6.375 2.707 1.072.867 2.09 1.277 3.056 1.277.96 0 2.513-1.122 4.66-3.392 2.153-2.263 4.082-5.693 5.782-10.267 1.694-4.598 2.543-8.122 2.543-10.621 0-2.48-.054-4.19-.164-5.092-2.379-2.603-6.767-4.666-13.168-6.2-6.39-1.53-13.552-2.289-21.476-2.289-17.438 0-31.073 5.49-40.92 16.47-9.855 10.982-14.773 25.24-14.773 42.79 0 20.607 5.035 36.227 15.103 46.868 10.085 10.64 23.327 15.953 39.743 15.953 8.827 0 16.664-.76 23.51-2.289 6.853-1.523 11.41-3.088 13.676-4.67l.68-53.137c0-3.087-8.149-4.488-17.29-4.645zm84.247-24.804c-5.431 0-9.98 2.496-13.671 7.47-3.672 4.98-5.517 11.969-5.517 20.963 0 9.013 1.754 15.914 5.27 20.722 3.508 4.823 8.117 7.225 13.835 7.225 5.715 0 10.358-2.432 13.924-7.313 3.566-4.862 5.353-11.823 5.353-20.884 0-9.054-1.846-16.023-5.524-20.89-3.674-4.861-8.23-7.293-13.67-7.293m-.083 89.477c-15.9 0-28.868-5.203-38.89-15.61-10.01-10.416-15.017-25.614-15.017-45.592 0-19.992 5.063-35.128 15.191-45.435 10.131-10.293 23.209-15.444 39.228-15.444 16.016 0 28.954 5.058 38.795 15.204 9.858 10.126 14.778 25.477 14.778 46.009 0 20.546-5.034 35.828-15.114 45.856-10.08 10.008-23.062 15.012-38.971 15.012m101.95-88.298v50.788c0 2.37.176 3.866.515 4.493.337.624 1.358.937 3.052.937 6.232 0 10.954-2.328 14.181-6.97 3.235-4.636 4.835-12.356 4.835-23.168 0-10.817-1.674-17.865-5-21.139-3.344-3.283-8.64-4.94-15.884-4.94zm-32.599 78.798V141.681c0-2.832.704-5.067 2.126-6.724 1.413-1.632 3.25-2.461 5.521-2.461h28.357c17.994 0 31.664 4.54 40.994 13.597 9.347 9.054 14.02 23.31 14.02 42.784 0 41.66-17.778 62.486-53.326 62.486h-29.03c-5.769 0-8.662-2.597-8.662-7.808m156.544-79.977c-5.432 0-9.994 2.496-13.678 7.47-3.67 4.98-5.508 11.969-5.508 20.963 0 9.013 1.758 15.914 5.262 20.722 3.505 4.823 8.119 7.225 13.837 7.225 5.717 0 10.363-2.432 13.924-7.313 3.568-4.862 5.355-11.823 5.355-20.884 0-9.054-1.843-16.023-5.522-20.89-3.68-4.861-8.23-7.293-13.67-7.293m-.087 89.477c-15.907 0-28.866-5.203-38.88-15.61-10.021-10.416-15.03-25.614-15.03-45.592 0-19.992 5.065-35.128 15.191-45.435 10.139-10.293 23.209-15.444 39.233-15.444 16.02 0 28.946 5.058 38.8 15.204 9.85 10.126 14.772 25.477 14.772 46.009 0 20.546-5.037 35.828-15.115 45.856-10.076 10.008-23.07 15.012-38.971 15.012m117.69-4.17c0 2.251-5.597 3.392-16.809 3.392-11.202 0-16.815-1.141-16.815-3.392v-85.248h-20.371c-1.928 0-3.286-2.597-4.077-7.818a56.267 56.267 0 0 1-.501-7.636c0-2.592.162-5.146.501-7.636.79-5.205 2.15-7.823 4.077-7.823h73.864c1.924 0 3.277 2.617 4.078 7.823.333 2.49.505 5.043.505 7.636 0 2.608-.172 5.152-.505 7.637-.8 5.22-2.154 7.817-4.078 7.817h-19.87z"/><path fill="#6d6e71" d="M487.93 322.997c-.94 1.926-2.664 3.691-5.188 5.289-2.52 1.607-5.722 2.406-9.611 2.406-5.132 0-9.259-1.617-12.394-4.887-3.122-3.243-4.686-7.92-4.686-14.022V296.57c0-5.97 1.473-10.548 4.431-13.743 2.95-3.17 6.903-4.78 11.84-4.78 4.824 0 8.564 1.27 11.212 3.781 2.639 2.519 4.025 6.038 4.146 10.532l-.066.2h-3.94c-.14-3.443-1.14-6.101-3.022-7.979-1.871-1.861-4.655-2.803-8.33-2.803-3.72 0-6.668 1.259-8.823 3.785-2.15 2.518-3.224 6.17-3.224 10.968v15.301c0 4.975 1.16 8.768 3.476 11.382 2.316 2.592 5.438 3.892 9.38 3.892 2.876 0 5.19-.51 6.92-1.554 1.738-1.028 2.942-2.285 3.624-3.775V308.45h-10.618v-3.704h14.873zm19.557 3.902c2.336 0 4.416-.661 6.232-2.01 1.82-1.353 3.096-3.063 3.852-5.146v-8.224h-6.756c-2.873 0-5.173.814-6.896 2.442-1.726 1.617-2.581 3.637-2.581 6.037 0 2.03.534 3.696 1.616 4.981 1.08 1.289 2.59 1.92 4.533 1.92m10.715 3.068a99.251 99.251 0 0 1-.48-3.225 21.745 21.745 0 0 1-.15-2.562 14.867 14.867 0 0 1-4.483 4.675c-1.836 1.236-3.878 1.848-6.128 1.848-3.147 0-5.567-.975-7.28-2.927-1.702-1.96-2.563-4.6-2.563-7.936 0-3.523 1.237-6.35 3.72-8.448 2.48-2.098 5.85-3.147 10.09-3.147h6.643v-4.672c0-2.686-.686-4.802-2.032-6.331-1.375-1.51-3.264-2.275-5.701-2.275-2.268 0-4.139.722-5.608 2.182-1.463 1.45-2.19 3.224-2.19 5.337l-3.944-.035-.07-.206c-.11-2.866.973-5.4 3.261-7.646 2.279-2.24 5.203-3.352 8.761-3.352 3.517 0 6.347 1.069 8.509 3.2 2.148 2.152 3.226 5.221 3.226 9.21v18.645c0 1.358.064 2.677.183 3.936a24.853 24.853 0 0 0 .627 3.729zm16.905-38.108.36 5.9c1-2.112 2.339-3.739 3.998-4.896 1.664-1.141 3.624-1.711 5.874-1.711 2.296 0 4.232.668 5.794 2.02 1.562 1.347 2.714 3.387 3.446 6.127.938-2.529 2.264-4.528 3.986-5.975 1.722-1.45 3.812-2.172 6.23-2.172 3.335 0 5.923 1.35 7.755 4.05 1.841 2.705 2.759 6.856 2.759 12.464v22.207h-4.246v-22.28c0-4.663-.645-7.946-1.9-9.834-1.261-1.89-3.071-2.842-5.41-2.842-2.462 0-4.384 1.04-5.767 3.152-1.375 2.112-2.223 4.754-2.531 7.945v23.86h-4.224v-22.258c0-4.554-.639-7.812-1.945-9.759-1.299-1.946-3.107-2.912-5.427-2.912-2.218 0-4.013.677-5.358 2.02-1.353 1.349-2.315 3.195-2.899 5.538v27.369h-4.22v-38.014zm61.457 3.021c-2.644 0-4.816 1.205-6.517 3.613-1.705 2.415-2.585 5.392-2.656 8.938h17.537v-1.626c0-3.137-.736-5.75-2.21-7.822-1.482-2.075-3.53-3.103-6.154-3.103m.598 35.735c-4.099 0-7.451-1.543-10.055-4.621-2.596-3.073-3.896-7.005-3.896-11.793v-6.313c0-4.798 1.303-8.798 3.912-11.979 2.616-3.167 5.758-4.75 9.441-4.75 3.983 0 7.068 1.413 9.27 4.246 2.209 2.837 3.312 6.65 3.312 11.434v4.171H587.39v3.162c0 3.68.882 6.744 2.635 9.19 1.757 2.45 4.144 3.666 7.136 3.666 2.077 0 3.888-.367 5.396-1.089a11.119 11.119 0 0 0 3.877-3.132l1.728 2.99c-1.148 1.456-2.634 2.633-4.45 3.505-1.811.868-4 1.312-6.551 1.312m46.411-35.734c-2.651 0-4.827 1.205-6.528 3.613-1.694 2.415-2.576 5.392-2.652 8.938h17.54v-1.626c0-3.137-.733-5.75-2.216-7.822-1.475-2.075-3.52-3.103-6.144-3.103m.593 35.735c-4.1 0-7.446-1.543-10.045-4.621-2.606-3.073-3.91-7.005-3.91-11.793v-6.313c0-4.798 1.309-8.798 3.913-11.979 2.623-3.167 5.766-4.75 9.45-4.75 3.975 0 7.072 1.413 9.27 4.246 2.2 2.837 3.304 6.65 3.304 11.434v4.171h-21.755v3.162c0 3.68.883 6.744 2.647 9.19 1.747 2.45 4.124 3.666 7.125 3.666 2.087 0 3.888-.367 5.392-1.089a11.229 11.229 0 0 0 3.894-3.132l1.717 2.99c-1.15 1.456-2.633 2.633-4.451 3.505-1.81.868-3.997 1.312-6.55 1.312m23.189-38.755.345 6.284c1.014-2.23 2.353-3.962 4.034-5.166 1.667-1.21 3.63-1.824 5.887-1.824 3.396 0 5.998 1.256 7.804 3.78 1.826 2.518 2.73 6.434 2.73 11.749v23.191h-4.249V306.72c0-4.343-.636-7.377-1.9-9.137-1.258-1.76-3.107-2.636-5.513-2.636-2.158 0-3.968.701-5.419 2.126-1.457 1.412-2.543 3.294-3.267 5.666v27.134h-4.219V291.86zm33.27 22.395c0 3.858.73 6.926 2.213 9.208 1.465 2.304 3.695 3.443 6.671 3.443 2.04 0 3.757-.544 5.167-1.657 1.405-1.113 2.514-2.662 3.336-4.627V301.79c-.79-2.025-1.874-3.66-3.244-4.92-1.368-1.24-3.102-1.863-5.186-1.863-2.97 0-5.216 1.294-6.708 3.891-1.502 2.603-2.25 5.995-2.25 10.161zm-4.262-5.195c0-5.386 1.088-9.714 3.274-12.975 2.169-3.245 5.187-4.871 9.03-4.871 2.134 0 4.007.52 5.607 1.564 1.603 1.024 2.928 2.523 3.992 4.43l.412-5.287h3.581v38.048c0 4.871-1.13 8.646-3.4 11.317-2.271 2.66-5.499 4.009-9.666 4.009-1.5 0-3.11-.235-4.832-.691-1.724-.456-3.252-1.054-4.59-1.805l1.168-3.704a14.108 14.108 0 0 0 3.831 1.716 15.179 15.179 0 0 0 4.352.616c3.023 0 5.262-.97 6.71-2.905 1.452-1.961 2.18-4.798 2.18-8.553v-4.597c-1.079 1.71-2.402 3.024-3.97 3.93-1.563.912-3.39 1.368-5.448 1.368-3.818 0-6.814-1.496-8.976-4.486-2.167-2.983-3.255-6.965-3.255-11.93zm40.2 20.916h-4.266V291.86h4.266zm0-48.968h-4.266v-6.005h4.266zm13.774 10.852.346 6.284c1.016-2.23 2.35-3.962 4.027-5.166 1.677-1.21 3.643-1.824 5.89-1.824 3.397 0 6.01 1.256 7.82 3.78 1.821 2.518 2.717 6.434 2.717 11.749v23.191h-4.248V306.72c0-4.343-.635-7.377-1.897-9.137-1.268-1.76-3.103-2.636-5.517-2.636-2.157 0-3.962.701-5.412 2.126-1.455 1.412-2.545 3.294-3.266 5.666v27.134h-4.224V291.86zm42.074 3.021c-2.652 0-4.825 1.205-6.518 3.613-1.699 2.415-2.584 5.392-2.66 8.938h17.54v-1.626c0-3.137-.731-5.75-2.21-7.822-1.476-2.075-3.525-3.103-6.152-3.103m.602 35.735c-4.11 0-7.456-1.543-10.048-4.621-2.602-3.073-3.903-7.005-3.903-11.793v-6.313c0-4.798 1.302-8.798 3.91-11.979 2.616-3.167 5.763-4.75 9.439-4.75 3.978 0 7.077 1.413 9.283 4.246 2.197 2.837 3.3 6.65 3.3 11.434v4.171h-21.76v3.162c0 3.68.887 6.744 2.642 9.19 1.754 2.45 4.133 3.666 7.137 3.666 2.08 0 3.88-.367 5.382-1.089a11.157 11.157 0 0 0 3.897-3.132l1.725 2.99c-1.156 1.456-2.64 2.633-4.454 3.505-1.81.868-3.998 1.312-6.55 1.312"/><g fill="#fff"><path d="M68.264 264.04v11.88q146.52 127.44 293.04 0v-11.88z"/><path fill="#478cbf" d="m68.264 264.04 54.72 5.04q4.32.36 5.4 5.04l1.44 24.12 47.52 3.6 2.88-21.96q.72-3.96 5.4-5.4h58.32q4.68 1.44 5.4 5.4l2.88 21.96 47.52-3.6 1.44-24.12q1.08-4.68 5.4-5.04l54.72-5.04v-88.56q10.8-14.04 20.16-29.16-12.6-21.24-29.88-38.88-15.48 7.2-29.52 16.92-14.4-13.32-31.68-23.04 2.52-18.36 2.88-36.72-21.24-10.08-44.28-15.12-9.36 15.48-16.56 32.04-17.64-2.52-35.28 0-7.2-16.56-16.56-32.04-23.04 5.04-44.28 15.12.36 18.36 2.88 36.72-17.28 9.72-31.68 23.04-14.04-9.72-29.52-16.92-17.28 17.64-29.88 38.88 9.36 15.12 20.16 29.16zm0 11.88v14.04c0 99.36 292.68 99.36 292.68 0v-14.04l-48.24 4.32-1.8 24.84q-.72 3.6-5.04 4.68l-58.32 3.96q-4.32 0-5.76-3.96l-3.6-23.4h-46.8l-3.6 23.4q-1.44 3.96-5.76 3.96l-58.32-3.96q-4.32-1.08-5.04-4.68l-1.8-24.84z"/><path d="M204.344 237.76c1.08 12.24 19.8 12.24 20.88 0V206.8c-1.08-12.24-19.8-12.24-20.88 0z"/><circle cx="291.464" cy="211.12" r="32.4"/><circle cx="138.104" cy="211.12" r="32.4"/></g><g fill="#414042"><circle cx="140.984" cy="213.28" r="21.6"/><circle cx="288.584" cy="213.28" r="21.6"/></g></svg> +<svg width="1024" height="414" viewBox="0 0 1024 414" xmlns="http://www.w3.org/2000/svg"><path fill="#414042" d="M523.82 188.382c-9.142-.142-19.603 1.764-19.603 1.764v17.842h10.52l-.117 7.953c0 2.946-2.92 4.427-8.747 4.427-5.831 0-10.982-2.47-15.45-7.395-4.48-4.932-6.708-12.141-6.708-21.64 0-9.519 2.176-16.537 6.536-21.065 4.35-4.524 10.05-6.794 17.064-6.794 2.946 0 5.996.476 9.168 1.445 3.174.962 5.293 1.863 6.375 2.707 1.072.867 2.09 1.277 3.056 1.277.96 0 2.513-1.122 4.66-3.392 2.153-2.263 4.082-5.693 5.782-10.267 1.694-4.598 2.543-8.122 2.543-10.621 0-2.48-.054-4.19-.164-5.092-2.379-2.603-6.767-4.666-13.168-6.2-6.39-1.53-13.552-2.289-21.476-2.289-17.438 0-31.073 5.49-40.92 16.47-9.855 10.982-14.773 25.24-14.773 42.79 0 20.607 5.035 36.227 15.103 46.868 10.085 10.64 23.327 15.953 39.743 15.953 8.827 0 16.664-.76 23.51-2.289 6.853-1.523 11.41-3.088 13.676-4.67l.68-53.137c0-3.087-8.149-4.488-17.29-4.645m84.247-24.804c-5.431 0-9.98 2.496-13.671 7.47-3.672 4.98-5.517 11.969-5.517 20.963 0 9.013 1.754 15.914 5.27 20.722 3.508 4.823 8.117 7.225 13.835 7.225 5.715 0 10.358-2.432 13.924-7.313q5.351-7.293 5.353-20.884c0-9.054-1.846-16.023-5.524-20.89q-5.51-7.292-13.67-7.293m-.083 89.477c-15.9 0-28.868-5.203-38.89-15.61q-15.016-15.624-15.017-45.592c0-19.992 5.063-35.128 15.191-45.435 10.131-10.293 23.209-15.444 39.228-15.444 16.016 0 28.954 5.058 38.795 15.204 9.858 10.126 14.778 25.477 14.778 46.009 0 20.546-5.034 35.828-15.114 45.856-10.08 10.008-23.062 15.012-38.971 15.012m101.95-88.298v50.788c0 2.37.176 3.866.515 4.493.337.624 1.358.937 3.052.937 6.232 0 10.954-2.328 14.181-6.97 3.235-4.636 4.835-12.356 4.835-23.168 0-10.817-1.674-17.865-5-21.139-3.344-3.283-8.64-4.94-15.884-4.94zm-32.599 78.798V141.681c0-2.832.704-5.067 2.126-6.724 1.413-1.632 3.25-2.461 5.521-2.461h28.357c17.994 0 31.664 4.54 40.994 13.597 9.347 9.054 14.02 23.31 14.02 42.784 0 41.66-17.778 62.486-53.326 62.486h-29.03c-5.769 0-8.662-2.597-8.662-7.808m156.544-79.977c-5.432 0-9.994 2.496-13.678 7.47q-5.507 7.471-5.508 20.963c0 9.013 1.758 15.914 5.262 20.722 3.505 4.823 8.119 7.225 13.837 7.225 5.717 0 10.363-2.432 13.924-7.313q5.354-7.293 5.355-20.884c0-9.054-1.843-16.023-5.522-20.89-3.68-4.861-8.23-7.293-13.67-7.293m-.087 89.477q-23.86 0-38.88-15.61-15.03-15.624-15.03-45.592c0-19.992 5.065-35.128 15.191-45.435 10.139-10.293 23.209-15.444 39.233-15.444 16.02 0 28.946 5.058 38.8 15.204 9.85 10.126 14.772 25.477 14.772 46.009 0 20.546-5.037 35.828-15.115 45.856-10.076 10.008-23.07 15.012-38.971 15.012m117.69-4.17c0 2.251-5.597 3.392-16.809 3.392-11.202 0-16.815-1.141-16.815-3.392v-85.248h-20.371c-1.928 0-3.286-2.597-4.077-7.818a56 56 0 0 1-.501-7.636c0-2.592.162-5.146.501-7.636.79-5.205 2.15-7.823 4.077-7.823h73.864c1.924 0 3.277 2.617 4.078 7.823.333 2.49.505 5.043.505 7.636 0 2.608-.172 5.152-.505 7.637-.8 5.22-2.154 7.817-4.078 7.817h-19.87z"/><path fill="#6d6e71" d="M487.93 322.997c-.94 1.926-2.664 3.691-5.188 5.289-2.52 1.607-5.722 2.406-9.611 2.406-5.132 0-9.259-1.617-12.394-4.887-3.122-3.243-4.686-7.92-4.686-14.022V296.57c0-5.97 1.473-10.548 4.431-13.743 2.95-3.17 6.903-4.78 11.84-4.78 4.824 0 8.564 1.27 11.212 3.781 2.639 2.519 4.025 6.038 4.146 10.532l-.066.2h-3.94c-.14-3.443-1.14-6.101-3.022-7.979-1.871-1.861-4.655-2.803-8.33-2.803-3.72 0-6.668 1.259-8.823 3.785-2.15 2.518-3.224 6.17-3.224 10.968v15.301q.001 7.462 3.476 11.382c2.316 2.592 5.438 3.892 9.38 3.892 2.876 0 5.19-.51 6.92-1.554 1.738-1.028 2.942-2.285 3.624-3.775V308.45h-10.618v-3.704h14.873zm19.557 3.902c2.336 0 4.416-.661 6.232-2.01 1.82-1.353 3.096-3.063 3.852-5.146v-8.224h-6.756q-4.31 0-6.896 2.442c-1.726 1.617-2.581 3.637-2.581 6.037 0 2.03.534 3.696 1.616 4.981 1.08 1.289 2.59 1.92 4.533 1.92m10.715 3.068a99 99 0 0 1-.48-3.225 22 22 0 0 1-.15-2.562 14.9 14.9 0 0 1-4.483 4.675c-1.836 1.236-3.878 1.848-6.128 1.848-3.147 0-5.567-.975-7.28-2.927-1.702-1.96-2.563-4.6-2.563-7.936 0-3.523 1.237-6.35 3.72-8.448 2.48-2.098 5.85-3.147 10.09-3.147h6.643v-4.672c0-2.686-.686-4.802-2.032-6.331-1.375-1.51-3.264-2.275-5.701-2.275-2.268 0-4.139.722-5.608 2.182-1.463 1.45-2.19 3.224-2.19 5.337l-3.944-.035-.07-.206c-.11-2.866.973-5.4 3.261-7.646 2.279-2.24 5.203-3.352 8.761-3.352 3.517 0 6.347 1.069 8.509 3.2q3.224 3.227 3.226 9.21v18.645c0 1.358.064 2.677.183 3.936a25 25 0 0 0 .627 3.729zm16.905-38.108.36 5.9c1-2.112 2.339-3.739 3.998-4.896q2.498-1.711 5.874-1.711c2.296 0 4.232.668 5.794 2.02 1.562 1.347 2.714 3.387 3.446 6.127.938-2.529 2.264-4.528 3.986-5.975 1.722-1.45 3.812-2.172 6.23-2.172 3.335 0 5.923 1.35 7.755 4.05 1.841 2.705 2.759 6.856 2.759 12.464v22.207h-4.246v-22.28c0-4.663-.645-7.946-1.9-9.834-1.261-1.89-3.071-2.842-5.41-2.842-2.462 0-4.384 1.04-5.767 3.152-1.375 2.112-2.223 4.754-2.531 7.945v23.86h-4.224v-22.258c0-4.554-.639-7.812-1.945-9.759-1.299-1.946-3.107-2.912-5.427-2.912-2.218 0-4.013.677-5.358 2.02-1.353 1.349-2.315 3.195-2.899 5.538v27.369h-4.22v-38.014zm61.457 3.021q-3.966 0-6.517 3.613c-1.705 2.415-2.585 5.392-2.656 8.938h17.537v-1.626c0-3.137-.736-5.75-2.21-7.822-1.482-2.075-3.53-3.103-6.154-3.103m.598 35.735c-4.099 0-7.451-1.543-10.055-4.621q-3.895-4.61-3.896-11.793v-6.313c0-4.798 1.303-8.798 3.912-11.979 2.616-3.167 5.758-4.75 9.441-4.75 3.983 0 7.068 1.413 9.27 4.246q3.313 4.257 3.312 11.434v4.171H587.39v3.162c0 3.68.882 6.744 2.635 9.19 1.757 2.45 4.144 3.666 7.136 3.666 2.077 0 3.888-.367 5.396-1.089a11.1 11.1 0 0 0 3.877-3.132l1.728 2.99c-1.148 1.456-2.634 2.633-4.45 3.505-1.811.868-4 1.312-6.551 1.312m46.411-35.734q-3.976 0-6.528 3.613-2.54 3.62-2.652 8.938h17.54v-1.626c0-3.137-.733-5.75-2.216-7.822-1.475-2.075-3.52-3.103-6.144-3.103m.593 35.735c-4.1 0-7.446-1.543-10.045-4.621q-3.91-4.61-3.91-11.793v-6.313c0-4.798 1.309-8.798 3.913-11.979 2.623-3.167 5.766-4.75 9.45-4.75 3.975 0 7.072 1.413 9.27 4.246 2.2 2.837 3.304 6.65 3.304 11.434v4.171h-21.755v3.162q0 5.52 2.647 9.19c1.747 2.45 4.124 3.666 7.125 3.666 2.087 0 3.888-.367 5.392-1.089a11.2 11.2 0 0 0 3.894-3.132l1.717 2.99c-1.15 1.456-2.633 2.633-4.451 3.505-1.81.868-3.997 1.312-6.55 1.312m23.189-38.755.345 6.284c1.014-2.23 2.353-3.962 4.034-5.166 1.667-1.21 3.63-1.824 5.887-1.824 3.396 0 5.998 1.256 7.804 3.78 1.826 2.518 2.73 6.434 2.73 11.749v23.191h-4.249V306.72c0-4.343-.636-7.377-1.9-9.137-1.258-1.76-3.107-2.636-5.513-2.636-2.158 0-3.968.701-5.419 2.126-1.457 1.412-2.543 3.294-3.267 5.666v27.134h-4.219V291.86zm33.27 22.395c0 3.858.73 6.926 2.213 9.208 1.465 2.304 3.695 3.443 6.671 3.443 2.04 0 3.757-.544 5.167-1.657 1.405-1.113 2.514-2.662 3.336-4.627V301.79c-.79-2.025-1.874-3.66-3.244-4.92-1.368-1.24-3.102-1.863-5.186-1.863-2.97 0-5.216 1.294-6.708 3.891-1.502 2.603-2.25 5.995-2.25 10.161zm-4.262-5.195c0-5.386 1.088-9.714 3.274-12.975 2.169-3.245 5.187-4.871 9.03-4.871 2.134 0 4.007.52 5.607 1.564 1.603 1.024 2.928 2.523 3.992 4.43l.412-5.287h3.581v38.048c0 4.871-1.13 8.646-3.4 11.317-2.271 2.66-5.499 4.009-9.666 4.009-1.5 0-3.11-.235-4.832-.691-1.724-.456-3.252-1.054-4.59-1.805l1.168-3.704a14.1 14.1 0 0 0 3.831 1.716 15.2 15.2 0 0 0 4.352.616q4.536-.001 6.71-2.905c1.452-1.961 2.18-4.798 2.18-8.553v-4.597c-1.079 1.71-2.402 3.024-3.97 3.93-1.563.912-3.39 1.368-5.448 1.368-3.818 0-6.814-1.496-8.976-4.486-2.167-2.983-3.255-6.965-3.255-11.93zm40.2 20.916h-4.266V291.86h4.266zm0-48.968h-4.266v-6.005h4.266zm13.774 10.852.346 6.284c1.016-2.23 2.35-3.962 4.027-5.166 1.677-1.21 3.643-1.824 5.89-1.824 3.397 0 6.01 1.256 7.82 3.78 1.821 2.518 2.717 6.434 2.717 11.749v23.191h-4.248V306.72c0-4.343-.635-7.377-1.897-9.137-1.268-1.76-3.103-2.636-5.517-2.636-2.157 0-3.962.701-5.412 2.126-1.455 1.412-2.545 3.294-3.266 5.666v27.134h-4.224V291.86zm42.074 3.021q-3.978 0-6.518 3.613-2.547 3.62-2.66 8.938h17.54v-1.626c0-3.137-.731-5.75-2.21-7.822-1.476-2.075-3.525-3.103-6.152-3.103m.602 35.735c-4.11 0-7.456-1.543-10.048-4.621q-3.903-4.61-3.903-11.793v-6.313c0-4.798 1.302-8.798 3.91-11.979q3.924-4.75 9.439-4.75c3.978 0 7.077 1.413 9.283 4.246 2.197 2.837 3.3 6.65 3.3 11.434v4.171h-21.76v3.162c0 3.68.887 6.744 2.642 9.19 1.754 2.45 4.133 3.666 7.137 3.666 2.08 0 3.88-.367 5.382-1.089a11.16 11.16 0 0 0 3.897-3.132l1.725 2.99c-1.156 1.456-2.64 2.633-4.454 3.505-1.81.868-3.998 1.312-6.55 1.312"/><g transform="scale(.36) translate(84 60)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg> diff --git a/logo_outlined.svg b/logo_outlined.svg index 6666915fb6..7ed2931059 100644 --- a/logo_outlined.svg +++ b/logo_outlined.svg @@ -1 +1 @@ -<svg width="1024" height="414" viewBox="0 0 1024 414" xmlns="http://www.w3.org/2000/svg"><path stroke="#fff" stroke-width="23.5" stroke-linejoin="round" d="M523.82 188.382c-9.142-.142-19.603 1.764-19.603 1.764v17.842h10.52l-.117 7.953c0 2.946-2.92 4.427-8.747 4.427-5.831 0-10.982-2.47-15.45-7.395-4.48-4.932-6.708-12.141-6.708-21.64 0-9.519 2.176-16.537 6.536-21.065 4.35-4.524 10.05-6.794 17.064-6.794 2.946 0 5.996.476 9.168 1.445 3.174.962 5.293 1.863 6.375 2.707 1.072.867 2.09 1.277 3.056 1.277.96 0 2.513-1.122 4.66-3.392 2.153-2.263 4.082-5.693 5.782-10.267 1.694-4.598 2.543-8.122 2.543-10.621 0-2.48-.054-4.19-.164-5.092-2.379-2.603-6.767-4.666-13.168-6.2-6.39-1.53-13.552-2.289-21.476-2.289-17.438 0-31.073 5.49-40.92 16.47-9.855 10.982-14.773 25.24-14.773 42.79 0 20.607 5.035 36.227 15.103 46.868 10.085 10.64 23.327 15.953 39.743 15.953 8.827 0 16.664-.76 23.51-2.289 6.853-1.523 11.41-3.088 13.676-4.67l.68-53.137c0-3.087-8.149-4.488-17.29-4.645zm84.247-24.804c-5.431 0-9.98 2.496-13.671 7.47-3.672 4.98-5.517 11.969-5.517 20.963 0 9.013 1.754 15.914 5.27 20.722 3.508 4.823 8.117 7.225 13.835 7.225 5.715 0 10.358-2.432 13.924-7.313 3.566-4.862 5.353-11.823 5.353-20.884 0-9.054-1.846-16.023-5.524-20.89-3.674-4.861-8.23-7.293-13.67-7.293m-.083 89.477c-15.9 0-28.868-5.203-38.89-15.61-10.01-10.416-15.017-25.614-15.017-45.592 0-19.992 5.063-35.128 15.191-45.435 10.131-10.293 23.209-15.444 39.228-15.444 16.016 0 28.954 5.058 38.795 15.204 9.858 10.126 14.778 25.477 14.778 46.009 0 20.546-5.034 35.828-15.114 45.856-10.08 10.008-23.062 15.012-38.971 15.012m101.95-88.298v50.788c0 2.37.176 3.866.515 4.493.337.624 1.358.937 3.052.937 6.232 0 10.954-2.328 14.181-6.97 3.235-4.636 4.835-12.356 4.835-23.168 0-10.817-1.674-17.865-5-21.139-3.344-3.283-8.64-4.94-15.884-4.94zm-32.599 78.798V141.681c0-2.832.704-5.067 2.126-6.724 1.413-1.632 3.25-2.461 5.521-2.461h28.357c17.994 0 31.664 4.54 40.994 13.597 9.347 9.054 14.02 23.31 14.02 42.784 0 41.66-17.778 62.486-53.326 62.486h-29.03c-5.769 0-8.662-2.597-8.662-7.808m156.544-79.977c-5.432 0-9.994 2.496-13.678 7.47-3.67 4.98-5.508 11.969-5.508 20.963 0 9.013 1.758 15.914 5.262 20.722 3.505 4.823 8.119 7.225 13.837 7.225 5.717 0 10.363-2.432 13.924-7.313 3.568-4.862 5.355-11.823 5.355-20.884 0-9.054-1.843-16.023-5.522-20.89-3.68-4.861-8.23-7.293-13.67-7.293m-.087 89.477c-15.907 0-28.866-5.203-38.88-15.61-10.021-10.416-15.03-25.614-15.03-45.592 0-19.992 5.065-35.128 15.191-45.435 10.139-10.293 23.209-15.444 39.233-15.444 16.02 0 28.946 5.058 38.8 15.204 9.85 10.126 14.772 25.477 14.772 46.009 0 20.546-5.037 35.828-15.115 45.856-10.076 10.008-23.07 15.012-38.971 15.012m117.69-4.17c0 2.251-5.597 3.392-16.809 3.392-11.202 0-16.815-1.141-16.815-3.392v-85.248h-20.371c-1.928 0-3.286-2.597-4.077-7.818a56.267 56.267 0 0 1-.501-7.636c0-2.592.162-5.146.501-7.636.79-5.205 2.15-7.823 4.077-7.823h73.864c1.924 0 3.277 2.617 4.078 7.823.333 2.49.505 5.043.505 7.636 0 2.608-.172 5.152-.505 7.637-.8 5.22-2.154 7.817-4.078 7.817h-19.87z"/><path fill="#414042" d="M523.82 188.382c-9.142-.142-19.603 1.764-19.603 1.764v17.842h10.52l-.117 7.953c0 2.946-2.92 4.427-8.747 4.427-5.831 0-10.982-2.47-15.45-7.395-4.48-4.932-6.708-12.141-6.708-21.64 0-9.519 2.176-16.537 6.536-21.065 4.35-4.524 10.05-6.794 17.064-6.794 2.946 0 5.996.476 9.168 1.445 3.174.962 5.293 1.863 6.375 2.707 1.072.867 2.09 1.277 3.056 1.277.96 0 2.513-1.122 4.66-3.392 2.153-2.263 4.082-5.693 5.782-10.267 1.694-4.598 2.543-8.122 2.543-10.621 0-2.48-.054-4.19-.164-5.092-2.379-2.603-6.767-4.666-13.168-6.2-6.39-1.53-13.552-2.289-21.476-2.289-17.438 0-31.073 5.49-40.92 16.47-9.855 10.982-14.773 25.24-14.773 42.79 0 20.607 5.035 36.227 15.103 46.868 10.085 10.64 23.327 15.953 39.743 15.953 8.827 0 16.664-.76 23.51-2.289 6.853-1.523 11.41-3.088 13.676-4.67l.68-53.137c0-3.087-8.149-4.488-17.29-4.645zm84.247-24.804c-5.431 0-9.98 2.496-13.671 7.47-3.672 4.98-5.517 11.969-5.517 20.963 0 9.013 1.754 15.914 5.27 20.722 3.508 4.823 8.117 7.225 13.835 7.225 5.715 0 10.358-2.432 13.924-7.313 3.566-4.862 5.353-11.823 5.353-20.884 0-9.054-1.846-16.023-5.524-20.89-3.674-4.861-8.23-7.293-13.67-7.293m-.083 89.477c-15.9 0-28.868-5.203-38.89-15.61-10.01-10.416-15.017-25.614-15.017-45.592 0-19.992 5.063-35.128 15.191-45.435 10.131-10.293 23.209-15.444 39.228-15.444 16.016 0 28.954 5.058 38.795 15.204 9.858 10.126 14.778 25.477 14.778 46.009 0 20.546-5.034 35.828-15.114 45.856-10.08 10.008-23.062 15.012-38.971 15.012m101.95-88.298v50.788c0 2.37.176 3.866.515 4.493.337.624 1.358.937 3.052.937 6.232 0 10.954-2.328 14.181-6.97 3.235-4.636 4.835-12.356 4.835-23.168 0-10.817-1.674-17.865-5-21.139-3.344-3.283-8.64-4.94-15.884-4.94zm-32.599 78.798V141.681c0-2.832.704-5.067 2.126-6.724 1.413-1.632 3.25-2.461 5.521-2.461h28.357c17.994 0 31.664 4.54 40.994 13.597 9.347 9.054 14.02 23.31 14.02 42.784 0 41.66-17.778 62.486-53.326 62.486h-29.03c-5.769 0-8.662-2.597-8.662-7.808m156.544-79.977c-5.432 0-9.994 2.496-13.678 7.47-3.67 4.98-5.508 11.969-5.508 20.963 0 9.013 1.758 15.914 5.262 20.722 3.505 4.823 8.119 7.225 13.837 7.225 5.717 0 10.363-2.432 13.924-7.313 3.568-4.862 5.355-11.823 5.355-20.884 0-9.054-1.843-16.023-5.522-20.89-3.68-4.861-8.23-7.293-13.67-7.293m-.087 89.477c-15.907 0-28.866-5.203-38.88-15.61-10.021-10.416-15.03-25.614-15.03-45.592 0-19.992 5.065-35.128 15.191-45.435 10.139-10.293 23.209-15.444 39.233-15.444 16.02 0 28.946 5.058 38.8 15.204 9.85 10.126 14.772 25.477 14.772 46.009 0 20.546-5.037 35.828-15.115 45.856-10.076 10.008-23.07 15.012-38.971 15.012m117.69-4.17c0 2.251-5.597 3.392-16.809 3.392-11.202 0-16.815-1.141-16.815-3.392v-85.248h-20.371c-1.928 0-3.286-2.597-4.077-7.818a56.267 56.267 0 0 1-.501-7.636c0-2.592.162-5.146.501-7.636.79-5.205 2.15-7.823 4.077-7.823h73.864c1.924 0 3.277 2.617 4.078 7.823.333 2.49.505 5.043.505 7.636 0 2.608-.172 5.152-.505 7.637-.8 5.22-2.154 7.817-4.078 7.817h-19.87z"/><path stroke="#fff" stroke-width="23.5" stroke-linejoin="round" d="M487.93 322.997c-.94 1.926-2.664 3.691-5.188 5.289-2.52 1.607-5.722 2.406-9.611 2.406-5.132 0-9.259-1.617-12.394-4.887-3.122-3.243-4.686-7.92-4.686-14.022V296.57c0-5.97 1.473-10.548 4.431-13.743 2.95-3.17 6.903-4.78 11.84-4.78 4.824 0 8.564 1.27 11.212 3.781 2.639 2.519 4.025 6.038 4.146 10.532l-.066.2h-3.94c-.14-3.443-1.14-6.101-3.022-7.979-1.871-1.861-4.655-2.803-8.33-2.803-3.72 0-6.668 1.259-8.823 3.785-2.15 2.518-3.224 6.17-3.224 10.968v15.301c0 4.975 1.16 8.768 3.476 11.382 2.316 2.592 5.438 3.892 9.38 3.892 2.876 0 5.19-.51 6.92-1.554 1.738-1.028 2.942-2.285 3.624-3.775V308.45h-10.618v-3.704h14.873zm19.557 3.902c2.336 0 4.416-.661 6.232-2.01 1.82-1.353 3.096-3.063 3.852-5.146v-8.224h-6.756c-2.873 0-5.173.814-6.896 2.442-1.726 1.617-2.581 3.637-2.581 6.037 0 2.03.534 3.696 1.616 4.981 1.08 1.289 2.59 1.92 4.533 1.92m10.715 3.068a99.251 99.251 0 0 1-.48-3.225 21.745 21.745 0 0 1-.15-2.562 14.867 14.867 0 0 1-4.483 4.675c-1.836 1.236-3.878 1.848-6.128 1.848-3.147 0-5.567-.975-7.28-2.927-1.702-1.96-2.563-4.6-2.563-7.936 0-3.523 1.237-6.35 3.72-8.448 2.48-2.098 5.85-3.147 10.09-3.147h6.643v-4.672c0-2.686-.686-4.802-2.032-6.331-1.375-1.51-3.264-2.275-5.701-2.275-2.268 0-4.139.722-5.608 2.182-1.463 1.45-2.19 3.224-2.19 5.337l-3.944-.035-.07-.206c-.11-2.866.973-5.4 3.261-7.646 2.279-2.24 5.203-3.352 8.761-3.352 3.517 0 6.347 1.069 8.509 3.2 2.148 2.152 3.226 5.221 3.226 9.21v18.645c0 1.358.064 2.677.183 3.936a24.853 24.853 0 0 0 .627 3.729zm16.905-38.108.36 5.9c1-2.112 2.339-3.739 3.998-4.896 1.664-1.141 3.624-1.711 5.874-1.711 2.296 0 4.232.668 5.794 2.02 1.562 1.347 2.714 3.387 3.446 6.127.938-2.529 2.264-4.528 3.986-5.975 1.722-1.45 3.812-2.172 6.23-2.172 3.335 0 5.923 1.35 7.755 4.05 1.841 2.705 2.759 6.856 2.759 12.464v22.207h-4.246v-22.28c0-4.663-.645-7.946-1.9-9.834-1.261-1.89-3.071-2.842-5.41-2.842-2.462 0-4.384 1.04-5.767 3.152-1.375 2.112-2.223 4.754-2.531 7.945v23.86h-4.224v-22.258c0-4.554-.639-7.812-1.945-9.759-1.299-1.946-3.107-2.912-5.427-2.912-2.218 0-4.013.677-5.358 2.02-1.353 1.349-2.315 3.195-2.899 5.538v27.369h-4.22v-38.014zm61.457 3.021c-2.644 0-4.816 1.205-6.517 3.613-1.705 2.415-2.585 5.392-2.656 8.938h17.537v-1.626c0-3.137-.736-5.75-2.21-7.822-1.482-2.075-3.53-3.103-6.154-3.103m.598 35.735c-4.099 0-7.451-1.543-10.055-4.621-2.596-3.073-3.896-7.005-3.896-11.793v-6.313c0-4.798 1.303-8.798 3.912-11.979 2.616-3.167 5.758-4.75 9.441-4.75 3.983 0 7.068 1.413 9.27 4.246 2.209 2.837 3.312 6.65 3.312 11.434v4.171H587.39v3.162c0 3.68.882 6.744 2.635 9.19 1.757 2.45 4.144 3.666 7.136 3.666 2.077 0 3.888-.367 5.396-1.089a11.119 11.119 0 0 0 3.877-3.132l1.728 2.99c-1.148 1.456-2.634 2.633-4.45 3.505-1.811.868-4 1.312-6.551 1.312m46.411-35.734c-2.651 0-4.827 1.205-6.528 3.613-1.694 2.415-2.576 5.392-2.652 8.938h17.54v-1.626c0-3.137-.733-5.75-2.216-7.822-1.475-2.075-3.52-3.103-6.144-3.103m.593 35.735c-4.1 0-7.446-1.543-10.045-4.621-2.606-3.073-3.91-7.005-3.91-11.793v-6.313c0-4.798 1.309-8.798 3.913-11.979 2.623-3.167 5.766-4.75 9.45-4.75 3.975 0 7.072 1.413 9.27 4.246 2.2 2.837 3.304 6.65 3.304 11.434v4.171h-21.755v3.162c0 3.68.883 6.744 2.647 9.19 1.747 2.45 4.124 3.666 7.125 3.666 2.087 0 3.888-.367 5.392-1.089a11.229 11.229 0 0 0 3.894-3.132l1.717 2.99c-1.15 1.456-2.633 2.633-4.451 3.505-1.81.868-3.997 1.312-6.55 1.312m23.189-38.755.345 6.284c1.014-2.23 2.353-3.962 4.034-5.166 1.667-1.21 3.63-1.824 5.887-1.824 3.396 0 5.998 1.256 7.804 3.78 1.826 2.518 2.73 6.434 2.73 11.749v23.191h-4.249V306.72c0-4.343-.636-7.377-1.9-9.137-1.258-1.76-3.107-2.636-5.513-2.636-2.158 0-3.968.701-5.419 2.126-1.457 1.412-2.543 3.294-3.267 5.666v27.134h-4.219V291.86zm33.27 22.395c0 3.858.73 6.926 2.213 9.208 1.465 2.304 3.695 3.443 6.671 3.443 2.04 0 3.757-.544 5.167-1.657 1.405-1.113 2.514-2.662 3.336-4.627V301.79c-.79-2.025-1.874-3.66-3.244-4.92-1.368-1.24-3.102-1.863-5.186-1.863-2.97 0-5.216 1.294-6.708 3.891-1.502 2.603-2.25 5.995-2.25 10.161zm-4.262-5.195c0-5.386 1.088-9.714 3.274-12.975 2.169-3.245 5.187-4.871 9.03-4.871 2.134 0 4.007.52 5.607 1.564 1.603 1.024 2.928 2.523 3.992 4.43l.412-5.287h3.581v38.048c0 4.871-1.13 8.646-3.4 11.317-2.271 2.66-5.499 4.009-9.666 4.009-1.5 0-3.11-.235-4.832-.691-1.724-.456-3.252-1.054-4.59-1.805l1.168-3.704a14.108 14.108 0 0 0 3.831 1.716 15.179 15.179 0 0 0 4.352.616c3.023 0 5.262-.97 6.71-2.905 1.452-1.961 2.18-4.798 2.18-8.553v-4.597c-1.079 1.71-2.402 3.024-3.97 3.93-1.563.912-3.39 1.368-5.448 1.368-3.818 0-6.814-1.496-8.976-4.486-2.167-2.983-3.255-6.965-3.255-11.93zm40.2 20.916h-4.266V291.86h4.266zm0-48.968h-4.266v-6.005h4.266zm13.774 10.852.346 6.284c1.016-2.23 2.35-3.962 4.027-5.166 1.677-1.21 3.643-1.824 5.89-1.824 3.397 0 6.01 1.256 7.82 3.78 1.821 2.518 2.717 6.434 2.717 11.749v23.191h-4.248V306.72c0-4.343-.635-7.377-1.897-9.137-1.268-1.76-3.103-2.636-5.517-2.636-2.157 0-3.962.701-5.412 2.126-1.455 1.412-2.545 3.294-3.266 5.666v27.134h-4.224V291.86zm42.074 3.021c-2.652 0-4.825 1.205-6.518 3.613-1.699 2.415-2.584 5.392-2.66 8.938h17.54v-1.626c0-3.137-.731-5.75-2.21-7.822-1.476-2.075-3.525-3.103-6.152-3.103m.602 35.735c-4.11 0-7.456-1.543-10.048-4.621-2.602-3.073-3.903-7.005-3.903-11.793v-6.313c0-4.798 1.302-8.798 3.91-11.979 2.616-3.167 5.763-4.75 9.439-4.75 3.978 0 7.077 1.413 9.283 4.246 2.197 2.837 3.3 6.65 3.3 11.434v4.171h-21.76v3.162c0 3.68.887 6.744 2.642 9.19 1.754 2.45 4.133 3.666 7.137 3.666 2.08 0 3.88-.367 5.382-1.089a11.157 11.157 0 0 0 3.897-3.132l1.725 2.99c-1.156 1.456-2.64 2.633-4.454 3.505-1.81.868-3.998 1.312-6.55 1.312"/><path fill="#6d6e71" d="M487.93 322.997c-.94 1.926-2.664 3.691-5.188 5.289-2.52 1.607-5.722 2.406-9.611 2.406-5.132 0-9.259-1.617-12.394-4.887-3.122-3.243-4.686-7.92-4.686-14.022V296.57c0-5.97 1.473-10.548 4.431-13.743 2.95-3.17 6.903-4.78 11.84-4.78 4.824 0 8.564 1.27 11.212 3.781 2.639 2.519 4.025 6.038 4.146 10.532l-.066.2h-3.94c-.14-3.443-1.14-6.101-3.022-7.979-1.871-1.861-4.655-2.803-8.33-2.803-3.72 0-6.668 1.259-8.823 3.785-2.15 2.518-3.224 6.17-3.224 10.968v15.301c0 4.975 1.16 8.768 3.476 11.382 2.316 2.592 5.438 3.892 9.38 3.892 2.876 0 5.19-.51 6.92-1.554 1.738-1.028 2.942-2.285 3.624-3.775V308.45h-10.618v-3.704h14.873zm19.557 3.902c2.336 0 4.416-.661 6.232-2.01 1.82-1.353 3.096-3.063 3.852-5.146v-8.224h-6.756c-2.873 0-5.173.814-6.896 2.442-1.726 1.617-2.581 3.637-2.581 6.037 0 2.03.534 3.696 1.616 4.981 1.08 1.289 2.59 1.92 4.533 1.92m10.715 3.068a99.251 99.251 0 0 1-.48-3.225 21.745 21.745 0 0 1-.15-2.562 14.867 14.867 0 0 1-4.483 4.675c-1.836 1.236-3.878 1.848-6.128 1.848-3.147 0-5.567-.975-7.28-2.927-1.702-1.96-2.563-4.6-2.563-7.936 0-3.523 1.237-6.35 3.72-8.448 2.48-2.098 5.85-3.147 10.09-3.147h6.643v-4.672c0-2.686-.686-4.802-2.032-6.331-1.375-1.51-3.264-2.275-5.701-2.275-2.268 0-4.139.722-5.608 2.182-1.463 1.45-2.19 3.224-2.19 5.337l-3.944-.035-.07-.206c-.11-2.866.973-5.4 3.261-7.646 2.279-2.24 5.203-3.352 8.761-3.352 3.517 0 6.347 1.069 8.509 3.2 2.148 2.152 3.226 5.221 3.226 9.21v18.645c0 1.358.064 2.677.183 3.936a24.853 24.853 0 0 0 .627 3.729zm16.905-38.108.36 5.9c1-2.112 2.339-3.739 3.998-4.896 1.664-1.141 3.624-1.711 5.874-1.711 2.296 0 4.232.668 5.794 2.02 1.562 1.347 2.714 3.387 3.446 6.127.938-2.529 2.264-4.528 3.986-5.975 1.722-1.45 3.812-2.172 6.23-2.172 3.335 0 5.923 1.35 7.755 4.05 1.841 2.705 2.759 6.856 2.759 12.464v22.207h-4.246v-22.28c0-4.663-.645-7.946-1.9-9.834-1.261-1.89-3.071-2.842-5.41-2.842-2.462 0-4.384 1.04-5.767 3.152-1.375 2.112-2.223 4.754-2.531 7.945v23.86h-4.224v-22.258c0-4.554-.639-7.812-1.945-9.759-1.299-1.946-3.107-2.912-5.427-2.912-2.218 0-4.013.677-5.358 2.02-1.353 1.349-2.315 3.195-2.899 5.538v27.369h-4.22v-38.014zm61.457 3.021c-2.644 0-4.816 1.205-6.517 3.613-1.705 2.415-2.585 5.392-2.656 8.938h17.537v-1.626c0-3.137-.736-5.75-2.21-7.822-1.482-2.075-3.53-3.103-6.154-3.103m.598 35.735c-4.099 0-7.451-1.543-10.055-4.621-2.596-3.073-3.896-7.005-3.896-11.793v-6.313c0-4.798 1.303-8.798 3.912-11.979 2.616-3.167 5.758-4.75 9.441-4.75 3.983 0 7.068 1.413 9.27 4.246 2.209 2.837 3.312 6.65 3.312 11.434v4.171H587.39v3.162c0 3.68.882 6.744 2.635 9.19 1.757 2.45 4.144 3.666 7.136 3.666 2.077 0 3.888-.367 5.396-1.089a11.119 11.119 0 0 0 3.877-3.132l1.728 2.99c-1.148 1.456-2.634 2.633-4.45 3.505-1.811.868-4 1.312-6.551 1.312m46.411-35.734c-2.651 0-4.827 1.205-6.528 3.613-1.694 2.415-2.576 5.392-2.652 8.938h17.54v-1.626c0-3.137-.733-5.75-2.216-7.822-1.475-2.075-3.52-3.103-6.144-3.103m.593 35.735c-4.1 0-7.446-1.543-10.045-4.621-2.606-3.073-3.91-7.005-3.91-11.793v-6.313c0-4.798 1.309-8.798 3.913-11.979 2.623-3.167 5.766-4.75 9.45-4.75 3.975 0 7.072 1.413 9.27 4.246 2.2 2.837 3.304 6.65 3.304 11.434v4.171h-21.755v3.162c0 3.68.883 6.744 2.647 9.19 1.747 2.45 4.124 3.666 7.125 3.666 2.087 0 3.888-.367 5.392-1.089a11.229 11.229 0 0 0 3.894-3.132l1.717 2.99c-1.15 1.456-2.633 2.633-4.451 3.505-1.81.868-3.997 1.312-6.55 1.312m23.189-38.755.345 6.284c1.014-2.23 2.353-3.962 4.034-5.166 1.667-1.21 3.63-1.824 5.887-1.824 3.396 0 5.998 1.256 7.804 3.78 1.826 2.518 2.73 6.434 2.73 11.749v23.191h-4.249V306.72c0-4.343-.636-7.377-1.9-9.137-1.258-1.76-3.107-2.636-5.513-2.636-2.158 0-3.968.701-5.419 2.126-1.457 1.412-2.543 3.294-3.267 5.666v27.134h-4.219V291.86zm33.27 22.395c0 3.858.73 6.926 2.213 9.208 1.465 2.304 3.695 3.443 6.671 3.443 2.04 0 3.757-.544 5.167-1.657 1.405-1.113 2.514-2.662 3.336-4.627V301.79c-.79-2.025-1.874-3.66-3.244-4.92-1.368-1.24-3.102-1.863-5.186-1.863-2.97 0-5.216 1.294-6.708 3.891-1.502 2.603-2.25 5.995-2.25 10.161zm-4.262-5.195c0-5.386 1.088-9.714 3.274-12.975 2.169-3.245 5.187-4.871 9.03-4.871 2.134 0 4.007.52 5.607 1.564 1.603 1.024 2.928 2.523 3.992 4.43l.412-5.287h3.581v38.048c0 4.871-1.13 8.646-3.4 11.317-2.271 2.66-5.499 4.009-9.666 4.009-1.5 0-3.11-.235-4.832-.691-1.724-.456-3.252-1.054-4.59-1.805l1.168-3.704a14.108 14.108 0 0 0 3.831 1.716 15.179 15.179 0 0 0 4.352.616c3.023 0 5.262-.97 6.71-2.905 1.452-1.961 2.18-4.798 2.18-8.553v-4.597c-1.079 1.71-2.402 3.024-3.97 3.93-1.563.912-3.39 1.368-5.448 1.368-3.818 0-6.814-1.496-8.976-4.486-2.167-2.983-3.255-6.965-3.255-11.93zm40.2 20.916h-4.266V291.86h4.266zm0-48.968h-4.266v-6.005h4.266zm13.774 10.852.346 6.284c1.016-2.23 2.35-3.962 4.027-5.166 1.677-1.21 3.643-1.824 5.89-1.824 3.397 0 6.01 1.256 7.82 3.78 1.821 2.518 2.717 6.434 2.717 11.749v23.191h-4.248V306.72c0-4.343-.635-7.377-1.897-9.137-1.268-1.76-3.103-2.636-5.517-2.636-2.157 0-3.962.701-5.412 2.126-1.455 1.412-2.545 3.294-3.266 5.666v27.134h-4.224V291.86zm42.074 3.021c-2.652 0-4.825 1.205-6.518 3.613-1.699 2.415-2.584 5.392-2.66 8.938h17.54v-1.626c0-3.137-.731-5.75-2.21-7.822-1.476-2.075-3.525-3.103-6.152-3.103m.602 35.735c-4.11 0-7.456-1.543-10.048-4.621-2.602-3.073-3.903-7.005-3.903-11.793v-6.313c0-4.798 1.302-8.798 3.91-11.979 2.616-3.167 5.763-4.75 9.439-4.75 3.978 0 7.077 1.413 9.283 4.246 2.197 2.837 3.3 6.65 3.3 11.434v4.171h-21.76v3.162c0 3.68.887 6.744 2.642 9.19 1.754 2.45 4.133 3.666 7.137 3.666 2.08 0 3.88-.367 5.382-1.089a11.157 11.157 0 0 0 3.897-3.132l1.725 2.99c-1.156 1.456-2.64 2.633-4.454 3.505-1.81.868-3.998 1.312-6.55 1.312"/><g fill="#fff"><path d="M68.607 265.353v11.979q147.741 128.502 295.482 0v-11.979z"/><path d="M68.607 291.489c0 100.188 295.119 100.188 295.119 0V176.055q10.89-14.157 20.328-29.403-12.705-21.417-30.129-39.204-15.609 7.26-29.766 17.061-14.52-13.431-31.944-23.232 2.541-18.513 2.904-37.026-21.417-10.164-44.649-15.246-9.438 15.609-16.698 32.307-17.787-2.541-35.574 0-7.26-16.698-16.698-32.307-23.232 5.082-44.649 15.246.363 18.513 2.904 37.026-17.424 9.801-31.944 23.232-14.157-9.801-29.766-17.061-17.424 17.787-30.129 39.204 9.438 15.246 20.328 29.403v115.434z" fill="none" stroke="#fff" stroke-width="23.5" stroke-linejoin="round"/><path fill="#478cbf" d="m68.607 265.353 55.176 5.082q4.356.363 5.445 5.082l1.452 24.321 47.916 3.63 2.904-22.143q.726-3.993 5.445-5.445h58.806q4.719 1.452 5.445 5.445l2.904 22.143 47.916-3.63 1.452-24.321q1.089-4.719 5.445-5.082l55.176-5.082v-89.298q10.89-14.157 20.328-29.403-12.705-21.417-30.129-39.204-15.609 7.26-29.766 17.061-14.52-13.431-31.944-23.232 2.541-18.513 2.904-37.026-21.417-10.164-44.649-15.246-9.438 15.609-16.698 32.307-17.787-2.541-35.574 0-7.26-16.698-16.698-32.307-23.232 5.082-44.649 15.246.363 18.513 2.904 37.026-17.424 9.801-31.944 23.232-14.157-9.801-29.766-17.061-17.424 17.787-30.129 39.204 9.438 15.246 20.328 29.403zm0 11.979v14.157c0 100.188 295.119 100.188 295.119 0v-14.157l-48.642 4.356-1.815 25.047q-.726 3.63-5.082 4.719l-58.806 3.993q-4.356 0-5.808-3.993l-3.63-23.595h-47.19l-3.63 23.595q-1.452 3.993-5.808 3.993l-58.806-3.993q-4.356-1.089-5.082-4.719l-1.815-25.047z"/><path d="M205.821 238.854c1.089 12.342 19.965 12.342 21.054 0v-31.218c-1.089-12.342-19.965-12.342-21.054 0z"/><circle cx="293.667" cy="211.992" r="32.67"/><circle cx="139.029" cy="211.992" r="32.67"/></g><g fill="#414042"><circle cx="141.933" cy="214.17" r="21.78"/><circle cx="290.763" cy="214.17" r="21.78"/></g></svg> +<svg width="1024" height="414" viewBox="0 0 1024 414" xmlns="http://www.w3.org/2000/svg"><path stroke="#fff" stroke-width="23.5" stroke-linejoin="round" d="M523.82 188.382c-9.142-.142-19.603 1.764-19.603 1.764v17.842h10.52l-.117 7.953c0 2.946-2.92 4.427-8.747 4.427-5.831 0-10.982-2.47-15.45-7.395-4.48-4.932-6.708-12.141-6.708-21.64 0-9.519 2.176-16.537 6.536-21.065 4.35-4.524 10.05-6.794 17.064-6.794 2.946 0 5.996.476 9.168 1.445 3.174.962 5.293 1.863 6.375 2.707 1.072.867 2.09 1.277 3.056 1.277.96 0 2.513-1.122 4.66-3.392 2.153-2.263 4.082-5.693 5.782-10.267 1.694-4.598 2.543-8.122 2.543-10.621 0-2.48-.054-4.19-.164-5.092-2.379-2.603-6.767-4.666-13.168-6.2-6.39-1.53-13.552-2.289-21.476-2.289-17.438 0-31.073 5.49-40.92 16.47-9.855 10.982-14.773 25.24-14.773 42.79 0 20.607 5.035 36.227 15.103 46.868 10.085 10.64 23.327 15.953 39.743 15.953 8.827 0 16.664-.76 23.51-2.289 6.853-1.523 11.41-3.088 13.676-4.67l.68-53.137c0-3.087-8.149-4.488-17.29-4.645zm84.247-24.804c-5.431 0-9.98 2.496-13.671 7.47-3.672 4.98-5.517 11.969-5.517 20.963 0 9.013 1.754 15.914 5.27 20.722 3.508 4.823 8.117 7.225 13.835 7.225 5.715 0 10.358-2.432 13.924-7.313q5.351-7.293 5.353-20.884c0-9.054-1.846-16.023-5.524-20.89q-5.51-7.292-13.67-7.293m-.083 89.477c-15.9 0-28.868-5.203-38.89-15.61q-15.016-15.624-15.017-45.592c0-19.992 5.063-35.128 15.191-45.435 10.131-10.293 23.209-15.444 39.228-15.444 16.016 0 28.954 5.058 38.795 15.204 9.858 10.126 14.778 25.477 14.778 46.009 0 20.546-5.034 35.828-15.114 45.856-10.08 10.008-23.062 15.012-38.971 15.012m101.95-88.298v50.788c0 2.37.176 3.866.515 4.493.337.624 1.358.937 3.052.937 6.232 0 10.954-2.328 14.181-6.97 3.235-4.636 4.835-12.356 4.835-23.168 0-10.817-1.674-17.865-5-21.139-3.344-3.283-8.64-4.94-15.884-4.94zm-32.599 78.798V141.681c0-2.832.704-5.067 2.126-6.724 1.413-1.632 3.25-2.461 5.521-2.461h28.357c17.994 0 31.664 4.54 40.994 13.597 9.347 9.054 14.02 23.31 14.02 42.784 0 41.66-17.778 62.486-53.326 62.486h-29.03c-5.769 0-8.662-2.597-8.662-7.808m156.544-79.977c-5.432 0-9.994 2.496-13.678 7.47q-5.507 7.471-5.508 20.963c0 9.013 1.758 15.914 5.262 20.722 3.505 4.823 8.119 7.225 13.837 7.225 5.717 0 10.363-2.432 13.924-7.313q5.354-7.293 5.355-20.884c0-9.054-1.843-16.023-5.522-20.89-3.68-4.861-8.23-7.293-13.67-7.293m-.087 89.477q-23.86 0-38.88-15.61-15.03-15.624-15.03-45.592c0-19.992 5.065-35.128 15.191-45.435 10.139-10.293 23.209-15.444 39.233-15.444 16.02 0 28.946 5.058 38.8 15.204 9.85 10.126 14.772 25.477 14.772 46.009 0 20.546-5.037 35.828-15.115 45.856-10.076 10.008-23.07 15.012-38.971 15.012m117.69-4.17c0 2.251-5.597 3.392-16.809 3.392-11.202 0-16.815-1.141-16.815-3.392v-85.248h-20.371c-1.928 0-3.286-2.597-4.077-7.818a56 56 0 0 1-.501-7.636c0-2.592.162-5.146.501-7.636.79-5.205 2.15-7.823 4.077-7.823h73.864c1.924 0 3.277 2.617 4.078 7.823.333 2.49.505 5.043.505 7.636 0 2.608-.172 5.152-.505 7.637-.8 5.22-2.154 7.817-4.078 7.817h-19.87z"/><path fill="#414042" d="M523.82 188.382c-9.142-.142-19.603 1.764-19.603 1.764v17.842h10.52l-.117 7.953c0 2.946-2.92 4.427-8.747 4.427-5.831 0-10.982-2.47-15.45-7.395-4.48-4.932-6.708-12.141-6.708-21.64 0-9.519 2.176-16.537 6.536-21.065 4.35-4.524 10.05-6.794 17.064-6.794 2.946 0 5.996.476 9.168 1.445 3.174.962 5.293 1.863 6.375 2.707 1.072.867 2.09 1.277 3.056 1.277.96 0 2.513-1.122 4.66-3.392 2.153-2.263 4.082-5.693 5.782-10.267 1.694-4.598 2.543-8.122 2.543-10.621 0-2.48-.054-4.19-.164-5.092-2.379-2.603-6.767-4.666-13.168-6.2-6.39-1.53-13.552-2.289-21.476-2.289-17.438 0-31.073 5.49-40.92 16.47-9.855 10.982-14.773 25.24-14.773 42.79 0 20.607 5.035 36.227 15.103 46.868 10.085 10.64 23.327 15.953 39.743 15.953 8.827 0 16.664-.76 23.51-2.289 6.853-1.523 11.41-3.088 13.676-4.67l.68-53.137c0-3.087-8.149-4.488-17.29-4.645m84.247-24.804c-5.431 0-9.98 2.496-13.671 7.47-3.672 4.98-5.517 11.969-5.517 20.963 0 9.013 1.754 15.914 5.27 20.722 3.508 4.823 8.117 7.225 13.835 7.225 5.715 0 10.358-2.432 13.924-7.313q5.351-7.293 5.353-20.884c0-9.054-1.846-16.023-5.524-20.89q-5.51-7.292-13.67-7.293m-.083 89.477c-15.9 0-28.868-5.203-38.89-15.61q-15.016-15.624-15.017-45.592c0-19.992 5.063-35.128 15.191-45.435 10.131-10.293 23.209-15.444 39.228-15.444 16.016 0 28.954 5.058 38.795 15.204 9.858 10.126 14.778 25.477 14.778 46.009 0 20.546-5.034 35.828-15.114 45.856-10.08 10.008-23.062 15.012-38.971 15.012m101.95-88.298v50.788c0 2.37.176 3.866.515 4.493.337.624 1.358.937 3.052.937 6.232 0 10.954-2.328 14.181-6.97 3.235-4.636 4.835-12.356 4.835-23.168 0-10.817-1.674-17.865-5-21.139-3.344-3.283-8.64-4.94-15.884-4.94zm-32.599 78.798V141.681c0-2.832.704-5.067 2.126-6.724 1.413-1.632 3.25-2.461 5.521-2.461h28.357c17.994 0 31.664 4.54 40.994 13.597 9.347 9.054 14.02 23.31 14.02 42.784 0 41.66-17.778 62.486-53.326 62.486h-29.03c-5.769 0-8.662-2.597-8.662-7.808m156.544-79.977c-5.432 0-9.994 2.496-13.678 7.47q-5.507 7.471-5.508 20.963c0 9.013 1.758 15.914 5.262 20.722 3.505 4.823 8.119 7.225 13.837 7.225 5.717 0 10.363-2.432 13.924-7.313q5.354-7.293 5.355-20.884c0-9.054-1.843-16.023-5.522-20.89-3.68-4.861-8.23-7.293-13.67-7.293m-.087 89.477q-23.86 0-38.88-15.61-15.03-15.624-15.03-45.592c0-19.992 5.065-35.128 15.191-45.435 10.139-10.293 23.209-15.444 39.233-15.444 16.02 0 28.946 5.058 38.8 15.204 9.85 10.126 14.772 25.477 14.772 46.009 0 20.546-5.037 35.828-15.115 45.856-10.076 10.008-23.07 15.012-38.971 15.012m117.69-4.17c0 2.251-5.597 3.392-16.809 3.392-11.202 0-16.815-1.141-16.815-3.392v-85.248h-20.371c-1.928 0-3.286-2.597-4.077-7.818a56 56 0 0 1-.501-7.636c0-2.592.162-5.146.501-7.636.79-5.205 2.15-7.823 4.077-7.823h73.864c1.924 0 3.277 2.617 4.078 7.823.333 2.49.505 5.043.505 7.636 0 2.608-.172 5.152-.505 7.637-.8 5.22-2.154 7.817-4.078 7.817h-19.87z"/><path stroke="#fff" stroke-width="23.5" stroke-linejoin="round" d="M487.93 322.997c-.94 1.926-2.664 3.691-5.188 5.289-2.52 1.607-5.722 2.406-9.611 2.406-5.132 0-9.259-1.617-12.394-4.887-3.122-3.243-4.686-7.92-4.686-14.022V296.57c0-5.97 1.473-10.548 4.431-13.743 2.95-3.17 6.903-4.78 11.84-4.78 4.824 0 8.564 1.27 11.212 3.781 2.639 2.519 4.025 6.038 4.146 10.532l-.066.2h-3.94c-.14-3.443-1.14-6.101-3.022-7.979-1.871-1.861-4.655-2.803-8.33-2.803-3.72 0-6.668 1.259-8.823 3.785-2.15 2.518-3.224 6.17-3.224 10.968v15.301q.001 7.462 3.476 11.382c2.316 2.592 5.438 3.892 9.38 3.892 2.876 0 5.19-.51 6.92-1.554 1.738-1.028 2.942-2.285 3.624-3.775V308.45h-10.618v-3.704h14.873zm19.557 3.902c2.336 0 4.416-.661 6.232-2.01 1.82-1.353 3.096-3.063 3.852-5.146v-8.224h-6.756q-4.31 0-6.896 2.442c-1.726 1.617-2.581 3.637-2.581 6.037 0 2.03.534 3.696 1.616 4.981 1.08 1.289 2.59 1.92 4.533 1.92m10.715 3.068a99 99 0 0 1-.48-3.225 22 22 0 0 1-.15-2.562 14.9 14.9 0 0 1-4.483 4.675c-1.836 1.236-3.878 1.848-6.128 1.848-3.147 0-5.567-.975-7.28-2.927-1.702-1.96-2.563-4.6-2.563-7.936 0-3.523 1.237-6.35 3.72-8.448 2.48-2.098 5.85-3.147 10.09-3.147h6.643v-4.672c0-2.686-.686-4.802-2.032-6.331-1.375-1.51-3.264-2.275-5.701-2.275-2.268 0-4.139.722-5.608 2.182-1.463 1.45-2.19 3.224-2.19 5.337l-3.944-.035-.07-.206c-.11-2.866.973-5.4 3.261-7.646 2.279-2.24 5.203-3.352 8.761-3.352 3.517 0 6.347 1.069 8.509 3.2q3.224 3.227 3.226 9.21v18.645c0 1.358.064 2.677.183 3.936a25 25 0 0 0 .627 3.729zm16.905-38.108.36 5.9c1-2.112 2.339-3.739 3.998-4.896q2.498-1.711 5.874-1.711c2.296 0 4.232.668 5.794 2.02 1.562 1.347 2.714 3.387 3.446 6.127.938-2.529 2.264-4.528 3.986-5.975 1.722-1.45 3.812-2.172 6.23-2.172 3.335 0 5.923 1.35 7.755 4.05 1.841 2.705 2.759 6.856 2.759 12.464v22.207h-4.246v-22.28c0-4.663-.645-7.946-1.9-9.834-1.261-1.89-3.071-2.842-5.41-2.842-2.462 0-4.384 1.04-5.767 3.152-1.375 2.112-2.223 4.754-2.531 7.945v23.86h-4.224v-22.258c0-4.554-.639-7.812-1.945-9.759-1.299-1.946-3.107-2.912-5.427-2.912-2.218 0-4.013.677-5.358 2.02-1.353 1.349-2.315 3.195-2.899 5.538v27.369h-4.22v-38.014zm61.457 3.021q-3.966 0-6.517 3.613c-1.705 2.415-2.585 5.392-2.656 8.938h17.537v-1.626c0-3.137-.736-5.75-2.21-7.822-1.482-2.075-3.53-3.103-6.154-3.103m.598 35.735c-4.099 0-7.451-1.543-10.055-4.621q-3.895-4.61-3.896-11.793v-6.313c0-4.798 1.303-8.798 3.912-11.979 2.616-3.167 5.758-4.75 9.441-4.75 3.983 0 7.068 1.413 9.27 4.246q3.313 4.257 3.312 11.434v4.171H587.39v3.162c0 3.68.882 6.744 2.635 9.19 1.757 2.45 4.144 3.666 7.136 3.666 2.077 0 3.888-.367 5.396-1.089a11.1 11.1 0 0 0 3.877-3.132l1.728 2.99c-1.148 1.456-2.634 2.633-4.45 3.505-1.811.868-4 1.312-6.551 1.312m46.411-35.734q-3.976 0-6.528 3.613-2.54 3.62-2.652 8.938h17.54v-1.626c0-3.137-.733-5.75-2.216-7.822-1.475-2.075-3.52-3.103-6.144-3.103m.593 35.735c-4.1 0-7.446-1.543-10.045-4.621q-3.91-4.61-3.91-11.793v-6.313c0-4.798 1.309-8.798 3.913-11.979 2.623-3.167 5.766-4.75 9.45-4.75 3.975 0 7.072 1.413 9.27 4.246 2.2 2.837 3.304 6.65 3.304 11.434v4.171h-21.755v3.162q0 5.52 2.647 9.19c1.747 2.45 4.124 3.666 7.125 3.666 2.087 0 3.888-.367 5.392-1.089a11.2 11.2 0 0 0 3.894-3.132l1.717 2.99c-1.15 1.456-2.633 2.633-4.451 3.505-1.81.868-3.997 1.312-6.55 1.312m23.189-38.755.345 6.284c1.014-2.23 2.353-3.962 4.034-5.166 1.667-1.21 3.63-1.824 5.887-1.824 3.396 0 5.998 1.256 7.804 3.78 1.826 2.518 2.73 6.434 2.73 11.749v23.191h-4.249V306.72c0-4.343-.636-7.377-1.9-9.137-1.258-1.76-3.107-2.636-5.513-2.636-2.158 0-3.968.701-5.419 2.126-1.457 1.412-2.543 3.294-3.267 5.666v27.134h-4.219V291.86zm33.27 22.395c0 3.858.73 6.926 2.213 9.208 1.465 2.304 3.695 3.443 6.671 3.443 2.04 0 3.757-.544 5.167-1.657 1.405-1.113 2.514-2.662 3.336-4.627V301.79c-.79-2.025-1.874-3.66-3.244-4.92-1.368-1.24-3.102-1.863-5.186-1.863-2.97 0-5.216 1.294-6.708 3.891-1.502 2.603-2.25 5.995-2.25 10.161zm-4.262-5.195c0-5.386 1.088-9.714 3.274-12.975 2.169-3.245 5.187-4.871 9.03-4.871 2.134 0 4.007.52 5.607 1.564 1.603 1.024 2.928 2.523 3.992 4.43l.412-5.287h3.581v38.048c0 4.871-1.13 8.646-3.4 11.317-2.271 2.66-5.499 4.009-9.666 4.009-1.5 0-3.11-.235-4.832-.691-1.724-.456-3.252-1.054-4.59-1.805l1.168-3.704a14.1 14.1 0 0 0 3.831 1.716 15.2 15.2 0 0 0 4.352.616q4.536-.001 6.71-2.905c1.452-1.961 2.18-4.798 2.18-8.553v-4.597c-1.079 1.71-2.402 3.024-3.97 3.93-1.563.912-3.39 1.368-5.448 1.368-3.818 0-6.814-1.496-8.976-4.486-2.167-2.983-3.255-6.965-3.255-11.93zm40.2 20.916h-4.266V291.86h4.266zm0-48.968h-4.266v-6.005h4.266zm13.774 10.852.346 6.284c1.016-2.23 2.35-3.962 4.027-5.166 1.677-1.21 3.643-1.824 5.89-1.824 3.397 0 6.01 1.256 7.82 3.78 1.821 2.518 2.717 6.434 2.717 11.749v23.191h-4.248V306.72c0-4.343-.635-7.377-1.897-9.137-1.268-1.76-3.103-2.636-5.517-2.636-2.157 0-3.962.701-5.412 2.126-1.455 1.412-2.545 3.294-3.266 5.666v27.134h-4.224V291.86zm42.074 3.021q-3.978 0-6.518 3.613-2.547 3.62-2.66 8.938h17.54v-1.626c0-3.137-.731-5.75-2.21-7.822-1.476-2.075-3.525-3.103-6.152-3.103m.602 35.735c-4.11 0-7.456-1.543-10.048-4.621q-3.903-4.61-3.903-11.793v-6.313c0-4.798 1.302-8.798 3.91-11.979q3.924-4.75 9.439-4.75c3.978 0 7.077 1.413 9.283 4.246 2.197 2.837 3.3 6.65 3.3 11.434v4.171h-21.76v3.162c0 3.68.887 6.744 2.642 9.19 1.754 2.45 4.133 3.666 7.137 3.666 2.08 0 3.88-.367 5.382-1.089a11.16 11.16 0 0 0 3.897-3.132l1.725 2.99c-1.156 1.456-2.64 2.633-4.454 3.505-1.81.868-3.998 1.312-6.55 1.312"/><path fill="#6d6e71" d="M487.93 322.997c-.94 1.926-2.664 3.691-5.188 5.289-2.52 1.607-5.722 2.406-9.611 2.406-5.132 0-9.259-1.617-12.394-4.887-3.122-3.243-4.686-7.92-4.686-14.022V296.57c0-5.97 1.473-10.548 4.431-13.743 2.95-3.17 6.903-4.78 11.84-4.78 4.824 0 8.564 1.27 11.212 3.781 2.639 2.519 4.025 6.038 4.146 10.532l-.066.2h-3.94c-.14-3.443-1.14-6.101-3.022-7.979-1.871-1.861-4.655-2.803-8.33-2.803-3.72 0-6.668 1.259-8.823 3.785-2.15 2.518-3.224 6.17-3.224 10.968v15.301q.001 7.462 3.476 11.382c2.316 2.592 5.438 3.892 9.38 3.892 2.876 0 5.19-.51 6.92-1.554 1.738-1.028 2.942-2.285 3.624-3.775V308.45h-10.618v-3.704h14.873zm19.557 3.902c2.336 0 4.416-.661 6.232-2.01 1.82-1.353 3.096-3.063 3.852-5.146v-8.224h-6.756q-4.31 0-6.896 2.442c-1.726 1.617-2.581 3.637-2.581 6.037 0 2.03.534 3.696 1.616 4.981 1.08 1.289 2.59 1.92 4.533 1.92m10.715 3.068a99 99 0 0 1-.48-3.225 22 22 0 0 1-.15-2.562 14.9 14.9 0 0 1-4.483 4.675c-1.836 1.236-3.878 1.848-6.128 1.848-3.147 0-5.567-.975-7.28-2.927-1.702-1.96-2.563-4.6-2.563-7.936 0-3.523 1.237-6.35 3.72-8.448 2.48-2.098 5.85-3.147 10.09-3.147h6.643v-4.672c0-2.686-.686-4.802-2.032-6.331-1.375-1.51-3.264-2.275-5.701-2.275-2.268 0-4.139.722-5.608 2.182-1.463 1.45-2.19 3.224-2.19 5.337l-3.944-.035-.07-.206c-.11-2.866.973-5.4 3.261-7.646 2.279-2.24 5.203-3.352 8.761-3.352 3.517 0 6.347 1.069 8.509 3.2q3.224 3.227 3.226 9.21v18.645c0 1.358.064 2.677.183 3.936a25 25 0 0 0 .627 3.729zm16.905-38.108.36 5.9c1-2.112 2.339-3.739 3.998-4.896q2.498-1.711 5.874-1.711c2.296 0 4.232.668 5.794 2.02 1.562 1.347 2.714 3.387 3.446 6.127.938-2.529 2.264-4.528 3.986-5.975 1.722-1.45 3.812-2.172 6.23-2.172 3.335 0 5.923 1.35 7.755 4.05 1.841 2.705 2.759 6.856 2.759 12.464v22.207h-4.246v-22.28c0-4.663-.645-7.946-1.9-9.834-1.261-1.89-3.071-2.842-5.41-2.842-2.462 0-4.384 1.04-5.767 3.152-1.375 2.112-2.223 4.754-2.531 7.945v23.86h-4.224v-22.258c0-4.554-.639-7.812-1.945-9.759-1.299-1.946-3.107-2.912-5.427-2.912-2.218 0-4.013.677-5.358 2.02-1.353 1.349-2.315 3.195-2.899 5.538v27.369h-4.22v-38.014zm61.457 3.021q-3.966 0-6.517 3.613c-1.705 2.415-2.585 5.392-2.656 8.938h17.537v-1.626c0-3.137-.736-5.75-2.21-7.822-1.482-2.075-3.53-3.103-6.154-3.103m.598 35.735c-4.099 0-7.451-1.543-10.055-4.621q-3.895-4.61-3.896-11.793v-6.313c0-4.798 1.303-8.798 3.912-11.979 2.616-3.167 5.758-4.75 9.441-4.75 3.983 0 7.068 1.413 9.27 4.246q3.313 4.257 3.312 11.434v4.171H587.39v3.162c0 3.68.882 6.744 2.635 9.19 1.757 2.45 4.144 3.666 7.136 3.666 2.077 0 3.888-.367 5.396-1.089a11.1 11.1 0 0 0 3.877-3.132l1.728 2.99c-1.148 1.456-2.634 2.633-4.45 3.505-1.811.868-4 1.312-6.551 1.312m46.411-35.734q-3.976 0-6.528 3.613-2.54 3.62-2.652 8.938h17.54v-1.626c0-3.137-.733-5.75-2.216-7.822-1.475-2.075-3.52-3.103-6.144-3.103m.593 35.735c-4.1 0-7.446-1.543-10.045-4.621q-3.91-4.61-3.91-11.793v-6.313c0-4.798 1.309-8.798 3.913-11.979 2.623-3.167 5.766-4.75 9.45-4.75 3.975 0 7.072 1.413 9.27 4.246 2.2 2.837 3.304 6.65 3.304 11.434v4.171h-21.755v3.162q0 5.52 2.647 9.19c1.747 2.45 4.124 3.666 7.125 3.666 2.087 0 3.888-.367 5.392-1.089a11.2 11.2 0 0 0 3.894-3.132l1.717 2.99c-1.15 1.456-2.633 2.633-4.451 3.505-1.81.868-3.997 1.312-6.55 1.312m23.189-38.755.345 6.284c1.014-2.23 2.353-3.962 4.034-5.166 1.667-1.21 3.63-1.824 5.887-1.824 3.396 0 5.998 1.256 7.804 3.78 1.826 2.518 2.73 6.434 2.73 11.749v23.191h-4.249V306.72c0-4.343-.636-7.377-1.9-9.137-1.258-1.76-3.107-2.636-5.513-2.636-2.158 0-3.968.701-5.419 2.126-1.457 1.412-2.543 3.294-3.267 5.666v27.134h-4.219V291.86zm33.27 22.395c0 3.858.73 6.926 2.213 9.208 1.465 2.304 3.695 3.443 6.671 3.443 2.04 0 3.757-.544 5.167-1.657 1.405-1.113 2.514-2.662 3.336-4.627V301.79c-.79-2.025-1.874-3.66-3.244-4.92-1.368-1.24-3.102-1.863-5.186-1.863-2.97 0-5.216 1.294-6.708 3.891-1.502 2.603-2.25 5.995-2.25 10.161zm-4.262-5.195c0-5.386 1.088-9.714 3.274-12.975 2.169-3.245 5.187-4.871 9.03-4.871 2.134 0 4.007.52 5.607 1.564 1.603 1.024 2.928 2.523 3.992 4.43l.412-5.287h3.581v38.048c0 4.871-1.13 8.646-3.4 11.317-2.271 2.66-5.499 4.009-9.666 4.009-1.5 0-3.11-.235-4.832-.691-1.724-.456-3.252-1.054-4.59-1.805l1.168-3.704a14.1 14.1 0 0 0 3.831 1.716 15.2 15.2 0 0 0 4.352.616q4.536-.001 6.71-2.905c1.452-1.961 2.18-4.798 2.18-8.553v-4.597c-1.079 1.71-2.402 3.024-3.97 3.93-1.563.912-3.39 1.368-5.448 1.368-3.818 0-6.814-1.496-8.976-4.486-2.167-2.983-3.255-6.965-3.255-11.93zm40.2 20.916h-4.266V291.86h4.266zm0-48.968h-4.266v-6.005h4.266zm13.774 10.852.346 6.284c1.016-2.23 2.35-3.962 4.027-5.166 1.677-1.21 3.643-1.824 5.89-1.824 3.397 0 6.01 1.256 7.82 3.78 1.821 2.518 2.717 6.434 2.717 11.749v23.191h-4.248V306.72c0-4.343-.635-7.377-1.897-9.137-1.268-1.76-3.103-2.636-5.517-2.636-2.157 0-3.962.701-5.412 2.126-1.455 1.412-2.545 3.294-3.266 5.666v27.134h-4.224V291.86zm42.074 3.021q-3.978 0-6.518 3.613-2.547 3.62-2.66 8.938h17.54v-1.626c0-3.137-.731-5.75-2.21-7.822-1.476-2.075-3.525-3.103-6.152-3.103m.602 35.735c-4.11 0-7.456-1.543-10.048-4.621q-3.903-4.61-3.903-11.793v-6.313c0-4.798 1.302-8.798 3.91-11.979q3.924-4.75 9.439-4.75c3.978 0 7.077 1.413 9.283 4.246 2.197 2.837 3.3 6.65 3.3 11.434v4.171h-21.76v3.162c0 3.68.887 6.744 2.642 9.19 1.754 2.45 4.133 3.666 7.137 3.666 2.08 0 3.88-.367 5.382-1.089a11.16 11.16 0 0 0 3.897-3.132l1.725 2.99c-1.156 1.456-2.64 2.633-4.454 3.505-1.81.868-3.998 1.312-6.55 1.312"/><g transform="scale(.363) translate(84 58)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="M105 745c0 276 813 276 814 0V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81v318z" fill="none" stroke="#fff" stroke-width="64" stroke-linejoin="round"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg> diff --git a/main/main.cpp b/main/main.cpp index 9215f2e848..cf40f764cf 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -398,15 +398,15 @@ void Main::print_header(bool p_rich) { if (VERSION_TIMESTAMP > 0) { // Version timestamp available. if (p_rich) { - print_line_rich("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC) - \u001b[4m" + String(VERSION_WEBSITE)); + Engine::get_singleton()->print_header_rich("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC) - \u001b[4m" + String(VERSION_WEBSITE)); } else { - print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC) - " + String(VERSION_WEBSITE)); + Engine::get_singleton()->print_header(String(VERSION_NAME) + " v" + get_full_version_string() + " (" + Time::get_singleton()->get_datetime_string_from_unix_time(VERSION_TIMESTAMP, true) + " UTC) - " + String(VERSION_WEBSITE)); } } else { if (p_rich) { - print_line_rich("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " - \u001b[4m" + String(VERSION_WEBSITE)); + Engine::get_singleton()->print_header_rich("\u001b[38;5;39m" + String(VERSION_NAME) + "\u001b[0m v" + get_full_version_string() + " - \u001b[4m" + String(VERSION_WEBSITE)); } else { - print_line(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); + Engine::get_singleton()->print_header(String(VERSION_NAME) + " v" + get_full_version_string() + " - " + String(VERSION_WEBSITE)); } } } @@ -767,6 +767,7 @@ Error Main::test_setup() { return OK; } + // The order is the same as in `Main::cleanup()`. void Main::test_cleanup() { ERR_FAIL_COND(!_start_success); @@ -978,8 +979,9 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph packed_data->add_pack_source(zip_packed_data); #endif - // Default exit code, can be modified for certain errors. - Error exit_code = ERR_INVALID_PARAMETER; + // Exit error code used in the `goto error` conditions. + // It's returned as the program exit code. ERR_HELP is special cased and handled as success (0). + Error exit_err = ERR_INVALID_PARAMETER; I = args.front(); while (I) { @@ -1029,12 +1031,12 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph } else if (I->get() == "-h" || I->get() == "--help" || I->get() == "/?") { // display help show_help = true; - exit_code = ERR_HELP; // Hack to force an early exit in `main()` with a success code. + exit_err = ERR_HELP; // Hack to force an early exit in `main()` with a success code. goto error; } else if (I->get() == "--version") { print_line(get_full_version_string()); - exit_code = ERR_HELP; // Hack to force an early exit in `main()` with a success code. + exit_err = ERR_HELP; // Hack to force an early exit in `main()` with a success code. goto error; } else if (I->get() == "-v" || I->get() == "--verbose") { // verbose output @@ -2461,7 +2463,7 @@ error: OS::get_singleton()->finalize_core(); locale = String(); - return exit_code; + return exit_err; } Error _parse_resource_dummy(void *p_data, VariantParser::Stream *p_stream, Ref<Resource> &r_res, int &line, String &r_err_str) { @@ -3143,7 +3145,10 @@ String Main::get_rendering_driver_name() { // everything the main loop needs to know about frame timings static MainTimerSync main_timer_sync; -bool Main::start() { +// Return value should be EXIT_SUCCESS if we start successfully +// and should move on to `OS::run`, and EXIT_FAILURE otherwise for +// an early exit with that error code. +int Main::start() { ERR_FAIL_COND_V(!_start_success, false); bool has_icon = false; @@ -3280,7 +3285,7 @@ bool Main::start() { { Ref<DirAccess> da = DirAccess::open(doc_tool_path); - ERR_FAIL_COND_V_MSG(da.is_null(), false, "Argument supplied to --doctool must be a valid directory path."); + ERR_FAIL_COND_V_MSG(da.is_null(), EXIT_FAILURE, "Argument supplied to --doctool must be a valid directory path."); } #ifndef MODULE_MONO_ENABLED @@ -3315,11 +3320,11 @@ bool Main::start() { // Create the module documentation directory if it doesn't exist Ref<DirAccess> da = DirAccess::create_for_path(path); err = da->make_dir_recursive(path); - ERR_FAIL_COND_V_MSG(err != OK, false, "Error: Can't create directory: " + path + ": " + itos(err)); + ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error: Can't create directory: " + path + ": " + itos(err)); print_line("Loading docs from: " + path); err = docsrc.load_classes(path); - ERR_FAIL_COND_V_MSG(err != OK, false, "Error loading docs from: " + path + ": " + itos(err)); + ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error loading docs from: " + path + ": " + itos(err)); } } @@ -3327,11 +3332,11 @@ bool Main::start() { // Create the main documentation directory if it doesn't exist Ref<DirAccess> da = DirAccess::create_for_path(index_path); err = da->make_dir_recursive(index_path); - ERR_FAIL_COND_V_MSG(err != OK, false, "Error: Can't create index directory: " + index_path + ": " + itos(err)); + ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error: Can't create index directory: " + index_path + ": " + itos(err)); print_line("Loading classes from: " + index_path); err = docsrc.load_classes(index_path); - ERR_FAIL_COND_V_MSG(err != OK, false, "Error loading classes from: " + index_path + ": " + itos(err)); + ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error loading classes from: " + index_path + ": " + itos(err)); checked_paths.insert(index_path); print_line("Merging docs..."); @@ -3340,20 +3345,19 @@ bool Main::start() { for (const String &E : checked_paths) { print_line("Erasing old docs at: " + E); err = DocTools::erase_classes(E); - ERR_FAIL_COND_V_MSG(err != OK, false, "Error erasing old docs at: " + E + ": " + itos(err)); + ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error erasing old docs at: " + E + ": " + itos(err)); } print_line("Generating new docs..."); err = doc.save_classes(index_path, doc_data_classes); - ERR_FAIL_COND_V_MSG(err != OK, false, "Error saving new docs:" + itos(err)); + ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error saving new docs:" + itos(err)); print_line("Deleting docs cache..."); if (FileAccess::exists(EditorHelp::get_cache_full_path())) { DirAccess::remove_file_or_error(EditorHelp::get_cache_full_path()); } - OS::get_singleton()->set_exit_code(EXIT_SUCCESS); - return false; + return EXIT_SUCCESS; } // GDExtension API and interface. @@ -3368,32 +3372,24 @@ bool Main::start() { } if (dump_gdextension_interface || dump_extension_api) { - OS::get_singleton()->set_exit_code(EXIT_SUCCESS); - return false; + return EXIT_SUCCESS; } if (validate_extension_api) { Engine::get_singleton()->set_editor_hint(true); // "extension_api.json" should always contains editor singletons. bool valid = GDExtensionAPIDump::validate_extension_json_file(validate_extension_api_file) == OK; - OS::get_singleton()->set_exit_code(valid ? EXIT_SUCCESS : EXIT_FAILURE); - return false; + return valid ? EXIT_SUCCESS : EXIT_FAILURE; } } #ifndef DISABLE_DEPRECATED if (converting_project) { int ret = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).convert(); - if (ret) { - OS::get_singleton()->set_exit_code(EXIT_SUCCESS); - } - return false; + return ret ? EXIT_SUCCESS : EXIT_FAILURE; } if (validating_converting_project) { bool ret = ProjectConverter3To4(converter_max_kb_file, converter_max_line_length).validate_conversion(); - if (ret) { - OS::get_singleton()->set_exit_code(EXIT_SUCCESS); - } - return false; + return ret ? EXIT_SUCCESS : EXIT_FAILURE; } #endif // DISABLE_DEPRECATED @@ -3410,7 +3406,7 @@ bool Main::start() { // this might end up triggered by valid usage, in which case we'll have to // fine-tune further. OS::get_singleton()->alert("Couldn't detect whether to run the editor, the project manager or a specific project. Aborting."); - ERR_FAIL_V_MSG(false, "Couldn't detect whether to run the editor, the project manager or a specific project. Aborting."); + ERR_FAIL_V_MSG(EXIT_FAILURE, "Couldn't detect whether to run the editor, the project manager or a specific project. Aborting."); } #endif @@ -3424,15 +3420,10 @@ bool Main::start() { if (!script.is_empty()) { Ref<Script> script_res = ResourceLoader::load(script); - ERR_FAIL_COND_V_MSG(script_res.is_null(), false, "Can't load script: " + script); + ERR_FAIL_COND_V_MSG(script_res.is_null(), EXIT_FAILURE, "Can't load script: " + script); if (check_only) { - if (!script_res->is_valid()) { - OS::get_singleton()->set_exit_code(EXIT_FAILURE); - } else { - OS::get_singleton()->set_exit_code(EXIT_SUCCESS); - } - return false; + return script_res->is_valid() ? EXIT_SUCCESS : EXIT_FAILURE; } if (script_res->can_instantiate()) { @@ -3444,13 +3435,13 @@ bool Main::start() { memdelete(obj); } OS::get_singleton()->alert(vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script)); - ERR_FAIL_V_MSG(false, vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script)); + ERR_FAIL_V_MSG(EXIT_FAILURE, vformat("Can't load the script \"%s\" as it doesn't inherit from SceneTree or MainLoop.", script)); } script_loop->set_script(script_res); main_loop = script_loop; } else { - return false; + return EXIT_FAILURE; } } else { // Not based on script path. if (!editor && !ClassDB::class_exists(main_loop_type) && ScriptServer::is_global_class(main_loop_type)) { @@ -3458,7 +3449,7 @@ bool Main::start() { Ref<Script> script_res = ResourceLoader::load(script_path); if (script_res.is_null()) { OS::get_singleton()->alert("Error: Could not load MainLoop script type: " + main_loop_type); - ERR_FAIL_V_MSG(false, vformat("Could not load global class %s.", main_loop_type)); + ERR_FAIL_V_MSG(EXIT_FAILURE, vformat("Could not load global class %s.", main_loop_type)); } StringName script_base = script_res->get_instance_base_type(); Object *obj = ClassDB::instantiate(script_base); @@ -3468,7 +3459,7 @@ bool Main::start() { memdelete(obj); } OS::get_singleton()->alert("Error: Invalid MainLoop script base type: " + script_base); - ERR_FAIL_V_MSG(false, vformat("The global class %s does not inherit from SceneTree or MainLoop.", main_loop_type)); + ERR_FAIL_V_MSG(EXIT_FAILURE, vformat("The global class %s does not inherit from SceneTree or MainLoop.", main_loop_type)); } script_loop->set_script(script_res); main_loop = script_loop; @@ -3482,15 +3473,15 @@ bool Main::start() { if (!main_loop) { if (!ClassDB::class_exists(main_loop_type)) { OS::get_singleton()->alert("Error: MainLoop type doesn't exist: " + main_loop_type); - return false; + return EXIT_FAILURE; } else { Object *ml = ClassDB::instantiate(main_loop_type); - ERR_FAIL_NULL_V_MSG(ml, false, "Can't instance MainLoop type."); + ERR_FAIL_NULL_V_MSG(ml, EXIT_FAILURE, "Can't instance MainLoop type."); main_loop = Object::cast_to<MainLoop>(ml); if (!main_loop) { memdelete(ml); - ERR_FAIL_V_MSG(false, "Invalid MainLoop type."); + ERR_FAIL_V_MSG(EXIT_FAILURE, "Invalid MainLoop type."); } } } @@ -3614,7 +3605,7 @@ bool Main::start() { Error err; Vector<String> paths = get_files_with_extension(gdscript_docs_path, "gd"); - ERR_FAIL_COND_V_MSG(paths.is_empty(), false, "Couldn't find any GDScript files under the given directory: " + gdscript_docs_path); + ERR_FAIL_COND_V_MSG(paths.is_empty(), EXIT_FAILURE, "Couldn't find any GDScript files under the given directory: " + gdscript_docs_path); for (const String &path : paths) { Ref<GDScript> gdscript = ResourceLoader::load(path); @@ -3629,14 +3620,13 @@ bool Main::start() { Ref<DirAccess> da = DirAccess::create_for_path(doc_tool_path); err = da->make_dir_recursive(doc_tool_path); - ERR_FAIL_COND_V_MSG(err != OK, false, "Error: Can't create GDScript docs directory: " + doc_tool_path + ": " + itos(err)); + ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error: Can't create GDScript docs directory: " + doc_tool_path + ": " + itos(err)); HashMap<String, String> doc_data_classes; err = docs.save_classes(doc_tool_path, doc_data_classes, false); - ERR_FAIL_COND_V_MSG(err != OK, false, "Error saving GDScript docs:" + itos(err)); + ERR_FAIL_COND_V_MSG(err != OK, EXIT_FAILURE, "Error saving GDScript docs:" + itos(err)); - OS::get_singleton()->set_exit_code(EXIT_SUCCESS); - return false; + return EXIT_SUCCESS; } #endif // MODULE_GDSCRIPT_ENABLED @@ -3751,7 +3741,7 @@ bool Main::start() { if (sep == -1) { Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - ERR_FAIL_COND_V(da.is_null(), false); + ERR_FAIL_COND_V(da.is_null(), EXIT_FAILURE); local_game_path = da->get_current_dir().path_join(local_game_path); } else { @@ -3801,7 +3791,7 @@ bool Main::start() { scene = scenedata->instantiate(); } - ERR_FAIL_NULL_V_MSG(scene, false, "Failed loading scene: " + local_game_path + "."); + ERR_FAIL_NULL_V_MSG(scene, EXIT_FAILURE, "Failed loading scene: " + local_game_path + "."); sml->add_current_scene(scene); #ifdef MACOS_ENABLED @@ -3874,7 +3864,7 @@ bool Main::start() { OS::get_singleton()->benchmark_end_measure("Startup", "Total"); OS::get_singleton()->benchmark_dump(); - return true; + return EXIT_SUCCESS; } /* Main iteration @@ -3904,10 +3894,10 @@ static uint64_t physics_process_max = 0; static uint64_t process_max = 0; static uint64_t navigation_process_max = 0; +// Return false means iterating further, returning true means `OS::run` +// will terminate the program. In case of failure, the OS exit code needs +// to be set explicitly here (defaults to EXIT_SUCCESS). bool Main::iteration() { - //for now do not error on this - //ERR_FAIL_COND_V(iterating, false); - iterating++; const uint64_t ticks = OS::get_singleton()->get_ticks_usec(); @@ -3967,6 +3957,11 @@ bool Main::iteration() { PhysicsServer3D::get_singleton()->flush_queries(); #endif // _3D_DISABLED + // Prepare the fixed timestep interpolated nodes BEFORE they are updated + // by the physics server, otherwise the current and previous transforms + // may be the same, and no interpolation takes place. + OS::get_singleton()->get_main_loop()->iteration_prepare(); + PhysicsServer2D::get_singleton()->sync(); PhysicsServer2D::get_singleton()->flush_queries(); diff --git a/main/main.h b/main/main.h index 755c7d841a..ff0fba6b51 100644 --- a/main/main.h +++ b/main/main.h @@ -78,7 +78,7 @@ public: static Error test_setup(); static void test_cleanup(); #endif - static bool start(); + static int start(); static bool iteration(); static void force_redraw(); diff --git a/main/main_timer_sync.cpp b/main/main_timer_sync.cpp index 569930d427..d358d9fa93 100644 --- a/main/main_timer_sync.cpp +++ b/main/main_timer_sync.cpp @@ -299,6 +299,17 @@ int64_t MainTimerSync::DeltaSmoother::smooth_delta(int64_t p_delta) { // before advance_core considers changing the physics_steps return from // the typical values as defined by typical_physics_steps double MainTimerSync::get_physics_jitter_fix() { + // Turn off jitter fix when using fixed timestep interpolation. + // Note this shouldn't be on UNTIL 3d interpolation is implemented, + // otherwise we will get people making 3d games with the physics_interpolation + // set to on getting jitter fix disabled unexpectedly. +#if 0 + if (Engine::get_singleton()->is_physics_interpolation_enabled()) { + // Would be better to write a simple bypass for jitter fix but this will do to get started. + return 0.0; + } +#endif + return Engine::get_singleton()->get_physics_jitter_fix(); } diff --git a/methods.py b/methods.py index 6cd944c6b0..7af621befc 100644 --- a/methods.py +++ b/methods.py @@ -179,7 +179,7 @@ def get_version_info(module_version_string="", silent=False): gitfolder = ".git" if os.path.isfile(".git"): - with open(".git", "r") as file: + with open(".git", "r", encoding="utf-8") as file: module_folder = file.readline().strip() if module_folder.startswith("gitdir: "): gitfolder = module_folder[8:] @@ -196,12 +196,12 @@ def get_version_info(module_version_string="", silent=False): head = os.path.join(gitfolder, ref) packedrefs = os.path.join(gitfolder, "packed-refs") if os.path.isfile(head): - with open(head, "r") as file: + with open(head, "r", encoding="utf-8") as file: githash = file.readline().strip() elif os.path.isfile(packedrefs): # Git may pack refs into a single file. This code searches .git/packed-refs file for the current ref's hash. # https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-pack-refs.html - for line in open(packedrefs, "r").read().splitlines(): + for line in open(packedrefs, "r", encoding="utf-8").read().splitlines(): if line.startswith("#"): continue (line_hash, line_ref) = line.split(" ") @@ -277,7 +277,7 @@ const uint64_t VERSION_TIMESTAMP = {git_timestamp}; def parse_cg_file(fname, uniforms, sizes, conditionals): - with open(fname, "r") as fs: + with open(fname, "r", encoding="utf-8") as fs: line = fs.readline() while line: @@ -1251,7 +1251,7 @@ def generate_vs_project(env, original_args, project_name="godot"): ).hexdigest() if os.path.exists(f"{project_name}.vcxproj.filters"): - with open(f"{project_name}.vcxproj.filters", "r") as file: + with open(f"{project_name}.vcxproj.filters", "r", encoding="utf-8") as file: existing_filters = file.read() match = re.search(r"(?ms)^<!-- CHECKSUM$.([0-9a-f]{32})", existing_filters) if match is not None and md5 == match.group(1): @@ -1263,7 +1263,7 @@ def generate_vs_project(env, original_args, project_name="godot"): if not skip_filters: print(f"Regenerating {project_name}.vcxproj.filters") - with open("misc/msvs/vcxproj.filters.template", "r") as file: + with open("misc/msvs/vcxproj.filters.template", "r", encoding="utf-8") as file: filters_template = file.read() for i in range(1, 10): filters_template = filters_template.replace(f"%%UUID{i}%%", str(uuid.uuid4())) @@ -1417,7 +1417,7 @@ def generate_vs_project(env, original_args, project_name="godot"): ) output = f'bin\\godot{env["PROGSUFFIX"]}' - with open("misc/msvs/props.template", "r") as file: + with open("misc/msvs/props.template", "r", encoding="utf-8") as file: props_template = file.read() props_template = props_template.replace("%%VSCONF%%", vsconf) @@ -1486,7 +1486,7 @@ def generate_vs_project(env, original_args, project_name="godot"): sln_uuid = str(uuid.uuid4()) if os.path.exists(f"{project_name}.sln"): - for line in open(f"{project_name}.sln", "r").read().splitlines(): + for line in open(f"{project_name}.sln", "r", encoding="utf-8").read().splitlines(): if line.startswith('Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}")'): proj_uuid = re.search( r"\"{(\b[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-\b[0-9a-fA-F]{12}\b)}\"$", @@ -1575,7 +1575,7 @@ def generate_vs_project(env, original_args, project_name="godot"): section2 = sorted(section2) if not get_bool(original_args, "vsproj_props_only", False): - with open("misc/msvs/vcxproj.template", "r") as file: + with open("misc/msvs/vcxproj.template", "r", encoding="utf-8") as file: proj_template = file.read() proj_template = proj_template.replace("%%UUID%%", proj_uuid) proj_template = proj_template.replace("%%CONFS%%", "\n ".join(configurations)) @@ -1587,7 +1587,7 @@ def generate_vs_project(env, original_args, project_name="godot"): f.write(proj_template) if not get_bool(original_args, "vsproj_props_only", False): - with open("misc/msvs/sln.template", "r") as file: + with open("misc/msvs/sln.template", "r", encoding="utf-8") as file: sln_template = file.read() sln_template = sln_template.replace("%%NAME%%", project_name) sln_template = sln_template.replace("%%UUID%%", proj_uuid) diff --git a/misc/dist/icon_console.svg b/misc/dist/icon_console.svg index 4a0d2d8d7d..10143d026b 100644 --- a/misc/dist/icon_console.svg +++ b/misc/dist/icon_console.svg @@ -1 +1 @@ -<svg width="1024" height="1024" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g><rect fill="#414042" stroke-width="20" stroke="#fff" x="550" y="650" width="430" height="330" rx="20"/><path fill="#fff" d="M590 750a10 10 0 0 0 0 14.142l70 70-70 70a10 10 0 0 0 0 14.142l20 20a10 10 0 0 0 14.142 0l97.071-97.071a10 10 0 0 0 0-14.142L624.142 730A10 10 0 0 0 610 730zm180 145a10 10 0 0 0-10 10v25a10 10 0 0 0 10 10h160a10 10 0 0 0 10-10v-25a10 10 0 0 0-10-10z"/></svg> +<svg width="1024" height="1024" xmlns="http://www.w3.org/2000/svg"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 814 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H446l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z" fill="#478cbf"/><path d="M483 600c0 34 58 34 58 0v-86c0-34-58-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g><rect fill="#414042" stroke-width="20" stroke="#fff" x="550" y="650" width="430" height="330" rx="20"/><path fill="#fff" d="M590 750a10 10 0 0 0 0 14.142l70 70-70 70a10 10 0 0 0 0 14.142l20 20a10 10 0 0 0 14.142 0l97.071-97.071a10 10 0 0 0 0-14.142L624.142 730A10 10 0 0 0 610 730zm180 145a10 10 0 0 0-10 10v25a10 10 0 0 0 10 10h160a10 10 0 0 0 10-10v-25a10 10 0 0 0-10-10z"/></svg> diff --git a/misc/dist/project_icon.svg b/misc/dist/project_icon.svg deleted file mode 100644 index 5bfc113daa..0000000000 --- a/misc/dist/project_icon.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="1024" height="1024" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><rect fill="#1e1a21" x="8" y="8" width="1008" height="1008" rx="176" stroke-width="16" stroke="#2e2832"/><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></svg> diff --git a/misc/extension_api_validation/4.2-stable.expected b/misc/extension_api_validation/4.2-stable.expected index 8623e8eb25..53a29fa660 100644 --- a/misc/extension_api_validation/4.2-stable.expected +++ b/misc/extension_api_validation/4.2-stable.expected @@ -99,15 +99,6 @@ Validate extension JSON: Error: Field 'classes/GLTFBufferView/methods/get_indice Change AudioStreamPlayer* is_autoplay_enabled and GLTFBufferView getters to be const. -GH-87379 --------- -Validate extension JSON: API was removed: classes/TileMap/methods/get_tileset -Validate extension JSON: API was removed: classes/TileMap/methods/set_tileset -Validate extension JSON: API was removed: classes/TileMap/properties/tile_set - -Moved to the parent TileMapLayerGroup class. No change should be necessary. - - GH-87340 -------- Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/RenderingDevice/methods/screen_get_framebuffer_format': arguments @@ -248,3 +239,23 @@ Validate extension JSON: Error: Field 'classes/AcceptDialog/methods/register_tex Validate extension JSON: Error: Field 'classes/AcceptDialog/methods/remove_button/arguments/0': type changed value in new API, from "Control" to "Button". Changed argument type to the more specific one actually expected by the method. Compatibility method registered. + + +GH-89992 +-------- +Validate extension JSON: Error: Field 'classes/Node/methods/replace_by/arguments': size changed value in new API, from 2 to 3. + +Added optional argument to prevent children to be reparented during replace_by. Compatibility method registered. + + +GH-88047 +-------- +Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3. +Validate extension JSON: Error: Field 'classes/AStar2D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3. +Validate extension JSON: Error: Field 'classes/AStar3D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3. +Validate extension JSON: Error: Field 'classes/AStar3D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3. +Validate extension JSON: Error: Field 'classes/AStarGrid2D/methods/get_id_path/arguments': size changed value in new API, from 2 to 3. +Validate extension JSON: Error: Field 'classes/AStarGrid2D/methods/get_point_path/arguments': size changed value in new API, from 2 to 3. + +Added optional "allow_partial_path" argument to get_id_path and get_point_path methods in AStar classes. +Compatibility methods registered. diff --git a/misc/scripts/check_ci_log.py b/misc/scripts/check_ci_log.py index d979d373de..d024a3e375 100755 --- a/misc/scripts/check_ci_log.py +++ b/misc/scripts/check_ci_log.py @@ -9,7 +9,7 @@ if len(sys.argv) < 2: fname = sys.argv[1] -with open(fname.strip(), "r") as fileread: +with open(fname.strip(), "r", encoding="utf-8") as fileread: file_contents = fileread.read() # If find "ERROR: AddressSanitizer:", then happens invalid read or write diff --git a/misc/scripts/copyright_headers.py b/misc/scripts/copyright_headers.py index b60eb32289..169795921f 100755 --- a/misc/scripts/copyright_headers.py +++ b/misc/scripts/copyright_headers.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import os import sys header = """\ @@ -35,58 +36,61 @@ header = """\ /**************************************************************************/ """ -fname = sys.argv[1] +if len(sys.argv) < 2: + print("Invalid usage of copyright_headers.py, it should be called with a path to one or multiple files.") + sys.exit(1) -# Handle replacing $filename with actual filename and keep alignment -fsingle = fname.strip() -if fsingle.find("/") != -1: - fsingle = fsingle[fsingle.rfind("/") + 1 :] -rep_fl = "$filename" -rep_fi = fsingle -len_fl = len(rep_fl) -len_fi = len(rep_fi) -# Pad with spaces to keep alignment -if len_fi < len_fl: - for x in range(len_fl - len_fi): - rep_fi += " " -elif len_fl < len_fi: - for x in range(len_fi - len_fl): - rep_fl += " " -if header.find(rep_fl) != -1: - text = header.replace(rep_fl, rep_fi) -else: - text = header.replace("$filename", fsingle) -text += "\n" +for f in sys.argv[1:]: + fname = f -# We now have the proper header, so we want to ignore the one in the original file -# and potentially empty lines and badly formatted lines, while keeping comments that -# come after the header, and then keep everything non-header unchanged. -# To do so, we skip empty lines that may be at the top in a first pass. -# In a second pass, we skip all consecutive comment lines starting with "/*", -# then we can append the rest (step 2). + # Handle replacing $filename with actual filename and keep alignment + fsingle = os.path.basename(fname.strip()) + rep_fl = "$filename" + rep_fi = fsingle + len_fl = len(rep_fl) + len_fi = len(rep_fi) + # Pad with spaces to keep alignment + if len_fi < len_fl: + for x in range(len_fl - len_fi): + rep_fi += " " + elif len_fl < len_fi: + for x in range(len_fi - len_fl): + rep_fl += " " + if header.find(rep_fl) != -1: + text = header.replace(rep_fl, rep_fi) + else: + text = header.replace("$filename", fsingle) + text += "\n" -with open(fname.strip(), "r") as fileread: - line = fileread.readline() - header_done = False + # We now have the proper header, so we want to ignore the one in the original file + # and potentially empty lines and badly formatted lines, while keeping comments that + # come after the header, and then keep everything non-header unchanged. + # To do so, we skip empty lines that may be at the top in a first pass. + # In a second pass, we skip all consecutive comment lines starting with "/*", + # then we can append the rest (step 2). - while line.strip() == "": # Skip empty lines at the top + with open(fname.strip(), "r", encoding="utf-8") as fileread: line = fileread.readline() + header_done = False - if line.find("/**********") == -1: # Godot header starts this way - # Maybe starting with a non-Godot comment, abort header magic - header_done = True + while line.strip() == "": # Skip empty lines at the top + line = fileread.readline() - while not header_done: # Handle header now - if line.find("/*") != 0: # No more starting with a comment + if line.find("/**********") == -1: # Godot header starts this way + # Maybe starting with a non-Godot comment, abort header magic header_done = True - if line.strip() != "": - text += line - line = fileread.readline() - while line != "": # Dump everything until EOF - text += line - line = fileread.readline() + while not header_done: # Handle header now + if line.find("/*") != 0: # No more starting with a comment + header_done = True + if line.strip() != "": + text += line + line = fileread.readline() + + while line != "": # Dump everything until EOF + text += line + line = fileread.readline() -# Write -with open(fname.strip(), "w", encoding="utf-8", newline="\n") as filewrite: - filewrite.write(text) + # Write + with open(fname.strip(), "w", encoding="utf-8", newline="\n") as filewrite: + filewrite.write(text) diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h index 3763700ff1..ce5b7f4045 100644 --- a/modules/dds/texture_loader_dds.h +++ b/modules/dds/texture_loader_dds.h @@ -35,10 +35,10 @@ class ResourceFormatDDS : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; virtual ~ResourceFormatDDS() {} }; diff --git a/modules/fbx/fbx_document.cpp b/modules/fbx/fbx_document.cpp index 367117edcb..1dbe4c535a 100644 --- a/modules/fbx/fbx_document.cpp +++ b/modules/fbx/fbx_document.cpp @@ -2347,7 +2347,7 @@ PackedByteArray FBXDocument::generate_buffer(Ref<GLTFState> p_state) { return PackedByteArray(); } -Error write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) { +Error FBXDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) { return ERR_UNAVAILABLE; } diff --git a/modules/fbx/fbx_document.h b/modules/fbx/fbx_document.h index ba48eb11ae..c9256df444 100644 --- a/modules/fbx/fbx_document.h +++ b/modules/fbx/fbx_document.h @@ -53,14 +53,13 @@ public: static String _gen_unique_name(HashSet<String> &unique_names, const String &p_name); public: - Error append_from_file(String p_path, Ref<GLTFState> p_state, uint32_t p_flags = 0, String p_base_path = String()); - Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags = 0); - Error append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags = 0); + Error append_from_file(String p_path, Ref<GLTFState> p_state, uint32_t p_flags = 0, String p_base_path = String()) override; + Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags = 0) override; + Error append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags = 0) override; -public: - Node *generate_scene(Ref<GLTFState> p_state, float p_bake_fps = 30.0f, bool p_trimming = false, bool p_remove_immutable_tracks = true); - PackedByteArray generate_buffer(Ref<GLTFState> p_state); - Error write_to_filesystem(Ref<GLTFState> p_state, const String &p_path); + Node *generate_scene(Ref<GLTFState> p_state, float p_bake_fps = 30.0f, bool p_trimming = false, bool p_remove_immutable_tracks = true) override; + PackedByteArray generate_buffer(Ref<GLTFState> p_state) override; + Error write_to_filesystem(Ref<GLTFState> p_state, const String &p_path) override; protected: static void _bind_methods(); diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index fd5ad837f9..781e284bfc 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -629,18 +629,18 @@ public: class ResourceFormatLoaderGDScript : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; - virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; + virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override; }; class ResourceFormatSaverGDScript : public ResourceFormatSaver { public: - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; - virtual bool recognize(const Ref<Resource> &p_resource) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; }; #endif // GDSCRIPT_H diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 12ff22c878..854c944e14 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -2665,6 +2665,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c GDScriptParser::DataType base_type = p_base.type; const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\""; + const bool use_string_names = EDITOR_GET("text_editor/completion/add_string_name_literals"); + const bool use_node_paths = EDITOR_GET("text_editor/completion/add_node_path_literals"); while (base_type.is_set() && !base_type.is_variant()) { switch (base_type.kind) { @@ -2698,8 +2700,14 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c List<String> options; obj->get_argument_options(p_method, p_argidx, &options); for (String &opt : options) { + // Handle user preference. if (opt.is_quoted()) { - opt = opt.unquote().quote(quote_style); // Handle user preference. + opt = opt.unquote().quote(quote_style); + if (use_string_names && info.arguments[p_argidx].type == Variant::STRING_NAME) { + opt = opt.indent("&"); + } else if (use_node_paths && info.arguments[p_argidx].type == Variant::NODE_PATH) { + opt = opt.indent("^"); + } } ScriptLanguage::CodeCompletionOption option(opt, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION); r_result.insert(option.display, option); diff --git a/modules/gdscript/tests/scripts/runtime/features/emit_after_await.gd b/modules/gdscript/tests/scripts/runtime/features/emit_after_await.gd new file mode 100644 index 0000000000..21fd526acc --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/emit_after_await.gd @@ -0,0 +1,12 @@ +# https://github.com/godotengine/godot/issues/89439 +extends Node + +signal my_signal + +func async_func(): + await my_signal + my_signal.emit() + +func test(): + async_func() + my_signal.emit() diff --git a/modules/gdscript/tests/scripts/runtime/features/emit_after_await.out b/modules/gdscript/tests/scripts/runtime/features/emit_after_await.out new file mode 100644 index 0000000000..d73c5eb7cd --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/emit_after_await.out @@ -0,0 +1 @@ +GDTEST_OK diff --git a/modules/gdscript/tests/scripts/runtime/features/emit_one_shot_is_non_recursive.gd b/modules/gdscript/tests/scripts/runtime/features/emit_one_shot_is_non_recursive.gd new file mode 100644 index 0000000000..5c328dcfcd --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/emit_one_shot_is_non_recursive.gd @@ -0,0 +1,22 @@ +# https://github.com/godotengine/godot/issues/89439 + +signal my_signal + +func foo(): + print("Foo") + my_signal.emit() + +func bar(): + print("Bar") + +func baz(): + print("Baz") + +func test(): + @warning_ignore("return_value_discarded") + my_signal.connect(foo, CONNECT_ONE_SHOT) + @warning_ignore("return_value_discarded") + my_signal.connect(bar, CONNECT_ONE_SHOT) + @warning_ignore("return_value_discarded") + my_signal.connect(baz) + my_signal.emit() diff --git a/modules/gdscript/tests/scripts/runtime/features/emit_one_shot_is_non_recursive.out b/modules/gdscript/tests/scripts/runtime/features/emit_one_shot_is_non_recursive.out new file mode 100644 index 0000000000..3399e08878 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/emit_one_shot_is_non_recursive.out @@ -0,0 +1,5 @@ +GDTEST_OK +Foo +Baz +Bar +Baz diff --git a/modules/gltf/extensions/physics/gltf_physics_shape.cpp b/modules/gltf/extensions/physics/gltf_physics_shape.cpp index 35c99adbe5..6c9ed82a69 100644 --- a/modules/gltf/extensions/physics/gltf_physics_shape.cpp +++ b/modules/gltf/extensions/physics/gltf_physics_shape.cpp @@ -129,6 +129,34 @@ void GLTFPhysicsShape::set_importer_mesh(Ref<ImporterMesh> p_importer_mesh) { importer_mesh = p_importer_mesh; } +Ref<ImporterMesh> _convert_hull_points_to_mesh(const Vector<Vector3> &p_hull_points) { + Ref<ImporterMesh> importer_mesh; + ERR_FAIL_COND_V_MSG(p_hull_points.size() < 3, importer_mesh, "GLTFPhysicsShape: Convex hull has fewer points (" + itos(p_hull_points.size()) + ") than the minimum of 3. At least 3 points are required in order to save to GLTF, since it uses a mesh to represent convex hulls."); + if (p_hull_points.size() > 255) { + WARN_PRINT("GLTFPhysicsShape: Convex hull has more points (" + itos(p_hull_points.size()) + ") than the recommended maximum of 255. This may not load correctly in other engines."); + } + // Convert the convex hull points into an array of faces. + Geometry3D::MeshData md; + Error err = ConvexHullComputer::convex_hull(p_hull_points, md); + ERR_FAIL_COND_V_MSG(err != OK, importer_mesh, "GLTFPhysicsShape: Failed to compute convex hull."); + Vector<Vector3> face_vertices; + for (uint32_t i = 0; i < md.faces.size(); i++) { + uint32_t index_count = md.faces[i].indices.size(); + for (uint32_t j = 1; j < index_count - 1; j++) { + face_vertices.append(p_hull_points[md.faces[i].indices[0]]); + face_vertices.append(p_hull_points[md.faces[i].indices[j]]); + face_vertices.append(p_hull_points[md.faces[i].indices[j + 1]]); + } + } + // Create an ImporterMesh from the faces. + importer_mesh.instantiate(); + Array surface_array; + surface_array.resize(Mesh::ArrayType::ARRAY_MAX); + surface_array[Mesh::ArrayType::ARRAY_VERTEX] = face_vertices; + importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array); + return importer_mesh; +} + Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_node(const CollisionShape3D *p_godot_shape_node) { Ref<GLTFPhysicsShape> gltf_shape; gltf_shape.instantiate(); @@ -163,30 +191,8 @@ Ref<GLTFPhysicsShape> GLTFPhysicsShape::from_node(const CollisionShape3D *p_godo gltf_shape->shape_type = "convex"; Ref<ConvexPolygonShape3D> convex = shape_resource; Vector<Vector3> hull_points = convex->get_points(); - ERR_FAIL_COND_V_MSG(hull_points.size() < 3, gltf_shape, "GLTFPhysicsShape: Convex hull has fewer points (" + itos(hull_points.size()) + ") than the minimum of 3. At least 3 points are required in order to save to GLTF, since it uses a mesh to represent convex hulls."); - if (hull_points.size() > 255) { - WARN_PRINT("GLTFPhysicsShape: Convex hull has more points (" + itos(hull_points.size()) + ") than the recommended maximum of 255. This may not load correctly in other engines."); - } - // Convert the convex hull points into an array of faces. - Geometry3D::MeshData md; - Error err = ConvexHullComputer::convex_hull(hull_points, md); - ERR_FAIL_COND_V_MSG(err != OK, gltf_shape, "GLTFPhysicsShape: Failed to compute convex hull."); - Vector<Vector3> face_vertices; - for (uint32_t i = 0; i < md.faces.size(); i++) { - uint32_t index_count = md.faces[i].indices.size(); - for (uint32_t j = 1; j < index_count - 1; j++) { - face_vertices.append(hull_points[md.faces[i].indices[0]]); - face_vertices.append(hull_points[md.faces[i].indices[j]]); - face_vertices.append(hull_points[md.faces[i].indices[j + 1]]); - } - } - // Create an ImporterMesh from the faces. - Ref<ImporterMesh> importer_mesh; - importer_mesh.instantiate(); - Array surface_array; - surface_array.resize(Mesh::ArrayType::ARRAY_MAX); - surface_array[Mesh::ArrayType::ARRAY_VERTEX] = face_vertices; - importer_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES, surface_array); + Ref<ImporterMesh> importer_mesh = _convert_hull_points_to_mesh(hull_points); + ERR_FAIL_COND_V_MSG(importer_mesh.is_null(), gltf_shape, "GLTFPhysicsShape: Failed to convert convex hull points to a mesh."); gltf_shape->set_importer_mesh(importer_mesh); } else if (cast_to<const ConcavePolygonShape3D>(shape_resource.ptr())) { gltf_shape->shape_type = "trimesh"; diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h index 1001b482cd..1901e89d51 100644 --- a/modules/gltf/gltf_document.h +++ b/modules/gltf/gltf_document.h @@ -311,13 +311,13 @@ private: static float get_max_component(const Color &p_color); public: - Error append_from_file(String p_path, Ref<GLTFState> p_state, uint32_t p_flags = 0, String p_base_path = String()); - Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags = 0); - Error append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags = 0); + virtual Error append_from_file(String p_path, Ref<GLTFState> p_state, uint32_t p_flags = 0, String p_base_path = String()); + virtual Error append_from_buffer(PackedByteArray p_bytes, String p_base_path, Ref<GLTFState> p_state, uint32_t p_flags = 0); + virtual Error append_from_scene(Node *p_node, Ref<GLTFState> p_state, uint32_t p_flags = 0); - Node *generate_scene(Ref<GLTFState> p_state, float p_bake_fps = 30.0f, bool p_trimming = false, bool p_remove_immutable_tracks = true); - PackedByteArray generate_buffer(Ref<GLTFState> p_state); - Error write_to_filesystem(Ref<GLTFState> p_state, const String &p_path); + virtual Node *generate_scene(Ref<GLTFState> p_state, float p_bake_fps = 30.0f, bool p_trimming = false, bool p_remove_immutable_tracks = true); + virtual PackedByteArray generate_buffer(Ref<GLTFState> p_state); + virtual Error write_to_filesystem(Ref<GLTFState> p_state, const String &p_path); public: Error _parse_gltf_state(Ref<GLTFState> p_state, const String &p_search_path); diff --git a/modules/ktx/texture_loader_ktx.h b/modules/ktx/texture_loader_ktx.h index 0ea676be6b..0de458a742 100644 --- a/modules/ktx/texture_loader_ktx.h +++ b/modules/ktx/texture_loader_ktx.h @@ -36,10 +36,10 @@ class ResourceFormatKTX : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; virtual ~ResourceFormatKTX() {} ResourceFormatKTX(); diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp index 5d22cb1301..b6f5d6ce57 100644 --- a/modules/lightmapper_rd/lightmapper_rd.cpp +++ b/modules/lightmapper_rd/lightmapper_rd.cpp @@ -233,8 +233,7 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_ MeshInstance &mi = mesh_instances.write[m_i]; Size2i s = Size2i(mi.data.albedo_on_uv2->get_width(), mi.data.albedo_on_uv2->get_height()); sizes.push_back(s); - atlas_size.width = MAX(atlas_size.width, s.width + 2); - atlas_size.height = MAX(atlas_size.height, s.height + 2); + atlas_size = atlas_size.max(s + Size2i(2, 2)); } int max = nearest_power_of_2_templated(atlas_size.width); diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index 858d1d3e4e..0dd1dc7c12 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -1408,7 +1408,11 @@ GDExtensionBool CSharpLanguage::_instance_binding_reference_callback(void *p_tok } void *CSharpLanguage::get_instance_binding(Object *p_object) { - void *binding = p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks); + return p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks); +} + +void *CSharpLanguage::get_instance_binding_with_setup(Object *p_object) { + void *binding = get_instance_binding(p_object); // Initially this was in `_instance_binding_create_callback`. However, after the new instance // binding re-write it was resulting in a deadlock in `_instance_binding_reference`, as @@ -1433,11 +1437,7 @@ void *CSharpLanguage::get_existing_instance_binding(Object *p_object) { #ifdef DEBUG_ENABLED CRASH_COND(p_object->has_instance_binding(p_object)); #endif - return p_object->get_instance_binding(get_singleton(), &_instance_binding_callbacks); -} - -void CSharpLanguage::set_instance_binding(Object *p_object, void *p_binding) { - p_object->set_instance_binding(get_singleton(), p_binding, &_instance_binding_callbacks); + return get_instance_binding(p_object); } bool CSharpLanguage::has_instance_binding(Object *p_object) { @@ -1464,13 +1464,6 @@ void CSharpLanguage::tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_i // Another reason for doing this is that this instance could outlive CSharpLanguage, which would // be problematic when using a script. See: https://github.com/godotengine/godot/issues/25621 - CSharpScriptBinding script_binding; - - script_binding.inited = true; - script_binding.type_name = *p_native_name; - script_binding.gchandle = gchandle; - script_binding.owner = p_unmanaged; - if (p_ref_counted) { // Unsafe refcount increment. The managed instance also counts as a reference. // This way if the unmanaged world has no references to our owner @@ -1486,14 +1479,13 @@ void CSharpLanguage::tie_native_managed_to_unmanaged(GCHandleIntPtr p_gchandle_i // The object was just created, no script instance binding should have been attached CRASH_COND(CSharpLanguage::has_instance_binding(p_unmanaged)); - void *data; - { - MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex()); - data = (void *)CSharpLanguage::get_singleton()->insert_script_binding(p_unmanaged, script_binding); - } + void *binding = CSharpLanguage::get_singleton()->get_instance_binding(p_unmanaged); - // Should be thread safe because the object was just created and nothing else should be referencing it - CSharpLanguage::set_instance_binding(p_unmanaged, data); + CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)binding)->value(); + script_binding.inited = true; + script_binding.type_name = *p_native_name; + script_binding.gchandle = gchandle; + script_binding.owner = p_unmanaged; } void CSharpLanguage::tie_user_managed_to_unmanaged(GCHandleIntPtr p_gchandle_intptr, Object *p_unmanaged, Ref<CSharpScript> *p_script, bool p_ref_counted) { @@ -2092,7 +2084,7 @@ CSharpInstance::~CSharpInstance() { bool die = _unreference_owner_unsafe(); CRASH_COND(die); // `owner_keep_alive` holds a reference, so it can't die - void *data = CSharpLanguage::get_instance_binding(owner); + void *data = CSharpLanguage::get_instance_binding_with_setup(owner); CRASH_COND(data == nullptr); CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get(); CRASH_COND(!script_binding.inited); diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h index 06d526f494..e3f39c50f4 100644 --- a/modules/mono/csharp_script.h +++ b/modules/mono/csharp_script.h @@ -442,7 +442,7 @@ class CSharpLanguage : public ScriptLanguage { public: static void *get_instance_binding(Object *p_object); static void *get_existing_instance_binding(Object *p_object); - static void set_instance_binding(Object *p_object, void *p_binding); + static void *get_instance_binding_with_setup(Object *p_object); static bool has_instance_binding(Object *p_object); const Mutex &get_language_bind_mutex() { diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props index b6c72bce9d..5c3af17e77 100644 --- a/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props +++ b/modules/mono/editor/Godot.NET.Sdk/Godot.NET.Sdk/Sdk/Sdk.props @@ -2,6 +2,8 @@ <Import Project="$(MSBuildThisFileDirectory)\SdkPackageVersions.props" /> <PropertyGroup> + <UsingGodotNETSdk>true</UsingGodotNETSdk> + <!-- Determines if we should import Microsoft.NET.Sdk, if it wasn't already imported. --> <GodotSdkImportsMicrosoftNetSdk Condition=" '$(UsingMicrosoftNETSdk)' != 'true' ">true</GodotSdkImportsMicrosoftNetSdk> </PropertyGroup> diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs index 63af6ee6e8..feaa1d07da 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Aabb.cs @@ -733,10 +733,7 @@ namespace Godot /// Converts this <see cref="Aabb"/> to a string. /// </summary> /// <returns>A string representation of this AABB.</returns> - public override readonly string ToString() - { - return $"{_position}, {_size}"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Aabb"/> to a string with the given <paramref name="format"/>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs index 589d6596f0..8679f32e1a 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs @@ -212,7 +212,7 @@ namespace Godot private void Rotate(Quaternion quaternion) { - this *= new Basis(quaternion); + this = new Basis(quaternion) * this; } private void SetDiagonal(Vector3 diagonal) @@ -1134,10 +1134,7 @@ namespace Godot /// Converts this <see cref="Basis"/> to a string. /// </summary> /// <returns>A string representation of this basis.</returns> - public override readonly string ToString() - { - return $"[X: {X}, Y: {Y}, Z: {Z}]"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Basis"/> to a string with the given <paramref name="format"/>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs index a1f1ade9b8..d3b9f2d2ae 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs @@ -1329,10 +1329,7 @@ namespace Godot /// Converts this <see cref="Color"/> to a string. /// </summary> /// <returns>A string representation of this color.</returns> - public override readonly string ToString() - { - return $"({R}, {G}, {B}, {A})"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Color"/> to a string with the given <paramref name="format"/>. @@ -1340,9 +1337,7 @@ namespace Godot /// <returns>A string representation of this color.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"({R.ToString(format)}, {G.ToString(format)}, {B.ToString(format)}, {A.ToString(format)})"; -#pragma warning restore CA1305 + return $"({R.ToString(format, CultureInfo.InvariantCulture)}, {G.ToString(format, CultureInfo.InvariantCulture)}, {B.ToString(format, CultureInfo.InvariantCulture)}, {A.ToString(format, CultureInfo.InvariantCulture)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs index 464b517428..94609984ac 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/NativeInterop/VariantUtils.cs @@ -235,13 +235,28 @@ namespace Godot.NativeInterop } public static godot_variant CreateFromSystemArrayOfStringName(Span<StringName> from) - => CreateFromArray(new Collections.Array(from)); + { + if (from == null) + return default; + using var fromGodot = new Collections.Array(from); + return CreateFromArray((godot_array)fromGodot.NativeValue); + } public static godot_variant CreateFromSystemArrayOfNodePath(Span<NodePath> from) - => CreateFromArray(new Collections.Array(from)); + { + if (from == null) + return default; + using var fromGodot = new Collections.Array(from); + return CreateFromArray((godot_array)fromGodot.NativeValue); + } public static godot_variant CreateFromSystemArrayOfRid(Span<Rid> from) - => CreateFromArray(new Collections.Array(from)); + { + if (from == null) + return default; + using var fromGodot = new Collections.Array(from); + return CreateFromArray((godot_array)fromGodot.NativeValue); + } public static godot_variant CreateFromSystemArrayOfGodotObject(GodotObject[]? from) { diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs index c5998eca5c..1f50a38e78 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -424,10 +425,7 @@ namespace Godot /// Converts this <see cref="Plane"/> to a string. /// </summary> /// <returns>A string representation of this plane.</returns> - public override readonly string ToString() - { - return $"{_normal}, {_d}"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Plane"/> to a string with the given <paramref name="format"/>. @@ -435,9 +433,7 @@ namespace Godot /// <returns>A string representation of this plane.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"{_normal.ToString(format)}, {_d.ToString(format)}"; -#pragma warning restore CA1305 + return $"{_normal.ToString(format)}, {_d.ToString(format, CultureInfo.InvariantCulture)}"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs index c0889fb0e8..fed0eb5e78 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -1012,10 +1013,7 @@ namespace Godot /// Converts this <see cref="Projection"/> to a string. /// </summary> /// <returns>A string representation of this projection.</returns> - public override readonly string ToString() - { - return $"{X.X}, {X.Y}, {X.Z}, {X.W}\n{Y.X}, {Y.Y}, {Y.Z}, {Y.W}\n{Z.X}, {Z.Y}, {Z.Z}, {Z.W}\n{W.X}, {W.Y}, {W.Z}, {W.W}\n"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Projection"/> to a string with the given <paramref name="format"/>. @@ -1023,12 +1021,10 @@ namespace Godot /// <returns>A string representation of this projection.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"{X.X.ToString(format)}, {X.Y.ToString(format)}, {X.Z.ToString(format)}, {X.W.ToString(format)}\n" + - $"{Y.X.ToString(format)}, {Y.Y.ToString(format)}, {Y.Z.ToString(format)}, {Y.W.ToString(format)}\n" + - $"{Z.X.ToString(format)}, {Z.Y.ToString(format)}, {Z.Z.ToString(format)}, {Z.W.ToString(format)}\n" + - $"{W.X.ToString(format)}, {W.Y.ToString(format)}, {W.Z.ToString(format)}, {W.W.ToString(format)}\n"; -#pragma warning restore CA1305 + return $"{X.X.ToString(format, CultureInfo.InvariantCulture)}, {X.Y.ToString(format, CultureInfo.InvariantCulture)}, {X.Z.ToString(format, CultureInfo.InvariantCulture)}, {X.W.ToString(format, CultureInfo.InvariantCulture)}\n" + + $"{Y.X.ToString(format, CultureInfo.InvariantCulture)}, {Y.Y.ToString(format, CultureInfo.InvariantCulture)}, {Y.Z.ToString(format, CultureInfo.InvariantCulture)}, {Y.W.ToString(format, CultureInfo.InvariantCulture)}\n" + + $"{Z.X.ToString(format, CultureInfo.InvariantCulture)}, {Z.Y.ToString(format, CultureInfo.InvariantCulture)}, {Z.Z.ToString(format, CultureInfo.InvariantCulture)}, {Z.W.ToString(format, CultureInfo.InvariantCulture)}\n" + + $"{W.X.ToString(format, CultureInfo.InvariantCulture)}, {W.Y.ToString(format, CultureInfo.InvariantCulture)}, {W.Z.ToString(format, CultureInfo.InvariantCulture)}, {W.W.ToString(format, CultureInfo.InvariantCulture)}\n"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs index 6a8cb1ba04..09511ebdca 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -811,10 +812,7 @@ namespace Godot /// Converts this <see cref="Quaternion"/> to a string. /// </summary> /// <returns>A string representation of this quaternion.</returns> - public override readonly string ToString() - { - return $"({X}, {Y}, {Z}, {W})"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Quaternion"/> to a string with the given <paramref name="format"/>. @@ -822,9 +820,7 @@ namespace Godot /// <returns>A string representation of this quaternion.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})"; -#pragma warning restore CA1305 + return $"({X.ToString(format, CultureInfo.InvariantCulture)}, {Y.ToString(format, CultureInfo.InvariantCulture)}, {Z.ToString(format, CultureInfo.InvariantCulture)}, {W.ToString(format, CultureInfo.InvariantCulture)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs index cf4ac45a9f..9d9065911e 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs @@ -469,10 +469,7 @@ namespace Godot /// Converts this <see cref="Rect2"/> to a string. /// </summary> /// <returns>A string representation of this rect.</returns> - public override readonly string ToString() - { - return $"{_position}, {_size}"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Rect2"/> to a string with the given <paramref name="format"/>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs index 58560df0c5..65704b3da7 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2I.cs @@ -429,10 +429,7 @@ namespace Godot /// Converts this <see cref="Rect2I"/> to a string. /// </summary> /// <returns>A string representation of this rect.</returns> - public override readonly string ToString() - { - return $"{_position}, {_size}"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Rect2I"/> to a string with the given <paramref name="format"/>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs index fccae94eac..4f0015c7ae 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rid.cs @@ -1,8 +1,7 @@ using System; using System.Diagnostics.CodeAnalysis; -using System.Runtime.CompilerServices; +using System.Globalization; using System.Runtime.InteropServices; -using Godot.NativeInterop; #nullable enable @@ -102,6 +101,6 @@ namespace Godot /// Converts this <see cref="Rid"/> to a string. /// </summary> /// <returns>A string representation of this Rid.</returns> - public override string ToString() => $"RID({Id})"; + public override readonly string ToString() => $"RID({Id.ToString(null, CultureInfo.InvariantCulture)})"; } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs index 3443277fee..a5fa89d3bf 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs @@ -650,10 +650,7 @@ namespace Godot /// Converts this <see cref="Transform2D"/> to a string. /// </summary> /// <returns>A string representation of this transform.</returns> - public override readonly string ToString() - { - return $"[X: {X}, Y: {Y}, O: {Origin}]"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Transform2D"/> to a string with the given <paramref name="format"/>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs index f80c0bd8dd..0f534d477f 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs @@ -674,10 +674,7 @@ namespace Godot /// Converts this <see cref="Transform3D"/> to a string. /// </summary> /// <returns>A string representation of this transform.</returns> - public override readonly string ToString() - { - return $"[X: {Basis.X}, Y: {Basis.Y}, Z: {Basis.Z}, O: {Origin}]"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Transform3D"/> to a string with the given <paramref name="format"/>. diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs index 8f1bc109c0..856fd54352 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -1016,10 +1017,7 @@ namespace Godot /// Converts this <see cref="Vector2"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override readonly string ToString() - { - return $"({X}, {Y})"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Vector2"/> to a string with the given <paramref name="format"/>. @@ -1027,9 +1025,7 @@ namespace Godot /// <returns>A string representation of this vector.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"({X.ToString(format)}, {Y.ToString(format)})"; -#pragma warning restore CA1305 + return $"({X.ToString(format, CultureInfo.InvariantCulture)}, {Y.ToString(format, CultureInfo.InvariantCulture)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs index 1a386d9da1..511cc7971c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -589,10 +590,7 @@ namespace Godot /// Converts this <see cref="Vector2I"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override readonly string ToString() - { - return $"({X}, {Y})"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Vector2I"/> to a string with the given <paramref name="format"/>. @@ -600,9 +598,7 @@ namespace Godot /// <returns>A string representation of this vector.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"({X.ToString(format)}, {Y.ToString(format)})"; -#pragma warning restore CA1305 + return $"({X.ToString(format, CultureInfo.InvariantCulture)}, {Y.ToString(format, CultureInfo.InvariantCulture)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs index 74c1616e3d..6300705107 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -1118,10 +1119,7 @@ namespace Godot /// Converts this <see cref="Vector3"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override readonly string ToString() - { - return $"({X}, {Y}, {Z})"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Vector3"/> to a string with the given <paramref name="format"/>. @@ -1129,9 +1127,7 @@ namespace Godot /// <returns>A string representation of this vector.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})"; -#pragma warning restore CA1305 + return $"({X.ToString(format, CultureInfo.InvariantCulture)}, {Y.ToString(format, CultureInfo.InvariantCulture)}, {Z.ToString(format, CultureInfo.InvariantCulture)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs index d0ad1922f6..aea46efc5b 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -644,10 +645,7 @@ namespace Godot /// Converts this <see cref="Vector3I"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override readonly string ToString() - { - return $"({X}, {Y}, {Z})"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Vector3I"/> to a string with the given <paramref name="format"/>. @@ -655,9 +653,7 @@ namespace Godot /// <returns>A string representation of this vector.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)})"; -#pragma warning restore CA1305 + return $"({X.ToString(format, CultureInfo.InvariantCulture)}, {Y.ToString(format, CultureInfo.InvariantCulture)}, {Z.ToString(format, CultureInfo.InvariantCulture)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs index 115e65bbdb..7c4832943c 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -894,10 +895,7 @@ namespace Godot /// Converts this <see cref="Vector4"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override string ToString() - { - return $"({X}, {Y}, {Z}, {W})"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Vector4"/> to a string with the given <paramref name="format"/>. @@ -905,9 +903,7 @@ namespace Godot /// <returns>A string representation of this vector.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})"; -#pragma warning restore CA1305 + return $"({X.ToString(format, CultureInfo.InvariantCulture)}, {Y.ToString(format, CultureInfo.InvariantCulture)}, {Z.ToString(format, CultureInfo.InvariantCulture)}, {W.ToString(format, CultureInfo.InvariantCulture)})"; } } } diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs index 527c8e5022..27aa86b7e4 100644 --- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs +++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Globalization; using System.Runtime.InteropServices; #nullable enable @@ -665,10 +666,7 @@ namespace Godot /// Converts this <see cref="Vector4I"/> to a string. /// </summary> /// <returns>A string representation of this vector.</returns> - public override readonly string ToString() - { - return $"({X}, {Y}, {Z}, {W})"; - } + public override readonly string ToString() => ToString(null); /// <summary> /// Converts this <see cref="Vector4I"/> to a string with the given <paramref name="format"/>. @@ -676,9 +674,7 @@ namespace Godot /// <returns>A string representation of this vector.</returns> public readonly string ToString(string? format) { -#pragma warning disable CA1305 // Disable warning: "Specify IFormatProvider" - return $"({X.ToString(format)}, {Y.ToString(format)}, {Z.ToString(format)}, {W.ToString(format)})"; -#pragma warning restore CA1305 + return $"({X.ToString(format, CultureInfo.InvariantCulture)}, {Y.ToString(format, CultureInfo.InvariantCulture)}, {Z.ToString(format, CultureInfo.InvariantCulture)}, {W.ToString(format, CultureInfo.InvariantCulture)})"; } } } diff --git a/modules/mono/glue/runtime_interop.cpp b/modules/mono/glue/runtime_interop.cpp index 0089e9c2a2..4bb324c0ee 100644 --- a/modules/mono/glue/runtime_interop.cpp +++ b/modules/mono/glue/runtime_interop.cpp @@ -239,7 +239,7 @@ GCHandleIntPtr godotsharp_internal_unmanaged_get_instance_binding_managed(Object CRASH_COND(!p_unmanaged); #endif - void *data = CSharpLanguage::get_instance_binding(p_unmanaged); + void *data = CSharpLanguage::get_instance_binding_with_setup(p_unmanaged); ERR_FAIL_NULL_V(data, { nullptr }); CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value(); ERR_FAIL_COND_V(!script_binding.inited, { nullptr }); @@ -252,7 +252,7 @@ GCHandleIntPtr godotsharp_internal_unmanaged_instance_binding_create_managed(Obj CRASH_COND(!p_unmanaged); #endif - void *data = CSharpLanguage::get_instance_binding(p_unmanaged); + void *data = CSharpLanguage::get_instance_binding_with_setup(p_unmanaged); ERR_FAIL_NULL_V(data, { nullptr }); CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value(); ERR_FAIL_COND_V(!script_binding.inited, { nullptr }); diff --git a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp index 599926ec99..29ebc38edf 100644 --- a/modules/multiplayer/editor/multiplayer_editor_plugin.cpp +++ b/modules/multiplayer/editor/multiplayer_editor_plugin.cpp @@ -149,7 +149,7 @@ void MultiplayerEditorPlugin::_node_removed(Node *p_node) { } void MultiplayerEditorPlugin::_pinned() { - if (!repl_editor->get_pin()->is_pressed()) { + if (!repl_editor->get_pin()->is_pressed() && repl_editor->get_current() == nullptr) { if (repl_editor->is_visible_in_tree()) { EditorNode::get_bottom_panel()->hide_bottom_panel(); } diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp index f6df212d35..6000e2b1d3 100644 --- a/modules/multiplayer/editor/replication_editor.cpp +++ b/modules/multiplayer/editor/replication_editor.cpp @@ -131,7 +131,7 @@ void ReplicationEditor::_pick_new_property() { EditorNode::get_singleton()->show_warning(TTR("Not possible to add a new property to synchronize without a root.")); return; } - pick_node->popup_scenetree_dialog(); + pick_node->popup_scenetree_dialog(nullptr, current); pick_node->get_filter_line_edit()->clear(); pick_node->get_filter_line_edit()->grab_focus(); } @@ -270,6 +270,7 @@ ReplicationEditor::ReplicationEditor() { pin = memnew(Button); pin->set_theme_type_variation("FlatButton"); pin->set_toggle_mode(true); + pin->set_tooltip_text(TTR("Pin replication editor")); hb->add_child(pin); tree = memnew(Tree); diff --git a/modules/navigation/3d/nav_mesh_generator_3d.cpp b/modules/navigation/3d/nav_mesh_generator_3d.cpp index b3391398a6..8b43eba080 100644 --- a/modules/navigation/3d/nav_mesh_generator_3d.cpp +++ b/modules/navigation/3d/nav_mesh_generator_3d.cpp @@ -750,11 +750,14 @@ void NavMeshGenerator3D::generator_bake_from_source_geometry_data(Ref<Navigation rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height); // ~30000000 seems to be around sweetspot where Editor baking breaks - if ((cfg.width * cfg.height) > 30000000) { - WARN_PRINT("NavigationMesh baking process will likely fail." - "\nSource geometry is suspiciously big for the current Cell Size and Cell Height in the NavMesh Resource bake settings." - "\nIf baking does not fail, the resulting NavigationMesh will create serious pathfinding performance issues." - "\nIt is advised to increase Cell Size and/or Cell Height in the NavMesh Resource bake settings or reduce the size / scale of the source geometry."); + if ((cfg.width * cfg.height) > 30000000 && GLOBAL_GET("navigation/baking/use_crash_prevention_checks")) { + ERR_FAIL_MSG("Baking interrupted." + "\nNavigationMesh baking process would likely crash the engine." + "\nSource geometry is suspiciously big for the current Cell Size and Cell Height in the NavMesh Resource bake settings." + "\nIf baking does not crash the engine or fail, the resulting NavigationMesh will create serious pathfinding performance issues." + "\nIt is advised to increase Cell Size and/or Cell Height in the NavMesh Resource bake settings or reduce the size / scale of the source geometry." + "\nIf you would like to try baking anyway, disable the 'navigation/baking/use_crash_prevention_checks' project setting."); + return; } bake_state = "Creating heightfield..."; // step #3 diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub index 209ebab388..f3a8e30763 100644 --- a/modules/raycast/SCsub +++ b/modules/raycast/SCsub @@ -15,10 +15,10 @@ if env["builtin_embree"]: embree_src = [ "common/sys/sysinfo.cpp", "common/sys/alloc.cpp", + "common/sys/estring.cpp", "common/sys/filename.cpp", "common/sys/library.cpp", "common/sys/thread.cpp", - "common/sys/string.cpp", "common/sys/regression.cpp", "common/sys/mutex.cpp", "common/sys/condition.cpp", @@ -36,6 +36,7 @@ if env["builtin_embree"]: "kernels/common/rtcore.cpp", "kernels/common/rtcore_builder.cpp", "kernels/common/scene.cpp", + "kernels/common/scene_verify.cpp", "kernels/common/alloc.cpp", "kernels/common/geometry.cpp", "kernels/common/scene_triangle_mesh.cpp", @@ -56,8 +57,6 @@ if env["builtin_embree"]: "kernels/bvh/bvh_builder_twolevel.cpp", "kernels/bvh/bvh_intersector1_bvh4.cpp", "kernels/bvh/bvh_intersector_hybrid4_bvh4.cpp", - "kernels/bvh/bvh_intersector_stream_bvh4.cpp", - "kernels/bvh/bvh_intersector_stream_filters.cpp", ] thirdparty_sources = [thirdparty_dir + file for file in embree_src] diff --git a/modules/raycast/godot_update_embree.py b/modules/raycast/godot_update_embree.py index 0e62824adc..c179060365 100644 --- a/modules/raycast/godot_update_embree.py +++ b/modules/raycast/godot_update_embree.py @@ -1,6 +1,13 @@ -import glob, os, shutil, subprocess, re +import glob +import os +import re +import shutil +import stat +import subprocess +from types import TracebackType +from typing import Any, Callable, Tuple, Type -git_tag = "v3.13.5" +git_tag = "v4.3.1" include_dirs = [ "common/tasking", @@ -15,7 +22,7 @@ include_dirs = [ "common/simd", "common/simd/arm", "common/simd/wasm", - "include/embree3", + "include/embree4", "kernels/subdiv", "kernels/geometry", ] @@ -23,10 +30,10 @@ include_dirs = [ cpp_files = [ "common/sys/sysinfo.cpp", "common/sys/alloc.cpp", + "common/sys/estring.cpp", "common/sys/filename.cpp", "common/sys/library.cpp", "common/sys/thread.cpp", - "common/sys/string.cpp", "common/sys/regression.cpp", "common/sys/mutex.cpp", "common/sys/condition.cpp", @@ -44,6 +51,7 @@ cpp_files = [ "kernels/common/rtcore.cpp", "kernels/common/rtcore_builder.cpp", "kernels/common/scene.cpp", + "kernels/common/scene_verify.cpp", "kernels/common/alloc.cpp", "kernels/common/geometry.cpp", "kernels/common/scene_triangle_mesh.cpp", @@ -65,26 +73,58 @@ cpp_files = [ "kernels/bvh/bvh_intersector1.cpp", "kernels/bvh/bvh_intersector1_bvh4.cpp", "kernels/bvh/bvh_intersector_hybrid4_bvh4.cpp", - "kernels/bvh/bvh_intersector_stream_bvh4.cpp", - "kernels/bvh/bvh_intersector_stream_filters.cpp", "kernels/bvh/bvh_intersector_hybrid.cpp", - "kernels/bvh/bvh_intersector_stream.cpp", ] -os.chdir("../../thirdparty") +config_files = [ + "kernels/config.h.in", + "kernels/rtcore_config.h.in", +] + +license_file = "LICENSE.txt" + +os.chdir(f"{os.path.dirname(__file__)}/../../thirdparty") dir_name = "embree" if os.path.exists(dir_name): shutil.rmtree(dir_name) +# In case something went wrong and embree-tmp stayed on the system. +if os.path.exists("embree-tmp"): + shutil.rmtree("embree-tmp") + subprocess.run(["git", "clone", "https://github.com/embree/embree.git", "embree-tmp"]) os.chdir("embree-tmp") subprocess.run(["git", "checkout", git_tag]) commit_hash = str(subprocess.check_output(["git", "rev-parse", "HEAD"], universal_newlines=True)).strip() + +def on_rm_error( + function: Callable[..., Any], path: str, excinfo: Tuple[Type[Exception], Exception, TracebackType] +) -> None: + """ + Error handler for `shutil.rmtree()`. + + If the error is due to read-only files, + it will change the file permissions and retry. + """ + os.chmod(path, stat.S_IWRITE) + os.unlink(path) + + +# 3.12 Python and beyond should replace `onerror` with `onexc`. +# We remove the .git directory because it contains +# a lot of read-only files that are problematic on Windows. +shutil.rmtree(".git", onerror=on_rm_error) + all_files = set(cpp_files) +for config_file in config_files: + all_files.add(config_file) + +all_files.add(license_file) + dest_dir = os.path.join("..", dir_name) for include_dir in include_dirs: headers = glob.iglob(os.path.join(include_dir, "*.h")) @@ -105,158 +145,34 @@ with open(os.path.join(dest_dir, "kernels/hash.h"), "w", encoding="utf-8", newli """ ) -with open(os.path.join(dest_dir, "kernels/config.h"), "w", encoding="utf-8", newline="\n") as config_file: - config_file.write( - """// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -/* #undef EMBREE_RAY_MASK */ -/* #undef EMBREE_STAT_COUNTERS */ -/* #undef EMBREE_BACKFACE_CULLING */ -/* #undef EMBREE_BACKFACE_CULLING_CURVES */ -#define EMBREE_FILTER_FUNCTION -/* #undef EMBREE_IGNORE_INVALID_RAYS */ -#define EMBREE_GEOMETRY_TRIANGLE -/* #undef EMBREE_GEOMETRY_QUAD */ -/* #undef EMBREE_GEOMETRY_CURVE */ -/* #undef EMBREE_GEOMETRY_SUBDIVISION */ -/* #undef EMBREE_GEOMETRY_USER */ -/* #undef EMBREE_GEOMETRY_INSTANCE */ -/* #undef EMBREE_GEOMETRY_GRID */ -/* #undef EMBREE_GEOMETRY_POINT */ -#define EMBREE_RAY_PACKETS -/* #undef EMBREE_COMPACT_POLYS */ - -#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0 -#define EMBREE_DISC_POINT_SELF_INTERSECTION_AVOIDANCE - -#if defined(EMBREE_GEOMETRY_TRIANGLE) - #define IF_ENABLED_TRIS(x) x -#else - #define IF_ENABLED_TRIS(x) -#endif - -#if defined(EMBREE_GEOMETRY_QUAD) - #define IF_ENABLED_QUADS(x) x -#else - #define IF_ENABLED_QUADS(x) -#endif - -#if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT) - #define IF_ENABLED_CURVES_OR_POINTS(x) x -#else - #define IF_ENABLED_CURVES_OR_POINTS(x) -#endif - -#if defined(EMBREE_GEOMETRY_CURVE) - #define IF_ENABLED_CURVES(x) x -#else - #define IF_ENABLED_CURVES(x) -#endif - -#if defined(EMBREE_GEOMETRY_POINT) - #define IF_ENABLED_POINTS(x) x -#else - #define IF_ENABLED_POINTS(x) -#endif - -#if defined(EMBREE_GEOMETRY_SUBDIVISION) - #define IF_ENABLED_SUBDIV(x) x -#else - #define IF_ENABLED_SUBDIV(x) -#endif +for config_file in config_files: + os.rename(os.path.join(dest_dir, config_file), os.path.join(dest_dir, config_file[:-3])) -#if defined(EMBREE_GEOMETRY_USER) - #define IF_ENABLED_USER(x) x -#else - #define IF_ENABLED_USER(x) -#endif - -#if defined(EMBREE_GEOMETRY_INSTANCE) - #define IF_ENABLED_INSTANCE(x) x -#else - #define IF_ENABLED_INSTANCE(x) -#endif - -#if defined(EMBREE_GEOMETRY_GRID) - #define IF_ENABLED_GRIDS(x) x -#else - #define IF_ENABLED_GRIDS(x) -#endif -""" - ) - - -with open("CMakeLists.txt", "r") as cmake_file: +with open("CMakeLists.txt", "r", encoding="utf-8") as cmake_file: cmake_content = cmake_file.read() major_version = int(re.compile(r"EMBREE_VERSION_MAJOR\s(\d+)").findall(cmake_content)[0]) minor_version = int(re.compile(r"EMBREE_VERSION_MINOR\s(\d+)").findall(cmake_content)[0]) patch_version = int(re.compile(r"EMBREE_VERSION_PATCH\s(\d+)").findall(cmake_content)[0]) -with open( - os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w", encoding="utf-8", newline="\n" -) as config_file: - config_file.write( - f"""// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#pragma once +shutil.move(os.path.join(dest_dir, "kernels/rtcore_config.h"), os.path.join(dest_dir, ("include/embree4/"))) -#define RTC_VERSION_MAJOR {major_version} -#define RTC_VERSION_MINOR {minor_version} -#define RTC_VERSION_PATCH {patch_version} -#define RTC_VERSION {major_version}{minor_version:02d}{patch_version:02d} -#define RTC_VERSION_STRING "{major_version}.{minor_version}.{patch_version}" - -#define RTC_MAX_INSTANCE_LEVEL_COUNT 1 - -#define EMBREE_MIN_WIDTH 0 -#define RTC_MIN_WIDTH EMBREE_MIN_WIDTH - -#if !defined(EMBREE_STATIC_LIB) -# define EMBREE_STATIC_LIB -#endif -/* #undef EMBREE_API_NAMESPACE*/ - -#if defined(EMBREE_API_NAMESPACE) -# define RTC_NAMESPACE -# define RTC_NAMESPACE_BEGIN namespace {{ -# define RTC_NAMESPACE_END }} -# define RTC_NAMESPACE_USE using namespace; -# define RTC_API_EXTERN_C -# undef EMBREE_API_NAMESPACE -#else -# define RTC_NAMESPACE_BEGIN -# define RTC_NAMESPACE_END -# define RTC_NAMESPACE_USE -# if defined(__cplusplus) -# define RTC_API_EXTERN_C extern "C" -# else -# define RTC_API_EXTERN_C -# endif -#endif - -#if defined(ISPC) -# define RTC_API_IMPORT extern "C" unmasked -# define RTC_API_EXPORT extern "C" unmasked -#elif defined(EMBREE_STATIC_LIB) -# define RTC_API_IMPORT RTC_API_EXTERN_C -# define RTC_API_EXPORT RTC_API_EXTERN_C -#elif defined(_WIN32) -# define RTC_API_IMPORT RTC_API_EXTERN_C __declspec(dllimport) -# define RTC_API_EXPORT RTC_API_EXTERN_C __declspec(dllexport) -#else -# define RTC_API_IMPORT RTC_API_EXTERN_C -# define RTC_API_EXPORT RTC_API_EXTERN_C __attribute__ ((visibility ("default"))) -#endif - -#if defined(RTC_EXPORT_API) -# define RTC_API RTC_API_EXPORT -#else -# define RTC_API RTC_API_IMPORT -#endif -""" - ) +with open( + os.path.join(dest_dir, "include/embree4/rtcore_config.h"), "r+", encoding="utf-8", newline="\n" +) as rtcore_config: + lines = rtcore_config.readlines() + rtcore_config.seek(0) + for i, line in enumerate(lines): + if line.startswith("#define RTC_VERSION_MAJOR"): + lines[i : i + 5] = [ + f"#define RTC_VERSION_MAJOR {major_version}\n", + f"#define RTC_VERSION_MINOR {minor_version}\n", + f"#define RTC_VERSION_PATCH {patch_version}\n", + f"#define RTC_VERSION {major_version}{minor_version:02d}{patch_version:02d}\n", + f'#define RTC_VERSION_STRING "{major_version}.{minor_version}.{patch_version}"\n', + ] + break + rtcore_config.writelines(lines) + rtcore_config.truncate() os.chdir("..") shutil.rmtree("embree-tmp") @@ -264,4 +180,4 @@ shutil.rmtree("embree-tmp") subprocess.run(["git", "restore", "embree/patches"]) for patch in os.listdir("embree/patches"): - subprocess.run(["git", "apply", "embree/patches/" + patch]) + subprocess.run(["git", "apply", f"embree/patches/{patch}"]) diff --git a/modules/raycast/lightmap_raycaster_embree.cpp b/modules/raycast/lightmap_raycaster_embree.cpp index 2a66c36d53..84d9e19a3f 100644 --- a/modules/raycast/lightmap_raycaster_embree.cpp +++ b/modules/raycast/lightmap_raycaster_embree.cpp @@ -69,11 +69,12 @@ void LightmapRaycasterEmbree::filter_function(const struct RTCFilterFunctionNArg } bool LightmapRaycasterEmbree::intersect(Ray &r_ray) { - RTCIntersectContext context; - - rtcInitIntersectContext(&context); - - rtcIntersect1(embree_scene, &context, (RTCRayHit *)&r_ray); + RTCRayQueryContext context; + rtcInitRayQueryContext(&context); + RTCIntersectArguments args; + rtcInitIntersectArguments(&args); + args.context = &context; + rtcIntersect1(embree_scene, (RTCRayHit *)&r_ray, &args); return r_ray.geomID != RTC_INVALID_GEOMETRY_ID; } diff --git a/modules/raycast/lightmap_raycaster_embree.h b/modules/raycast/lightmap_raycaster_embree.h index d1999e329e..2b4530a368 100644 --- a/modules/raycast/lightmap_raycaster_embree.h +++ b/modules/raycast/lightmap_raycaster_embree.h @@ -37,7 +37,7 @@ #include "core/object/object.h" #include "scene/3d/lightmapper.h" -#include <embree3/rtcore.h> +#include <embree4/rtcore.h> class LightmapRaycasterEmbree : public LightmapRaycaster { GDCLASS(LightmapRaycasterEmbree, LightmapRaycaster); diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp index 5005000eae..94d8b267d1 100644 --- a/modules/raycast/raycast_occlusion_cull.cpp +++ b/modules/raycast/raycast_occlusion_cull.cpp @@ -488,11 +488,13 @@ void RaycastOcclusionCull::Scenario::update() { } void RaycastOcclusionCull::Scenario::_raycast(uint32_t p_idx, const RaycastThreadData *p_raycast_data) const { - RTCIntersectContext ctx; - rtcInitIntersectContext(&ctx); - ctx.flags = RTC_INTERSECT_CONTEXT_FLAG_COHERENT; - - rtcIntersect16((const int *)&p_raycast_data->masks[p_idx * TILE_RAYS], ebr_scene[current_scene_idx], &ctx, &p_raycast_data->rays[p_idx]); + RTCRayQueryContext context; + rtcInitRayQueryContext(&context); + RTCIntersectArguments args; + rtcInitIntersectArguments(&args); + args.flags = RTC_RAY_QUERY_FLAG_COHERENT; + args.context = &context; + rtcIntersect16((const int *)&p_raycast_data->masks[p_idx * TILE_RAYS], ebr_scene[current_scene_idx], &p_raycast_data->rays[p_idx], &args); } void RaycastOcclusionCull::Scenario::raycast(CameraRayTile *r_rays, const uint32_t *p_valid_masks, uint32_t p_tile_count) const { @@ -536,6 +538,64 @@ void RaycastOcclusionCull::buffer_set_size(RID p_buffer, const Vector2i &p_size) buffers[p_buffer].resize(p_size); } +Projection RaycastOcclusionCull::_jitter_projection(const Projection &p_cam_projection, const Size2i &p_viewport_size) { + if (!_jitter_enabled) { + return p_cam_projection; + } + + // Prevent divide by zero when using NULL viewport. + if ((p_viewport_size.x <= 0) || (p_viewport_size.y <= 0)) { + return p_cam_projection; + } + + Projection p = p_cam_projection; + + int32_t frame = Engine::get_singleton()->get_frames_drawn(); + frame %= 9; + + Vector2 jitter; + + switch (frame) { + default: + break; + case 1: { + jitter = Vector2(-1, -1); + } break; + case 2: { + jitter = Vector2(1, -1); + } break; + case 3: { + jitter = Vector2(-1, 1); + } break; + case 4: { + jitter = Vector2(1, 1); + } break; + case 5: { + jitter = Vector2(-0.5f, -0.5f); + } break; + case 6: { + jitter = Vector2(0.5f, -0.5f); + } break; + case 7: { + jitter = Vector2(-0.5f, 0.5f); + } break; + case 8: { + jitter = Vector2(0.5f, 0.5f); + } break; + } + + // The multiplier here determines the divergence from center, + // and is to some extent a balancing act. + // Higher divergence gives fewer false hidden, but more false shown. + // False hidden is obvious to viewer, false shown is not. + // False shown can lower percentage that are occluded, and therefore performance. + jitter *= Vector2(1 / (float)p_viewport_size.x, 1 / (float)p_viewport_size.y) * 0.05f; + + p.add_jitter_offset(jitter); + + return p; +} + void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_transform, const Projection &p_cam_projection, bool p_cam_orthogonal) { if (!buffers.has(p_buffer)) { return; @@ -550,7 +610,9 @@ void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_ Scenario &scenario = scenarios[buffer.scenario_rid]; scenario.update(); - buffer.update_camera_rays(p_cam_transform, p_cam_projection, p_cam_orthogonal); + Projection jittered_proj = _jitter_projection(p_cam_projection, buffer.get_occlusion_buffer_size()); + + buffer.update_camera_rays(p_cam_transform, jittered_proj, p_cam_orthogonal); scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks.ptr(), buffer.camera_rays_tile_count); buffer.sort_rays(-p_cam_transform.basis.get_column(2), p_cam_orthogonal); @@ -596,6 +658,7 @@ void RaycastOcclusionCull::_init_embree() { RaycastOcclusionCull::RaycastOcclusionCull() { raycast_singleton = this; int default_quality = GLOBAL_GET("rendering/occlusion_culling/bvh_build_quality"); + _jitter_enabled = GLOBAL_GET("rendering/occlusion_culling/jitter_projection"); build_quality = RS::ViewportOcclusionCullingBuildQuality(default_quality); } diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h index ab5eb4eaf0..335a685672 100644 --- a/modules/raycast/raycast_occlusion_cull.h +++ b/modules/raycast/raycast_occlusion_cull.h @@ -40,7 +40,7 @@ #include "scene/resources/mesh.h" #include "servers/rendering/renderer_scene_occlusion_cull.h" -#include <embree3/rtcore.h> +#include <embree4/rtcore.h> class RaycastOcclusionCull : public RendererSceneOcclusionCull { typedef RTCRayHit16 CameraRayTile; @@ -163,8 +163,10 @@ private: HashMap<RID, Scenario> scenarios; HashMap<RID, RaycastHZBuffer> buffers; RS::ViewportOcclusionCullingBuildQuality build_quality; + bool _jitter_enabled = false; void _init_embree(); + Projection _jitter_projection(const Projection &p_cam_projection, const Size2i &p_viewport_size); public: virtual bool is_occluder(RID p_rid) override; diff --git a/modules/raycast/static_raycaster_embree.cpp b/modules/raycast/static_raycaster_embree.cpp index f9076d30dd..a6ad340397 100644 --- a/modules/raycast/static_raycaster_embree.cpp +++ b/modules/raycast/static_raycaster_embree.cpp @@ -53,9 +53,12 @@ void StaticRaycasterEmbree::free() { } bool StaticRaycasterEmbree::intersect(Ray &r_ray) { - RTCIntersectContext context; - rtcInitIntersectContext(&context); - rtcIntersect1(embree_scene, &context, (RTCRayHit *)&r_ray); + RTCRayQueryContext context; + rtcInitRayQueryContext(&context); + RTCIntersectArguments args; + rtcInitIntersectArguments(&args); + args.context = &context; + rtcIntersect1(embree_scene, (RTCRayHit *)&r_ray, &args); return r_ray.geomID != RTC_INVALID_GEOMETRY_ID; } diff --git a/modules/raycast/static_raycaster_embree.h b/modules/raycast/static_raycaster_embree.h index 24e1c7b92f..3ffab32bad 100644 --- a/modules/raycast/static_raycaster_embree.h +++ b/modules/raycast/static_raycaster_embree.h @@ -35,7 +35,7 @@ #include "core/math/static_raycaster.h" -#include <embree3/rtcore.h> +#include <embree4/rtcore.h> class StaticRaycasterEmbree : public StaticRaycaster { GDCLASS(StaticRaycasterEmbree, StaticRaycaster); diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp index fc06e24bee..f5174d7d46 100644 --- a/modules/text_server_adv/text_server_adv.cpp +++ b/modules/text_server_adv/text_server_adv.cpp @@ -1234,7 +1234,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontAdvanced *p_font_data, } if (p_font_data->embolden != 0.f) { - FT_Pos strength = p_font_data->embolden * p_size.x * 4; // 26.6 fractional units (1 / 64). + FT_Pos strength = p_font_data->embolden * p_size.x * fd->oversampling * 4; // 26.6 fractional units (1 / 64). FT_Outline_Embolden(&fd->face->glyph->outline, strength); } diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp index 4c0ed084d8..302bd677fe 100644 --- a/modules/text_server_fb/text_server_fb.cpp +++ b/modules/text_server_fb/text_server_fb.cpp @@ -669,7 +669,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontFallback *p_font_data, } if (p_font_data->embolden != 0.f) { - FT_Pos strength = p_font_data->embolden * p_size.x * 4; // 26.6 fractional units (1 / 64). + FT_Pos strength = p_font_data->embolden * p_size.x * fd->oversampling * 4; // 26.6 fractional units (1 / 64). FT_Outline_Embolden(&fd->face->glyph->outline, strength); } diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h index 21d4caef45..1e7fd088cc 100644 --- a/modules/theora/video_stream_theora.h +++ b/modules/theora/video_stream_theora.h @@ -173,10 +173,10 @@ public: class ResourceFormatLoaderTheora : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; #endif // VIDEO_STREAM_THEORA_H diff --git a/modules/webp/resource_saver_webp.h b/modules/webp/resource_saver_webp.h index 5546c69e6d..65cd4377db 100644 --- a/modules/webp/resource_saver_webp.h +++ b/modules/webp/resource_saver_webp.h @@ -39,9 +39,9 @@ public: static Error save_image(const String &p_path, const Ref<Image> &p_img, const bool p_lossy = false, const float p_quality = 0.75f); static Vector<uint8_t> save_image_to_buffer(const Ref<Image> &p_img, const bool p_lossy = false, const float p_quality = 0.75f); - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual bool recognize(const Ref<Resource> &p_resource) const; - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; ResourceSaverWebP(); }; diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp index 90759810b1..c6f2f82117 100644 --- a/platform/android/display_server_android.cpp +++ b/platform/android/display_server_android.cpp @@ -71,6 +71,8 @@ bool DisplayServerAndroid::has_feature(Feature p_feature) const { case FEATURE_MOUSE: //case FEATURE_MOUSE_WARP: //case FEATURE_NATIVE_DIALOG: + //case FEATURE_NATIVE_DIALOG_INPUT: + //case FEATURE_NATIVE_DIALOG_FILE: //case FEATURE_NATIVE_ICON: //case FEATURE_WINDOW_TRANSPARENCY: case FEATURE_CLIPBOARD: diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp index 894c13cc0b..64ef1397ba 100644 --- a/platform/android/export/export_plugin.cpp +++ b/platform/android/export/export_plugin.cpp @@ -3096,7 +3096,7 @@ Error EditorExportPlatformAndroid::export_project_helper(const Ref<EditorExportP return err; } if (user_data.libs.size() > 0) { - Ref<FileAccess> fa = FileAccess::open(GDEXTENSION_LIBS_PATH, FileAccess::WRITE); + Ref<FileAccess> fa = FileAccess::open(gdextension_libs_path, FileAccess::WRITE); fa->store_string(JSON::stringify(user_data.libs, "\t")); } } else { diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java index 9a6b6d5037..9df890e6bd 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java @@ -293,15 +293,15 @@ public final class PermissionsUtil { /** * Returns the permissions defined in the AndroidManifest.xml file. * @param context the caller context for this method. - * @return manifest permissions list + * @return mutable copy of manifest permissions list * @throws PackageManager.NameNotFoundException the exception is thrown when a given package, application, or component name cannot be found. */ - public static List<String> getManifestPermissions(Context context) throws PackageManager.NameNotFoundException { + public static ArrayList<String> getManifestPermissions(Context context) throws PackageManager.NameNotFoundException { PackageManager packageManager = context.getPackageManager(); PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS); if (packageInfo.requestedPermissions == null) - return Collections.emptyList(); - return Arrays.asList(packageInfo.requestedPermissions); + return new ArrayList<String>(); + return new ArrayList<>(Arrays.asList(packageInfo.requestedPermissions)); } /** diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 85d5cf2796..2215f706c5 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -250,7 +250,7 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, } if (step.get() == 1) { - if (!Main::start()) { + if (Main::start() != EXIT_SUCCESS) { return true; // should exit instead and print the error } diff --git a/platform/ios/app_delegate.mm b/platform/ios/app_delegate.mm index 5a0c57be93..37d2696434 100644 --- a/platform/ios/app_delegate.mm +++ b/platform/ios/app_delegate.mm @@ -116,6 +116,8 @@ static ViewController *mainViewController = nil; } else if (sessionCategorySetting == SESSION_CATEGORY_PLAY_AND_RECORD) { category = AVAudioSessionCategoryPlayAndRecord; options |= AVAudioSessionCategoryOptionDefaultToSpeaker; + options |= AVAudioSessionCategoryOptionAllowBluetoothA2DP; + options |= AVAudioSessionCategoryOptionAllowAirPlay; } else if (sessionCategorySetting == SESSION_CATEGORY_PLAYBACK) { category = AVAudioSessionCategoryPlayback; } else if (sessionCategorySetting == SESSION_CATEGORY_RECORD) { diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm index e1c3dcd372..f84fb01ad0 100644 --- a/platform/ios/display_server_ios.mm +++ b/platform/ios/display_server_ios.mm @@ -328,6 +328,8 @@ bool DisplayServerIOS::has_feature(Feature p_feature) const { // case FEATURE_MOUSE: // case FEATURE_MOUSE_WARP: // case FEATURE_NATIVE_DIALOG: + // case FEATURE_NATIVE_DIALOG_INPUT: + // case FEATURE_NATIVE_DIALOG_FILE: // case FEATURE_NATIVE_ICON: // case FEATURE_WINDOW_TRANSPARENCY: case FEATURE_CLIPBOARD: diff --git a/platform/ios/godot_ios.mm b/platform/ios/godot_ios.mm index 5e66c8b47b..9d35d43344 100644 --- a/platform/ios/godot_ios.mm +++ b/platform/ios/godot_ios.mm @@ -102,15 +102,16 @@ int ios_main(int argc, char **argv) { Error err = Main::setup(fargv[0], argc - 1, &fargv[1], false); - if (err == ERR_HELP) { // Returned by --help and --version, so success. - return 0; - } else if (err != OK) { - return 255; + if (err != OK) { + if (err == ERR_HELP) { // Returned by --help and --version, so success. + return EXIT_SUCCESS; + } + return EXIT_FAILURE; } os->initialize_modules(); - return 0; + return os->get_exit_code(); } void ios_finish() { diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp index a2b6fbeb25..b0880c86b8 100644 --- a/platform/linuxbsd/godot_linuxbsd.cpp +++ b/platform/linuxbsd/godot_linuxbsd.cpp @@ -72,18 +72,19 @@ int main(int argc, char *argv[]) { char *ret = getcwd(cwd, PATH_MAX); Error err = Main::setup(argv[0], argc - 1, &argv[1]); + if (err != OK) { free(cwd); - if (err == ERR_HELP) { // Returned by --help and --version, so success. - return 0; + return EXIT_SUCCESS; } - return 255; + return EXIT_FAILURE; } - if (Main::start()) { - os.set_exit_code(EXIT_SUCCESS); - os.run(); // it is actually the OS that decides how to run + if (Main::start() == EXIT_SUCCESS) { + os.run(); + } else { + os.set_exit_code(EXIT_FAILURE); } Main::cleanup(); diff --git a/platform/linuxbsd/wayland/display_server_wayland.cpp b/platform/linuxbsd/wayland/display_server_wayland.cpp index 80b6029c9d..d00d5deb2c 100644 --- a/platform/linuxbsd/wayland/display_server_wayland.cpp +++ b/platform/linuxbsd/wayland/display_server_wayland.cpp @@ -210,8 +210,10 @@ bool DisplayServerWayland::has_feature(Feature p_feature) const { return true; } break; + //case FEATURE_NATIVE_DIALOG: + //case FEATURE_NATIVE_DIALOG_INPUT: #ifdef DBUS_ENABLED - case FEATURE_NATIVE_DIALOG: { + case FEATURE_NATIVE_DIALOG_FILE: { return true; } break; #endif diff --git a/platform/linuxbsd/wayland/wayland_thread.cpp b/platform/linuxbsd/wayland/wayland_thread.cpp index 5040f5dd45..7f9008e952 100644 --- a/platform/linuxbsd/wayland/wayland_thread.cpp +++ b/platform/linuxbsd/wayland/wayland_thread.cpp @@ -1563,7 +1563,7 @@ void WaylandThread::_wl_pointer_on_frame(void *data, struct wl_pointer *wl_point } if (old_pd.pressed_button_mask != pd.pressed_button_mask) { - BitField<MouseButtonMask> pressed_mask_delta = BitField<MouseButtonMask>((uint32_t)old_pd.pressed_button_mask ^ (uint32_t)pd.pressed_button_mask); + BitField<MouseButtonMask> pressed_mask_delta = old_pd.pressed_button_mask ^ pd.pressed_button_mask; const MouseButton buttons_to_test[] = { MouseButton::LEFT, @@ -2454,7 +2454,7 @@ void WaylandThread::_wp_tablet_tool_on_frame(void *data, struct zwp_tablet_tool_ mm->set_relative_screen_position(mm->get_relative()); Vector2i pos_delta = td.position - old_td.position; - uint32_t time_delta = td.motion_time - td.motion_time; + uint32_t time_delta = td.motion_time - old_td.motion_time; mm->set_velocity((Vector2)pos_delta / time_delta); Ref<InputEventMessage> inputev_msg; diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp index 34aa15abbb..9069dd423f 100644 --- a/platform/linuxbsd/x11/display_server_x11.cpp +++ b/platform/linuxbsd/x11/display_server_x11.cpp @@ -128,8 +128,10 @@ bool DisplayServerX11::has_feature(Feature p_feature) const { //case FEATURE_HIDPI: case FEATURE_ICON: #ifdef DBUS_ENABLED - case FEATURE_NATIVE_DIALOG: + case FEATURE_NATIVE_DIALOG_FILE: #endif + //case FEATURE_NATIVE_DIALOG: + //case FEATURE_NATIVE_DIALOG_INPUT: //case FEATURE_NATIVE_ICON: case FEATURE_SWAP_BUFFERS: #ifdef DBUS_ENABLED @@ -1995,8 +1997,7 @@ void DisplayServerX11::window_set_current_screen(int p_screen, WindowID p_window Size2i wsize = window_get_size(p_window); wpos += srect.position; if (srect != Rect2i()) { - wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3); - wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3); + wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3); } window_set_position(wpos, p_window); } @@ -2224,8 +2225,7 @@ void DisplayServerX11::window_set_size(const Size2i p_size, WindowID p_window) { ERR_FAIL_COND(!windows.has(p_window)); Size2i size = p_size; - size.x = MAX(1, size.x); - size.y = MAX(1, size.y); + size = size.max(Size2i(1, 1)); WindowData &wd = windows[p_window]; @@ -5212,7 +5212,7 @@ void DisplayServerX11::set_icon(const Ref<Image> &p_icon) { if (g_set_icon_error) { g_set_icon_error = false; - WARN_PRINT("Icon too large, attempting to resize icon."); + WARN_PRINT(vformat("Icon too large (%dx%d), attempting to downscale icon.", w, h)); int new_width, new_height; if (w > h) { @@ -5451,8 +5451,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V } else { Rect2i srect = screen_get_usable_rect(rq_screen); Point2i wpos = p_rect.position; - wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3); - wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3); + wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3); win_rect.position = wpos; } diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h index 09073a8030..7c9d073afc 100644 --- a/platform/macos/display_server_macos.h +++ b/platform/macos/display_server_macos.h @@ -241,6 +241,8 @@ public: NSImage *_convert_to_nsimg(Ref<Image> &p_image) const; Point2i _get_screens_origin() const; + void set_menu_delegate(NSMenu *p_menu); + void send_event(NSEvent *p_event); void send_window_event(const WindowData &p_wd, WindowEvent p_event); void release_pressed_events(); diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm index c52ed00b3d..d06eab8531 100644 --- a/platform/macos/display_server_macos.mm +++ b/platform/macos/display_server_macos.mm @@ -83,8 +83,7 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod Rect2i srect = screen_get_usable_rect(rq_screen); Point2i wpos = p_rect.position; if (srect != Rect2i()) { - wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3); - wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3); + wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3); } // macOS native y-coordinate relative to _get_screens_origin() is negative, // Godot passes a positive value. @@ -291,6 +290,10 @@ void DisplayServerMacOS::_update_displays_arrangement() { displays_arrangement_dirty = false; } +void DisplayServerMacOS::set_menu_delegate(NSMenu *p_menu) { + [p_menu setDelegate:menu_delegate]; +} + Point2i DisplayServerMacOS::_get_screens_origin() const { // Returns the native top-left screen coordinate of the smallest rectangle // that encompasses all screens. Needed in get_screen_position(), @@ -756,6 +759,8 @@ bool DisplayServerMacOS::has_feature(Feature p_feature) const { case FEATURE_CURSOR_SHAPE: case FEATURE_CUSTOM_CURSOR_SHAPE: case FEATURE_NATIVE_DIALOG: + case FEATURE_NATIVE_DIALOG_INPUT: + case FEATURE_NATIVE_DIALOG_FILE: case FEATURE_IME: case FEATURE_WINDOW_TRANSPARENCY: case FEATURE_HIDPI: @@ -1877,8 +1882,7 @@ void DisplayServerMacOS::window_set_current_screen(int p_screen, WindowID p_wind Size2i wsize = window_get_size(p_window); wpos += srect.position; - wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3); - wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3); + wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3); window_set_position(wpos, p_window); if (was_fullscreen) { @@ -2309,8 +2313,7 @@ void DisplayServerMacOS::window_set_window_buttons_offset(const Vector2i &p_offs WindowData &wd = windows[p_window]; float scale = screen_get_max_scale(); wd.wb_offset = p_offset / scale; - wd.wb_offset.x = MAX(wd.wb_offset.x, 12); - wd.wb_offset.y = MAX(wd.wb_offset.y, 12); + wd.wb_offset = wd.wb_offset.max(Vector2i(12, 12)); if (wd.window_button_view) { [wd.window_button_view setOffset:NSMakePoint(wd.wb_offset.x, wd.wb_offset.y)]; } diff --git a/platform/macos/godot_main_macos.mm b/platform/macos/godot_main_macos.mm index 3959fb686c..942c351ac0 100644 --- a/platform/macos/godot_main_macos.mm +++ b/platform/macos/godot_main_macos.mm @@ -69,18 +69,21 @@ int main(int argc, char **argv) { err = Main::setup(argv[0], argc - first_arg, &argv[first_arg]); } - if (err == ERR_HELP) { // Returned by --help and --version, so success. - return 0; - } else if (err != OK) { - return 255; + if (err != OK) { + if (err == ERR_HELP) { // Returned by --help and --version, so success. + return EXIT_SUCCESS; + } + return EXIT_FAILURE; } - bool ok; + int ret; @autoreleasepool { - ok = Main::start(); + ret = Main::start(); } - if (ok) { - os.run(); // It is actually the OS that decides how to run. + if (ret == EXIT_SUCCESS) { + os.run(); + } else { + os.set_exit_code(EXIT_FAILURE); } @autoreleasepool { diff --git a/platform/macos/native_menu_macos.h b/platform/macos/native_menu_macos.h index c00a510fd5..1d9feb64a7 100644 --- a/platform/macos/native_menu_macos.h +++ b/platform/macos/native_menu_macos.h @@ -33,7 +33,7 @@ #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" -#include "servers/native_menu.h" +#include "servers/display/native_menu.h" #import <AppKit/AppKit.h> #import <ApplicationServices/ApplicationServices.h> diff --git a/platform/macos/native_menu_macos.mm b/platform/macos/native_menu_macos.mm index 250b64dc04..8c2dd98862 100644 --- a/platform/macos/native_menu_macos.mm +++ b/platform/macos/native_menu_macos.mm @@ -223,6 +223,11 @@ RID NativeMenuMacOS::get_system_menu(SystemMenus p_menu_id) const { RID NativeMenuMacOS::create_menu() { MenuData *md = memnew(MenuData); md->menu = [[NSMenu alloc] initWithTitle:@""]; + [md->menu setAutoenablesItems:NO]; + DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton(); + if (ds) { + ds->set_menu_delegate(md->menu); + } RID rid = menus.make_rid(md); menu_lookup[md->menu] = rid; return rid; diff --git a/platform/web/detect.py b/platform/web/detect.py index e692c79a20..2d2cc288a1 100644 --- a/platform/web/detect.py +++ b/platform/web/detect.py @@ -86,7 +86,7 @@ def configure(env: "SConsEnvironment"): supported_arches = ["wasm32"] if env["arch"] not in supported_arches: print( - 'Unsupported CPU architecture "%s" for iOS. Supported architectures are: %s.' + 'Unsupported CPU architecture "%s" for Web. Supported architectures are: %s.' % (env["arch"], ", ".join(supported_arches)) ) sys.exit() diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp index 281f312000..06f5eb82f7 100644 --- a/platform/web/display_server_web.cpp +++ b/platform/web/display_server_web.cpp @@ -1128,6 +1128,8 @@ bool DisplayServerWeb::has_feature(Feature p_feature) const { return true; //case FEATURE_MOUSE_WARP: //case FEATURE_NATIVE_DIALOG: + //case FEATURE_NATIVE_DIALOG_INPUT: + //case FEATURE_NATIVE_DIALOG_FILE: //case FEATURE_NATIVE_ICON: //case FEATURE_WINDOW_TRANSPARENCY: //case FEATURE_KEEP_SCREEN_ON: diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp index 45671ca491..4b93ce9e75 100644 --- a/platform/web/os_web.cpp +++ b/platform/web/os_web.cpp @@ -105,6 +105,10 @@ Error OS_Web::execute(const String &p_path, const List<String> &p_arguments, Str return create_process(p_path, p_arguments); } +Dictionary OS_Web::execute_with_pipe(const String &p_path, const List<String> &p_arguments) { + ERR_FAIL_V_MSG(Dictionary(), "OS::execute_with_pipe is not available on the Web platform."); +} + Error OS_Web::create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id, bool p_open_console) { Array args; for (const String &E : p_arguments) { diff --git a/platform/web/os_web.h b/platform/web/os_web.h index e578c93925..16f8ea8550 100644 --- a/platform/web/os_web.h +++ b/platform/web/os_web.h @@ -80,6 +80,7 @@ public: bool main_loop_iterate(); Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override; + Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) override; Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; Error kill(const ProcessID &p_pid) override; int get_process_id() const override; diff --git a/platform/web/web_main.cpp b/platform/web/web_main.cpp index ad2a801881..04513f6d57 100644 --- a/platform/web/web_main.cpp +++ b/platform/web/web_main.cpp @@ -109,24 +109,22 @@ extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) { // Proper shutdown in case of setup failure. if (err != OK) { - int exit_code = (int)err; - if (err == ERR_HELP) { - exit_code = 0; // Called with --help. - } - os->set_exit_code(exit_code); // Will only exit after sync. emscripten_set_main_loop(exit_callback, -1, false); godot_js_os_finish_async(cleanup_after_sync); - return exit_code; + if (err == ERR_HELP) { // Returned by --help and --version, so success. + return EXIT_SUCCESS; + } + return EXIT_FAILURE; } - os->set_exit_code(0); main_started = true; // Ease up compatibility. ResourceLoader::set_abort_on_missing_resources(false); - Main::start(); + int ret = Main::start(); + os->set_exit_code(ret); os->get_main_loop()->initialize(); #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_project_manager_hint() && FileAccess::exists("/tmp/preload.zip")) { @@ -140,5 +138,5 @@ extern EMSCRIPTEN_KEEPALIVE int godot_web_main(int argc, char *argv[]) { // We are inside an animation frame, we want to immediately draw on the newly setup canvas. main_loop_callback(); - return 0; + return os->get_exit_code(); } diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp index 2093f552ce..e540b7617f 100644 --- a/platform/windows/display_server_windows.cpp +++ b/platform/windows/display_server_windows.cpp @@ -114,6 +114,8 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const { case FEATURE_ICON: case FEATURE_NATIVE_ICON: case FEATURE_NATIVE_DIALOG: + case FEATURE_NATIVE_DIALOG_INPUT: + case FEATURE_NATIVE_DIALOG_FILE: case FEATURE_SWAP_BUFFERS: case FEATURE_KEEP_SCREEN_ON: case FEATURE_TEXT_TO_SPEECH: @@ -903,8 +905,7 @@ static BOOL CALLBACK _MonitorEnumProcPos(HMONITOR hMonitor, HDC hdcMonitor, LPRE static BOOL CALLBACK _MonitorEnumProcOrigin(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) { EnumPosData *data = (EnumPosData *)dwData; - data->pos.x = MIN(data->pos.x, lprcMonitor->left); - data->pos.y = MIN(data->pos.y, lprcMonitor->top); + data->pos = data->pos.min(Point2(lprcMonitor->left, lprcMonitor->top)); return TRUE; } @@ -1637,8 +1638,7 @@ void DisplayServerWindows::window_set_current_screen(int p_screen, WindowID p_wi Size2i wsize = window_get_size(p_window); wpos += srect.position; - wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - wsize.width / 3); - wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - wsize.height / 3); + wpos = wpos.clamp(srect.position, srect.position + srect.size - wsize / 3); window_set_position(wpos, p_window); } } @@ -5076,8 +5076,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode, Rect2i srect = screen_get_usable_rect(rq_screen); Point2i wpos = p_rect.position; if (srect != Rect2i()) { - wpos.x = CLAMP(wpos.x, srect.position.x, srect.position.x + srect.size.width - p_rect.size.width / 3); - wpos.y = CLAMP(wpos.y, srect.position.y, srect.position.y + srect.size.height - p_rect.size.height / 3); + wpos = wpos.clamp(srect.position, srect.position + srect.size - p_rect.size / 3); } WindowRect.left = wpos.x; @@ -5497,6 +5496,32 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(95)); GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(96)); GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98)); + if (os_ver.dwBuildNumber >= 17763) { + AllowDarkModeForAppPtr AllowDarkModeForApp = nullptr; + SetPreferredAppModePtr SetPreferredAppMode = nullptr; + FlushMenuThemesPtr FlushMenuThemes = nullptr; + if (os_ver.dwBuildNumber < 18362) { + AllowDarkModeForApp = (AllowDarkModeForAppPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(135)); + } else { + SetPreferredAppMode = (SetPreferredAppModePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(135)); + FlushMenuThemes = (FlushMenuThemesPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(136)); + } + RefreshImmersiveColorPolicyStatePtr RefreshImmersiveColorPolicyState = (RefreshImmersiveColorPolicyStatePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(104)); + if (ShouldAppsUseDarkMode) { + bool dark_mode = ShouldAppsUseDarkMode(); + if (SetPreferredAppMode) { + SetPreferredAppMode(dark_mode ? APPMODE_ALLOWDARK : APPMODE_DEFAULT); + } else if (AllowDarkModeForApp) { + AllowDarkModeForApp(dark_mode); + } + if (RefreshImmersiveColorPolicyState) { + RefreshImmersiveColorPolicyState(); + } + if (FlushMenuThemes) { + FlushMenuThemes(); + } + } + } ux_theme_available = ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference; if (os_ver.dwBuildNumber >= 18363) { diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h index 910b9baa45..1191f22968 100644 --- a/platform/windows/display_server_windows.h +++ b/platform/windows/display_server_windows.h @@ -154,11 +154,23 @@ typedef UINT(WINAPI *WTInfoPtr)(UINT p_category, UINT p_index, LPVOID p_output); typedef BOOL(WINAPI *WTPacketPtr)(HANDLE p_ctx, UINT p_param, LPVOID p_packets); typedef BOOL(WINAPI *WTEnablePtr)(HANDLE p_ctx, BOOL p_enable); +enum PreferredAppMode { + APPMODE_DEFAULT = 0, + APPMODE_ALLOWDARK = 1, + APPMODE_FORCEDARK = 2, + APPMODE_FORCELIGHT = 3, + APPMODE_MAX = 4 +}; + typedef bool(WINAPI *ShouldAppsUseDarkModePtr)(); typedef DWORD(WINAPI *GetImmersiveColorFromColorSetExPtr)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode); typedef int(WINAPI *GetImmersiveColorTypeFromNamePtr)(const WCHAR *name); typedef int(WINAPI *GetImmersiveUserColorSetPreferencePtr)(bool bForceCheckRegistry, bool bSkipCheckOnFail); typedef HRESULT(WINAPI *RtlGetVersionPtr)(OSVERSIONINFOW *lpVersionInformation); +typedef bool(WINAPI *AllowDarkModeForAppPtr)(bool darkMode); +typedef PreferredAppMode(WINAPI *SetPreferredAppModePtr)(PreferredAppMode appMode); +typedef void(WINAPI *RefreshImmersiveColorPolicyStatePtr)(); +typedef void(WINAPI *FlushMenuThemesPtr)(); // Windows Ink API #ifndef POINTER_STRUCTURES diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp index f86ecd87fb..5f41b4e568 100644 --- a/platform/windows/godot_windows.cpp +++ b/platform/windows/godot_windows.cpp @@ -171,13 +171,15 @@ int widechar_main(int argc, wchar_t **argv) { delete[] argv_utf8; if (err == ERR_HELP) { // Returned by --help and --version, so success. - return 0; + return EXIT_SUCCESS; } - return 255; + return EXIT_FAILURE; } - if (Main::start()) { + if (Main::start() == EXIT_SUCCESS) { os.run(); + } else { + os.set_exit_code(EXIT_FAILURE); } Main::cleanup(); diff --git a/platform/windows/native_menu_windows.cpp b/platform/windows/native_menu_windows.cpp index 13d1cc2a67..40a08f87df 100644 --- a/platform/windows/native_menu_windows.cpp +++ b/platform/windows/native_menu_windows.cpp @@ -141,7 +141,7 @@ RID NativeMenuWindows::create_menu() { ZeroMemory(&menu_info, sizeof(menu_info)); menu_info.cbSize = sizeof(menu_info); menu_info.fMask = MIM_STYLE; - menu_info.dwStyle = MNS_NOTIFYBYPOS | MNS_MODELESS; + menu_info.dwStyle = MNS_NOTIFYBYPOS; SetMenuInfo(md->menu, &menu_info); RID rid = menus.make_rid(md); @@ -189,7 +189,9 @@ void NativeMenuWindows::popup(const RID &p_rid, const Vector2i &p_position) { if (md->is_rtl) { flags |= TPM_LAYOUTRTL; } + SetForegroundWindow(hwnd); TrackPopupMenuEx(md->menu, flags, p_position.x, p_position.y, hwnd, nullptr); + PostMessage(hwnd, WM_NULL, 0, 0); } void NativeMenuWindows::set_interface_direction(const RID &p_rid, bool p_is_rtl) { @@ -556,9 +558,16 @@ int NativeMenuWindows::find_item_index_with_text(const RID &p_rid, const String ZeroMemory(&item, sizeof(item)); item.cbSize = sizeof(item); item.fMask = MIIM_STRING; + item.dwTypeData = nullptr; if (GetMenuItemInfoW(md->menu, i, true, &item)) { - if (String::utf16((const char16_t *)item.dwTypeData) == p_text) { - return i; + item.cch++; + Char16String str; + str.resize(item.cch); + item.dwTypeData = (LPWSTR)str.ptrw(); + if (GetMenuItemInfoW(md->menu, i, true, &item)) { + if (String::utf16((const char16_t *)str.get_data()) == p_text) { + return i; + } } } } @@ -700,8 +709,15 @@ String NativeMenuWindows::get_item_text(const RID &p_rid, int p_idx) const { ZeroMemory(&item, sizeof(item)); item.cbSize = sizeof(item); item.fMask = MIIM_STRING; + item.dwTypeData = nullptr; if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) { - return String::utf16((const char16_t *)item.dwTypeData); + item.cch++; + Char16String str; + str.resize(item.cch); + item.dwTypeData = (LPWSTR)str.ptrw(); + if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) { + return String::utf16((const char16_t *)str.get_data()); + } } return String(); } diff --git a/platform/windows/native_menu_windows.h b/platform/windows/native_menu_windows.h index 6eab56d8b6..74fd231903 100644 --- a/platform/windows/native_menu_windows.h +++ b/platform/windows/native_menu_windows.h @@ -33,7 +33,7 @@ #include "core/templates/hash_map.h" #include "core/templates/rid_owner.h" -#include "servers/native_menu.h" +#include "servers/display/native_menu.h" #define WIN32_LEAN_AND_MEAN #include <windows.h> diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index 152b9ac10f..c39b327953 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -42,6 +42,7 @@ #include "drivers/unix/net_socket_posix.h" #include "drivers/windows/dir_access_windows.h" #include "drivers/windows/file_access_windows.h" +#include "drivers/windows/file_access_windows_pipe.h" #include "main/main.h" #include "servers/audio_server.h" #include "servers/rendering/rendering_server_default.h" @@ -178,6 +179,7 @@ void OS_Windows::initialize() { FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_RESOURCES); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_USERDATA); FileAccess::make_default<FileAccessWindows>(FileAccess::ACCESS_FILESYSTEM); + FileAccess::make_default<FileAccessWindowsPipe>(FileAccess::ACCESS_PIPE); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_RESOURCES); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_USERDATA); DirAccess::make_default<DirAccessWindows>(DirAccess::ACCESS_FILESYSTEM); @@ -727,6 +729,105 @@ Dictionary OS_Windows::get_memory_info() const { return meminfo; } +Dictionary OS_Windows::execute_with_pipe(const String &p_path, const List<String> &p_arguments) { +#define CLEAN_PIPES \ + if (pipe_in[0] != 0) { \ + CloseHandle(pipe_in[0]); \ + } \ + if (pipe_in[1] != 0) { \ + CloseHandle(pipe_in[1]); \ + } \ + if (pipe_out[0] != 0) { \ + CloseHandle(pipe_out[0]); \ + } \ + if (pipe_out[1] != 0) { \ + CloseHandle(pipe_out[1]); \ + } \ + if (pipe_err[0] != 0) { \ + CloseHandle(pipe_err[0]); \ + } \ + if (pipe_err[1] != 0) { \ + CloseHandle(pipe_err[1]); \ + } + + Dictionary ret; + + String path = p_path.replace("/", "\\"); + String command = _quote_command_line_argument(path); + for (const String &E : p_arguments) { + command += " " + _quote_command_line_argument(E); + } + + // Create pipes. + HANDLE pipe_in[2] = { 0, 0 }; + HANDLE pipe_out[2] = { 0, 0 }; + HANDLE pipe_err[2] = { 0, 0 }; + + SECURITY_ATTRIBUTES sa; + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = true; + sa.lpSecurityDescriptor = nullptr; + + ERR_FAIL_COND_V(!CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0), ret); + if (!SetHandleInformation(pipe_in[1], HANDLE_FLAG_INHERIT, 0)) { + CLEAN_PIPES + ERR_FAIL_V(ret); + } + if (!CreatePipe(&pipe_out[0], &pipe_out[1], &sa, 0)) { + CLEAN_PIPES + ERR_FAIL_V(ret); + } + if (!SetHandleInformation(pipe_out[0], HANDLE_FLAG_INHERIT, 0)) { + CLEAN_PIPES + ERR_FAIL_V(ret); + } + if (!CreatePipe(&pipe_err[0], &pipe_err[1], &sa, 0)) { + CLEAN_PIPES + ERR_FAIL_V(ret); + } + ERR_FAIL_COND_V(!SetHandleInformation(pipe_err[0], HANDLE_FLAG_INHERIT, 0), ret); + + // Create process. + ProcessInfo pi; + ZeroMemory(&pi.si, sizeof(pi.si)); + pi.si.cb = sizeof(pi.si); + ZeroMemory(&pi.pi, sizeof(pi.pi)); + LPSTARTUPINFOW si_w = (LPSTARTUPINFOW)&pi.si; + + pi.si.dwFlags |= STARTF_USESTDHANDLES; + pi.si.hStdInput = pipe_in[0]; + pi.si.hStdOutput = pipe_out[1]; + pi.si.hStdError = pipe_err[1]; + + DWORD creation_flags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW; + + if (!CreateProcessW(nullptr, (LPWSTR)(command.utf16().ptrw()), nullptr, nullptr, true, creation_flags, nullptr, nullptr, si_w, &pi.pi)) { + CLEAN_PIPES + ERR_FAIL_V_MSG(ret, "Could not create child process: " + command); + } + CloseHandle(pipe_in[0]); + CloseHandle(pipe_out[1]); + CloseHandle(pipe_err[1]); + + ProcessID pid = pi.pi.dwProcessId; + process_map->insert(pid, pi); + + Ref<FileAccessWindowsPipe> main_pipe; + main_pipe.instantiate(); + main_pipe->open_existing(pipe_out[0], pipe_in[1]); + + Ref<FileAccessWindowsPipe> err_pipe; + err_pipe.instantiate(); + err_pipe->open_existing(pipe_err[0], 0); + + ret["stdio"] = main_pipe; + ret["stderr"] = err_pipe; + ret["pid"] = pid; + +#undef CLEAN_PIPES + return ret; +} + Error OS_Windows::execute(const String &p_path, const List<String> &p_arguments, String *r_pipe, int *r_exitcode, bool read_stderr, Mutex *p_pipe_mutex, bool p_open_console) { String path = p_path.replace("/", "\\"); String command = _quote_command_line_argument(path); diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 351cb32c9b..c703a3ddca 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -181,6 +181,7 @@ public: virtual Dictionary get_memory_info() const override; virtual Error execute(const String &p_path, const List<String> &p_arguments, String *r_pipe = nullptr, int *r_exitcode = nullptr, bool read_stderr = false, Mutex *p_pipe_mutex = nullptr, bool p_open_console = false) override; + virtual Dictionary execute_with_pipe(const String &p_path, const List<String> &p_arguments) override; virtual Error create_process(const String &p_path, const List<String> &p_arguments, ProcessID *r_child_id = nullptr, bool p_open_console = false) override; virtual Error kill(const ProcessID &p_pid) override; virtual int get_process_id() const override; diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 722858b674..e9bab274c6 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -54,7 +54,12 @@ void Camera2D::_update_scroll() { if (is_current()) { ERR_FAIL_COND(custom_viewport && !ObjectDB::get_instance(custom_viewport_id)); - Transform2D xform = get_camera_transform(); + Transform2D xform; + if (is_physics_interpolated_and_enabled()) { + xform = _interpolation_data.xform_prev.interpolate_with(_interpolation_data.xform_curr, Engine::get_singleton()->get_physics_interpolation_fraction()); + } else { + xform = get_camera_transform(); + } viewport->set_canvas_transform(xform); @@ -68,15 +73,26 @@ void Camera2D::_update_scroll() { } void Camera2D::_update_process_callback() { - if (_is_editing_in_editor()) { + if (is_physics_interpolated_and_enabled()) { + set_process_internal(is_current()); + set_physics_process_internal(is_current()); + +#ifdef TOOLS_ENABLED + if (process_callback == CAMERA2D_PROCESS_IDLE) { + WARN_PRINT_ONCE("Camera2D overridden to physics process mode due to use of physics interpolation."); + } +#endif + } else if (_is_editing_in_editor()) { set_process_internal(false); set_physics_process_internal(false); - } else if (process_callback == CAMERA2D_PROCESS_IDLE) { - set_process_internal(true); - set_physics_process_internal(false); } else { - set_process_internal(false); - set_physics_process_internal(true); + if (process_callback == CAMERA2D_PROCESS_IDLE) { + set_process_internal(true); + set_physics_process_internal(false); + } else { + set_process_internal(false); + set_physics_process_internal(true); + } } } @@ -161,8 +177,15 @@ Transform2D Camera2D::get_camera_transform() { } } + // FIXME: There is a bug here, introduced before physics interpolation. + // Smoothing occurs rather confusingly during the call to get_camera_transform(). + // It may be called MULTIPLE TIMES on certain frames, + // therefore smoothing is not currently applied only once per frame / tick, + // which will result in some haphazard results. if (position_smoothing_enabled && !_is_editing_in_editor()) { - real_t c = position_smoothing_speed * (process_callback == CAMERA2D_PROCESS_PHYSICS ? get_physics_process_delta_time() : get_process_delta_time()); + bool physics_process = (process_callback == CAMERA2D_PROCESS_PHYSICS) || is_physics_interpolated_and_enabled(); + real_t delta = physics_process ? get_physics_process_delta_time() : get_process_delta_time(); + real_t c = position_smoothing_speed * delta; smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos; ret_camera_pos = smoothed_camera_pos; //camera_pos=camera_pos*(1.0-position_smoothing_speed)+new_camera_pos*position_smoothing_speed; @@ -223,17 +246,52 @@ Transform2D Camera2D::get_camera_transform() { return xform.affine_inverse(); } +void Camera2D::_ensure_update_interpolation_data() { + // The "curr -> previous" update can either occur + // on NOTIFICATION_INTERNAL_PHYSICS_PROCESS, OR + // on NOTIFICATION_TRANSFORM_CHANGED, + // if NOTIFICATION_TRANSFORM_CHANGED takes place earlier than + // NOTIFICATION_INTERNAL_PHYSICS_PROCESS on a tick. + // This is to ensure that the data keeps flowing, but the new data + // doesn't overwrite before prev has been set. + + // Keep the data flowing. + uint64_t tick = Engine::get_singleton()->get_physics_frames(); + if (_interpolation_data.last_update_physics_tick != tick) { + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + _interpolation_data.last_update_physics_tick = tick; + } +} + void Camera2D::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_INTERNAL_PROCESS: - case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + case NOTIFICATION_INTERNAL_PROCESS: { _update_scroll(); } break; + case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { + if (is_physics_interpolated_and_enabled()) { + _ensure_update_interpolation_data(); + _interpolation_data.xform_curr = get_camera_transform(); + } else { + _update_scroll(); + } + } break; + + case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: { + // Force the limits etc. to update. + _interpolation_data.xform_curr = get_camera_transform(); + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { - if (!position_smoothing_enabled || _is_editing_in_editor()) { + if ((!position_smoothing_enabled && !is_physics_interpolated_and_enabled()) || _is_editing_in_editor()) { _update_scroll(); } + if (is_physics_interpolated_and_enabled()) { + _ensure_update_interpolation_data(); + _interpolation_data.xform_curr = get_camera_transform(); + } } break; case NOTIFICATION_ENTER_TREE: { @@ -260,6 +318,15 @@ void Camera2D::_notification(int p_what) { _update_process_callback(); first = true; _update_scroll(); + + // Note that NOTIFICATION_RESET_PHYSICS_INTERPOLATION + // is automatically called before this because Camera2D is inherited + // from CanvasItem. However, the camera transform is not up to date + // until this point, so we do an extra manual reset. + if (is_physics_interpolated_and_enabled()) { + _interpolation_data.xform_curr = get_camera_transform(); + _interpolation_data.xform_prev = _interpolation_data.xform_curr; + } } break; case NOTIFICATION_EXIT_TREE: { @@ -431,12 +498,17 @@ void Camera2D::_make_current(Object *p_which) { queue_redraw(); - if (p_which == this) { + bool was_current = viewport->get_camera_2d() == this; + bool is_current = p_which == this; + + if (is_current) { viewport->_camera_2d_set(this); - } else { - if (viewport->get_camera_2d() == this) { - viewport->_camera_2d_set(nullptr); - } + } else if (was_current) { + viewport->_camera_2d_set(nullptr); + } + + if (is_current != was_current) { + _update_process_callback(); } } @@ -456,6 +528,7 @@ void Camera2D::make_current() { _make_current(this); } _update_scroll(); + _update_process_callback(); } void Camera2D::clear_current() { @@ -468,6 +541,8 @@ void Camera2D::clear_current() { if (!custom_viewport || ObjectDB::get_instance(custom_viewport_id)) { viewport->assign_next_enabled_camera_2d(group_name); } + + _update_process_callback(); } bool Camera2D::is_current() const { diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 5693d05ee5..bf25267aa8 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -102,6 +102,14 @@ protected: Camera2DProcessCallback process_callback = CAMERA2D_PROCESS_IDLE; + struct InterpolationData { + Transform2D xform_curr; + Transform2D xform_prev; + uint32_t last_update_physics_tick = 0; + } _interpolation_data; + + void _ensure_update_interpolation_data(); + Size2 _get_camera_screen_size() const; protected: diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index c03786caef..79732d7861 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -197,6 +197,10 @@ Light2D::BlendMode Light2D::get_blend_mode() const { return blend_mode; } +void Light2D::_physics_interpolated_changed() { + RenderingServer::get_singleton()->canvas_light_set_interpolated(canvas_light, is_physics_interpolated()); +} + void Light2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -212,6 +216,17 @@ void Light2D::_notification(int p_what) { _update_light_visibility(); } break; + case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: { + if (is_visible_in_tree() && is_physics_interpolated()) { + // Explicitly make sure the transform is up to date in RenderingServer before + // resetting. This is necessary because NOTIFICATION_TRANSFORM_CHANGED + // is normally deferred, and a client change to transform will not always be sent + // before the reset, so we need to guarantee this. + RS::get_singleton()->canvas_light_set_transform(canvas_light, get_global_transform()); + RS::get_singleton()->canvas_light_reset_physics_interpolation(canvas_light); + } + } break; + case NOTIFICATION_EXIT_TREE: { RS::get_singleton()->canvas_light_attach_to_canvas(canvas_light, RID()); _update_light_visibility(); diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index 3c1171deae..8a0c2a2a92 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -74,6 +74,7 @@ private: void _update_light_visibility(); virtual void owner_changed_notify() override; + virtual void _physics_interpolated_changed() override; protected: _FORCE_INLINE_ RID _get_light() const { return canvas_light; } diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp index 61f5d5cd46..092c987ac0 100644 --- a/scene/2d/light_occluder_2d.cpp +++ b/scene/2d/light_occluder_2d.cpp @@ -158,6 +158,10 @@ void LightOccluder2D::_poly_changed() { #endif } +void LightOccluder2D::_physics_interpolated_changed() { + RenderingServer::get_singleton()->canvas_light_occluder_set_interpolated(occluder, is_physics_interpolated()); +} + void LightOccluder2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_CANVAS: { @@ -199,6 +203,17 @@ void LightOccluder2D::_notification(int p_what) { case NOTIFICATION_EXIT_CANVAS: { RS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID()); } break; + + case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: { + if (is_visible_in_tree() && is_physics_interpolated()) { + // Explicitly make sure the transform is up to date in RenderingServer before + // resetting. This is necessary because NOTIFICATION_TRANSFORM_CHANGED + // is normally deferred, and a client change to transform will not always be sent + // before the reset, so we need to guarantee this. + RS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform()); + RS::get_singleton()->canvas_light_occluder_reset_physics_interpolation(occluder); + } + } break; } } diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h index dd3130394e..4c499d0465 100644 --- a/scene/2d/light_occluder_2d.h +++ b/scene/2d/light_occluder_2d.h @@ -86,6 +86,8 @@ class LightOccluder2D : public Node2D { bool sdf_collision = false; void _poly_changed(); + virtual void _physics_interpolated_changed() override; + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/scene/2d/parallax_2d.cpp b/scene/2d/parallax_2d.cpp index f516fd41ac..7e47e0f061 100644 --- a/scene/2d/parallax_2d.cpp +++ b/scene/2d/parallax_2d.cpp @@ -129,6 +129,7 @@ void Parallax2D::_update_repeat() { Point2 repeat_scale = repeat_size * get_scale(); RenderingServer::get_singleton()->canvas_set_item_repeat(get_canvas_item(), repeat_scale, repeat_times); + RenderingServer::get_singleton()->canvas_item_set_interpolated(get_canvas_item(), false); } void Parallax2D::set_scroll_scale(const Size2 &p_scale) { @@ -287,4 +288,6 @@ void Parallax2D::_bind_methods() { } Parallax2D::Parallax2D() { + // Parallax2D is always updated every frame so there is no need to interpolate. + set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_OFF); } diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 3dd0d7b61c..e2a7e9e154 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -73,6 +73,7 @@ void ParallaxLayer::_update_mirroring() { RID ci = get_canvas_item(); Point2 mirrorScale = mirroring * get_scale(); RenderingServer::get_singleton()->canvas_set_item_mirroring(c, ci, mirrorScale); + RenderingServer::get_singleton()->canvas_item_set_interpolated(ci, false); } } @@ -162,4 +163,6 @@ void ParallaxLayer::_bind_methods() { } ParallaxLayer::ParallaxLayer() { + // ParallaxLayer is always updated every frame so there is no need to interpolate. + set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_OFF); } diff --git a/scene/2d/physics/collision_polygon_2d.cpp b/scene/2d/physics/collision_polygon_2d.cpp index 96ef346d23..72ee4d52c5 100644 --- a/scene/2d/physics/collision_polygon_2d.cpp +++ b/scene/2d/physics/collision_polygon_2d.cpp @@ -132,17 +132,16 @@ void CollisionPolygon2D::_notification(int p_what) { } if (polygon.size() > 2) { -#define DEBUG_DECOMPOSE -#if defined(TOOLS_ENABLED) && defined(DEBUG_DECOMPOSE) - Vector<Vector<Vector2>> decomp = _decompose_in_convex(); - - Color c(0.4, 0.9, 0.1); - for (int i = 0; i < decomp.size(); i++) { - c.set_hsv(Math::fmod(c.get_h() + 0.738, 1), c.get_s(), c.get_v(), 0.5); - draw_colored_polygon(decomp[i], c); +#ifdef TOOLS_ENABLED + if (build_mode == BUILD_SOLIDS) { + Vector<Vector<Vector2>> decomp = _decompose_in_convex(); + + Color c(0.4, 0.9, 0.1); + for (int i = 0; i < decomp.size(); i++) { + c.set_hsv(Math::fmod(c.get_h() + 0.738, 1), c.get_s(), c.get_v(), 0.5); + draw_colored_polygon(decomp[i], c); + } } -#else - draw_colored_polygon(polygon, get_tree()->get_debug_collisions_color()); #endif const Color stroke_color = Color(0.9, 0.2, 0.0); diff --git a/scene/2d/sprite_2d.cpp b/scene/2d/sprite_2d.cpp index 3c19dd0020..5745a59297 100644 --- a/scene/2d/sprite_2d.cpp +++ b/scene/2d/sprite_2d.cpp @@ -374,8 +374,7 @@ bool Sprite2D::is_pixel_opaque(const Point2 &p_point) const { q.y = texture->get_size().height - q.y - 1; } } else { - q.x = MIN(q.x, texture->get_size().width - 1); - q.y = MIN(q.y, texture->get_size().height - 1); + q = q.min(texture->get_size() - Vector2(1, 1)); } return texture->is_pixel_opaque((int)q.x, (int)q.y); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index f8737730ba..bbf1d09bbc 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -32,7 +32,7 @@ #include "tile_map.compat.inc" #include "core/core_string_names.h" -#include "scene/2d/tile_map_layer.h" +#include "core/io/marshalls.h" #include "scene/gui/control.h" #define TILEMAP_CALL_FOR_LAYER(layer, function, ...) \ @@ -49,10 +49,118 @@ ERR_FAIL_INDEX_V(layer, (int)layers.size(), err_value); \ return layers[layer]->function(__VA_ARGS__); +void TileMap::_tile_set_changed() { + update_configuration_warnings(); +} + void TileMap::_emit_changed() { emit_signal(CoreStringNames::get_singleton()->changed); } +void TileMap::_set_tile_map_data_using_compatibility_format(int p_layer, TileMapDataFormat p_format, const Vector<int> &p_data) { + ERR_FAIL_INDEX(p_layer, (int)layers.size()); + ERR_FAIL_COND(p_format >= TileMapDataFormat::TILE_MAP_DATA_FORMAT_MAX); +#ifndef DISABLE_DEPRECATED + ERR_FAIL_COND_MSG(p_format != (TileMapDataFormat)(TILE_MAP_DATA_FORMAT_MAX - 1), "Old TileMap data format detected despite DISABLE_DEPRECATED being set compilation time."); +#endif // DISABLE_DEPRECATED + + // Set data for a given tile from raw data. + int c = p_data.size(); + const int *r = p_data.ptr(); + + int offset = (p_format >= TileMapDataFormat::TILE_MAP_DATA_FORMAT_2) ? 3 : 2; + ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %d. Expected modulo: %d", c, offset)); + + layers[p_layer]->clear(); + + for (int i = 0; i < c; i += offset) { + const uint8_t *ptr = (const uint8_t *)&r[i]; + uint8_t local[12]; + for (int j = 0; j < ((p_format >= TileMapDataFormat::TILE_MAP_DATA_FORMAT_2) ? 12 : 8); j++) { + local[j] = ptr[j]; + } + +#ifdef BIG_ENDIAN_ENABLED + SWAP(local[0], local[3]); + SWAP(local[1], local[2]); + SWAP(local[4], local[7]); + SWAP(local[5], local[6]); + //TODO: ask someone to check this... + if (FORMAT >= FORMAT_2) { + SWAP(local[8], local[11]); + SWAP(local[9], local[10]); + } +#endif + // Extracts position in TileMap. + int16_t x = decode_uint16(&local[0]); + int16_t y = decode_uint16(&local[2]); + + if (p_format == TileMapDataFormat::TILE_MAP_DATA_FORMAT_3) { + uint16_t source_id = decode_uint16(&local[4]); + uint16_t atlas_coords_x = decode_uint16(&local[6]); + uint16_t atlas_coords_y = decode_uint16(&local[8]); + uint16_t alternative_tile = decode_uint16(&local[10]); + layers[p_layer]->set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile); + } else { +#ifndef DISABLE_DEPRECATED + // Previous decated format. + uint32_t v = decode_uint32(&local[4]); + // Extract the transform flags that used to be in the tilemap. + bool flip_h = v & (1UL << 29); + bool flip_v = v & (1UL << 30); + bool transpose = v & (1UL << 31); + v &= (1UL << 29) - 1; + + // Extract autotile/atlas coords. + int16_t coord_x = 0; + int16_t coord_y = 0; + if (p_format == TileMapDataFormat::TILE_MAP_DATA_FORMAT_2) { + coord_x = decode_uint16(&local[8]); + coord_y = decode_uint16(&local[10]); + } + + if (tile_set.is_valid()) { + Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose); + if (a.size() == 3) { + layers[p_layer]->set_cell(Vector2i(x, y), a[0], a[1], a[2]); + } else { + ERR_PRINT(vformat("No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s", v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose)); + } + } else { + int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2); + layers[p_layer]->set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile); + } +#endif // DISABLE_DEPRECATED + } + } +} + +Vector<int> TileMap::_get_tile_map_data_using_compatibility_format(int p_layer) const { + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), Vector<int>()); + + // Export tile data to raw format. + const HashMap<Vector2i, CellData> tile_map_layer_data = layers[p_layer]->get_tile_map_layer_data(); + Vector<int> tile_data; + tile_data.resize(tile_map_layer_data.size() * 3); + int *w = tile_data.ptrw(); + + // Save in highest format. + + int idx = 0; + for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { + uint8_t *ptr = (uint8_t *)&w[idx]; + encode_uint16((int16_t)(E.key.x), &ptr[0]); + encode_uint16((int16_t)(E.key.y), &ptr[2]); + encode_uint16(E.value.cell.source_id, &ptr[4]); + encode_uint16(E.value.cell.coord_x, &ptr[6]); + encode_uint16(E.value.cell.coord_y, &ptr[8]); + encode_uint16(E.value.cell.alternative_tile, &ptr[10]); + idx += 3; + } + + return tile_data; +} + void TileMap::_notification(int p_what) { switch (p_what) { case TileMap::NOTIFICATION_INTERNAL_PHYSICS_PROCESS: { @@ -199,6 +307,34 @@ void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref< } } +void TileMap::set_tileset(const Ref<TileSet> &p_tileset) { + if (p_tileset == tile_set) { + return; + } + + // Set the tileset, registering to its changes. + if (tile_set.is_valid()) { + tile_set->disconnect_changed(callable_mp(this, &TileMap::_tile_set_changed)); + } + + tile_set = p_tileset; + + if (tile_set.is_valid()) { + tile_set->connect_changed(callable_mp(this, &TileMap::_tile_set_changed)); + } + + for (int i = 0; i < get_child_count(); i++) { + TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); + if (layer) { + layer->set_tile_set(tile_set); + } + } +} + +Ref<TileSet> TileMap::get_tileset() const { + return tile_set; +} + int TileMap::get_layers_count() const { return layers.size(); } @@ -215,6 +351,7 @@ void TileMap::add_layer(int p_to_pos) { layers.insert(p_to_pos, new_layer); add_child(new_layer, false, INTERNAL_MODE_FRONT); new_layer->set_name(vformat("Layer%d", p_to_pos)); + new_layer->set_tile_set(tile_set); move_child(new_layer, p_to_pos); for (uint32_t i = 0; i < layers.size(); i++) { layers[i]->set_as_tile_map_internal_node(i); @@ -251,8 +388,11 @@ void TileMap::remove_layer(int p_layer) { ERR_FAIL_INDEX(p_layer, (int)layers.size()); // Clear before removing the layer. - layers[p_layer]->queue_free(); + TileMapLayer *removed = layers[p_layer]; layers.remove_at(p_layer); + remove_child(removed); + removed->queue_free(); + for (uint32_t i = 0; i < layers.size(); i++) { layers[i]->set_as_tile_map_internal_node(i); } @@ -349,7 +489,7 @@ void TileMap::set_collision_visibility_mode(TileMap::VisibilityMode p_show_colli } collision_visibility_mode = p_show_collision; for (TileMapLayer *layer : layers) { - layer->set_collision_visibility_mode(TileMapLayer::VisibilityMode(p_show_collision)); + layer->set_collision_visibility_mode(TileMapLayer::DebugVisibilityMode(p_show_collision)); } _emit_changed(); } @@ -364,7 +504,7 @@ void TileMap::set_navigation_visibility_mode(TileMap::VisibilityMode p_show_navi } navigation_visibility_mode = p_show_navigation; for (TileMapLayer *layer : layers) { - layer->set_navigation_visibility_mode(TileMapLayer::VisibilityMode(p_show_navigation)); + layer->set_navigation_visibility_mode(TileMapLayer::DebugVisibilityMode(p_show_navigation)); } _emit_changed(); } @@ -394,19 +534,85 @@ void TileMap::erase_cell(int p_layer, const Vector2i &p_coords) { } int TileMap::get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { - TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSet::INVALID_SOURCE, get_cell_source_id, p_coords, p_use_proxies); + if (p_use_proxies && tile_set.is_valid()) { + if (p_layer < 0) { + p_layer = layers.size() + p_layer; + } + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSet::INVALID_SOURCE); + + int source_id = layers[p_layer]->get_cell_source_id(p_coords); + Vector2i atlas_coords = layers[p_layer]->get_cell_atlas_coords(p_coords); + int alternative_id = layers[p_layer]->get_cell_alternative_tile(p_coords); + + Array arr = tile_set->map_tile_proxy(source_id, atlas_coords, alternative_id); + ERR_FAIL_COND_V(arr.size() != 3, TileSet::INVALID_SOURCE); + return arr[0]; + } else { + TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSet::INVALID_SOURCE, get_cell_source_id, p_coords); + } } Vector2i TileMap::get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { - TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_ATLAS_COORDS, get_cell_atlas_coords, p_coords, p_use_proxies); + if (p_use_proxies && tile_set.is_valid()) { + if (p_layer < 0) { + p_layer = layers.size() + p_layer; + } + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSetAtlasSource::INVALID_ATLAS_COORDS); + + int source_id = layers[p_layer]->get_cell_source_id(p_coords); + Vector2i atlas_coords = layers[p_layer]->get_cell_atlas_coords(p_coords); + int alternative_id = layers[p_layer]->get_cell_alternative_tile(p_coords); + + Array arr = tile_set->map_tile_proxy(source_id, atlas_coords, alternative_id); + ERR_FAIL_COND_V(arr.size() != 3, TileSetSource::INVALID_ATLAS_COORDS); + return arr[1]; + } else { + TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_ATLAS_COORDS, get_cell_atlas_coords, p_coords); + } } int TileMap::get_cell_alternative_tile(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { - TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_TILE_ALTERNATIVE, get_cell_alternative_tile, p_coords, p_use_proxies); + if (p_use_proxies && tile_set.is_valid()) { + if (p_layer < 0) { + p_layer = layers.size() + p_layer; + } + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TileSetSource::INVALID_TILE_ALTERNATIVE); + + int source_id = layers[p_layer]->get_cell_source_id(p_coords); + Vector2i atlas_coords = layers[p_layer]->get_cell_atlas_coords(p_coords); + int alternative_id = layers[p_layer]->get_cell_alternative_tile(p_coords); + + Array arr = tile_set->map_tile_proxy(source_id, atlas_coords, alternative_id); + ERR_FAIL_COND_V(arr.size() != 3, TileSetSource::INVALID_TILE_ALTERNATIVE); + return arr[2]; + } else { + TILEMAP_CALL_FOR_LAYER_V(p_layer, TileSetSource::INVALID_TILE_ALTERNATIVE, get_cell_alternative_tile, p_coords); + } } TileData *TileMap::get_cell_tile_data(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { - TILEMAP_CALL_FOR_LAYER_V(p_layer, nullptr, get_cell_tile_data, p_coords, p_use_proxies); + if (p_use_proxies && tile_set.is_valid()) { + if (p_layer < 0) { + p_layer = layers.size() + p_layer; + } + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr); + + int source_id = layers[p_layer]->get_cell_source_id(p_coords); + Vector2i atlas_coords = layers[p_layer]->get_cell_atlas_coords(p_coords); + int alternative_id = layers[p_layer]->get_cell_alternative_tile(p_coords); + + Array arr = tile_set->map_tile_proxy(source_id, atlas_coords, alternative_id); + ERR_FAIL_COND_V(arr.size() != 3, nullptr); + + Ref<TileSetAtlasSource> atlas_source = tile_set->get_source(arr[0]); + if (atlas_source.is_valid()) { + return atlas_source->get_tile_data(arr[1], arr[2]); + } else { + return nullptr; + } + } else { + TILEMAP_CALL_FOR_LAYER_V(p_layer, nullptr, get_cell_tile_data, p_coords); + } } Ref<TileMapPattern> TileMap::get_pattern(int p_layer, TypedArray<Vector2i> p_coords_array) { @@ -451,7 +657,10 @@ void TileMap::set_cells_terrain_path(int p_layer, TypedArray<Vector2i> p_path, i } TileMapCell TileMap::get_cell(int p_layer, const Vector2i &p_coords, bool p_use_proxies) const { - TILEMAP_CALL_FOR_LAYER_V(p_layer, TileMapCell(), get_cell, p_coords, p_use_proxies); + if (p_use_proxies) { + WARN_DEPRECATED_MSG("use_proxies is deprecated."); + } + TILEMAP_CALL_FOR_LAYER_V(p_layer, TileMapCell(), get_cell, p_coords); } Vector2i TileMap::get_coords_for_body_rid(RID p_physics_body) { @@ -478,6 +687,13 @@ void TileMap::fix_invalid_tiles() { } } +#ifdef TOOLS_ENABLED +TileMapLayer *TileMap::duplicate_layer_from_internal(int p_layer) { + ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), nullptr); + return Object::cast_to<TileMapLayer>(layers[p_layer]->duplicate(DUPLICATE_USE_INSTANTIATION | DUPLICATE_FROM_EDITOR)); +} +#endif // TOOLS_ENABLED + void TileMap::clear_layer(int p_layer) { TILEMAP_CALL_FOR_LAYER(p_layer, clear) } @@ -540,10 +756,11 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { add_child(new_layer, false, INTERNAL_MODE_FRONT); new_layer->set_as_tile_map_internal_node(0); new_layer->set_name("Layer0"); + new_layer->set_tile_set(tile_set); new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed)); layers.push_back(new_layer); } - layers[0]->set_tile_data(format, p_value); + _set_tile_map_data_using_compatibility_format(0, format, p_value); _emit_changed(); return true; } @@ -565,6 +782,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { add_child(new_layer, false, INTERNAL_MODE_FRONT); new_layer->set_as_tile_map_internal_node(index); new_layer->set_name(vformat("Layer%d", index)); + new_layer->set_tile_set(tile_set); new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed)); layers.push_back(new_layer); } @@ -596,7 +814,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { set_layer_navigation_enabled(index, p_value); return true; } else if (components[1] == "tile_data") { - layers[index]->set_tile_data(format, p_value); + _set_tile_map_data_using_compatibility_format(index, format, p_value); _emit_changed(); return true; } else { @@ -609,7 +827,7 @@ bool TileMap::_set(const StringName &p_name, const Variant &p_value) { bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { Vector<String> components = String(p_name).split("/", true, 2); if (p_name == "format") { - r_ret = TileMapDataFormat::FORMAT_MAX - 1; // When saving, always save highest format. + r_ret = TileMapDataFormat::TILE_MAP_DATA_FORMAT_MAX - 1; // When saving, always save highest format. return true; } #ifndef DISABLE_DEPRECATED @@ -646,7 +864,7 @@ bool TileMap::_get(const StringName &p_name, Variant &r_ret) const { r_ret = is_layer_navigation_enabled(index); return true; } else if (components[1] == "tile_data") { - r_ret = layers[index]->get_tile_data(); + r_ret = _get_tile_map_data_using_compatibility_format(index); return true; } else { return false; @@ -899,6 +1117,9 @@ void TileMap::_bind_methods() { ClassDB::bind_method(D_METHOD("force_update", "layer"), &TileMap::force_update, DEFVAL(-1)); #endif // DISABLE_DEPRECATED + ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMap::set_tileset); + ClassDB::bind_method(D_METHOD("get_tileset"), &TileMap::get_tileset); + ClassDB::bind_method(D_METHOD("set_rendering_quadrant_size", "size"), &TileMap::set_rendering_quadrant_size); ClassDB::bind_method(D_METHOD("get_rendering_quadrant_size"), &TileMap::get_rendering_quadrant_size); @@ -969,6 +1190,7 @@ void TileMap::_bind_methods() { GDVIRTUAL_BIND(_use_tile_data_runtime_update, "layer", "coords"); GDVIRTUAL_BIND(_tile_data_runtime_update, "layer", "coords", "tile_data"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "rendering_quadrant_size", PROPERTY_HINT_RANGE, "1,128,1"), "set_rendering_quadrant_size", "get_rendering_quadrant_size"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_animatable"), "set_collision_animatable", "is_collision_animatable"); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_collision_visibility_mode", "get_collision_visibility_mode"); @@ -976,7 +1198,7 @@ void TileMap::_bind_methods() { ADD_ARRAY("layers", "layer_"); - ADD_PROPERTY_DEFAULT("format", TileMapDataFormat::FORMAT_1); + ADD_PROPERTY_DEFAULT("format", TileMapDataFormat::TILE_MAP_DATA_FORMAT_1); ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed)); @@ -990,6 +1212,7 @@ TileMap::TileMap() { add_child(new_layer, false, INTERNAL_MODE_FRONT); new_layer->set_as_tile_map_internal_node(0); new_layer->set_name("Layer0"); + new_layer->set_tile_set(tile_set); new_layer->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &TileMap::_emit_changed)); layers.push_back(new_layer); default_layer = memnew(TileMapLayer); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index edea90fa95..41068ea978 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -31,7 +31,7 @@ #ifndef TILE_MAP_H #define TILE_MAP_H -#include "scene/2d/tile_map_layer_group.h" +#include "scene/2d/tile_map_layer.h" #include "scene/resources/2d/tile_set.h" class Control; @@ -39,14 +39,14 @@ class TileMapLayer; class TerrainConstraint; enum TileMapDataFormat { - FORMAT_1 = 0, - FORMAT_2, - FORMAT_3, - FORMAT_MAX, + TILE_MAP_DATA_FORMAT_1 = 0, + TILE_MAP_DATA_FORMAT_2, + TILE_MAP_DATA_FORMAT_3, + TILE_MAP_DATA_FORMAT_MAX, }; -class TileMap : public TileMapLayerGroup { - GDCLASS(TileMap, TileMapLayerGroup) +class TileMap : public Node2D { + GDCLASS(TileMap, Node2D) public: // Kept for compatibility, but should use TileMapLayer::VisibilityMode instead. @@ -60,11 +60,12 @@ private: friend class TileSetPlugin; // A compatibility enum to specify how is the data if formatted. - mutable TileMapDataFormat format = TileMapDataFormat::FORMAT_3; + mutable TileMapDataFormat format = TileMapDataFormat::TILE_MAP_DATA_FORMAT_3; static constexpr float FP_ADJUST = 0.00001; // Properties. + Ref<TileSet> tile_set; int rendering_quadrant_size = 16; bool collision_animatable = false; VisibilityMode collision_visibility_mode = VISIBILITY_MODE_DEFAULT; @@ -78,8 +79,14 @@ private: Transform2D last_valid_transform; Transform2D new_transform; + void _tile_set_changed(); + void _emit_changed(); + // Kept for compatibility with TileMap. With TileMapLayers as individual nodes, the format is stored directly in the array. + void _set_tile_map_data_using_compatibility_format(int p_layer, TileMapDataFormat p_format, const Vector<int> &p_data); + Vector<int> _get_tile_map_data_using_compatibility_format(int p_layer) const; + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -114,6 +121,10 @@ public: static void draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<TileSet> p_tile_set, int p_atlas_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile, int p_frame = -1, Color p_modulation = Color(1.0, 1.0, 1.0, 1.0), const TileData *p_tile_data_override = nullptr, real_t p_normalized_animation_offset = 0.0); + // Accessors. + void set_tileset(const Ref<TileSet> &p_tileset); + Ref<TileSet> get_tileset() const; + // Layers management. int get_layers_count() const; void add_layer(int p_to_pos); @@ -200,6 +211,11 @@ public: // Fixing and clearing methods. void fix_invalid_tiles(); +#ifdef TOOLS_ENABLED + // Moving layers outside of TileMap. + TileMapLayer *duplicate_layer_from_internal(int p_layer); +#endif // TOOLS_ENABLED + // Clears tiles from a given layer. void clear_layer(int p_layer); void clear(); diff --git a/scene/2d/tile_map_layer.cpp b/scene/2d/tile_map_layer.cpp index c7aa4c2be4..3f10eb7661 100644 --- a/scene/2d/tile_map_layer.cpp +++ b/scene/2d/tile_map_layer.cpp @@ -32,6 +32,7 @@ #include "core/core_string_names.h" #include "core/io/marshalls.h" +#include "scene/2d/tile_map.h" #include "scene/gui/control.h" #include "scene/resources/world_2d.h" #include "servers/navigation_server_2d.h" @@ -51,11 +52,10 @@ Vector2i TileMapLayer::_coords_to_debug_quadrant_coords(const Vector2i &p_coords } void TileMapLayer::_debug_update() { - const Ref<TileSet> &tile_set = get_effective_tile_set(); RenderingServer *rs = RenderingServer::get_singleton(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree(); + bool forced_cleanup = in_destructor || !enabled || tile_set.is_null() || !is_visible_in_tree(); if (forced_cleanup) { for (KeyValue<Vector2i, Ref<DebugQuadrant>> &kv : debug_quadrant_map) { @@ -84,7 +84,7 @@ void TileMapLayer::_debug_update() { if (_debug_was_cleaned_up || anything_changed) { // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { CellData &cell_data = kv.value; _debug_quadrants_update_cell(cell_data, dirty_debug_quadrant_list); } @@ -179,33 +179,21 @@ void TileMapLayer::_debug_quadrants_update_cell(CellData &r_cell_data, SelfList< /////////////////////////////// Rendering ////////////////////////////////////// void TileMapLayer::_rendering_update() { - const Ref<TileSet> &tile_set = get_effective_tile_set(); RenderingServer *rs = RenderingServer::get_singleton(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree(); + bool forced_cleanup = in_destructor || !enabled || tile_set.is_null() || !is_visible_in_tree(); // ----------- Layer level processing ----------- if (!forced_cleanup) { // Modulate the layer. Color layer_modulate = get_modulate(); #ifdef TOOLS_ENABLED - const TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(get_parent()); - if (tile_map_layer_group) { - const Vector<StringName> selected_layers = tile_map_layer_group->get_selected_layers(); - if (tile_map_layer_group->is_highlighting_selected_layer() && selected_layers.size() == 1 && get_name() != selected_layers[0]) { - TileMapLayer *selected_layer = Object::cast_to<TileMapLayer>(tile_map_layer_group->get_node_or_null(String(selected_layers[0]))); - if (selected_layer) { - int z_selected = selected_layer->get_z_index(); - int layer_z_index = get_z_index(); - if (layer_z_index < z_selected || (layer_z_index == z_selected && get_index() < selected_layer->get_index())) { - layer_modulate = layer_modulate.darkened(0.5); - } else if (layer_z_index > z_selected || (layer_z_index == z_selected && get_index() > selected_layer->get_index())) { - layer_modulate = layer_modulate.darkened(0.5); - layer_modulate.a *= 0.3; - } - } - } + if (highlight_mode == HIGHLIGHT_MODE_BELOW) { + layer_modulate = layer_modulate.darkened(0.5); + } else if (highlight_mode == HIGHLIGHT_MODE_ABOVE) { + layer_modulate = layer_modulate.darkened(0.5); + layer_modulate.a *= 0.3; } #endif // TOOLS_ENABLED rs->canvas_item_set_modulate(get_canvas_item(), layer_modulate); @@ -219,7 +207,7 @@ void TileMapLayer::_rendering_update() { // Check if anything changed that might change the quadrant shape. // If so, recreate everything. bool quandrant_shape_changed = dirty.flags[DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE] || - (is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET])); + (is_y_sort_enabled() && (dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ENABLED] || dirty.flags[DIRTY_FLAGS_LAYER_Y_SORT_ORIGIN] || dirty.flags[DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM] || dirty.flags[DIRTY_FLAGS_TILE_SET])); // Free all quadrants. if (forced_cleanup || quandrant_shape_changed) { @@ -238,9 +226,9 @@ void TileMapLayer::_rendering_update() { if (!forced_cleanup) { // List all quadrants to update, recreating them if needed. - if (dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || _rendering_was_cleaned_up) { + if (dirty.flags[DIRTY_FLAGS_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || _rendering_was_cleaned_up) { // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { CellData &cell_data = kv.value; _rendering_quadrants_update_cell(cell_data, dirty_rendering_quadrant_list); } @@ -356,6 +344,14 @@ void TileMapLayer::_rendering_update() { // Drawing the tile in the canvas item. TileMap::draw_tile(ci, local_tile_pos - rendering_quadrant->canvas_items_position, tile_set, cell_data.cell.source_id, cell_data.cell.get_atlas_coords(), cell_data.cell.alternative_tile, -1, get_self_modulate(), tile_data, random_animation_offset); } + + // Reset physics interpolation for any recreated canvas items. + if (is_physics_interpolated_and_enabled() && is_visible_in_tree()) { + for (const RID &ci : rendering_quadrant->canvas_items) { + rs->canvas_item_reset_physics_interpolation(ci); + } + } + } else { // Free the quadrant. for (int i = 0; i < rendering_quadrant->canvas_items.size(); i++) { @@ -412,13 +408,13 @@ void TileMapLayer::_rendering_update() { // ----------- Occluders processing ----------- if (forced_cleanup) { // Clean everything. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { _rendering_occluders_clear_cell(kv.value); } } else { - if (_rendering_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]) { + if (_rendering_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_SET]) { // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { _rendering_occluders_update_cell(kv.value); } } else { @@ -437,11 +433,10 @@ void TileMapLayer::_rendering_update() { void TileMapLayer::_rendering_notification(int p_what) { RenderingServer *rs = RenderingServer::get_singleton(); - const Ref<TileSet> &tile_set = get_effective_tile_set(); if (p_what == NOTIFICATION_TRANSFORM_CHANGED || p_what == NOTIFICATION_ENTER_CANVAS || p_what == NOTIFICATION_VISIBILITY_CHANGED) { if (tile_set.is_valid()) { Transform2D tilemap_xform = get_global_transform(); - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { const CellData &cell_data = kv.value; for (const RID &occluder : cell_data.occluders) { if (occluder.is_null()) { @@ -453,12 +448,19 @@ void TileMapLayer::_rendering_notification(int p_what) { } } } + } else if (p_what == NOTIFICATION_RESET_PHYSICS_INTERPOLATION) { + for (const KeyValue<Vector2i, Ref<RenderingQuadrant>> &kv : rendering_quadrant_map) { + for (const RID &ci : kv.value->canvas_items) { + if (ci.is_null()) { + continue; + } + rs->canvas_item_reset_physics_interpolation(ci); + } + } } } void TileMapLayer::_rendering_quadrants_update_cell(CellData &r_cell_data, SelfList<RenderingQuadrant>::List &r_dirty_rendering_quadrant_list) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - // Check if the cell is valid and retrieve its y_sort_origin. bool is_valid = false; int tile_y_sort_origin = 0; @@ -556,7 +558,6 @@ void TileMapLayer::_rendering_occluders_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); RenderingServer *rs = RenderingServer::get_singleton(); // Free unused occluders then resize the occluders array. @@ -625,8 +626,7 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND(!tile_set.is_valid()); + ERR_FAIL_COND(tile_set.is_null()); if (!Engine::get_singleton()->is_editor_hint()) { return; @@ -674,19 +674,17 @@ void TileMapLayer::_rendering_draw_cell_debug(const RID &p_canvas_item, const Ve /////////////////////////////// Physics ////////////////////////////////////// void TileMapLayer::_physics_update() { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !is_inside_tree() || !tile_set.is_valid(); + bool forced_cleanup = in_destructor || !enabled || !collision_enabled || !is_inside_tree() || tile_set.is_null(); if (forced_cleanup) { // Clean everything. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { _physics_clear_cell(kv.value); } } else { - if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { + if (_physics_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { _physics_update_cell(kv.value); } } else { @@ -704,7 +702,6 @@ void TileMapLayer::_physics_update() { } void TileMapLayer::_physics_notification(int p_what) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); Transform2D gl_transform = get_global_transform(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); @@ -712,7 +709,7 @@ void TileMapLayer::_physics_notification(int p_what) { case NOTIFICATION_TRANSFORM_CHANGED: // Move the collisison shapes along with the TileMap. if (is_inside_tree() && tile_set.is_valid()) { - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { const CellData &cell_data = kv.value; for (RID body : cell_data.bodies) { @@ -730,7 +727,7 @@ void TileMapLayer::_physics_notification(int p_what) { if (is_inside_tree()) { RID space = get_world_2d()->get_space(); - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { const CellData &cell_data = kv.value; for (RID body : cell_data.bodies) { @@ -757,7 +754,6 @@ void TileMapLayer::_physics_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); Transform2D gl_transform = get_global_transform(); RID space = get_world_2d()->get_space(); PhysicsServer2D *ps = PhysicsServer2D::get_singleton(); @@ -874,8 +870,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { // Draw the debug collision shapes. - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND(!tile_set.is_valid()); + ERR_FAIL_COND(tile_set.is_null()); if (!get_tree()) { return; @@ -883,13 +878,13 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect bool show_collision = false; switch (collision_visibility_mode) { - case TileMapLayer::VISIBILITY_MODE_DEFAULT: + case TileMapLayer::DEBUG_VISIBILITY_MODE_DEFAULT: show_collision = !Engine::get_singleton()->is_editor_hint() && get_tree()->is_debugging_collisions_hint(); break; - case TileMapLayer::VISIBILITY_MODE_FORCE_HIDE: + case TileMapLayer::DEBUG_VISIBILITY_MODE_FORCE_HIDE: show_collision = false; break; - case TileMapLayer::VISIBILITY_MODE_FORCE_SHOW: + case TileMapLayer::DEBUG_VISIBILITY_MODE_FORCE_SHOW: show_collision = true; break; } @@ -931,10 +926,9 @@ void TileMapLayer::_physics_draw_cell_debug(const RID &p_canvas_item, const Vect void TileMapLayer::_navigation_update() { ERR_FAIL_NULL(NavigationServer2D::get_singleton()); NavigationServer2D *ns = NavigationServer2D::get_singleton(); - const Ref<TileSet> &tile_set = get_effective_tile_set(); // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !is_inside_tree() || !tile_set.is_valid(); + bool forced_cleanup = in_destructor || !enabled || !navigation_enabled || !is_inside_tree() || tile_set.is_null(); // ----------- Layer level processing ----------- // All this processing is kept for compatibility with the TileMap node. @@ -963,13 +957,13 @@ void TileMapLayer::_navigation_update() { // ----------- Navigation regions processing ----------- if (forced_cleanup) { // Clean everything. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { _navigation_clear_cell(kv.value); } } else { - if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_MAP]) { + if (_navigation_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE] || dirty.flags[DIRTY_FLAGS_LAYER_NAVIGATION_MAP]) { // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { _navigation_update_cell(kv.value); } } else { @@ -987,11 +981,10 @@ void TileMapLayer::_navigation_update() { } void TileMapLayer::_navigation_notification(int p_what) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); if (p_what == NOTIFICATION_TRANSFORM_CHANGED) { if (tile_set.is_valid()) { Transform2D tilemap_xform = get_global_transform(); - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { const CellData &cell_data = kv.value; // Update navigation regions transform. for (const RID ®ion : cell_data.navigation_regions) { @@ -1021,7 +1014,6 @@ void TileMapLayer::_navigation_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); NavigationServer2D *ns = NavigationServer2D::get_singleton(); Transform2D gl_xform = get_global_transform(); RID navigation_map = navigation_map_override.is_valid() ? navigation_map_override : get_world_2d()->get_navigation_map(); @@ -1102,13 +1094,13 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V // Draw the debug collision shapes. bool show_navigation = false; switch (navigation_visibility_mode) { - case TileMapLayer::VISIBILITY_MODE_DEFAULT: + case TileMapLayer::DEBUG_VISIBILITY_MODE_DEFAULT: show_navigation = !Engine::get_singleton()->is_editor_hint() && get_tree()->is_debugging_navigation_hint(); break; - case TileMapLayer::VISIBILITY_MODE_FORCE_HIDE: + case TileMapLayer::DEBUG_VISIBILITY_MODE_FORCE_HIDE: show_navigation = false; break; - case TileMapLayer::VISIBILITY_MODE_FORCE_SHOW: + case TileMapLayer::DEBUG_VISIBILITY_MODE_FORCE_SHOW: show_navigation = true; break; } @@ -1121,8 +1113,6 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V return; } - const Ref<TileSet> &tile_set = get_effective_tile_set(); - RenderingServer *rs = RenderingServer::get_singleton(); const NavigationServer2D *ns2d = NavigationServer2D::get_singleton(); @@ -1207,20 +1197,18 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V /////////////////////////////// Scenes ////////////////////////////////////// void TileMapLayer::_scenes_update() { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !is_inside_tree() || !tile_set.is_valid(); + bool forced_cleanup = in_destructor || !enabled || !is_inside_tree() || tile_set.is_null(); if (forced_cleanup) { // Clean everything. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { _scenes_clear_cell(kv.value); } } else { - if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { + if (_scenes_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_SET] || dirty.flags[DIRTY_FLAGS_LAYER_IN_TREE]) { // Update all cells. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { _scenes_update_cell(kv.value); } } else { @@ -1253,8 +1241,6 @@ void TileMapLayer::_scenes_clear_cell(CellData &r_cell_data) { } void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - // Clear the scene in any case. _scenes_clear_cell(r_cell_data); @@ -1295,8 +1281,7 @@ void TileMapLayer::_scenes_update_cell(CellData &r_cell_data) { #ifdef DEBUG_ENABLED void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vector2 &p_quadrant_pos, const CellData &r_cell_data) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND(!tile_set.is_valid()); + ERR_FAIL_COND(tile_set.is_null()); if (!Engine::get_singleton()->is_editor_hint()) { return; @@ -1345,22 +1330,20 @@ void TileMapLayer::_scenes_draw_cell_debug(const RID &p_canvas_item, const Vecto ///////////////////////////////////////////////////////////////////// void TileMapLayer::_build_runtime_update_tile_data() { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - // Check if we should cleanup everything. - bool forced_cleanup = in_destructor || !enabled || !tile_set.is_valid() || !is_visible_in_tree(); + bool forced_cleanup = in_destructor || !enabled || tile_set.is_null() || !is_visible_in_tree(); if (!forced_cleanup) { bool valid_runtime_update = GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update); bool valid_runtime_update_for_tilemap = tile_map_node && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_use_tile_data_runtime_update) && tile_map_node->GDVIRTUAL_IS_OVERRIDDEN(_tile_data_runtime_update); // For keeping compatibility. if (valid_runtime_update || valid_runtime_update_for_tilemap) { bool use_tilemap_for_runtime = valid_runtime_update_for_tilemap && !valid_runtime_update; - if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_LAYER_GROUP_TILE_SET]) { + if (_runtime_update_tile_data_was_cleaned_up || dirty.flags[DIRTY_FLAGS_TILE_SET]) { _runtime_update_needs_all_cells_cleaned_up = true; - for (KeyValue<Vector2i, CellData> &E : tile_map) { + for (KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { _build_runtime_update_tile_data_for_cell(E.value, use_tilemap_for_runtime); } } else if (dirty.flags[DIRTY_FLAGS_LAYER_RUNTIME_UPDATE]) { - for (KeyValue<Vector2i, CellData> &E : tile_map) { + for (KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { _build_runtime_update_tile_data_for_cell(E.value, use_tilemap_for_runtime, true); } } else { @@ -1378,8 +1361,6 @@ void TileMapLayer::_build_runtime_update_tile_data() { } void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_data, bool p_use_tilemap_for_runtime, bool p_auto_add_to_dirty_list) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - TileMapCell &c = r_cell_data.cell; TileSetSource *source; if (tile_set->has_source(c.source_id)) { @@ -1429,7 +1410,7 @@ void TileMapLayer::_build_runtime_update_tile_data_for_cell(CellData &r_cell_dat void TileMapLayer::_clear_runtime_update_tile_data() { if (_runtime_update_needs_all_cells_cleaned_up) { - for (KeyValue<Vector2i, CellData> &E : tile_map) { + for (KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { _clear_runtime_update_tile_data_for_cell(E.value); } _runtime_update_needs_all_cells_cleaned_up = false; @@ -1450,8 +1431,7 @@ void TileMapLayer::_clear_runtime_update_tile_data_for_cell(CellData &r_cell_dat } TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints(int p_terrain_set, const Vector2i &p_position, const RBSet<TerrainConstraint> &p_constraints, TileSet::TerrainsPattern p_current_pattern) const { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (!tile_set.is_valid()) { + if (tile_set.is_null()) { return TileSet::TerrainsPattern(); } // Returns all tiles compatible with the given constraints. @@ -1511,8 +1491,7 @@ TileSet::TerrainsPattern TileMapLayer::_get_best_terrain_pattern_for_constraints } RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (!tile_set.is_valid()) { + if (tile_set.is_null()) { return RBSet<TerrainConstraint>(); } @@ -1532,8 +1511,7 @@ RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_added_patte } RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (!tile_set.is_valid()) { + if (tile_set.is_null()) { return RBSet<TerrainConstraint>(); } @@ -1619,6 +1597,12 @@ RBSet<TerrainConstraint> TileMapLayer::_get_terrain_constraints_from_painted_cel return constraints; } +void TileMapLayer::_tile_set_changed() { + dirty.flags[DIRTY_FLAGS_TILE_SET] = true; + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); +} + void TileMapLayer::_renamed() { emit_signal(CoreStringNames::get_singleton()->changed); } @@ -1689,7 +1673,7 @@ void TileMapLayer::_internal_update() { // Remove cells that are empty after the cleanup. for (const Vector2i &coords : to_delete) { - tile_map.erase(coords); + tile_map_layer_data.erase(coords); } // Clear the dirty cells list. @@ -1737,12 +1721,115 @@ void TileMapLayer::_notification(int p_what) { } void TileMapLayer::_bind_methods() { + // --- Cells manipulation --- + // Generic cells manipulations and access. ClassDB::bind_method(D_METHOD("set_cell", "coords", "source_id", "atlas_coords", "alternative_tile"), &TileMapLayer::set_cell, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(0)); + ClassDB::bind_method(D_METHOD("erase_cell", "coords"), &TileMapLayer::erase_cell); + ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMapLayer::fix_invalid_tiles); + ClassDB::bind_method(D_METHOD("clear"), &TileMapLayer::clear); + + ClassDB::bind_method(D_METHOD("get_cell_source_id", "coords"), &TileMapLayer::get_cell_source_id); + ClassDB::bind_method(D_METHOD("get_cell_atlas_coords", "coords"), &TileMapLayer::get_cell_atlas_coords); + ClassDB::bind_method(D_METHOD("get_cell_alternative_tile", "coords"), &TileMapLayer::get_cell_alternative_tile); + ClassDB::bind_method(D_METHOD("get_cell_tile_data", "coords"), &TileMapLayer::get_cell_tile_data); + + ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMapLayer::get_used_cells); + ClassDB::bind_method(D_METHOD("get_used_cells_by_id", "source_id", "atlas_coords", "alternative_tile"), &TileMapLayer::get_used_cells_by_id, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE)); + ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMapLayer::get_used_rect); + + // Patterns. + ClassDB::bind_method(D_METHOD("get_pattern", "coords_array"), &TileMapLayer::get_pattern); + ClassDB::bind_method(D_METHOD("set_pattern", "position", "pattern"), &TileMapLayer::set_pattern); + + // Terrains. + ClassDB::bind_method(D_METHOD("set_cells_terrain_connect", "cells", "terrain_set", "terrain", "ignore_empty_terrains"), &TileMapLayer::set_cells_terrain_connect, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("set_cells_terrain_path", "path", "terrain_set", "terrain", "ignore_empty_terrains"), &TileMapLayer::set_cells_terrain_path, DEFVAL(true)); + + // --- Physics helpers --- + ClassDB::bind_method(D_METHOD("has_body_rid", "body"), &TileMapLayer::has_body_rid); + ClassDB::bind_method(D_METHOD("get_coords_for_body_rid", "body"), &TileMapLayer::get_coords_for_body_rid); + + // --- Runtime --- + ClassDB::bind_method(D_METHOD("update_internals"), &TileMapLayer::update_internals); + ClassDB::bind_method(D_METHOD("notify_runtime_tile_data_update"), &TileMapLayer::notify_runtime_tile_data_update, DEFVAL(-1)); + + // --- Shortcuts to methods defined in TileSet --- + ClassDB::bind_method(D_METHOD("map_pattern", "position_in_tilemap", "coords_in_pattern", "pattern"), &TileMapLayer::map_pattern); + ClassDB::bind_method(D_METHOD("get_surrounding_cells", "coords"), &TileMapLayer::get_surrounding_cells); + ClassDB::bind_method(D_METHOD("get_neighbor_cell", "coords", "neighbor"), &TileMapLayer::get_neighbor_cell); + ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &TileMapLayer::map_to_local); + ClassDB::bind_method(D_METHOD("local_to_map", "local_position"), &TileMapLayer::local_to_map); + + // --- Accessors --- + ClassDB::bind_method(D_METHOD("set_tile_map_data_from_array", "tile_map_layer_data"), &TileMapLayer::set_tile_map_data_from_array); + ClassDB::bind_method(D_METHOD("get_tile_map_data_as_array"), &TileMapLayer::get_tile_map_data_as_array); + + ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &TileMapLayer::set_enabled); + ClassDB::bind_method(D_METHOD("is_enabled"), &TileMapLayer::is_enabled); + + ClassDB::bind_method(D_METHOD("set_tile_set", "tile_set"), &TileMapLayer::set_tile_set); + ClassDB::bind_method(D_METHOD("get_tile_set"), &TileMapLayer::get_tile_set); + + ClassDB::bind_method(D_METHOD("set_y_sort_origin", "y_sort_origin"), &TileMapLayer::set_y_sort_origin); + ClassDB::bind_method(D_METHOD("get_y_sort_origin"), &TileMapLayer::get_y_sort_origin); + ClassDB::bind_method(D_METHOD("set_rendering_quadrant_size", "size"), &TileMapLayer::set_rendering_quadrant_size); + ClassDB::bind_method(D_METHOD("get_rendering_quadrant_size"), &TileMapLayer::get_rendering_quadrant_size); + + ClassDB::bind_method(D_METHOD("set_collision_enabled", "enabled"), &TileMapLayer::set_collision_enabled); + ClassDB::bind_method(D_METHOD("is_collision_enabled"), &TileMapLayer::is_collision_enabled); + ClassDB::bind_method(D_METHOD("set_use_kinematic_bodies", "use_kinematic_bodies"), &TileMapLayer::set_use_kinematic_bodies); + ClassDB::bind_method(D_METHOD("is_using_kinematic_bodies"), &TileMapLayer::is_using_kinematic_bodies); + ClassDB::bind_method(D_METHOD("set_collision_visibility_mode", "visibility_mode"), &TileMapLayer::set_collision_visibility_mode); + ClassDB::bind_method(D_METHOD("get_collision_visibility_mode"), &TileMapLayer::get_collision_visibility_mode); + + ClassDB::bind_method(D_METHOD("set_navigation_enabled", "enabled"), &TileMapLayer::set_navigation_enabled); + ClassDB::bind_method(D_METHOD("is_navigation_enabled"), &TileMapLayer::is_navigation_enabled); + ClassDB::bind_method(D_METHOD("set_navigation_map", "map"), &TileMapLayer::set_navigation_map); + ClassDB::bind_method(D_METHOD("get_navigation_map"), &TileMapLayer::get_navigation_map); + ClassDB::bind_method(D_METHOD("set_navigation_visibility_mode", "show_navigation"), &TileMapLayer::set_navigation_visibility_mode); + ClassDB::bind_method(D_METHOD("get_navigation_visibility_mode"), &TileMapLayer::get_navigation_visibility_mode); GDVIRTUAL_BIND(_use_tile_data_runtime_update, "coords"); GDVIRTUAL_BIND(_tile_data_runtime_update, "coords", "tile_data"); + ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "tile_map_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_tile_map_data_from_array", "get_tile_map_data_as_array"); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "is_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tile_set", "get_tile_set"); + ADD_GROUP("Rendering", ""); + ADD_PROPERTY(PropertyInfo(Variant::INT, "y_sort_origin"), "set_y_sort_origin", "get_y_sort_origin"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "rendering_quadrant_size"), "set_rendering_quadrant_size", "get_rendering_quadrant_size"); + ADD_GROUP("Physics", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collision_enabled"), "set_collision_enabled", "is_collision_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_kinematic_bodies"), "set_use_kinematic_bodies", "is_using_kinematic_bodies"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_collision_visibility_mode", "get_collision_visibility_mode"); + ADD_GROUP("Navigation", ""); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "navigation_enabled"), "set_navigation_enabled", "is_navigation_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "navigation_visibility_mode", PROPERTY_HINT_ENUM, "Default,Force Show,Force Hide"), "set_navigation_visibility_mode", "get_navigation_visibility_mode"); + ADD_SIGNAL(MethodInfo(CoreStringNames::get_singleton()->changed)); + + ADD_PROPERTY_DEFAULT("tile_map_data_format", TileMapDataFormat::TILE_MAP_DATA_FORMAT_1); + + BIND_ENUM_CONSTANT(DEBUG_VISIBILITY_MODE_DEFAULT); + BIND_ENUM_CONSTANT(DEBUG_VISIBILITY_MODE_FORCE_HIDE); + BIND_ENUM_CONSTANT(DEBUG_VISIBILITY_MODE_FORCE_SHOW); +} + +void TileMapLayer::_update_self_texture_filter(RS::CanvasItemTextureFilter p_texture_filter) { + // Set a default texture filter for the whole tilemap. + CanvasItem::_update_self_texture_filter(p_texture_filter); + dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_FILTER] = true; + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); +} + +void TileMapLayer::_update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat) { + // Set a default texture repeat for the whole tilemap. + CanvasItem::_update_self_texture_repeat(p_texture_repeat); + dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_REPEAT] = true; + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); } void TileMapLayer::set_as_tile_map_internal_node(int p_index) { @@ -1759,7 +1846,6 @@ void TileMapLayer::set_as_tile_map_internal_node(int p_index) { } Rect2 TileMapLayer::get_rect(bool &r_changed) const { - const Ref<TileSet> &tile_set = get_effective_tile_set(); if (tile_set.is_null()) { r_changed = rect_cache != Rect2(); return Rect2(); @@ -1772,7 +1858,7 @@ Rect2 TileMapLayer::get_rect(bool &r_changed) const { if (rect_cache_dirty) { Rect2 r_total; bool first = true; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { + for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { Rect2 r; r.position = tile_set->map_to_local(E.key); r.size = Size2(); @@ -1794,8 +1880,7 @@ Rect2 TileMapLayer::get_rect(bool &r_changed) const { } HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constraints(const Vector<Vector2i> &p_to_replace, int p_terrain_set, const RBSet<TerrainConstraint> &p_constraints) const { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (!tile_set.is_valid()) { + if (tile_set.is_null()) { return HashMap<Vector2i, TileSet::TerrainsPattern>(); } @@ -1843,8 +1928,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_constrain HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) const { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_COND_V(tile_set.is_null(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); // Build list and set of tiles that can be modified (painted and their surroundings). @@ -1949,8 +2033,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_connect(c HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(const Vector<Vector2i> &p_coords_array, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) const { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_COND_V(tile_set.is_null(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); // Make sure the path is correct and build the peering bit list while doing it. @@ -2023,8 +2106,7 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_path(cons HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains) const { HashMap<Vector2i, TileSet::TerrainsPattern> output; - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND_V(!tile_set.is_valid(), output); + ERR_FAIL_COND_V(tile_set.is_null(), output); ERR_FAIL_INDEX_V(p_terrain_set, tile_set->get_terrain_sets_count(), output); // Build list and set of tiles that can be modified (painted and their surroundings). @@ -2074,153 +2156,18 @@ HashMap<Vector2i, TileSet::TerrainsPattern> TileMapLayer::terrain_fill_pattern(c return output; } -TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords, bool p_use_proxies) const { - if (!tile_map.has(p_coords)) { +TileMapCell TileMapLayer::get_cell(const Vector2i &p_coords) const { + if (!tile_map_layer_data.has(p_coords)) { return TileMapCell(); } else { - TileMapCell c = tile_map.find(p_coords)->value.cell; - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (p_use_proxies && tile_set.is_valid()) { - Array proxyed = tile_set->map_tile_proxy(c.source_id, c.get_atlas_coords(), c.alternative_tile); - c.source_id = proxyed[0]; - c.set_atlas_coords(proxyed[1]); - c.alternative_tile = proxyed[2]; - } - return c; + return tile_map_layer_data.find(p_coords)->value.cell; } } -void TileMapLayer::set_tile_data(TileMapDataFormat p_format, const Vector<int> &p_data) { - ERR_FAIL_COND(p_format > TileMapDataFormat::FORMAT_3); - - // Set data for a given tile from raw data. - - int c = p_data.size(); - const int *r = p_data.ptr(); - - int offset = (p_format >= TileMapDataFormat::FORMAT_2) ? 3 : 2; - ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset)); - - clear(); - -#ifdef DISABLE_DEPRECATED - ERR_FAIL_COND_MSG(p_format != TileMapDataFormat::FORMAT_3, vformat("Cannot handle deprecated TileMapLayer data format version %d. This Godot version was compiled with no support for deprecated data.", p_format)); -#endif - - for (int i = 0; i < c; i += offset) { - const uint8_t *ptr = (const uint8_t *)&r[i]; - uint8_t local[12]; - for (int j = 0; j < ((p_format >= TileMapDataFormat::FORMAT_2) ? 12 : 8); j++) { - local[j] = ptr[j]; - } - -#ifdef BIG_ENDIAN_ENABLED - - SWAP(local[0], local[3]); - SWAP(local[1], local[2]); - SWAP(local[4], local[7]); - SWAP(local[5], local[6]); - //TODO: ask someone to check this... - if (FORMAT >= FORMAT_2) { - SWAP(local[8], local[11]); - SWAP(local[9], local[10]); - } -#endif - // Extracts position in TileMap. - int16_t x = decode_uint16(&local[0]); - int16_t y = decode_uint16(&local[2]); - - if (p_format == TileMapDataFormat::FORMAT_3) { - uint16_t source_id = decode_uint16(&local[4]); - uint16_t atlas_coords_x = decode_uint16(&local[6]); - uint16_t atlas_coords_y = decode_uint16(&local[8]); - uint16_t alternative_tile = decode_uint16(&local[10]); - set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile); - } else { -#ifndef DISABLE_DEPRECATED - // Previous decated format. - - uint32_t v = decode_uint32(&local[4]); - // Extract the transform flags that used to be in the tilemap. - bool flip_h = v & (1UL << 29); - bool flip_v = v & (1UL << 30); - bool transpose = v & (1UL << 31); - v &= (1UL << 29) - 1; - - // Extract autotile/atlas coords. - int16_t coord_x = 0; - int16_t coord_y = 0; - if (p_format == TileMapDataFormat::FORMAT_2) { - coord_x = decode_uint16(&local[8]); - coord_y = decode_uint16(&local[10]); - } - - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (tile_set.is_valid()) { - Array a = tile_set->compatibility_tilemap_map(v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose); - if (a.size() == 3) { - set_cell(Vector2i(x, y), a[0], a[1], a[2]); - } else { - ERR_PRINT(vformat("No valid tile in Tileset for: tile:%s coords:%s flip_h:%s flip_v:%s transpose:%s", v, Vector2i(coord_x, coord_y), flip_h, flip_v, transpose)); - } - } else { - int compatibility_alternative_tile = ((int)flip_h) + ((int)flip_v << 1) + ((int)transpose << 2); - set_cell(Vector2i(x, y), v, Vector2i(coord_x, coord_y), compatibility_alternative_tile); - } -#endif - } - } -} - -Vector<int> TileMapLayer::get_tile_data() const { - // Export tile data to raw format. - Vector<int> tile_data; - tile_data.resize(tile_map.size() * 3); - int *w = tile_data.ptrw(); - - // Save in highest format. - - int idx = 0; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - uint8_t *ptr = (uint8_t *)&w[idx]; - encode_uint16((int16_t)(E.key.x), &ptr[0]); - encode_uint16((int16_t)(E.key.y), &ptr[2]); - encode_uint16(E.value.cell.source_id, &ptr[4]); - encode_uint16(E.value.cell.coord_x, &ptr[6]); - encode_uint16(E.value.cell.coord_y, &ptr[8]); - encode_uint16(E.value.cell.alternative_tile, &ptr[10]); - idx += 3; - } - - return tile_data; -} - -void TileMapLayer::notify_tile_map_layer_group_change(DirtyFlags p_what) { - if (p_what == DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS || - p_what == DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED || - p_what == DIRTY_FLAGS_LAYER_GROUP_TILE_SET) { - emit_signal(CoreStringNames::get_singleton()->changed); - } - - dirty.flags[p_what] = true; - _queue_internal_update(); -} - -void TileMapLayer::update_internals() { - pending_update = true; - _deferred_internal_update(); -} - -void TileMapLayer::notify_runtime_tile_data_update() { - dirty.flags[TileMapLayer::DIRTY_FLAGS_LAYER_RUNTIME_UPDATE] = true; - _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); -} - -void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) { +void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile) { // Set the current cell tile (using integer position). Vector2i pk(p_coords); - HashMap<Vector2i, CellData>::Iterator E = tile_map.find(pk); + HashMap<Vector2i, CellData>::Iterator E = tile_map_layer_data.find(pk); int source_id = p_source_id; Vector2i atlas_coords = p_atlas_coords; @@ -2241,7 +2188,7 @@ void TileMapLayer::set_cell(const Vector2i &p_coords, int p_source_id, const Vec // Insert a new cell in the tile map. CellData new_cell_data; new_cell_data.coords = pk; - E = tile_map.insert(pk, new_cell_data); + E = tile_map_layer_data.insert(pk, new_cell_data); } else { if (E->value.cell.source_id == source_id && E->value.cell.get_atlas_coords() == atlas_coords && E->value.cell.alternative_tile == alternative_tile) { return; // Nothing changed. @@ -2266,83 +2213,139 @@ void TileMapLayer::erase_cell(const Vector2i &p_coords) { set_cell(p_coords, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); } -int TileMapLayer::get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies) const { +void TileMapLayer::fix_invalid_tiles() { + ERR_FAIL_COND_MSG(tile_set.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet."); + + RBSet<Vector2i> coords; + for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { + TileSetSource *source = *tile_set->get_source(E.value.cell.source_id); + if (!source || !source->has_tile(E.value.cell.get_atlas_coords()) || !source->has_alternative_tile(E.value.cell.get_atlas_coords(), E.value.cell.alternative_tile)) { + coords.insert(E.key); + } + } + for (const Vector2i &E : coords) { + set_cell(E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); + } +} + +void TileMapLayer::clear() { + // Remove all tiles. + for (KeyValue<Vector2i, CellData> &kv : tile_map_layer_data) { + erase_cell(kv.key); + } + used_rect_cache_dirty = true; +} + +int TileMapLayer::get_cell_source_id(const Vector2i &p_coords) const { // Get a cell source id from position. - HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); + HashMap<Vector2i, CellData>::ConstIterator E = tile_map_layer_data.find(p_coords); if (!E) { return TileSet::INVALID_SOURCE; } - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (p_use_proxies && tile_set.is_valid()) { - Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); - return proxyed[0]; - } - return E->value.cell.source_id; } -Vector2i TileMapLayer::get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies) const { +Vector2i TileMapLayer::get_cell_atlas_coords(const Vector2i &p_coords) const { // Get a cell source id from position. - HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); + HashMap<Vector2i, CellData>::ConstIterator E = tile_map_layer_data.find(p_coords); if (!E) { return TileSetSource::INVALID_ATLAS_COORDS; } - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (p_use_proxies && tile_set.is_valid()) { - Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); - return proxyed[1]; - } - return E->value.cell.get_atlas_coords(); } -int TileMapLayer::get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies) const { +int TileMapLayer::get_cell_alternative_tile(const Vector2i &p_coords) const { // Get a cell source id from position. - HashMap<Vector2i, CellData>::ConstIterator E = tile_map.find(p_coords); + HashMap<Vector2i, CellData>::ConstIterator E = tile_map_layer_data.find(p_coords); if (!E) { return TileSetSource::INVALID_TILE_ALTERNATIVE; } - const Ref<TileSet> &tile_set = get_effective_tile_set(); - if (p_use_proxies && tile_set.is_valid()) { - Array proxyed = tile_set->map_tile_proxy(E->value.cell.source_id, E->value.cell.get_atlas_coords(), E->value.cell.alternative_tile); - return proxyed[2]; - } - return E->value.cell.alternative_tile; } -TileData *TileMapLayer::get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies) const { - int source_id = get_cell_source_id(p_coords, p_use_proxies); +TileData *TileMapLayer::get_cell_tile_data(const Vector2i &p_coords) const { + int source_id = get_cell_source_id(p_coords); if (source_id == TileSet::INVALID_SOURCE) { return nullptr; } - const Ref<TileSet> &tile_set = get_effective_tile_set(); Ref<TileSetAtlasSource> source = tile_set->get_source(source_id); if (source.is_valid()) { - return source->get_tile_data(get_cell_atlas_coords(p_coords, p_use_proxies), get_cell_alternative_tile(p_coords, p_use_proxies)); + return source->get_tile_data(get_cell_atlas_coords(p_coords), get_cell_alternative_tile(p_coords)); } return nullptr; } -void TileMapLayer::clear() { - // Remove all tiles. - for (KeyValue<Vector2i, CellData> &kv : tile_map) { - erase_cell(kv.key); +TypedArray<Vector2i> TileMapLayer::get_used_cells() const { + // Returns the cells used in the tilemap. + TypedArray<Vector2i> a; + for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { + const TileMapCell &c = E.value.cell; + if (c.source_id == TileSet::INVALID_SOURCE) { + continue; + } + a.push_back(E.key); } - used_rect_cache_dirty = true; + + return a; +} + +TypedArray<Vector2i> TileMapLayer::get_used_cells_by_id(int p_source_id, const Vector2i &p_atlas_coords, int p_alternative_tile) const { + // Returns the cells used in the tilemap. + TypedArray<Vector2i> a; + for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { + const TileMapCell &c = E.value.cell; + if (c.source_id == TileSet::INVALID_SOURCE) { + continue; + } + if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == c.source_id) && + (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == c.get_atlas_coords()) && + (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == c.alternative_tile)) { + a.push_back(E.key); + } + } + + return a; +} + +Rect2i TileMapLayer::get_used_rect() const { + // Return the rect of the currently used area. + if (used_rect_cache_dirty) { + used_rect_cache = Rect2i(); + + bool first = true; + for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { + const TileMapCell &c = E.value.cell; + if (c.source_id == TileSet::INVALID_SOURCE) { + continue; + } + if (first) { + used_rect_cache = Rect2i(E.key, Size2i()); + first = false; + } else { + used_rect_cache.expand_to(E.key); + } + } + if (!first) { + // Only if we have at least one cell. + // The cache expands to top-left coordinate, so we add one full tile. + used_rect_cache.size += Vector2i(1, 1); + } + used_rect_cache_dirty = false; + } + + return used_rect_cache; } Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_array) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND_V(!tile_set.is_valid(), nullptr); + ERR_FAIL_COND_V(tile_set.is_null(), nullptr); Ref<TileMapPattern> output; output.instantiate(); @@ -2395,7 +2398,6 @@ Ref<TileMapPattern> TileMapLayer::get_pattern(TypedArray<Vector2i> p_coords_arra } void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); ERR_FAIL_COND(tile_set.is_null()); ERR_FAIL_COND(p_pattern.is_null()); @@ -2407,8 +2409,7 @@ void TileMapLayer::set_pattern(const Vector2i &p_position, const Ref<TileMapPatt } void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND(!tile_set.is_valid()); + ERR_FAIL_COND(tile_set.is_null()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); Vector<Vector2i> cells_vector; @@ -2447,8 +2448,7 @@ void TileMapLayer::set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p } void TileMapLayer::set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains) { - const Ref<TileSet> &tile_set = get_effective_tile_set(); - ERR_FAIL_COND(!tile_set.is_valid()); + ERR_FAIL_COND(tile_set.is_null()); ERR_FAIL_INDEX(p_terrain_set, tile_set->get_terrain_sets_count()); Vector<Vector2i> vector_path; @@ -2487,65 +2487,50 @@ void TileMapLayer::set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_ter } } -TypedArray<Vector2i> TileMapLayer::get_used_cells() const { - // Returns the cells used in the tilemap. - TypedArray<Vector2i> a; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - const TileMapCell &c = E.value.cell; - if (c.source_id == TileSet::INVALID_SOURCE) { - continue; - } - a.push_back(E.key); - } +bool TileMapLayer::has_body_rid(RID p_physics_body) const { + return bodies_coords.has(p_physics_body); +} - return a; +Vector2i TileMapLayer::get_coords_for_body_rid(RID p_physics_body) const { + const Vector2i *found = bodies_coords.getptr(p_physics_body); + ERR_FAIL_NULL_V(found, Vector2i()); + return *found; } -TypedArray<Vector2i> TileMapLayer::get_used_cells_by_id(int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const { - // Returns the cells used in the tilemap. - TypedArray<Vector2i> a; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - const TileMapCell &c = E.value.cell; - if (c.source_id == TileSet::INVALID_SOURCE) { - continue; - } - if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == c.source_id) && - (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == c.get_atlas_coords()) && - (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == c.alternative_tile)) { - a.push_back(E.key); - } - } +void TileMapLayer::update_internals() { + pending_update = true; + _deferred_internal_update(); +} - return a; +void TileMapLayer::notify_runtime_tile_data_update() { + dirty.flags[TileMapLayer::DIRTY_FLAGS_LAYER_RUNTIME_UPDATE] = true; + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); } -Rect2i TileMapLayer::get_used_rect() const { - // Return the rect of the currently used area. - if (used_rect_cache_dirty) { - used_rect_cache = Rect2i(); +Vector2i TileMapLayer::map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern) { + ERR_FAIL_COND_V(tile_set.is_null(), Vector2i()); + return tile_set->map_pattern(p_position_in_tilemap, p_coords_in_pattern, p_pattern); +} - bool first = true; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - const TileMapCell &c = E.value.cell; - if (c.source_id == TileSet::INVALID_SOURCE) { - continue; - } - if (first) { - used_rect_cache = Rect2i(E.key.x, E.key.y, 0, 0); - first = false; - } else { - used_rect_cache.expand_to(E.key); - } - } - if (!first) { - // Only if we have at least one cell. - // The cache expands to top-left coordinate, so we add one full tile. - used_rect_cache.size += Vector2i(1, 1); - } - used_rect_cache_dirty = false; - } +TypedArray<Vector2i> TileMapLayer::get_surrounding_cells(const Vector2i &p_coords) { + ERR_FAIL_COND_V(tile_set.is_null(), TypedArray<Vector2i>()); + return tile_set->get_surrounding_cells(p_coords); +} - return used_rect_cache; +Vector2i TileMapLayer::get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const { + ERR_FAIL_COND_V(tile_set.is_null(), Vector2i()); + return tile_set->get_neighbor_cell(p_coords, p_cell_neighbor); +} + +Vector2 TileMapLayer::map_to_local(const Vector2i &p_pos) const { + ERR_FAIL_COND_V(tile_set.is_null(), Vector2()); + return tile_set->map_to_local(p_pos); +} + +Vector2i TileMapLayer::local_to_map(const Vector2 &p_pos) const { + ERR_FAIL_COND_V(tile_set.is_null(), Vector2i()); + return tile_set->local_to_map(p_pos); } void TileMapLayer::set_enabled(bool p_enabled) { @@ -2556,16 +2541,127 @@ void TileMapLayer::set_enabled(bool p_enabled) { dirty.flags[DIRTY_FLAGS_LAYER_ENABLED] = true; _queue_internal_update(); emit_signal(CoreStringNames::get_singleton()->changed); - - if (tile_map_node) { - tile_map_node->update_configuration_warnings(); - } } bool TileMapLayer::is_enabled() const { return enabled; } +void TileMapLayer::set_tile_set(const Ref<TileSet> &p_tile_set) { + if (p_tile_set == tile_set) { + return; + } + + dirty.flags[DIRTY_FLAGS_TILE_SET] = true; + _queue_internal_update(); + + // Set the TileSet, registering to its changes. + if (tile_set.is_valid()) { + tile_set->disconnect_changed(callable_mp(this, &TileMapLayer::_tile_set_changed)); + } + + tile_set = p_tile_set; + + if (tile_set.is_valid()) { + tile_set->connect_changed(callable_mp(this, &TileMapLayer::_tile_set_changed)); + } + + emit_signal(CoreStringNames::get_singleton()->changed); + + // Trigger updates for TileSet's read-only status. + notify_property_list_changed(); +} + +Ref<TileSet> TileMapLayer::get_tile_set() const { + return tile_set; +} + +void TileMapLayer::set_highlight_mode(HighlightMode p_highlight_mode) { + if (p_highlight_mode == highlight_mode) { + return; + } + highlight_mode = p_highlight_mode; + _queue_internal_update(); +} + +TileMapLayer::HighlightMode TileMapLayer::get_highlight_mode() const { + return highlight_mode; +} + +void TileMapLayer::set_tile_map_data_from_array(const Vector<uint8_t> &p_data) { + const int cell_data_struct_size = 12; + + int size = p_data.size(); + const uint8_t *ptr = p_data.ptr(); + + // Index in the array. + int index = 0; + + // First extract the data version. + ERR_FAIL_COND_MSG(size < 2, "Corrupted tile map data: not enough bytes."); + uint16_t format = decode_uint16(&ptr[index]); + index += 2; + ERR_FAIL_COND_MSG(format >= TileMapLayerDataFormat::TILE_MAP_LAYER_DATA_FORMAT_MAX, vformat("Unsupported tile map data format: %s. Expected format ID lower or equal to: %s", format, TileMapLayerDataFormat::TILE_MAP_LAYER_DATA_FORMAT_MAX - 1)); + + // Clear the TileMap. + clear(); + + while (index < size) { + ERR_FAIL_COND_MSG(index + cell_data_struct_size > size, vformat("Corrupted tile map data: tiles might be missing.")); + + // Get a pointer at the start of the cell data. + const uint8_t *cell_data_ptr = &ptr[index]; + + // Extracts position in TileMap. + int16_t x = decode_uint16(&cell_data_ptr[0]); + int16_t y = decode_uint16(&cell_data_ptr[2]); + + // Extracts the tile identifiers. + uint16_t source_id = decode_uint16(&cell_data_ptr[4]); + uint16_t atlas_coords_x = decode_uint16(&cell_data_ptr[6]); + uint16_t atlas_coords_y = decode_uint16(&cell_data_ptr[8]); + uint16_t alternative_tile = decode_uint16(&cell_data_ptr[10]); + + set_cell(Vector2i(x, y), source_id, Vector2i(atlas_coords_x, atlas_coords_y), alternative_tile); + index += cell_data_struct_size; + } +} + +Vector<uint8_t> TileMapLayer::get_tile_map_data_as_array() const { + const int cell_data_struct_size = 12; + + Vector<uint8_t> tile_map_data_array; + tile_map_data_array.resize(2 + tile_map_layer_data.size() * cell_data_struct_size); + uint8_t *ptr = tile_map_data_array.ptrw(); + + // Index in the array. + int index = 0; + + // Save the version. + encode_uint16(TileMapLayerDataFormat::TILE_MAP_LAYER_DATA_FORMAT_MAX - 1, &ptr[index]); + index += 2; + + // Save in highest format. + for (const KeyValue<Vector2i, CellData> &E : tile_map_layer_data) { + // Get a pointer at the start of the cell data. + uint8_t *cell_data_ptr = (uint8_t *)&ptr[index]; + + // Store position in TileMap. + encode_uint16((int16_t)(E.key.x), &cell_data_ptr[0]); + encode_uint16((int16_t)(E.key.y), &cell_data_ptr[2]); + + // Store the tile identifiers. + encode_uint16(E.value.cell.source_id, &cell_data_ptr[4]); + encode_uint16(E.value.cell.coord_x, &cell_data_ptr[6]); + encode_uint16(E.value.cell.coord_y, &cell_data_ptr[8]); + encode_uint16(E.value.cell.alternative_tile, &cell_data_ptr[10]); + + index += cell_data_struct_size; + } + + return tile_map_data_array; +} + void TileMapLayer::set_self_modulate(const Color &p_self_modulate) { if (get_self_modulate() == p_self_modulate) { return; @@ -2585,9 +2681,6 @@ void TileMapLayer::set_y_sort_enabled(bool p_y_sort_enabled) { _queue_internal_update(); emit_signal(CoreStringNames::get_singleton()->changed); - if (tile_map_node) { - tile_map_node->update_configuration_warnings(); - } _update_notify_local_transform(); } @@ -2613,10 +2706,6 @@ void TileMapLayer::set_z_index(int p_z_index) { dirty.flags[DIRTY_FLAGS_LAYER_Z_INDEX] = true; _queue_internal_update(); emit_signal(CoreStringNames::get_singleton()->changed); - - if (tile_map_node) { - tile_map_node->update_configuration_warnings(); - } } void TileMapLayer::set_light_mask(int p_light_mask) { @@ -2629,22 +2718,6 @@ void TileMapLayer::set_light_mask(int p_light_mask) { emit_signal(CoreStringNames::get_singleton()->changed); } -void TileMapLayer::set_texture_filter(TextureFilter p_texture_filter) { - // Set a default texture filter for the whole tilemap. - CanvasItem::set_texture_filter(p_texture_filter); - dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_FILTER] = true; - _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); -} - -void TileMapLayer::set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) { - // Set a default texture repeat for the whole tilemap. - CanvasItem::set_texture_repeat(p_texture_repeat); - dirty.flags[DIRTY_FLAGS_LAYER_TEXTURE_REPEAT] = true; - _queue_internal_update(); - emit_signal(CoreStringNames::get_singleton()->changed); -} - void TileMapLayer::set_rendering_quadrant_size(int p_size) { if (rendering_quadrant_size == p_size) { return; @@ -2661,6 +2734,20 @@ int TileMapLayer::get_rendering_quadrant_size() const { return rendering_quadrant_size; } +void TileMapLayer::set_collision_enabled(bool p_enabled) { + if (collision_enabled == p_enabled) { + return; + } + collision_enabled = p_enabled; + dirty.flags[DIRTY_FLAGS_LAYER_COLLISION_ENABLED] = true; + _queue_internal_update(); + emit_signal(CoreStringNames::get_singleton()->changed); +} + +bool TileMapLayer::is_collision_enabled() const { + return collision_enabled; +} + void TileMapLayer::set_use_kinematic_bodies(bool p_use_kinematic_bodies) { use_kinematic_bodies = p_use_kinematic_bodies; dirty.flags[DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES] = p_use_kinematic_bodies; @@ -2672,7 +2759,7 @@ bool TileMapLayer::is_using_kinematic_bodies() const { return use_kinematic_bodies; } -void TileMapLayer::set_collision_visibility_mode(TileMapLayer::VisibilityMode p_show_collision) { +void TileMapLayer::set_collision_visibility_mode(TileMapLayer::DebugVisibilityMode p_show_collision) { if (collision_visibility_mode == p_show_collision) { return; } @@ -2682,7 +2769,7 @@ void TileMapLayer::set_collision_visibility_mode(TileMapLayer::VisibilityMode p_ emit_signal(CoreStringNames::get_singleton()->changed); } -TileMapLayer::VisibilityMode TileMapLayer::get_collision_visibility_mode() const { +TileMapLayer::DebugVisibilityMode TileMapLayer::get_collision_visibility_mode() const { return collision_visibility_mode; } @@ -2719,7 +2806,7 @@ RID TileMapLayer::get_navigation_map() const { return RID(); } -void TileMapLayer::set_navigation_visibility_mode(TileMapLayer::VisibilityMode p_show_navigation) { +void TileMapLayer::set_navigation_visibility_mode(TileMapLayer::DebugVisibilityMode p_show_navigation) { if (navigation_visibility_mode == p_show_navigation) { return; } @@ -2729,43 +2816,10 @@ void TileMapLayer::set_navigation_visibility_mode(TileMapLayer::VisibilityMode p emit_signal(CoreStringNames::get_singleton()->changed); } -TileMapLayer::VisibilityMode TileMapLayer::get_navigation_visibility_mode() const { +TileMapLayer::DebugVisibilityMode TileMapLayer::get_navigation_visibility_mode() const { return navigation_visibility_mode; } -void TileMapLayer::fix_invalid_tiles() { - Ref<TileSet> tileset = get_effective_tile_set(); - ERR_FAIL_COND_MSG(tileset.is_null(), "Cannot call fix_invalid_tiles() on a TileMap without a valid TileSet."); - - RBSet<Vector2i> coords; - for (const KeyValue<Vector2i, CellData> &E : tile_map) { - TileSetSource *source = *tileset->get_source(E.value.cell.source_id); - if (!source || !source->has_tile(E.value.cell.get_atlas_coords()) || !source->has_alternative_tile(E.value.cell.get_atlas_coords(), E.value.cell.alternative_tile)) { - coords.insert(E.key); - } - } - for (const Vector2i &E : coords) { - set_cell(E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE); - } -} - -bool TileMapLayer::has_body_rid(RID p_physics_body) const { - return bodies_coords.has(p_physics_body); -} - -Vector2i TileMapLayer::get_coords_for_body_rid(RID p_physics_body) const { - return bodies_coords[p_physics_body]; -} - -Ref<TileSet> TileMapLayer::get_effective_tile_set() const { - TileMapLayerGroup *tile_map_layer_group = Object::cast_to<TileMapLayerGroup>(get_parent()); - if (tile_map_layer_group) { - return tile_map_layer_group->get_tileset(); - } else { - return Ref<TileSet>(); - } -} - TileMapLayer::TileMapLayer() { set_notify_transform(true); } diff --git a/scene/2d/tile_map_layer.h b/scene/2d/tile_map_layer.h index c58c72949c..da48eb38d9 100644 --- a/scene/2d/tile_map_layer.h +++ b/scene/2d/tile_map_layer.h @@ -31,10 +31,15 @@ #ifndef TILE_MAP_LAYER_H #define TILE_MAP_LAYER_H -#include "scene/2d/tile_map.h" #include "scene/resources/2d/tile_set.h" class TileSetAtlasSource; +class TileMap; + +enum TileMapLayerDataFormat { + TILE_MAP_LAYER_DATA_FORMAT_0 = 0, + TILE_MAP_LAYER_DATA_FORMAT_MAX, +}; class TerrainConstraint { private: @@ -218,14 +223,21 @@ class TileMapLayer : public Node2D { GDCLASS(TileMapLayer, Node2D); public: - enum VisibilityMode { - VISIBILITY_MODE_DEFAULT, - VISIBILITY_MODE_FORCE_SHOW, - VISIBILITY_MODE_FORCE_HIDE, + enum HighlightMode { + HIGHLIGHT_MODE_DEFAULT, + HIGHLIGHT_MODE_ABOVE, + HIGHLIGHT_MODE_BELOW, + }; + + enum DebugVisibilityMode { + DEBUG_VISIBILITY_MODE_DEFAULT, + DEBUG_VISIBILITY_MODE_FORCE_SHOW, + DEBUG_VISIBILITY_MODE_FORCE_HIDE, }; enum DirtyFlags { DIRTY_FLAGS_LAYER_ENABLED = 0, + DIRTY_FLAGS_LAYER_IN_TREE, DIRTY_FLAGS_LAYER_IN_CANVAS, DIRTY_FLAGS_LAYER_LOCAL_TRANSFORM, @@ -238,6 +250,7 @@ public: DIRTY_FLAGS_LAYER_TEXTURE_FILTER, DIRTY_FLAGS_LAYER_TEXTURE_REPEAT, DIRTY_FLAGS_LAYER_RENDERING_QUADRANT_SIZE, + DIRTY_FLAGS_LAYER_COLLISION_ENABLED, DIRTY_FLAGS_LAYER_USE_KINEMATIC_BODIES, DIRTY_FLAGS_LAYER_COLLISION_VISIBILITY_MODE, DIRTY_FLAGS_LAYER_NAVIGATION_ENABLED, @@ -249,26 +262,33 @@ public: DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS, DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED, - DIRTY_FLAGS_LAYER_GROUP_TILE_SET, + + DIRTY_FLAGS_TILE_SET, DIRTY_FLAGS_MAX, }; private: - // Exposed properties. + // Properties. + HashMap<Vector2i, CellData> tile_map_layer_data; + bool enabled = true; + Ref<TileSet> tile_set; + + HighlightMode highlight_mode = HIGHLIGHT_MODE_DEFAULT; + int y_sort_origin = 0; int rendering_quadrant_size = 16; + bool collision_enabled = true; bool use_kinematic_bodies = false; - VisibilityMode collision_visibility_mode = VISIBILITY_MODE_DEFAULT; + DebugVisibilityMode collision_visibility_mode = DEBUG_VISIBILITY_MODE_DEFAULT; bool navigation_enabled = true; RID navigation_map_override; - VisibilityMode navigation_visibility_mode = VISIBILITY_MODE_DEFAULT; + DebugVisibilityMode navigation_visibility_mode = DEBUG_VISIBILITY_MODE_DEFAULT; // Internal. - HashMap<Vector2i, CellData> tile_map; bool pending_update = false; // For keeping compatibility with TileMap. @@ -348,6 +368,8 @@ private: RBSet<TerrainConstraint> _get_terrain_constraints_from_added_pattern(const Vector2i &p_position, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern) const; RBSet<TerrainConstraint> _get_terrain_constraints_from_painted_cells_list(const RBSet<Vector2i> &p_painted, int p_terrain_set, bool p_ignore_empty_terrains) const; + void _tile_set_changed(); + void _renamed(); void _update_notify_local_transform(); @@ -358,11 +380,21 @@ private: protected: void _notification(int p_what); + static void _bind_methods(); + virtual void _update_self_texture_filter(RS::CanvasItemTextureFilter p_texture_filter) override; + virtual void _update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat) override; + public: // TileMap node. void set_as_tile_map_internal_node(int p_index); + int get_index_in_tile_map() const { + return layer_index_in_tile_map_node; + } + const HashMap<Vector2i, CellData> &get_tile_map_layer_data() const { + return tile_map_layer_data; + } // Rect caching. Rect2 get_rect(bool &r_changed) const; @@ -374,27 +406,26 @@ public: HashMap<Vector2i, TileSet::TerrainsPattern> terrain_fill_pattern(const Vector<Vector2i> &p_coords_array, int p_terrain_set, TileSet::TerrainsPattern p_terrains_pattern, bool p_ignore_empty_terrains = true) const; // Not exposed. // Not exposed to users. - TileMapCell get_cell(const Vector2i &p_coords, bool p_use_proxies = false) const; + TileMapCell get_cell(const Vector2i &p_coords) const; - // For TileMap node's use. - void set_tile_data(TileMapDataFormat p_format, const Vector<int> &p_data); - Vector<int> get_tile_data() const; - void notify_tile_map_layer_group_change(DirtyFlags p_what); - - void update_internals(); - void notify_runtime_tile_data_update(); + ////////////// Exposed functions ////////////// - // --- Exposed in TileMap --- - // Cells manipulation. - void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); + // --- Cells manipulation --- + // Generic cells manipulations and data access. + void set_cell(const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i &p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0); void erase_cell(const Vector2i &p_coords); - - int get_cell_source_id(const Vector2i &p_coords, bool p_use_proxies = false) const; - Vector2i get_cell_atlas_coords(const Vector2i &p_coords, bool p_use_proxies = false) const; - int get_cell_alternative_tile(const Vector2i &p_coords, bool p_use_proxies = false) const; - TileData *get_cell_tile_data(const Vector2i &p_coords, bool p_use_proxies = false) const; // Helper method to make accessing the data easier. + void fix_invalid_tiles(); void clear(); + int get_cell_source_id(const Vector2i &p_coords) const; + Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const; + int get_cell_alternative_tile(const Vector2i &p_coords) const; + TileData *get_cell_tile_data(const Vector2i &p_coords) const; // Helper method to make accessing the data easier. + + TypedArray<Vector2i> get_used_cells() const; + TypedArray<Vector2i> get_used_cells_by_id(int p_source_id = TileSet::INVALID_SOURCE, const Vector2i &p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const; + Rect2i get_used_rect() const; + // Patterns. Ref<TileMapPattern> get_pattern(TypedArray<Vector2i> p_coords_array); void set_pattern(const Vector2i &p_position, const Ref<TileMapPattern> p_pattern); @@ -403,54 +434,62 @@ public: void set_cells_terrain_connect(TypedArray<Vector2i> p_cells, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); void set_cells_terrain_path(TypedArray<Vector2i> p_path, int p_terrain_set, int p_terrain, bool p_ignore_empty_terrains = true); - // Cells usage. - TypedArray<Vector2i> get_used_cells() const; - TypedArray<Vector2i> get_used_cells_by_id(int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const; - Rect2i get_used_rect() const; + // --- Physics helpers --- + bool has_body_rid(RID p_physics_body) const; + Vector2i get_coords_for_body_rid(RID p_physics_body) const; // For finding tiles from collision. + + // --- Runtime --- + void update_internals(); + void notify_runtime_tile_data_update(); + GDVIRTUAL1R(bool, _use_tile_data_runtime_update, Vector2i); + GDVIRTUAL2(_tile_data_runtime_update, Vector2i, TileData *); + + // --- Shortcuts to methods defined in TileSet --- + Vector2i map_pattern(const Vector2i &p_position_in_tilemap, const Vector2i &p_coords_in_pattern, Ref<TileMapPattern> p_pattern); + TypedArray<Vector2i> get_surrounding_cells(const Vector2i &p_coords); + Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const; + Vector2 map_to_local(const Vector2i &p_pos) const; + Vector2i local_to_map(const Vector2 &p_pos) const; + + // --- Accessors --- + void set_tile_map_data_from_array(const Vector<uint8_t> &p_data); + Vector<uint8_t> get_tile_map_data_as_array() const; - // Layer properties. void set_enabled(bool p_enabled); bool is_enabled() const; + void set_tile_set(const Ref<TileSet> &p_tile_set); + Ref<TileSet> get_tile_set() const; + + void set_highlight_mode(HighlightMode p_highlight_mode); + HighlightMode get_highlight_mode() const; + virtual void set_self_modulate(const Color &p_self_modulate) override; virtual void set_y_sort_enabled(bool p_y_sort_enabled) override; void set_y_sort_origin(int p_y_sort_origin); int get_y_sort_origin() const; virtual void set_z_index(int p_z_index) override; virtual void set_light_mask(int p_light_mask) override; - virtual void set_texture_filter(CanvasItem::TextureFilter p_texture_filter) override; - virtual void set_texture_repeat(CanvasItem::TextureRepeat p_texture_repeat) override; void set_rendering_quadrant_size(int p_size); int get_rendering_quadrant_size() const; + void set_collision_enabled(bool p_enabled); + bool is_collision_enabled() const; void set_use_kinematic_bodies(bool p_use_kinematic_bodies); bool is_using_kinematic_bodies() const; - void set_collision_visibility_mode(VisibilityMode p_show_collision); - VisibilityMode get_collision_visibility_mode() const; + void set_collision_visibility_mode(DebugVisibilityMode p_show_collision); + DebugVisibilityMode get_collision_visibility_mode() const; void set_navigation_enabled(bool p_enabled); bool is_navigation_enabled() const; void set_navigation_map(RID p_map); RID get_navigation_map() const; - void set_navigation_visibility_mode(VisibilityMode p_show_navigation); - VisibilityMode get_navigation_visibility_mode() const; - - // Fixing and clearing methods. - void fix_invalid_tiles(); - - // Find coords for body. - bool has_body_rid(RID p_physics_body) const; - Vector2i get_coords_for_body_rid(RID p_physics_body) const; // For finding tiles from collision. - - // Helper. - Ref<TileSet> get_effective_tile_set() const; - - // Virtual function to modify the TileData at runtime. - GDVIRTUAL1R(bool, _use_tile_data_runtime_update, Vector2i); - GDVIRTUAL2(_tile_data_runtime_update, Vector2i, TileData *); - // --- + void set_navigation_visibility_mode(DebugVisibilityMode p_show_navigation); + DebugVisibilityMode get_navigation_visibility_mode() const; TileMapLayer(); ~TileMapLayer(); }; +VARIANT_ENUM_CAST(TileMapLayer::DebugVisibilityMode); + #endif // TILE_MAP_LAYER_H diff --git a/scene/2d/tile_map_layer_group.cpp b/scene/2d/tile_map_layer_group.cpp deleted file mode 100644 index 132b4bbba5..0000000000 --- a/scene/2d/tile_map_layer_group.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/**************************************************************************/ -/* tile_map_layer_group.cpp */ -/**************************************************************************/ -/* 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. */ -/**************************************************************************/ - -#include "tile_map_layer_group.h" - -#include "core/core_string_names.h" -#include "scene/2d/tile_map_layer.h" -#include "scene/resources/2d/tile_set.h" - -#ifdef TOOLS_ENABLED - -void TileMapLayerGroup::_cleanup_selected_layers() { - for (int i = 0; i < selected_layers.size(); i++) { - const String name = selected_layers[i]; - TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_node_or_null(name)); - if (!layer) { - selected_layers.remove_at(i); - i--; - } - } -} - -#endif // TOOLS_ENABLED - -void TileMapLayerGroup::_tile_set_changed() { - for (int i = 0; i < get_child_count(); i++) { - TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); - if (layer) { - layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET); - } - } - - update_configuration_warnings(); -} - -#ifdef TOOLS_ENABLED - -void TileMapLayerGroup::set_selected_layers(Vector<StringName> p_layer_names) { - selected_layers = p_layer_names; - _cleanup_selected_layers(); - - // Update the layers modulation. - for (int i = 0; i < get_child_count(); i++) { - TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); - if (layer) { - layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_SELECTED_LAYERS); - } - } -} - -Vector<StringName> TileMapLayerGroup::get_selected_layers() const { - return selected_layers; -} - -void TileMapLayerGroup::set_highlight_selected_layer(bool p_highlight_selected_layer) { - if (highlight_selected_layer == p_highlight_selected_layer) { - return; - } - - highlight_selected_layer = p_highlight_selected_layer; - - for (int i = 0; i < get_child_count(); i++) { - TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); - if (layer) { - layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_HIGHLIGHT_SELECTED); - } - } -} - -bool TileMapLayerGroup::is_highlighting_selected_layer() const { - return highlight_selected_layer; -} - -#endif // TOOLS_ENABLED - -void TileMapLayerGroup::remove_child_notify(Node *p_child) { -#ifdef TOOLS_ENABLED - _cleanup_selected_layers(); -#endif // TOOLS_ENABLED -} - -void TileMapLayerGroup::_bind_methods() { - ClassDB::bind_method(D_METHOD("set_tileset", "tileset"), &TileMapLayerGroup::set_tileset); - ClassDB::bind_method(D_METHOD("get_tileset"), &TileMapLayerGroup::get_tileset); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "tile_set", PROPERTY_HINT_RESOURCE_TYPE, "TileSet"), "set_tileset", "get_tileset"); -} - -void TileMapLayerGroup::set_tileset(const Ref<TileSet> &p_tileset) { - if (p_tileset == tile_set) { - return; - } - - // Set the tileset, registering to its changes. - if (tile_set.is_valid()) { - tile_set->disconnect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed)); - } - - tile_set = p_tileset; - - if (tile_set.is_valid()) { - tile_set->connect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed)); - } - - for (int i = 0; i < get_child_count(); i++) { - TileMapLayer *layer = Object::cast_to<TileMapLayer>(get_child(i)); - if (layer) { - layer->notify_tile_map_layer_group_change(TileMapLayer::DIRTY_FLAGS_LAYER_GROUP_TILE_SET); - } - } -} - -Ref<TileSet> TileMapLayerGroup::get_tileset() const { - return tile_set; -} - -TileMapLayerGroup::~TileMapLayerGroup() { - if (tile_set.is_valid()) { - tile_set->disconnect_changed(callable_mp(this, &TileMapLayerGroup::_tile_set_changed)); - } -} diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp index 6878df21d8..caabb4225f 100644 --- a/scene/3d/decal.cpp +++ b/scene/3d/decal.cpp @@ -31,7 +31,7 @@ #include "decal.h" void Decal::set_size(const Vector3 &p_size) { - size = Vector3(MAX(0.001, p_size.x), MAX(0.001, p_size.y), MAX(0.001, p_size.z)); + size = p_size.max(Vector3(0.001, 0.001, 0.001)); RS::get_singleton()->decal_set_size(decal, size); update_gizmos(); } diff --git a/scene/3d/fog_volume.cpp b/scene/3d/fog_volume.cpp index 12ca1888c4..8af386f282 100644 --- a/scene/3d/fog_volume.cpp +++ b/scene/3d/fog_volume.cpp @@ -73,9 +73,7 @@ bool FogVolume::_get(const StringName &p_name, Variant &r_property) const { void FogVolume::set_size(const Vector3 &p_size) { size = p_size; - size.x = MAX(0.0, size.x); - size.y = MAX(0.0, size.y); - size.z = MAX(0.0, size.z); + size = size.max(Vector3()); RS::get_singleton()->fog_volume_set_size(_get_volume(), size); update_gizmos(); } diff --git a/scene/3d/gpu_particles_collision_3d.cpp b/scene/3d/gpu_particles_collision_3d.cpp index cbc75801b0..8fd5f25749 100644 --- a/scene/3d/gpu_particles_collision_3d.cpp +++ b/scene/3d/gpu_particles_collision_3d.cpp @@ -330,7 +330,7 @@ void GPUParticlesCollisionSDF3D::_find_closest_distance(const Vector3 &p_pos, co Vector3 center = p_bvh[p_bvh_cell].bounds.position + he; Vector3 rel = (p_pos - center).abs(); - Vector3 closest(MIN(rel.x, he.x), MIN(rel.y, he.y), MIN(rel.z, he.z)); + Vector3 closest = rel.min(he); float d = rel.distance_to(closest); if (d >= r_closest_distance) { @@ -382,9 +382,7 @@ Vector3i GPUParticlesCollisionSDF3D::get_estimated_cell_size() const { float cell_size = aabb.get_longest_axis_size() / float(subdiv); Vector3i sdf_size = Vector3i(aabb.size / cell_size); - sdf_size.x = MAX(1, sdf_size.x); - sdf_size.y = MAX(1, sdf_size.y); - sdf_size.z = MAX(1, sdf_size.z); + sdf_size = sdf_size.max(Vector3i(1, 1, 1)); return sdf_size; } @@ -397,9 +395,7 @@ Ref<Image> GPUParticlesCollisionSDF3D::bake() { float cell_size = aabb.get_longest_axis_size() / float(subdiv); Vector3i sdf_size = Vector3i(aabb.size / cell_size); - sdf_size.x = MAX(1, sdf_size.x); - sdf_size.y = MAX(1, sdf_size.y); - sdf_size.z = MAX(1, sdf_size.z); + sdf_size = sdf_size.max(Vector3i(1, 1, 1)); if (bake_begin_function) { bake_begin_function(100); diff --git a/scene/3d/occluder_instance_3d.cpp b/scene/3d/occluder_instance_3d.cpp index 8d995a8785..2f77185d0d 100644 --- a/scene/3d/occluder_instance_3d.cpp +++ b/scene/3d/occluder_instance_3d.cpp @@ -236,7 +236,7 @@ void BoxOccluder3D::set_size(const Vector3 &p_size) { return; } - size = Vector3(MAX(p_size.x, 0.0f), MAX(p_size.y, 0.0f), MAX(p_size.z, 0.0f)); + size = p_size.max(Vector3()); _update(); } diff --git a/scene/3d/voxel_gi.cpp b/scene/3d/voxel_gi.cpp index eb8569fa30..938d6e5699 100644 --- a/scene/3d/voxel_gi.cpp +++ b/scene/3d/voxel_gi.cpp @@ -294,7 +294,7 @@ VoxelGI::Subdiv VoxelGI::get_subdiv() const { void VoxelGI::set_size(const Vector3 &p_size) { // Prevent very small size dimensions as these breaks baking if other size dimensions are set very high. - size = Vector3(MAX(1.0, p_size.x), MAX(1.0, p_size.y), MAX(1.0, p_size.z)); + size = p_size.max(Vector3(1.0, 1.0, 1.0)); update_gizmos(); } diff --git a/scene/3d/xr_body_modifier_3d.cpp b/scene/3d/xr_body_modifier_3d.cpp index 477241947a..ac648d66d0 100644 --- a/scene/3d/xr_body_modifier_3d.cpp +++ b/scene/3d/xr_body_modifier_3d.cpp @@ -252,11 +252,6 @@ void XRBodyModifier3D::_get_joint_data() { } } - // If the root bone is not found then use the skeleton root bone. - if (bones[XRBodyTracker::JOINT_ROOT] == -1) { - bones[XRBodyTracker::JOINT_ROOT] = 0; - } - // Assemble the joint relationship to the available skeleton bones. for (int i = 0; i < XRBodyTracker::JOINT_MAX; i++) { // Get the skeleton bone (skip if not found). diff --git a/scene/animation/animation_blend_space_1d.cpp b/scene/animation/animation_blend_space_1d.cpp index 4cbd9b1d76..36343edd11 100644 --- a/scene/animation/animation_blend_space_1d.cpp +++ b/scene/animation/animation_blend_space_1d.cpp @@ -33,12 +33,17 @@ #include "animation_blend_tree.h" void AnimationNodeBlendSpace1D::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::FLOAT, blend_position)); r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); - r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } Variant AnimationNodeBlendSpace1D::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + if (p_parameter == closest) { return -1; } else { @@ -272,9 +277,9 @@ void AnimationNodeBlendSpace1D::_add_blend_point(int p_index, const Ref<Animatio } } -double AnimationNodeBlendSpace1D::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeBlendSpace1D::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { if (blend_points_used == 0) { - return 0.0; + return NodeTimeInfo(); } AnimationMixer::PlaybackInfo pi = p_playback_info; @@ -287,8 +292,7 @@ double AnimationNodeBlendSpace1D::_process(const AnimationMixer::PlaybackInfo p_ double blend_pos = get_parameter(blend_position); int cur_closest = get_parameter(closest); - double cur_length_internal = get_parameter(length_internal); - double max_time_remaining = 0.0; + NodeTimeInfo mind; if (blend_mode == BLEND_MODE_INTERPOLATED) { int point_lower = -1; @@ -341,12 +345,17 @@ double AnimationNodeBlendSpace1D::_process(const AnimationMixer::PlaybackInfo p_ } // actually blend the animations now - + bool first = true; + double max_weight = 0.0; for (int i = 0; i < blend_points_used; i++) { if (i == point_lower || i == point_higher) { pi.weight = weights[i]; - double remaining = blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only); - max_time_remaining = MAX(max_time_remaining, remaining); + NodeTimeInfo t = blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only); + if (first || pi.weight > max_weight) { + max_weight = pi.weight; + mind = t; + first = false; + } } else if (sync) { pi.weight = 0; blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only); @@ -365,7 +374,7 @@ double AnimationNodeBlendSpace1D::_process(const AnimationMixer::PlaybackInfo p_ } if (new_closest != cur_closest && new_closest != -1) { - double from = 0.0; + NodeTimeInfo from; if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) { //for ping-pong loop Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node); @@ -376,18 +385,17 @@ double AnimationNodeBlendSpace1D::_process(const AnimationMixer::PlaybackInfo p_ //see how much animation remains pi.seeked = false; pi.weight = 0; - from = cur_length_internal - blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only); + from = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only); } - pi.time = from; + pi.time = from.position; pi.seeked = true; pi.weight = 1.0; - max_time_remaining = blend_node(blend_points[new_closest].node, blend_points[new_closest].name, pi, FILTER_IGNORE, true, p_test_only); - cur_length_internal = from + max_time_remaining; + mind = blend_node(blend_points[new_closest].node, blend_points[new_closest].name, pi, FILTER_IGNORE, true, p_test_only); cur_closest = new_closest; } else { pi.weight = 1.0; - max_time_remaining = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only); + mind = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only); } if (sync) { @@ -402,8 +410,7 @@ double AnimationNodeBlendSpace1D::_process(const AnimationMixer::PlaybackInfo p_ } set_parameter(closest, cur_closest); - set_parameter(length_internal, cur_length_internal); - return max_time_remaining; + return mind; } String AnimationNodeBlendSpace1D::get_caption() const { diff --git a/scene/animation/animation_blend_space_1d.h b/scene/animation/animation_blend_space_1d.h index 40679d55ef..64ae4d0505 100644 --- a/scene/animation/animation_blend_space_1d.h +++ b/scene/animation/animation_blend_space_1d.h @@ -68,7 +68,6 @@ protected: StringName blend_position = "blend_position"; StringName closest = "closest"; - StringName length_internal = "length_internal"; BlendMode blend_mode = BLEND_MODE_INTERPOLATED; @@ -114,7 +113,7 @@ public: void set_use_sync(bool p_sync); bool is_using_sync() const; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; String get_caption() const override; Ref<AnimationNode> get_child_by_name(const StringName &p_name) const override; diff --git a/scene/animation/animation_blend_space_2d.cpp b/scene/animation/animation_blend_space_2d.cpp index d5c6253e9d..2634248231 100644 --- a/scene/animation/animation_blend_space_2d.cpp +++ b/scene/animation/animation_blend_space_2d.cpp @@ -34,16 +34,19 @@ #include "core/math/geometry_2d.h" void AnimationNodeBlendSpace2D::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::VECTOR2, blend_position)); r_list->push_back(PropertyInfo(Variant::INT, closest, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); - r_list->push_back(PropertyInfo(Variant::FLOAT, length_internal, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } Variant AnimationNodeBlendSpace2D::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + if (p_parameter == closest) { return -1; - } else if (p_parameter == length_internal) { - return 0; } else { return Vector2(); } @@ -442,19 +445,18 @@ void AnimationNodeBlendSpace2D::_blend_triangle(const Vector2 &p_pos, const Vect r_weights[2] = w; } -double AnimationNodeBlendSpace2D::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeBlendSpace2D::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { _update_triangles(); Vector2 blend_pos = get_parameter(blend_position); int cur_closest = get_parameter(closest); - double cur_length_internal = get_parameter(length_internal); - double mind = 0.0; //time of min distance point + NodeTimeInfo mind; //time of min distance point AnimationMixer::PlaybackInfo pi = p_playback_info; if (blend_mode == BLEND_MODE_INTERPOLATED) { if (triangles.size() == 0) { - return 0; + return NodeTimeInfo(); } Vector2 best_point; @@ -500,7 +502,7 @@ double AnimationNodeBlendSpace2D::_process(const AnimationMixer::PlaybackInfo p_ } } - ERR_FAIL_COND_V(blend_triangle == -1, 0); //should never reach here + ERR_FAIL_COND_V(blend_triangle == -1, NodeTimeInfo()); //should never reach here int triangle_points[3]; for (int j = 0; j < 3; j++) { @@ -509,15 +511,17 @@ double AnimationNodeBlendSpace2D::_process(const AnimationMixer::PlaybackInfo p_ first = true; + bool found = false; + double max_weight = 0.0; for (int i = 0; i < blend_points_used; i++) { - bool found = false; for (int j = 0; j < 3; j++) { if (i == triangle_points[j]) { //blend with the given weight pi.weight = blend_weights[j]; - double t = blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only); - if (first || t < mind) { + NodeTimeInfo t = blend_node(blend_points[i].node, blend_points[i].name, pi, FILTER_IGNORE, true, p_test_only); + if (first || pi.weight > max_weight) { mind = t; + max_weight = pi.weight; first = false; } found = true; @@ -543,7 +547,7 @@ double AnimationNodeBlendSpace2D::_process(const AnimationMixer::PlaybackInfo p_ } if (new_closest != cur_closest && new_closest != -1) { - double from = 0.0; + NodeTimeInfo from; if (blend_mode == BLEND_MODE_DISCRETE_CARRY && cur_closest != -1) { //for ping-pong loop Ref<AnimationNodeAnimation> na_c = static_cast<Ref<AnimationNodeAnimation>>(blend_points[cur_closest].node); @@ -554,14 +558,13 @@ double AnimationNodeBlendSpace2D::_process(const AnimationMixer::PlaybackInfo p_ //see how much animation remains pi.seeked = false; pi.weight = 0; - from = cur_length_internal - blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only); + from = blend_node(blend_points[cur_closest].node, blend_points[cur_closest].name, pi, FILTER_IGNORE, true, p_test_only); } - pi.time = from; + pi.time = from.position; pi.seeked = true; pi.weight = 1.0; mind = blend_node(blend_points[new_closest].node, blend_points[new_closest].name, pi, FILTER_IGNORE, true, p_test_only); - cur_length_internal = from + mind; cur_closest = new_closest; } else { pi.weight = 1.0; @@ -580,7 +583,6 @@ double AnimationNodeBlendSpace2D::_process(const AnimationMixer::PlaybackInfo p_ } set_parameter(closest, cur_closest); - set_parameter(length_internal, cur_length_internal); return mind; } diff --git a/scene/animation/animation_blend_space_2d.h b/scene/animation/animation_blend_space_2d.h index 33a821d80c..c26ff2bce0 100644 --- a/scene/animation/animation_blend_space_2d.h +++ b/scene/animation/animation_blend_space_2d.h @@ -65,7 +65,6 @@ protected: StringName blend_position = "blend_position"; StringName closest = "closest"; - StringName length_internal = "length_internal"; Vector2 max_space = Vector2(1, 1); Vector2 min_space = Vector2(-1, -1); Vector2 snap = Vector2(0.1, 0.1); @@ -129,7 +128,7 @@ public: void set_y_label(const String &p_label); String get_y_label() const; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; virtual String get_caption() const override; Vector2 get_closest_point(const Vector2 &p_point); diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp index 4a01b2ad65..71f9c45eea 100644 --- a/scene/animation/animation_blend_tree.cpp +++ b/scene/animation/animation_blend_tree.cpp @@ -44,7 +44,26 @@ StringName AnimationNodeAnimation::get_animation() const { Vector<String> (*AnimationNodeAnimation::get_editable_animation_list)() = nullptr; void AnimationNodeAnimation::get_parameter_list(List<PropertyInfo> *r_list) const { - r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + AnimationNode::get_parameter_list(r_list); +} + +AnimationNode::NodeTimeInfo AnimationNodeAnimation::get_node_time_info() const { + NodeTimeInfo nti; + if (!process_state->tree->has_animation(animation)) { + return nti; + } + + if (use_custom_timeline) { + nti.length = timeline_length; + nti.loop_mode = loop_mode; + } else { + Ref<Animation> anim = process_state->tree->get_animation(animation); + nti.length = (double)anim->get_length(); + nti.loop_mode = anim->get_loop_mode(); + } + nti.position = get_parameter(current_position); + + return nti; } void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const { @@ -62,11 +81,34 @@ void AnimationNodeAnimation::_validate_property(PropertyInfo &p_property) const p_property.hint_string = anims; } } + + if (!use_custom_timeline) { + if (p_property.name == "timeline_length" || p_property.name == "start_offset" || p_property.name == "loop_mode" || p_property.name == "stretch_time_scale") { + p_property.usage = PROPERTY_USAGE_NONE; + } + } } -double AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { - double cur_time = get_parameter(time); +AnimationNode::NodeTimeInfo AnimationNodeAnimation::process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { + process_state->is_testing = p_test_only; + AnimationMixer::PlaybackInfo pi = p_playback_info; + if (p_playback_info.seeked) { + pi.delta = get_node_time_info().position - p_playback_info.time; + } else { + pi.time = get_node_time_info().position + (backward ? -p_playback_info.delta : p_playback_info.delta); + } + + NodeTimeInfo nti = _process(pi, p_test_only); + + if (!p_test_only) { + set_node_time_info(nti); + } + + return nti; +} + +AnimationNode::NodeTimeInfo AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { if (!process_state->tree->has_animation(animation)) { AnimationNodeBlendTree *tree = Object::cast_to<AnimationNodeBlendTree>(node_state.parent); if (tree) { @@ -77,87 +119,129 @@ double AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_pla make_invalid(vformat(RTR("Animation not found: '%s'"), animation)); } - return 0; + return NodeTimeInfo(); } Ref<Animation> anim = process_state->tree->get_animation(animation); double anim_size = (double)anim->get_length(); - double step = 0.0; - double prev_time = cur_time; + + NodeTimeInfo cur_nti = get_node_time_info(); + double cur_len = cur_nti.length; + double cur_time = p_playback_info.time; + double cur_delta = p_playback_info.delta; + + Animation::LoopMode cur_loop_mode = cur_nti.loop_mode; + double prev_time = cur_nti.position; + Animation::LoopedFlag looped_flag = Animation::LOOPED_FLAG_NONE; bool node_backward = play_mode == PLAY_MODE_BACKWARD; - double p_time = p_playback_info.time; bool p_seek = p_playback_info.seeked; bool p_is_external_seeking = p_playback_info.is_external_seeking; - if (p_playback_info.seeked) { - step = p_time - cur_time; - cur_time = p_time; + bool is_just_looped = false; + + // 1. Progress for AnimationNode. + if (cur_loop_mode != Animation::LOOP_NONE) { + if (cur_loop_mode == Animation::LOOP_LINEAR) { + if (!Math::is_zero_approx(cur_len)) { + if (prev_time <= cur_len && cur_time > cur_len) { + is_just_looped = true; // Don't break with negative timescale since remain will not be 0. + } + cur_time = Math::fposmod(cur_time, cur_len); + } + backward = false; + } else { + if (!Math::is_zero_approx(cur_len)) { + if (prev_time >= 0 && cur_time < 0) { + backward = !backward; + } else if (prev_time <= cur_len && cur_time > cur_len) { + backward = !backward; + is_just_looped = true; // Don't break with negative timescale since remain will not be 0. + } + cur_time = Math::pingpong(cur_time, cur_len); + } + } } else { - p_time *= backward ? -1.0 : 1.0; - cur_time = cur_time + p_time; - step = p_time; + if (cur_time < 0) { + cur_delta += cur_time; + cur_time = 0; + } else if (cur_time > cur_len) { + cur_delta += cur_time - cur_len; + cur_time = cur_len; + } + backward = false; + // If ended, don't progress AnimationNode. So set delta to 0. + if (!Math::is_zero_approx(cur_delta)) { + if (play_mode == PLAY_MODE_FORWARD) { + if (prev_time >= cur_len) { + cur_delta = 0; + } + } else { + if (prev_time <= 0) { + cur_delta = 0; + } + } + } } - bool is_looping = false; - if (anim->get_loop_mode() == Animation::LOOP_PINGPONG) { + // 2. For return, store "AnimationNode" time info here, not "Animation" time info as below. + NodeTimeInfo nti; + nti.length = cur_len; + nti.position = cur_time; + nti.delta = cur_delta; + nti.loop_mode = cur_loop_mode; + nti.is_just_looped = is_just_looped; + + // 3. Progress for Animation. + double prev_playback_time = prev_time - start_offset; + double cur_playback_time = cur_time - start_offset; + if (stretch_time_scale) { + double mlt = anim_size / cur_len; + cur_playback_time *= mlt; + cur_delta *= mlt; + } + if (cur_loop_mode == Animation::LOOP_LINEAR) { if (!Math::is_zero_approx(anim_size)) { - if (prev_time >= 0 && cur_time < 0) { - backward = !backward; + prev_playback_time = Math::fposmod(prev_playback_time, anim_size); + cur_playback_time = Math::fposmod(cur_playback_time, anim_size); + if (prev_playback_time >= 0 && cur_playback_time < 0) { looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START; } - if (prev_time <= anim_size && cur_time > anim_size) { - backward = !backward; + if (prev_playback_time <= anim_size && cur_playback_time > anim_size) { looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END; } - cur_time = Math::pingpong(cur_time, anim_size); } - is_looping = true; - } else if (anim->get_loop_mode() == Animation::LOOP_LINEAR) { + } else if (cur_loop_mode == Animation::LOOP_PINGPONG) { if (!Math::is_zero_approx(anim_size)) { - if (prev_time >= 0 && cur_time < 0) { + if (Math::fposmod(cur_playback_time, anim_size * 2.0) >= anim_size) { + cur_delta = -cur_delta; // Needed for retrieveing discrete keys correctly. + } + prev_playback_time = Math::pingpong(prev_playback_time, anim_size); + cur_playback_time = Math::pingpong(cur_playback_time, anim_size); + if (prev_playback_time >= 0 && cur_playback_time < 0) { looped_flag = node_backward ? Animation::LOOPED_FLAG_END : Animation::LOOPED_FLAG_START; } - if (prev_time <= anim_size && cur_time > anim_size) { + if (prev_playback_time <= anim_size && cur_playback_time > anim_size) { looped_flag = node_backward ? Animation::LOOPED_FLAG_START : Animation::LOOPED_FLAG_END; } - cur_time = Math::fposmod(cur_time, anim_size); } - backward = false; - is_looping = true; } else { - if (cur_time < 0) { - step += cur_time; - cur_time = 0; - } else if (cur_time > anim_size) { - step += anim_size - cur_time; - cur_time = anim_size; - } - backward = false; - - // If ended, don't progress animation. So set delta to 0. - if (p_time > 0) { - if (play_mode == PLAY_MODE_FORWARD) { - if (prev_time >= anim_size) { - step = 0; - } - } else { - if (prev_time <= 0) { - step = 0; - } - } + if (cur_playback_time < 0) { + cur_playback_time = 0; + } else if (cur_playback_time > anim_size) { + cur_playback_time = anim_size; } // Emit start & finish signal. Internally, the detections are the same for backward. // We should use call_deferred since the track keys are still being processed. if (process_state->tree && !p_test_only) { // AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection. - if (p_seek && !p_is_external_seeking && cur_time == 0) { + if (p_seek && !p_is_external_seeking && cur_playback_time == 0) { process_state->tree->call_deferred(SNAME("emit_signal"), "animation_started", animation); } // Finished. - if (prev_time < anim_size && cur_time >= anim_size) { + if (prev_time - start_offset < anim_size && cur_playback_time >= anim_size) { process_state->tree->call_deferred(SNAME("emit_signal"), "animation_finished", animation); } } @@ -166,19 +250,18 @@ double AnimationNodeAnimation::_process(const AnimationMixer::PlaybackInfo p_pla if (!p_test_only) { AnimationMixer::PlaybackInfo pi = p_playback_info; if (play_mode == PLAY_MODE_FORWARD) { - pi.time = cur_time; - pi.delta = step; + pi.time = cur_playback_time; + pi.delta = cur_delta; } else { - pi.time = anim_size - cur_time; - pi.delta = -step; + pi.time = anim_size - cur_playback_time; + pi.delta = -cur_delta; } pi.weight = 1.0; pi.looped_flag = looped_flag; blend_animation(animation, pi); } - set_parameter(time, cur_time); - return is_looping ? HUGE_LENGTH : anim_size - cur_time; + return nti; } String AnimationNodeAnimation::get_caption() const { @@ -201,6 +284,48 @@ bool AnimationNodeAnimation::is_backward() const { return backward; } +void AnimationNodeAnimation::set_use_custom_timeline(bool p_use_custom_timeline) { + use_custom_timeline = p_use_custom_timeline; + notify_property_list_changed(); +} + +bool AnimationNodeAnimation::is_using_custom_timeline() const { + return use_custom_timeline; +} + +void AnimationNodeAnimation::set_timeline_length(double p_length) { + timeline_length = p_length; +} + +double AnimationNodeAnimation::get_timeline_length() const { + return timeline_length; +} + +void AnimationNodeAnimation::set_stretch_time_scale(bool p_strech_time_scale) { + stretch_time_scale = p_strech_time_scale; + notify_property_list_changed(); +} + +bool AnimationNodeAnimation::is_stretching_time_scale() const { + return stretch_time_scale; +} + +void AnimationNodeAnimation::set_start_offset(double p_offset) { + start_offset = p_offset; +} + +double AnimationNodeAnimation::get_start_offset() const { + return start_offset; +} + +void AnimationNodeAnimation::set_loop_mode(Animation::LoopMode p_loop_mode) { + loop_mode = p_loop_mode; +} + +Animation::LoopMode AnimationNodeAnimation::get_loop_mode() const { + return loop_mode; +} + void AnimationNodeAnimation::_bind_methods() { ClassDB::bind_method(D_METHOD("set_animation", "name"), &AnimationNodeAnimation::set_animation); ClassDB::bind_method(D_METHOD("get_animation"), &AnimationNodeAnimation::get_animation); @@ -208,8 +333,28 @@ void AnimationNodeAnimation::_bind_methods() { ClassDB::bind_method(D_METHOD("set_play_mode", "mode"), &AnimationNodeAnimation::set_play_mode); ClassDB::bind_method(D_METHOD("get_play_mode"), &AnimationNodeAnimation::get_play_mode); + ClassDB::bind_method(D_METHOD("set_use_custom_timeline", "use_custom_timeline"), &AnimationNodeAnimation::set_use_custom_timeline); + ClassDB::bind_method(D_METHOD("is_using_custom_timeline"), &AnimationNodeAnimation::is_using_custom_timeline); + + ClassDB::bind_method(D_METHOD("set_timeline_length", "timeline_length"), &AnimationNodeAnimation::set_timeline_length); + ClassDB::bind_method(D_METHOD("get_timeline_length"), &AnimationNodeAnimation::get_timeline_length); + + ClassDB::bind_method(D_METHOD("set_stretch_time_scale", "stretch_time_scale"), &AnimationNodeAnimation::set_stretch_time_scale); + ClassDB::bind_method(D_METHOD("is_stretching_time_scale"), &AnimationNodeAnimation::is_stretching_time_scale); + + ClassDB::bind_method(D_METHOD("set_start_offset", "start_offset"), &AnimationNodeAnimation::set_start_offset); + ClassDB::bind_method(D_METHOD("get_start_offset"), &AnimationNodeAnimation::get_start_offset); + + ClassDB::bind_method(D_METHOD("set_loop_mode", "loop_mode"), &AnimationNodeAnimation::set_loop_mode); + ClassDB::bind_method(D_METHOD("get_loop_mode"), &AnimationNodeAnimation::get_loop_mode); + ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "animation"), "set_animation", "get_animation"); ADD_PROPERTY(PropertyInfo(Variant::INT, "play_mode", PROPERTY_HINT_ENUM, "Forward,Backward"), "set_play_mode", "get_play_mode"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_custom_timeline"), "set_use_custom_timeline", "is_using_custom_timeline"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "timeline_length", PROPERTY_HINT_RANGE, "0.001,60,0.001,or_greater,or_less,hide_slider,suffix:s"), "set_timeline_length", "get_timeline_length"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stretch_time_scale"), "set_stretch_time_scale", "is_stretching_time_scale"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "start_offset", PROPERTY_HINT_RANGE, "-60,60,0.001,or_greater,or_less,hide_slider,suffix:s"), "set_start_offset", "get_start_offset"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "None,Linear,Ping-Pong"), "set_loop_mode", "get_loop_mode"); BIND_ENUM_CONSTANT(PLAY_MODE_FORWARD); BIND_ENUM_CONSTANT(PLAY_MODE_BACKWARD); @@ -240,16 +385,21 @@ AnimationNodeSync::AnimationNodeSync() { //////////////////////////////////////////////////////// void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::BOOL, active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); r_list->push_back(PropertyInfo(Variant::BOOL, internal_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); r_list->push_back(PropertyInfo(Variant::INT, request, PROPERTY_HINT_ENUM, ",Fire,Abort,Fade Out")); - r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); - r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); + r_list->push_back(PropertyInfo(Variant::FLOAT, fade_in_remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); r_list->push_back(PropertyInfo(Variant::FLOAT, fade_out_remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + if (p_parameter == request) { return ONE_SHOT_REQUEST_NONE; } else if (p_parameter == active || p_parameter == internal_active) { @@ -262,6 +412,10 @@ Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_pa } bool AnimationNodeOneShot::is_parameter_read_only(const StringName &p_parameter) const { + if (AnimationNode::is_parameter_read_only(p_parameter)) { + return true; + } + if (p_parameter == active || p_parameter == internal_active) { return true; } @@ -332,6 +486,14 @@ AnimationNodeOneShot::MixMode AnimationNodeOneShot::get_mix_mode() const { return mix; } +void AnimationNodeOneShot::set_break_loop_at_end(bool p_enable) { + break_loop_at_end = p_enable; +} + +bool AnimationNodeOneShot::is_loop_broken_at_end() const { + return break_loop_at_end; +} + String AnimationNodeOneShot::get_caption() const { return "OneShot"; } @@ -340,14 +502,14 @@ bool AnimationNodeOneShot::has_filter() const { return true; } -double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request)); bool cur_active = get_parameter(active); bool cur_internal_active = get_parameter(internal_active); - double cur_time = get_parameter(time); - double cur_remaining = get_parameter(remaining); - double cur_fade_out_remaining = get_parameter(fade_out_remaining); + NodeTimeInfo cur_nti = get_node_time_info(); double cur_time_to_restart = get_parameter(time_to_restart); + double cur_fade_in_remaining = get_parameter(fade_in_remaining); + double cur_fade_out_remaining = get_parameter(fade_out_remaining); set_parameter(request, ONE_SHOT_REQUEST_NONE); @@ -356,6 +518,8 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb bool is_fading_out = cur_active == true && cur_internal_active == false; double p_time = p_playback_info.time; + double p_delta = p_playback_info.delta; + double abs_delta = Math::abs(p_delta); bool p_seek = p_playback_info.seeked; bool p_is_external_seeking = p_playback_info.is_external_seeking; @@ -374,6 +538,7 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb // Request fading. is_fading_out = true; cur_fade_out_remaining = fade_out; + cur_fade_in_remaining = 0; } else { // Shot is ended, do nothing. is_shooting = false; @@ -382,7 +547,7 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb set_parameter(time_to_restart, -1); } else if (!do_start && !cur_active) { if (cur_time_to_restart >= 0.0 && !p_seek) { - cur_time_to_restart -= p_time; + cur_time_to_restart -= abs_delta; if (cur_time_to_restart < 0) { do_start = true; // Restart. } @@ -413,8 +578,11 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb } if (do_start) { - cur_time = 0; os_seek = true; + if (!cur_internal_active) { + cur_fade_in_remaining = fade_in; // If already active, don't fade-in again. + } + cur_internal_active = true; set_parameter(request, ONE_SHOT_REQUEST_NONE); set_parameter(internal_active, true); set_parameter(active, true); @@ -422,20 +590,17 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb real_t blend = 1.0; bool use_blend = sync; - if (cur_time < fade_in) { + + if (cur_fade_in_remaining > 0) { if (fade_in > 0) { use_blend = true; - blend = cur_time / fade_in; + blend = (fade_in - cur_fade_in_remaining) / fade_in; if (fade_in_curve.is_valid()) { blend = fade_in_curve->sample(blend); } } else { blend = 0; // Should not happen. } - } else if (!do_start && !is_fading_out && cur_remaining <= fade_out) { - is_fading_out = true; - cur_fade_out_remaining = cur_remaining; - set_parameter(internal_active, false); } if (is_fading_out) { @@ -451,34 +616,36 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb } AnimationMixer::PlaybackInfo pi = p_playback_info; - double main_rem = 0.0; + NodeTimeInfo main_nti; if (mix == MIX_MODE_ADD) { pi.weight = 1.0; - main_rem = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); + main_nti = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); } else { pi.seeked &= use_blend; pi.weight = 1.0 - blend; - main_rem = blend_input(0, pi, FILTER_BLEND, sync, p_test_only); // Unlike below, processing this edge is a corner case. + main_nti = blend_input(0, pi, FILTER_BLEND, sync, p_test_only); // Unlike below, processing this edge is a corner case. } + pi = p_playback_info; - if (os_seek) { - pi.time = cur_time; + if (do_start) { + pi.time = 0; + } else if (os_seek) { + pi.time = cur_nti.position; } pi.seeked = os_seek; pi.weight = Math::is_zero_approx(blend) ? CMP_EPSILON : blend; - double os_rem = blend_input(1, pi, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. - if (do_start) { - cur_remaining = os_rem; + NodeTimeInfo os_nti = blend_input(1, pi, FILTER_PASS, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. + + if (cur_fade_in_remaining <= 0 && !do_start && !is_fading_out && os_nti.get_remain(break_loop_at_end) <= fade_out) { + is_fading_out = true; + cur_fade_out_remaining = os_nti.get_remain(break_loop_at_end); + cur_fade_in_remaining = 0; + set_parameter(internal_active, false); } - if (p_seek) { - cur_time = p_time; - } else { - cur_time += p_time; - cur_remaining = os_rem; - cur_fade_out_remaining -= p_time; - if (cur_remaining <= 0 || (is_fading_out && cur_fade_out_remaining <= 0)) { + if (!p_seek) { + if (os_nti.get_remain(break_loop_at_end) <= 0 || (is_fading_out && cur_fade_out_remaining <= 0)) { set_parameter(internal_active, false); set_parameter(active, false); if (auto_restart) { @@ -486,13 +653,17 @@ double AnimationNodeOneShot::_process(const AnimationMixer::PlaybackInfo p_playb set_parameter(time_to_restart, restart_sec); } } + double d = Math::abs(os_nti.delta); + if (!do_start) { + cur_fade_in_remaining = MAX(0, cur_fade_in_remaining - d); // Don't consider seeked delta by restart. + } + cur_fade_out_remaining = MAX(0, cur_fade_out_remaining - d); } - set_parameter(time, cur_time); - set_parameter(remaining, cur_remaining); + set_parameter(fade_in_remaining, cur_fade_in_remaining); set_parameter(fade_out_remaining, cur_fade_out_remaining); - return MAX(main_rem, cur_remaining); + return cur_internal_active ? os_nti : main_nti; } void AnimationNodeOneShot::_bind_methods() { @@ -508,6 +679,9 @@ void AnimationNodeOneShot::_bind_methods() { ClassDB::bind_method(D_METHOD("set_fadeout_curve", "curve"), &AnimationNodeOneShot::set_fade_out_curve); ClassDB::bind_method(D_METHOD("get_fadeout_curve"), &AnimationNodeOneShot::get_fade_out_curve); + ClassDB::bind_method(D_METHOD("set_break_loop_at_end", "enable"), &AnimationNodeOneShot::set_break_loop_at_end); + ClassDB::bind_method(D_METHOD("is_loop_broken_at_end"), &AnimationNodeOneShot::is_loop_broken_at_end); + ClassDB::bind_method(D_METHOD("set_autorestart", "active"), &AnimationNodeOneShot::set_auto_restart_enabled); ClassDB::bind_method(D_METHOD("has_autorestart"), &AnimationNodeOneShot::is_auto_restart_enabled); @@ -526,6 +700,7 @@ void AnimationNodeOneShot::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fadein_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_fadein_curve", "get_fadein_curve"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fadeout_time", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_fadeout_time", "get_fadeout_time"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fadeout_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_fadeout_curve", "get_fadeout_curve"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "break_loop_at_end"), "set_break_loop_at_end", "is_loop_broken_at_end"); ADD_GROUP("Auto Restart", "autorestart_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autorestart"), "set_autorestart", "has_autorestart"); @@ -550,10 +725,16 @@ AnimationNodeOneShot::AnimationNodeOneShot() { //////////////////////////////////////////////// void AnimationNodeAdd2::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater")); } Variant AnimationNodeAdd2::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + return 0; } @@ -565,16 +746,16 @@ bool AnimationNodeAdd2::has_filter() const { return true; } -double AnimationNodeAdd2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeAdd2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(add_amount); AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = 1.0; - double rem0 = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); + NodeTimeInfo nti = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); pi.weight = amount; blend_input(1, pi, FILTER_PASS, sync, p_test_only); - return rem0; + return nti; } void AnimationNodeAdd2::_bind_methods() { @@ -588,10 +769,16 @@ AnimationNodeAdd2::AnimationNodeAdd2() { //////////////////////////////////////////////// void AnimationNodeAdd3::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::FLOAT, add_amount, PROPERTY_HINT_RANGE, "-1,1,0.01,or_less,or_greater")); } Variant AnimationNodeAdd3::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + return 0; } @@ -603,18 +790,18 @@ bool AnimationNodeAdd3::has_filter() const { return true; } -double AnimationNodeAdd3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeAdd3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(add_amount); AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = MAX(0, -amount); blend_input(0, pi, FILTER_PASS, sync, p_test_only); pi.weight = 1.0; - double rem0 = blend_input(1, pi, FILTER_IGNORE, sync, p_test_only); + NodeTimeInfo nti = blend_input(1, pi, FILTER_IGNORE, sync, p_test_only); pi.weight = MAX(0, amount); blend_input(2, pi, FILTER_PASS, sync, p_test_only); - return rem0; + return nti; } void AnimationNodeAdd3::_bind_methods() { @@ -629,10 +816,16 @@ AnimationNodeAdd3::AnimationNodeAdd3() { ///////////////////////////////////////////// void AnimationNodeBlend2::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater")); } Variant AnimationNodeBlend2::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + return 0; // For blend amount. } @@ -640,16 +833,16 @@ String AnimationNodeBlend2::get_caption() const { return "Blend2"; } -double AnimationNodeBlend2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeBlend2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(blend_amount); AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = 1.0 - amount; - double rem0 = blend_input(0, pi, FILTER_BLEND, sync, p_test_only); + NodeTimeInfo nti0 = blend_input(0, pi, FILTER_BLEND, sync, p_test_only); pi.weight = amount; - double rem1 = blend_input(1, pi, FILTER_PASS, sync, p_test_only); + NodeTimeInfo nti1 = blend_input(1, pi, FILTER_PASS, sync, p_test_only); - return amount > 0.5 ? rem1 : rem0; // Hacky but good enough. + return amount > 0.5 ? nti1 : nti0; // Hacky but good enough. } bool AnimationNodeBlend2::has_filter() const { @@ -667,10 +860,16 @@ AnimationNodeBlend2::AnimationNodeBlend2() { ////////////////////////////////////// void AnimationNodeBlend3::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::FLOAT, blend_amount, PROPERTY_HINT_RANGE, "-1,1,0.01,or_less,or_greater")); } Variant AnimationNodeBlend3::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + return 0; // For blend amount. } @@ -678,18 +877,18 @@ String AnimationNodeBlend3::get_caption() const { return "Blend3"; } -double AnimationNodeBlend3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeBlend3::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(blend_amount); AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = MAX(0, -amount); - double rem0 = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); + NodeTimeInfo nti0 = blend_input(0, pi, FILTER_IGNORE, sync, p_test_only); pi.weight = 1.0 - ABS(amount); - double rem1 = blend_input(1, pi, FILTER_IGNORE, sync, p_test_only); + NodeTimeInfo nti1 = blend_input(1, pi, FILTER_IGNORE, sync, p_test_only); pi.weight = MAX(0, amount); - double rem2 = blend_input(2, pi, FILTER_IGNORE, sync, p_test_only); + NodeTimeInfo nti2 = blend_input(2, pi, FILTER_IGNORE, sync, p_test_only); - return amount > 0.5 ? rem2 : (amount < -0.5 ? rem0 : rem1); // Hacky but good enough. + return amount > 0.5 ? nti2 : (amount < -0.5 ? nti0 : nti1); // Hacky but good enough. } void AnimationNodeBlend3::_bind_methods() { @@ -704,10 +903,16 @@ AnimationNodeBlend3::AnimationNodeBlend3() { //////////////////////////////////////////////// void AnimationNodeSub2::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::FLOAT, sub_amount, PROPERTY_HINT_RANGE, "0,1,0.01,or_less,or_greater")); } Variant AnimationNodeSub2::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + return 0; } @@ -719,7 +924,7 @@ bool AnimationNodeSub2::has_filter() const { return true; } -double AnimationNodeSub2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeSub2::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double amount = get_parameter(sub_amount); AnimationMixer::PlaybackInfo pi = p_playback_info; @@ -742,10 +947,16 @@ AnimationNodeSub2::AnimationNodeSub2() { ///////////////////////////////// void AnimationNodeTimeScale::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::FLOAT, scale, PROPERTY_HINT_RANGE, "-32,32,0.01,or_less,or_greater")); } Variant AnimationNodeTimeScale::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + return 1.0; // Initial timescale. } @@ -753,13 +964,13 @@ String AnimationNodeTimeScale::get_caption() const { return "TimeScale"; } -double AnimationNodeTimeScale::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeTimeScale::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double cur_scale = get_parameter(scale); AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = 1.0; if (!pi.seeked) { - pi.time *= cur_scale; + pi.delta *= cur_scale; } return blend_input(0, pi, FILTER_IGNORE, true, p_test_only); @@ -775,10 +986,16 @@ AnimationNodeTimeScale::AnimationNodeTimeScale() { //////////////////////////////////// void AnimationNodeTimeSeek::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::FLOAT, seek_pos_request, PROPERTY_HINT_RANGE, "-1,3600,0.01,or_greater")); // It will be reset to -1 after seeking the position immediately. } Variant AnimationNodeTimeSeek::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + return -1.0; // Initial seek request. } @@ -786,7 +1003,7 @@ String AnimationNodeTimeSeek::get_caption() const { return "TimeSeek"; } -double AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeTimeSeek::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { double cur_seek_pos = get_parameter(seek_pos_request); AnimationMixer::PlaybackInfo pi = p_playback_info; @@ -833,6 +1050,8 @@ bool AnimationNodeTransition::_set(const StringName &p_path, const Variant &p_va set_input_name(which, p_value); } else if (what == "auto_advance") { set_input_as_auto_advance(which, p_value); + } else if (what == "break_loop_at_end") { + set_input_break_loop_at_end(which, p_value); } else if (what == "reset") { set_input_reset(which, p_value); } else { @@ -858,6 +1077,8 @@ bool AnimationNodeTransition::_get(const StringName &p_path, Variant &r_ret) con r_ret = get_input_name(which); } else if (what == "auto_advance") { r_ret = is_input_set_as_auto_advance(which); + } else if (what == "break_loop_at_end") { + r_ret = is_input_loop_broken_at_end(which); } else if (what == "reset") { r_ret = is_input_reset(which); } else { @@ -868,6 +1089,7 @@ bool AnimationNodeTransition::_get(const StringName &p_path, Variant &r_ret) con } void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); String anims; for (int i = 0; i < get_input_count(); i++) { if (i > 0) { @@ -880,12 +1102,16 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con r_list->push_back(PropertyInfo(Variant::STRING, transition_request, PROPERTY_HINT_ENUM, anims)); // For transition request. It will be cleared after setting the value immediately. r_list->push_back(PropertyInfo(Variant::INT, current_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); // To avoid finding the index every frame, use this internally. r_list->push_back(PropertyInfo(Variant::INT, prev_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); - r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE)); } Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const { - if (p_parameter == time || p_parameter == prev_xfading) { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + + if (p_parameter == prev_xfading) { return 0.0; } else if (p_parameter == prev_index || p_parameter == current_index) { return -1; @@ -895,6 +1121,10 @@ Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p } bool AnimationNodeTransition::is_parameter_read_only(const StringName &p_parameter) const { + if (AnimationNode::is_parameter_read_only(p_parameter)) { + return true; + } + if (p_parameter == current_state || p_parameter == current_index) { return true; } @@ -947,6 +1177,16 @@ bool AnimationNodeTransition::is_input_set_as_auto_advance(int p_input) const { return input_data[p_input].auto_advance; } +void AnimationNodeTransition::set_input_break_loop_at_end(int p_input, bool p_enable) { + ERR_FAIL_INDEX(p_input, get_input_count()); + input_data.write[p_input].break_loop_at_end = p_enable; +} + +bool AnimationNodeTransition::is_input_loop_broken_at_end(int p_input) const { + ERR_FAIL_INDEX_V(p_input, get_input_count(), false); + return input_data[p_input].break_loop_at_end; +} + void AnimationNodeTransition::set_input_reset(int p_input, bool p_enable) { ERR_FAIL_INDEX(p_input, get_input_count()); input_data.write[p_input].reset = p_enable; @@ -981,12 +1221,12 @@ bool AnimationNodeTransition::is_allow_transition_to_self() const { return allow_transition_to_self; } -double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { String cur_transition_request = get_parameter(transition_request); int cur_current_index = get_parameter(current_index); int cur_prev_index = get_parameter(prev_index); - double cur_time = get_parameter(time); + NodeTimeInfo cur_nti = get_node_time_info(); double cur_prev_xfading = get_parameter(prev_xfading); bool switched = false; @@ -1052,7 +1292,6 @@ double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_pl // Special case for restart. if (restart) { - set_parameter(time, 0); pi.time = 0; pi.seeked = true; pi.weight = 1.0; @@ -1061,16 +1300,12 @@ double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_pl if (switched) { cur_prev_xfading = xfade_time; - cur_time = 0; } if (cur_current_index < 0 || cur_current_index >= get_input_count() || cur_prev_index >= get_input_count()) { - return 0; + return NodeTimeInfo(); } - double rem = 0.0; - double abs_time = Math::abs(p_time); - if (sync) { pi.weight = 0; for (int i = 0; i < get_input_count(); i++) { @@ -1081,20 +1316,11 @@ double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_pl } if (cur_prev_index < 0) { // Process current animation, check for transition. - pi.weight = 1.0; - rem = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only); - - if (p_seek) { - cur_time = abs_time; - } else { - cur_time += abs_time; - } - - if (input_data[cur_current_index].auto_advance && rem <= xfade_time) { + cur_nti = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only); + if (input_data[cur_current_index].auto_advance && cur_nti.get_remain(input_data[cur_current_index].break_loop_at_end) <= xfade_time) { set_parameter(transition_request, get_input_name((cur_current_index + 1) % get_input_count())); } - } else { // Cross-fading from prev to current. real_t blend = 0.0; @@ -1117,33 +1343,30 @@ double AnimationNodeTransition::_process(const AnimationMixer::PlaybackInfo p_pl pi.time = 0; pi.seeked = true; } - rem = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only); + cur_nti = blend_input(cur_current_index, pi, FILTER_IGNORE, true, p_test_only); pi = p_playback_info; pi.seeked &= use_blend; pi.weight = blend; blend_input(cur_prev_index, pi, FILTER_IGNORE, true, p_test_only); - if (p_seek) { - cur_time = abs_time; - } else { - cur_time += abs_time; - cur_prev_xfading -= abs_time; - if (cur_prev_xfading < 0) { + if (!p_seek) { + if (cur_prev_xfading <= 0) { set_parameter(prev_index, -1); } + cur_prev_xfading -= Math::abs(p_playback_info.delta); } } - set_parameter(time, cur_time); set_parameter(prev_xfading, cur_prev_xfading); - return rem; + return cur_nti; } void AnimationNodeTransition::_get_property_list(List<PropertyInfo> *p_list) const { for (int i = 0; i < get_input_count(); i++) { p_list->push_back(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/auto_advance", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/break_loop_at_end", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::BOOL, "input_" + itos(i) + "/reset", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL)); } } @@ -1154,6 +1377,9 @@ void AnimationNodeTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_input_as_auto_advance", "input", "enable"), &AnimationNodeTransition::set_input_as_auto_advance); ClassDB::bind_method(D_METHOD("is_input_set_as_auto_advance", "input"), &AnimationNodeTransition::is_input_set_as_auto_advance); + ClassDB::bind_method(D_METHOD("set_input_break_loop_at_end", "input", "enable"), &AnimationNodeTransition::set_input_break_loop_at_end); + ClassDB::bind_method(D_METHOD("is_input_loop_broken_at_end", "input"), &AnimationNodeTransition::is_input_loop_broken_at_end); + ClassDB::bind_method(D_METHOD("set_input_reset", "input", "enable"), &AnimationNodeTransition::set_input_reset); ClassDB::bind_method(D_METHOD("is_input_reset", "input"), &AnimationNodeTransition::is_input_reset); @@ -1181,7 +1407,7 @@ String AnimationNodeOutput::get_caption() const { return "Output"; } -double AnimationNodeOutput::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeOutput::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = 1.0; return blend_input(0, pi, FILTER_IGNORE, true, p_test_only); @@ -1400,10 +1626,10 @@ String AnimationNodeBlendTree::get_caption() const { return "BlendTree"; } -double AnimationNodeBlendTree::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeBlendTree::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { Ref<AnimationNodeOutput> output = nodes[SceneStringNames::get_singleton()->output].node; node_state.connections = nodes[SceneStringNames::get_singleton()->output].connections; - ERR_FAIL_COND_V(output.is_null(), 0); + ERR_FAIL_COND_V(output.is_null(), NodeTimeInfo()); AnimationMixer::PlaybackInfo pi = p_playback_info; pi.weight = 1.0; diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h index cf0884b892..c7ef7ed624 100644 --- a/scene/animation/animation_blend_tree.h +++ b/scene/animation/animation_blend_tree.h @@ -37,7 +37,12 @@ class AnimationNodeAnimation : public AnimationRootNode { GDCLASS(AnimationNodeAnimation, AnimationRootNode); StringName animation; - StringName time = "time"; + + bool use_custom_timeline = false; + double timeline_length = 1.0; + Animation::LoopMode loop_mode = Animation::LOOP_NONE; + bool stretch_time_scale = true; + double start_offset = 0.0; uint64_t last_version = 0; bool skip = false; @@ -50,10 +55,13 @@ public: void get_parameter_list(List<PropertyInfo> *r_list) const override; + virtual NodeTimeInfo get_node_time_info() const override; // Wrapper of get_parameter(). + static Vector<String> (*get_editable_animation_list)(); virtual String get_caption() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; void set_animation(const StringName &p_name); StringName get_animation() const; @@ -64,6 +72,21 @@ public: void set_backward(bool p_backward); bool is_backward() const; + void set_use_custom_timeline(bool p_use_custom_timeline); + bool is_using_custom_timeline() const; + + void set_timeline_length(double p_length); + double get_timeline_length() const; + + void set_stretch_time_scale(bool p_strech_time_scale); + bool is_stretching_time_scale() const; + + void set_start_offset(double p_offset); + double get_start_offset() const; + + void set_loop_mode(Animation::LoopMode p_loop_mode); + Animation::LoopMode get_loop_mode() const; + AnimationNodeAnimation(); protected: @@ -118,12 +141,12 @@ private: double auto_restart_delay = 1.0; double auto_restart_random_delay = 0.0; MixMode mix = MIX_MODE_BLEND; + bool break_loop_at_end = false; StringName request = PNAME("request"); StringName active = PNAME("active"); StringName internal_active = PNAME("internal_active"); - StringName time = "time"; - StringName remaining = "remaining"; + StringName fade_in_remaining = "fade_in_remaining"; StringName fade_out_remaining = "fade_out_remaining"; StringName time_to_restart = "time_to_restart"; @@ -160,8 +183,11 @@ public: void set_mix_mode(MixMode p_mix); MixMode get_mix_mode() const; + void set_break_loop_at_end(bool p_enable); + bool is_loop_broken_at_end() const; + virtual bool has_filter() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeOneShot(); }; @@ -184,7 +210,7 @@ public: virtual String get_caption() const override; virtual bool has_filter() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeAdd2(); }; @@ -204,7 +230,7 @@ public: virtual String get_caption() const override; virtual bool has_filter() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeAdd3(); }; @@ -222,7 +248,7 @@ public: virtual Variant get_parameter_default_value(const StringName &p_parameter) const override; virtual String get_caption() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; virtual bool has_filter() const override; AnimationNodeBlend2(); @@ -242,7 +268,7 @@ public: virtual String get_caption() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeBlend3(); }; @@ -261,7 +287,7 @@ public: virtual String get_caption() const override; virtual bool has_filter() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeSub2(); }; @@ -280,7 +306,7 @@ public: virtual String get_caption() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeTimeScale(); }; @@ -299,7 +325,7 @@ public: virtual String get_caption() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeTimeSeek(); }; @@ -309,11 +335,11 @@ class AnimationNodeTransition : public AnimationNodeSync { struct InputData { bool auto_advance = false; + bool break_loop_at_end = false; bool reset = true; }; Vector<InputData> input_data; - StringName time = "time"; StringName prev_xfading = "prev_xfading"; StringName prev_index = "prev_index"; StringName current_index = PNAME("current_index"); @@ -351,6 +377,9 @@ public: void set_input_as_auto_advance(int p_input, bool p_enable); bool is_input_set_as_auto_advance(int p_input) const; + void set_input_break_loop_at_end(int p_input, bool p_enable); + bool is_input_loop_broken_at_end(int p_input) const; + void set_input_reset(int p_input, bool p_enable); bool is_input_reset(int p_input) const; @@ -363,7 +392,7 @@ public: void set_allow_transition_to_self(bool p_enable); bool is_allow_transition_to_self() const; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeTransition(); }; @@ -373,7 +402,7 @@ class AnimationNodeOutput : public AnimationNode { public: virtual String get_caption() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; AnimationNodeOutput(); }; @@ -445,7 +474,7 @@ public: void get_node_connections(List<NodeConnection> *r_connections) const; virtual String get_caption() const override; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; void get_node_list(List<StringName> *r_list); diff --git a/scene/animation/animation_mixer.cpp b/scene/animation/animation_mixer.cpp index 7080a5338b..22f919ad36 100644 --- a/scene/animation/animation_mixer.cpp +++ b/scene/animation/animation_mixer.cpp @@ -1596,7 +1596,7 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { } } break; case Animation::TYPE_ANIMATION: { - if (p_update_only || Math::is_zero_approx(blend)) { + if (Math::is_zero_approx(blend)) { continue; } TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track); @@ -1623,10 +1623,10 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { double at_anim_pos = 0.0; switch (anim->get_loop_mode()) { case Animation::LOOP_NONE: { - at_anim_pos = MAX((double)anim->get_length(), time - pos); //seek to end + at_anim_pos = MIN((double)anim->get_length(), time - pos); // Seek to end. } break; case Animation::LOOP_LINEAR: { - at_anim_pos = Math::fposmod(time - pos, (double)anim->get_length()); //seek to loop + at_anim_pos = Math::fposmod(time - pos, (double)anim->get_length()); // Seek to loop. } break; case Animation::LOOP_PINGPONG: { at_anim_pos = Math::pingpong(time - pos, (double)a->get_length()); @@ -1634,14 +1634,14 @@ void AnimationMixer::_blend_process(double p_delta, bool p_update_only) { default: break; } - if (player2->is_playing() || seeked) { - player2->seek(at_anim_pos); + if (player2->is_playing()) { + player2->seek(at_anim_pos, false, p_update_only); player2->play(anim_name); t->playing = true; playing_caches.insert(t); } else { player2->set_assigned_animation(anim_name); - player2->seek(at_anim_pos, true); + player2->seek(at_anim_pos, true, p_update_only); } } else { // Find stuff to play. diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp index ec44641484..0484694555 100644 --- a/scene/animation/animation_node_state_machine.cpp +++ b/scene/animation/animation_node_state_machine.cpp @@ -101,12 +101,22 @@ float AnimationNodeStateMachineTransition::get_xfade_time() const { void AnimationNodeStateMachineTransition::set_xfade_curve(const Ref<Curve> &p_curve) { xfade_curve = p_curve; + emit_changed(); } Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const { return xfade_curve; } +void AnimationNodeStateMachineTransition::set_break_loop_at_end(bool p_enable) { + break_loop_at_end = p_enable; + emit_changed(); +} + +bool AnimationNodeStateMachineTransition::is_loop_broken_at_end() const { + return break_loop_at_end; +} + void AnimationNodeStateMachineTransition::set_reset(bool p_reset) { reset = p_reset; emit_changed(); @@ -141,6 +151,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve); ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve); + ClassDB::bind_method(D_METHOD("set_break_loop_at_end", "enable"), &AnimationNodeStateMachineTransition::set_break_loop_at_end); + ClassDB::bind_method(D_METHOD("is_loop_broken_at_end"), &AnimationNodeStateMachineTransition::is_loop_broken_at_end); + ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeStateMachineTransition::set_reset); ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeStateMachineTransition::is_reset); @@ -153,6 +166,7 @@ void AnimationNodeStateMachineTransition::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "break_loop_at_end"), "set_break_loop_at_end", "is_loop_broken_at_end"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset"); ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority"); @@ -310,19 +324,19 @@ TypedArray<StringName> AnimationNodeStateMachinePlayback::_get_travel_path() con } float AnimationNodeStateMachinePlayback::get_current_play_pos() const { - return pos_current; + return current_nti.position; } float AnimationNodeStateMachinePlayback::get_current_length() const { - return len_current; + return current_nti.length; } float AnimationNodeStateMachinePlayback::get_fade_from_play_pos() const { - return pos_fade_from; + return fadeing_from_nti.position; } float AnimationNodeStateMachinePlayback::get_fade_from_length() const { - return len_fade_from; + return fadeing_from_nti.length; } float AnimationNodeStateMachinePlayback::get_fading_time() const { @@ -665,21 +679,22 @@ bool AnimationNodeStateMachinePlayback::_make_travel_path(AnimationTree *p_tree, } } -double AnimationNodeStateMachinePlayback::process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { - double rem = _process(p_base_path, p_state_machine, p_playback_info, p_test_only); +AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { + AnimationNode::NodeTimeInfo nti = _process(p_base_path, p_state_machine, p_playback_info, p_test_only); start_request = StringName(); next_request = false; stop_request = false; reset_request_on_teleport = false; - return rem; + return nti; } -double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeStateMachinePlayback::_process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { _set_base_path(p_base_path); AnimationTree *tree = p_state_machine->process_state->tree; double p_time = p_playback_info.time; + double p_delta = p_playback_info.delta; bool p_seek = p_playback_info.seeked; bool p_is_external_seeking = p_playback_info.is_external_seeking; @@ -690,8 +705,8 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An if (p_state_machine->get_state_machine_type() != AnimationNodeStateMachine::STATE_MACHINE_TYPE_GROUPED) { path.clear(); _clear_path_children(tree, p_state_machine, p_test_only); - _start(p_state_machine); } + _start(p_state_machine); reset_request = true; } else { // Reset current state. @@ -705,11 +720,11 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An travel_request = StringName(); path.clear(); playing = false; - return 0; + return AnimationNode::NodeTimeInfo(); } if (!playing && start_request != StringName() && travel_request != StringName()) { - return 0; + return AnimationNode::NodeTimeInfo(); } // Process start/travel request. @@ -732,7 +747,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An _start(p_state_machine); } else { StringName node = start_request; - ERR_FAIL_V_MSG(0, "No such node: '" + node + "'"); + ERR_FAIL_V_MSG(AnimationNode::NodeTimeInfo(), "No such node: '" + node + "'"); } } @@ -766,7 +781,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An teleport_request = true; } } else { - ERR_FAIL_V_MSG(0, "No such node: '" + temp_travel_request + "'"); + ERR_FAIL_V_MSG(AnimationNode::NodeTimeInfo(), "No such node: '" + temp_travel_request + "'"); } } } @@ -777,16 +792,14 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An teleport_request = false; // Clear fadeing on teleport. fading_from = StringName(); + fadeing_from_nti = AnimationNode::NodeTimeInfo(); fading_pos = 0; // Init current length. - pos_current = 0; // Overwritten suddenly in main process. - pi.time = 0; pi.seeked = true; pi.is_external_seeking = false; pi.weight = 0; - - len_current = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); + current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Don't process first node if not necessary, insteads process next node. _transition_to_next_recursive(tree, p_state_machine, p_test_only); } @@ -795,7 +808,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An if (!p_state_machine->states.has(current)) { playing = false; // Current does not exist. _set_current(p_state_machine, StringName()); - return 0; + return AnimationNode::NodeTimeInfo(); } // Special case for grouped state machine Start/End to make priority with parent blend (means don't treat Start and End states as RESET animations). @@ -813,7 +826,7 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An fading_from = StringName(); } else { if (!p_seek) { - fading_pos += p_time; + fading_pos += Math::abs(p_delta); } fade_blend = MIN(1.0, fading_pos / fading_time); } @@ -829,18 +842,14 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An } // Main process. - double rem = 0.0; pi = p_playback_info; pi.weight = fade_blend; if (reset_request) { reset_request = false; pi.time = 0; pi.seeked = true; - len_current = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); - rem = len_current; - } else { - rem = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. } + current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. // Cross-fade process. if (fading_from != StringName()) { @@ -852,7 +861,6 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An fade_blend_inv = 1.0; } - float fading_from_rem = 0.0; pi = p_playback_info; pi.weight = fade_blend_inv; if (_reset_request_for_fading_from) { @@ -860,57 +868,41 @@ double AnimationNodeStateMachinePlayback::_process(const String &p_base_path, An pi.time = 0; pi.seeked = true; } - fading_from_rem = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. - - // Guess playback position. - if (fading_from_rem > len_fade_from) { /// Weird but ok. - len_fade_from = fading_from_rem; - } - pos_fade_from = len_fade_from - fading_from_rem; + fadeing_from_nti = p_state_machine->blend_node(p_state_machine->states[fading_from].node, fading_from, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); // Blend values must be more than CMP_EPSILON to process discrete keys in edge. if (fading_pos >= fading_time) { - fading_from = StringName(); // Finish fading. + // Finish fading. + fading_from = StringName(); + fadeing_from_nti = AnimationNode::NodeTimeInfo(); } } - // Guess playback position. - if (rem > len_current) { // Weird but ok. - len_current = rem; - } - pos_current = len_current - rem; - // Find next and see when to transition. _transition_to_next_recursive(tree, p_state_machine, p_test_only); // Predict remaining time. - double remain = rem; // If we can't predict the end of state machine, the time remaining must be INFINITY. - if (p_state_machine->get_state_machine_type() == AnimationNodeStateMachine::STATE_MACHINE_TYPE_NESTED) { // There is no next transition. if (!p_state_machine->has_transition_from(current)) { if (fading_from != StringName()) { - remain = MAX(rem, fading_time - fading_pos); - } else { - remain = rem; + return current_nti.get_remain() > fadeing_from_nti.get_remain() ? current_nti : fadeing_from_nti; } - return remain; + return current_nti; } } if (current == p_state_machine->end_node) { - if (fading_from != StringName()) { - remain = MAX(0, fading_time - fading_pos); - } else { - remain = 0; + if (fading_from != StringName() && fadeing_from_nti.get_remain() > 0) { + return fadeing_from_nti; } - return remain; + return AnimationNode::NodeTimeInfo(); } if (!is_end()) { - return HUGE_LENGTH; + current_nti.is_infinity = true; } - return remain; + return current_nti; } bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only) { @@ -952,6 +944,7 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, p_test_only); } fading_from = StringName(); + fadeing_from_nti = AnimationNode::NodeTimeInfo(); fading_time = 0; fading_pos = 0; } @@ -968,11 +961,10 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT _reset_request_for_fading_from = reset_request; // To avoid processing doubly, it must be reset in the fading process within _process(). reset_request = next.is_reset; - pos_fade_from = pos_current; - len_fade_from = len_current; + fadeing_from_nti = current_nti; if (next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) { - pi.time = MIN(pos_current, len_current); + pi.time = current_nti.position; pi.seeked = true; pi.is_external_seeking = false; pi.weight = 0; @@ -980,24 +972,11 @@ bool AnimationNodeStateMachinePlayback::_transition_to_next_recursive(AnimationT } // Just get length to find next recursive. - double rem = 0.0; pi.time = 0; pi.is_external_seeking = false; pi.weight = 0; - if (next.is_reset) { - pi.seeked = true; - len_current = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Just retrieve remain length, don't process. - rem = len_current; - } else { - pi.seeked = false; - rem = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Just retrieve remain length, don't process. - } - - // Guess playback position. - if (rem > len_current) { // Weird but ok. - len_current = rem; - } - pos_current = len_current - rem; + pi.seeked = next.is_reset; + current_nti = p_state_machine->blend_node(p_state_machine->states[current].node, current, pi, AnimationNode::FILTER_IGNORE, true, true); // Just retrieve remain length, don't process. // Fading must be processed. if (fading_time) { @@ -1028,6 +1007,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p playback->_next_main(); // Then, fadeing should be end. fading_from = StringName(); + fadeing_from_nti = AnimationNode::NodeTimeInfo(); fading_pos = 0; } else { return true; @@ -1039,7 +1019,7 @@ bool AnimationNodeStateMachinePlayback::_can_transition_to_next(AnimationTree *p } if (current != p_state_machine->start_node && p_next.switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_AT_END) { - return pos_current >= len_current - p_next.xfade; + return current_nti.get_remain(p_next.break_loop_at_end) <= p_next.xfade; } return true; } @@ -1084,6 +1064,7 @@ AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_ next.curve = ref_transition->get_xfade_curve(); next.switch_mode = ref_transition->get_switch_mode(); next.is_reset = ref_transition->is_reset(); + next.break_loop_at_end = ref_transition->is_loop_broken_at_end(); } } } else { @@ -1113,6 +1094,7 @@ AnimationNodeStateMachinePlayback::NextInfo AnimationNodeStateMachinePlayback::_ next.curve = ref_transition->get_xfade_curve(); next.switch_mode = ref_transition->get_switch_mode(); next.is_reset = ref_transition->is_reset(); + next.break_loop_at_end = ref_transition->is_loop_broken_at_end(); } } @@ -1233,6 +1215,7 @@ AnimationNodeStateMachinePlayback::AnimationNodeStateMachinePlayback() { /////////////////////////////////////////////////////// void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) const { + AnimationNode::get_parameter_list(r_list); r_list->push_back(PropertyInfo(Variant::OBJECT, playback, PROPERTY_HINT_RESOURCE_TYPE, "AnimationNodeStateMachinePlayback", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ALWAYS_DUPLICATE)); // Don't store this object in .tres, it always needs to be made as unique object. List<StringName> advance_conditions; for (int i = 0; i < transitions.size(); i++) { @@ -1249,6 +1232,11 @@ void AnimationNodeStateMachine::get_parameter_list(List<PropertyInfo> *r_list) c } Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName &p_parameter) const { + Variant ret = AnimationNode::get_parameter_default_value(p_parameter); + if (ret != Variant()) { + return ret; + } + if (p_parameter == playback) { Ref<AnimationNodeStateMachinePlayback> p; p.instantiate(); @@ -1259,6 +1247,10 @@ Variant AnimationNodeStateMachine::get_parameter_default_value(const StringName } bool AnimationNodeStateMachine::is_parameter_read_only(const StringName &p_parameter) const { + if (AnimationNode::is_parameter_read_only(p_parameter)) { + return true; + } + if (p_parameter == playback) { return true; } @@ -1622,9 +1614,9 @@ Vector2 AnimationNodeStateMachine::get_graph_offset() const { return graph_offset; } -double AnimationNodeStateMachine::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNodeStateMachine::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { Ref<AnimationNodeStateMachinePlayback> playback_new = get_parameter(playback); - ERR_FAIL_COND_V(playback_new.is_null(), 0.0); + ERR_FAIL_COND_V(playback_new.is_null(), AnimationNode::NodeTimeInfo()); playback_new->_set_grouped(state_machine_type == STATE_MACHINE_TYPE_GROUPED); if (p_test_only) { playback_new = playback_new->duplicate(); // Don't process original when testing. diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h index fa0eca5877..8078ffb26d 100644 --- a/scene/animation/animation_node_state_machine.h +++ b/scene/animation/animation_node_state_machine.h @@ -57,6 +57,7 @@ private: StringName advance_condition_name; float xfade_time = 0.0; Ref<Curve> xfade_curve; + bool break_loop_at_end = false; bool reset = true; int priority = 1; String advance_expression; @@ -85,6 +86,9 @@ public: void set_xfade_time(float p_xfade); float get_xfade_time() const; + void set_break_loop_at_end(bool p_enable); + bool is_loop_broken_at_end() const; + void set_reset(bool p_reset); bool is_reset() const; @@ -210,7 +214,7 @@ public: void set_graph_offset(const Vector2 &p_offset); Vector2 get_graph_offset() const; - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false) override; virtual String get_caption() const override; virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) const override; @@ -246,6 +250,7 @@ class AnimationNodeStateMachinePlayback : public Resource { Ref<Curve> curve; AnimationNodeStateMachineTransition::SwitchMode switch_mode; bool is_reset; + bool break_loop_at_end; }; struct ChildStateMachineInfo { @@ -257,18 +262,14 @@ class AnimationNodeStateMachinePlayback : public Resource { Ref<AnimationNodeStateMachineTransition> default_transition; String base_path; - double len_fade_from = 0.0; - double pos_fade_from = 0.0; - - double len_current = 0.0; - double pos_current = 0.0; - + AnimationNode::NodeTimeInfo current_nti; StringName current; Ref<Curve> current_curve; Ref<AnimationNodeStateMachineTransition> group_start_transition; Ref<AnimationNodeStateMachineTransition> group_end_transition; + AnimationNode::NodeTimeInfo fadeing_from_nti; StringName fading_from; float fading_time = 0.0; float fading_pos = 0.0; @@ -301,8 +302,8 @@ class AnimationNodeStateMachinePlayback : public Resource { bool _travel_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_is_allow_transition_to_self, bool p_is_parent_same_state, bool p_test_only); void _start_children(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, const String &p_path, bool p_test_only); - double process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only); - double _process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only); + AnimationNode::NodeTimeInfo process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only); + AnimationNode::NodeTimeInfo _process(const String &p_base_path, AnimationNodeStateMachine *p_state_machine, const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only); bool _check_advance_condition(const Ref<AnimationNodeStateMachine> p_state_machine, const Ref<AnimationNodeStateMachineTransition> p_transition) const; bool _transition_to_next_recursive(AnimationTree *p_tree, AnimationNodeStateMachine *p_state_machine, bool p_test_only); diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp index 2c2d8387f3..2d0bd9c258 100644 --- a/scene/animation/animation_tree.cpp +++ b/scene/animation/animation_tree.cpp @@ -46,6 +46,10 @@ void AnimationNode::get_parameter_list(List<PropertyInfo> *r_list) const { r_list->push_back(PropertyInfo::from_dict(d)); } } + + r_list->push_back(PropertyInfo(Variant::FLOAT, current_length, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY)); + r_list->push_back(PropertyInfo(Variant::FLOAT, current_position, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY)); + r_list->push_back(PropertyInfo(Variant::FLOAT, current_delta, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_READ_ONLY)); } Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter) const { @@ -56,8 +60,15 @@ Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter bool AnimationNode::is_parameter_read_only(const StringName &p_parameter) const { bool ret = false; - GDVIRTUAL_CALL(_is_parameter_read_only, p_parameter, ret); - return ret; + if (GDVIRTUAL_CALL(_is_parameter_read_only, p_parameter, ret) && ret) { + return true; + } + + if (p_parameter == current_length || p_parameter == current_position || p_parameter == current_delta) { + return true; + } + + return false; } void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) { @@ -81,6 +92,20 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const { return process_state->tree->property_map[path].first; } +void AnimationNode::set_node_time_info(const NodeTimeInfo &p_node_time_info) { + set_parameter(current_length, p_node_time_info.length); + set_parameter(current_position, p_node_time_info.position); + set_parameter(current_delta, p_node_time_info.delta); +} + +AnimationNode::NodeTimeInfo AnimationNode::get_node_time_info() const { + NodeTimeInfo nti; + nti.length = get_parameter(current_length); + nti.position = get_parameter(current_position); + nti.delta = get_parameter(current_delta); + return nti; +} + void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) { Dictionary cn; if (GDVIRTUAL_CALL(_get_child_nodes, cn)) { @@ -101,11 +126,11 @@ void AnimationNode::blend_animation(const StringName &p_animation, AnimationMixe process_state->tree->make_animation_instance(p_animation, p_playback_info); } -double AnimationNode::_pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNode::_pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { process_state = p_process_state; - double t = process(p_playback_info, p_test_only); + NodeTimeInfo nti = process(p_playback_info, p_test_only); process_state = nullptr; - return t; + return nti; } void AnimationNode::make_invalid(const String &p_reason) { @@ -122,11 +147,11 @@ AnimationTree *AnimationNode::get_animation_tree() const { return process_state->tree; } -double AnimationNode::blend_input(int p_input, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) { - ERR_FAIL_INDEX_V(p_input, inputs.size(), 0); +AnimationNode::NodeTimeInfo AnimationNode::blend_input(int p_input, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) { + ERR_FAIL_INDEX_V(p_input, inputs.size(), NodeTimeInfo()); AnimationNodeBlendTree *blend_tree = Object::cast_to<AnimationNodeBlendTree>(node_state.parent); - ERR_FAIL_NULL_V(blend_tree, 0); + ERR_FAIL_NULL_V(blend_tree, NodeTimeInfo()); // Update connections. StringName current_name = blend_tree->get_node_name(Ref<AnimationNode>(this)); @@ -136,32 +161,31 @@ double AnimationNode::blend_input(int p_input, AnimationMixer::PlaybackInfo p_pl StringName node_name = node_state.connections[p_input]; if (!blend_tree->has_node(node_name)) { make_invalid(vformat(RTR("Nothing connected to input '%s' of node '%s'."), get_input_name(p_input), current_name)); - return 0; + return NodeTimeInfo(); } Ref<AnimationNode> node = blend_tree->get_node(node_name); - ERR_FAIL_COND_V(node.is_null(), 0); + ERR_FAIL_COND_V(node.is_null(), NodeTimeInfo()); real_t activity = 0.0; Vector<AnimationTree::Activity> *activity_ptr = process_state->tree->input_activity_map.getptr(node_state.base_path); - double ret = _blend_node(node, node_name, nullptr, p_playback_info, p_filter, p_sync, p_test_only, &activity); + NodeTimeInfo nti = _blend_node(node, node_name, nullptr, p_playback_info, p_filter, p_sync, p_test_only, &activity); if (activity_ptr && p_input < activity_ptr->size()) { activity_ptr->write[p_input].last_pass = process_state->last_pass; activity_ptr->write[p_input].activity = activity; } - return ret; + return nti; } -double AnimationNode::blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) { - ERR_FAIL_COND_V(p_node.is_null(), 0); - +AnimationNode::NodeTimeInfo AnimationNode::blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only) { + ERR_FAIL_COND_V(p_node.is_null(), NodeTimeInfo()); p_node->node_state.connections.clear(); return _blend_node(p_node, p_subpath, this, p_playback_info, p_filter, p_sync, p_test_only, nullptr); } -double AnimationNode::_blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationNode *p_new_parent, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only, real_t *r_activity) { - ERR_FAIL_NULL_V(process_state, 0); +AnimationNode::NodeTimeInfo AnimationNode::_blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationNode *p_new_parent, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter, bool p_sync, bool p_test_only, real_t *r_activity) { + ERR_FAIL_NULL_V(process_state, NodeTimeInfo()); int blend_count = node_state.track_weights.size(); @@ -261,7 +285,7 @@ double AnimationNode::_blend_node(Ref<AnimationNode> p_node, const StringName &p new_parent = p_new_parent; new_path = String(node_state.base_path) + String(p_subpath) + "/"; } else { - ERR_FAIL_NULL_V(node_state.parent, 0); + ERR_FAIL_NULL_V(node_state.parent, NodeTimeInfo()); new_parent = node_state.parent; new_path = String(new_parent->node_state.base_path) + String(p_subpath) + "/"; } @@ -271,7 +295,7 @@ double AnimationNode::_blend_node(Ref<AnimationNode> p_node, const StringName &p p_node->node_state.base_path = new_path; p_node->node_state.parent = new_parent; if (!p_playback_info.seeked && !p_sync && !any_valid) { - p_playback_info.time = 0.0; + p_playback_info.delta = 0.0; return p_node->_pre_process(process_state, p_playback_info, p_test_only); } return p_node->_pre_process(process_state, p_playback_info, p_test_only); @@ -328,15 +352,31 @@ int AnimationNode::find_input(const String &p_name) const { return idx; } -double AnimationNode::process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { +AnimationNode::NodeTimeInfo AnimationNode::process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { process_state->is_testing = p_test_only; - return _process(p_playback_info, p_test_only); + + AnimationMixer::PlaybackInfo pi = p_playback_info; + if (p_playback_info.seeked) { + pi.delta = get_node_time_info().position - p_playback_info.time; + } else { + pi.time = get_node_time_info().position + p_playback_info.delta; + } + + NodeTimeInfo nti = _process(pi, p_test_only); + + if (!p_test_only) { + set_node_time_info(nti); + } + + return nti; } -double AnimationNode::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { - double ret = 0; - GDVIRTUAL_CALL(_process, p_playback_info.time, p_playback_info.seeked, p_playback_info.is_external_seeking, p_test_only, ret); - return ret; +AnimationNode::NodeTimeInfo AnimationNode::_process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only) { + double r_ret = 0.0; + GDVIRTUAL_CALL(_process, p_playback_info.time, p_playback_info.seeked, p_playback_info.is_external_seeking, p_test_only, r_ret); + NodeTimeInfo nti; + nti.delta = r_ret; + return nti; } void AnimationNode::set_filter_path(const NodePath &p_path, bool p_enable) { @@ -432,7 +472,8 @@ double AnimationNode::blend_node_ex(const StringName &p_sub_path, Ref<AnimationN info.seeked = p_seek; info.is_external_seeking = p_is_external_seeking; info.weight = p_blend; - return blend_node(p_node, p_sub_path, info, p_filter, p_sync, p_test_only); + NodeTimeInfo nti = blend_node(p_node, p_sub_path, info, p_filter, p_sync, p_test_only); + return nti.length - nti.position; } double AnimationNode::blend_input_ex(int p_input, double p_time, bool p_seek, bool p_is_external_seeking, real_t p_blend, FilterAction p_filter, bool p_sync, bool p_test_only) { @@ -441,8 +482,37 @@ double AnimationNode::blend_input_ex(int p_input, double p_time, bool p_seek, bo info.seeked = p_seek; info.is_external_seeking = p_is_external_seeking; info.weight = p_blend; - return blend_input(p_input, info, p_filter, p_sync, p_test_only); + NodeTimeInfo nti = blend_input(p_input, info, p_filter, p_sync, p_test_only); + return nti.length - nti.position; +} + +#ifdef TOOLS_ENABLED +void AnimationNode::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + const String pf = p_function; + if (p_idx == 0) { + if (pf == "find_input") { + for (const AnimationNode::Input &E : inputs) { + r_options->push_back(E.name.quote()); + } + } else if (pf == "get_parameter" || pf == "set_parameter") { + bool is_setter = pf == "set_parameter"; + List<PropertyInfo> parameters; + get_parameter_list(¶meters); + for (const PropertyInfo &E : parameters) { + if (is_setter && is_parameter_read_only(E.name)) { + continue; + } + r_options->push_back(E.name.quote()); + } + } else if (pf == "set_filter_path" || pf == "is_path_filtered") { + for (const KeyValue<NodePath, bool> &E : filter) { + r_options->push_back(String(E.key).quote()); + } + } + } + Resource::get_argument_options(p_function, p_idx, r_options); } +#endif void AnimationNode::_bind_methods() { ClassDB::bind_method(D_METHOD("add_input", "name"), &AnimationNode::add_input); @@ -568,11 +638,12 @@ bool AnimationTree::_blend_pre_process(double p_delta, int p_track_count, const if (started) { // If started, seek. pi.seeked = true; + pi.delta = p_delta; root_animation_node->_pre_process(&process_state, pi, false); started = false; } else { pi.seeked = false; - pi.time = p_delta; + pi.delta = p_delta; root_animation_node->_pre_process(&process_state, pi, false); } } diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h index 87928e4d20..2a58822275 100644 --- a/scene/animation/animation_tree.h +++ b/scene/animation/animation_tree.h @@ -63,6 +63,34 @@ public: HashMap<NodePath, bool> filter; bool filter_enabled = false; + // To propagate information from upstream for use in estimation of playback progress. + // These values must be taken from the result of blend_node() or blend_input() and must be essentially read-only. + // For example, if you want to change the position, you need to change the pi.time value of PlaybackInfo passed to blend_input(pi) and get the result. + struct NodeTimeInfo { + // Retain the previous frame values. These are stored into the AnimationTree's Map and exposing them as read-only values. + double length = 0.0; + double position = 0.0; + double delta = 0.0; + + // Needs internally to estimate remain time, the previous frame values are not retained. + Animation::LoopMode loop_mode = Animation::LOOP_NONE; + bool is_just_looped = false; // For breaking loop, it is true when just looped. + bool is_infinity = false; // For unpredictable state machine's end. + + bool is_looping() { + return loop_mode != Animation::LOOP_NONE; + } + double get_remain(bool p_break_loop = false) { + if ((is_looping() && !p_break_loop) || is_infinity) { + return HUGE_LENGTH; + } + if (p_break_loop && is_just_looped) { + return 0; + } + return length - position; + } + }; + // Temporary state for blending process which needs to be stored in each AnimationNodes. struct NodeState { StringName base_path; @@ -84,16 +112,23 @@ public: Array _get_filters() const; void _set_filters(const Array &p_filters); friend class AnimationNodeBlendTree; - double _blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationNode *p_new_parent, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false, real_t *r_activity = nullptr); - double _pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false); + + // The time information is passed from upstream to downstream by AnimationMixer::PlaybackInfo::p_playback_info until AnimationNodeAnimation processes it. + // Conversely, AnimationNodeAnimation returns the processed result as NodeTimeInfo from downstream to upstream. + NodeTimeInfo _blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationNode *p_new_parent, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false, real_t *r_activity = nullptr); + NodeTimeInfo _pre_process(ProcessState *p_process_state, AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false); protected: - virtual double _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false); - double process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false); + StringName current_length = "current_length"; + StringName current_position = "current_position"; + StringName current_delta = "current_delta"; + + virtual NodeTimeInfo process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false); // To organize time information. Virtualizing for especially AnimationNodeAnimation needs to take "backward" into account. + virtual NodeTimeInfo _process(const AnimationMixer::PlaybackInfo p_playback_info, bool p_test_only = false); // Main process. void blend_animation(const StringName &p_animation, AnimationMixer::PlaybackInfo p_playback_info); - double blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false); - double blend_input(int p_input, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false); + NodeTimeInfo blend_node(Ref<AnimationNode> p_node, const StringName &p_subpath, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false); + NodeTimeInfo blend_input(int p_input, AnimationMixer::PlaybackInfo p_playback_info, FilterAction p_filter = FILTER_IGNORE, bool p_sync = true, bool p_test_only = false); // Bind-able methods to expose for compatibility, moreover AnimationMixer::PlaybackInfo is not exposed. void blend_animation_ex(const StringName &p_animation, double p_time, double p_delta, bool p_seeked, bool p_is_external_seeking, real_t p_blend, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE); @@ -124,6 +159,9 @@ public: void set_parameter(const StringName &p_name, const Variant &p_value); Variant get_parameter(const StringName &p_name) const; + void set_node_time_info(const NodeTimeInfo &p_node_time_info); // Wrapper of set_parameter(). + virtual NodeTimeInfo get_node_time_info() const; // Wrapper of get_parameter(). + struct ChildNode { StringName name; Ref<AnimationNode> node; @@ -151,6 +189,10 @@ public: virtual bool has_filter() const; +#ifdef TOOLS_ENABLED + virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; +#endif + virtual Ref<AnimationNode> get_child_by_name(const StringName &p_name) const; Ref<AnimationNode> find_node_by_path(const String &p_name) const; diff --git a/scene/gui/aspect_ratio_container.cpp b/scene/gui/aspect_ratio_container.cpp index 94240ccead..711dd13781 100644 --- a/scene/gui/aspect_ratio_container.cpp +++ b/scene/gui/aspect_ratio_container.cpp @@ -46,8 +46,7 @@ Size2 AspectRatioContainer::get_minimum_size() const { continue; } Size2 minsize = c->get_combined_minimum_size(); - ms.width = MAX(ms.width, minsize.width); - ms.height = MAX(ms.height, minsize.height); + ms = ms.max(minsize); } return ms; } @@ -144,8 +143,7 @@ void AspectRatioContainer::_notification(int p_what) { } break; } child_size *= scale_factor; - child_size.x = MAX(child_size.x, child_minsize.x); - child_size.y = MAX(child_size.y, child_minsize.y); + child_size = child_size.max(child_minsize); float align_x = 0.5; switch (alignment_horizontal) { diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp index 7a860cdea7..acdeae289b 100644 --- a/scene/gui/center_container.cpp +++ b/scene/gui/center_container.cpp @@ -47,8 +47,7 @@ Size2 CenterContainer::get_minimum_size() const { continue; } Size2 minsize = c->get_combined_minimum_size(); - ms.width = MAX(ms.width, minsize.width); - ms.height = MAX(ms.height, minsize.height); + ms = ms.max(minsize); } return ms; diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp index 46c20e4a1c..af6696834e 100644 --- a/scene/gui/check_box.cpp +++ b/scene/gui/check_box.cpp @@ -36,28 +36,28 @@ Size2 CheckBox::get_icon_size() const { Size2 tex_size = Size2(0, 0); if (!theme_cache.checked.is_null()) { - tex_size = Size2(theme_cache.checked->get_width(), theme_cache.checked->get_height()); + tex_size = theme_cache.checked->get_size(); } if (!theme_cache.unchecked.is_null()) { - tex_size = Size2(MAX(tex_size.width, theme_cache.unchecked->get_width()), MAX(tex_size.height, theme_cache.unchecked->get_height())); + tex_size = tex_size.max(theme_cache.unchecked->get_size()); } if (!theme_cache.radio_checked.is_null()) { - tex_size = Size2(MAX(tex_size.width, theme_cache.radio_checked->get_width()), MAX(tex_size.height, theme_cache.radio_checked->get_height())); + tex_size = tex_size.max(theme_cache.radio_checked->get_size()); } if (!theme_cache.radio_unchecked.is_null()) { - tex_size = Size2(MAX(tex_size.width, theme_cache.radio_unchecked->get_width()), MAX(tex_size.height, theme_cache.radio_unchecked->get_height())); + tex_size = tex_size.max(theme_cache.radio_unchecked->get_size()); } if (!theme_cache.checked_disabled.is_null()) { - tex_size = Size2(MAX(tex_size.width, theme_cache.checked_disabled->get_width()), MAX(tex_size.height, theme_cache.checked_disabled->get_height())); + tex_size = tex_size.max(theme_cache.checked_disabled->get_size()); } if (!theme_cache.unchecked_disabled.is_null()) { - tex_size = Size2(MAX(tex_size.width, theme_cache.unchecked_disabled->get_width()), MAX(tex_size.height, theme_cache.unchecked_disabled->get_height())); + tex_size = tex_size.max(theme_cache.unchecked_disabled->get_size()); } if (!theme_cache.radio_checked_disabled.is_null()) { - tex_size = Size2(MAX(tex_size.width, theme_cache.radio_checked_disabled->get_width()), MAX(tex_size.height, theme_cache.radio_checked_disabled->get_height())); + tex_size = tex_size.max(theme_cache.radio_checked_disabled->get_size()); } if (!theme_cache.radio_unchecked_disabled.is_null()) { - tex_size = Size2(MAX(tex_size.width, theme_cache.radio_unchecked_disabled->get_width()), MAX(tex_size.height, theme_cache.radio_unchecked_disabled->get_height())); + tex_size = tex_size.max(theme_cache.radio_unchecked_disabled->get_size()); } return tex_size; } diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp index ca2ef220fd..ab3b74a3c3 100644 --- a/scene/gui/check_button.cpp +++ b/scene/gui/check_button.cpp @@ -57,10 +57,10 @@ Size2 CheckButton::get_icon_size() const { Size2 tex_size = Size2(0, 0); if (!on_tex.is_null()) { - tex_size = Size2(on_tex->get_width(), on_tex->get_height()); + tex_size = on_tex->get_size(); } if (!off_tex.is_null()) { - tex_size = Size2(MAX(tex_size.width, off_tex->get_width()), MAX(tex_size.height, off_tex->get_height())); + tex_size = tex_size.max(off_tex->get_size()); } return tex_size; diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 632e6af2ce..4f90504e35 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -3398,9 +3398,16 @@ void CodeEdit::_filter_code_completion_candidates_impl() { int offset = option.default_value.get_type() == Variant::COLOR ? line_height : 0; if (in_string != -1) { + // The completion string may have a literal behind it, which should be removed before re-quoting. + String literal; + if (option.insert_text.substr(1).is_quoted()) { + literal = option.display.left(1); + option.display = option.display.substr(1); + option.insert_text = option.insert_text.substr(1); + } String quote = single_quote ? "'" : "\""; - option.display = option.display.unquote().quote(quote); - option.insert_text = option.insert_text.unquote().quote(quote); + option.display = literal + (option.display.unquote().quote(quote)); + option.insert_text = literal + (option.insert_text.unquote().quote(quote)); } if (option.display.length() == 0) { diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index ee2122f269..3b62f6c23d 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -714,6 +714,10 @@ Color ColorPicker::get_pick_color() const { return color; } +Color ColorPicker::get_old_color() const { + return old_color; +} + void ColorPicker::set_picker_shape(PickerShapeType p_shape) { ERR_FAIL_INDEX(p_shape, SHAPE_MAX); if (p_shape == current_shape) { @@ -1514,7 +1518,7 @@ void ColorPicker::_pick_finished() { return; } - if (Input::get_singleton()->is_key_pressed(Key::ESCAPE)) { + if (Input::get_singleton()->is_action_just_pressed(SNAME("ui_cancel"))) { set_pick_color(old_color); } else { emit_signal(SNAME("color_changed"), color); @@ -1627,7 +1631,12 @@ void ColorPicker::_html_focus_exit() { if (c_text->is_menu_visible()) { return; } - _html_submitted(c_text->get_text()); + + if (is_visible_in_tree()) { + _html_submitted(c_text->get_text()); + } else { + _update_text_value(); + } } void ColorPicker::set_can_add_swatches(bool p_enabled) { @@ -2026,6 +2035,15 @@ ColorPicker::~ColorPicker() { ///////////////// +void ColorPickerPopupPanel::_input_from_window(const Ref<InputEvent> &p_event) { + if (p_event->is_action_pressed(SNAME("ui_accept"), false, true)) { + _close_pressed(); + } + PopupPanel::_input_from_window(p_event); +} + +///////////////// + void ColorPickerButton::_about_to_popup() { set_pressed(true); if (picker) { @@ -2040,6 +2058,10 @@ void ColorPickerButton::_color_changed(const Color &p_color) { } void ColorPickerButton::_modal_closed() { + if (Input::get_singleton()->is_action_just_pressed(SNAME("ui_cancel"))) { + set_pick_color(picker->get_old_color()); + emit_signal(SNAME("color_changed"), color); + } emit_signal(SNAME("popup_closed")); set_pressed(false); } @@ -2137,7 +2159,7 @@ PopupPanel *ColorPickerButton::get_popup() { void ColorPickerButton::_update_picker() { if (!picker) { - popup = memnew(PopupPanel); + popup = memnew(ColorPickerPopupPanel); popup->set_wrap_controls(true); picker = memnew(ColorPicker); picker->set_anchors_and_offsets_preset(PRESET_FULL_RECT); diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h index 282926d1ff..ad028584b1 100644 --- a/scene/gui/color_picker.h +++ b/scene/gui/color_picker.h @@ -317,12 +317,11 @@ public: void set_edit_alpha(bool p_show); bool is_editing_alpha() const; - int get_preset_size(); - void _set_pick_color(const Color &p_color, bool p_update_sliders); void set_pick_color(const Color &p_color); Color get_pick_color() const; void set_old_color(const Color &p_color); + Color get_old_color() const; void set_display_old_color(bool p_enabled); bool is_displaying_old_color() const; @@ -375,6 +374,10 @@ public: ~ColorPicker(); }; +class ColorPickerPopupPanel : public PopupPanel { + virtual void _input_from_window(const Ref<InputEvent> &p_event) override; +}; + class ColorPickerButton : public Button { GDCLASS(ColorPickerButton, Button); diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index d65399446c..62bb14459d 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -1653,8 +1653,7 @@ Size2 Control::get_custom_minimum_size() const { void Control::_update_minimum_size_cache() { Size2 minsize = get_minimum_size(); - minsize.x = MAX(minsize.x, data.custom_minimum_size.x); - minsize.y = MAX(minsize.y, data.custom_minimum_size.y); + minsize = minsize.max(data.custom_minimum_size); data.minimum_size_cache = minsize; data.minimum_size_valid = true; @@ -3690,6 +3689,8 @@ void Control::_bind_methods() { Control::Control() { data.theme_owner = memnew(ThemeOwner(this)); + + set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_OFF); } Control::~Control() { diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 3746b667f6..c13a2e281a 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -252,8 +252,7 @@ Size2 AcceptDialog::_get_contents_minimum_size() const { } Size2 child_minsize = c->get_combined_minimum_size(); - content_minsize.x = MAX(child_minsize.x, content_minsize.x); - content_minsize.y = MAX(child_minsize.y, content_minsize.y); + content_minsize = child_minsize.max(content_minsize); } // Then we take the background panel as it provides the offsets, diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index a53dffd0d2..1163c0e390 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -68,7 +68,7 @@ void FileDialog::popup(const Rect2i &p_rect) { } #endif - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) { + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) { String root; if (access == ACCESS_RESOURCES) { root = ProjectSettings::get_singleton()->get_resource_path(); @@ -91,7 +91,7 @@ void FileDialog::set_visible(bool p_visible) { } #endif - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) { + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_NATIVE_DIALOG_FILE) && (use_native_dialog || OS::get_singleton()->is_sandboxed())) { if (p_visible) { String root; if (access == ACCESS_RESOURCES) { @@ -197,15 +197,15 @@ void FileDialog::_notification(int p_what) { dir_up->end_bulk_theme_override(); dir_prev->begin_bulk_theme_override(); - dir_prev->add_theme_color_override("icon_color_normal", theme_cache.icon_normal_color); - dir_prev->add_theme_color_override("icon_color_hover", theme_cache.icon_hover_color); + dir_prev->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color); + dir_prev->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color); dir_prev->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color); dir_prev->add_theme_color_override("icon_color_pressed", theme_cache.icon_pressed_color); dir_prev->end_bulk_theme_override(); dir_next->begin_bulk_theme_override(); - dir_next->add_theme_color_override("icon_color_normal", theme_cache.icon_normal_color); - dir_next->add_theme_color_override("icon_color_hover", theme_cache.icon_hover_color); + dir_next->add_theme_color_override("icon_normal_color", theme_cache.icon_normal_color); + dir_next->add_theme_color_override("icon_hover_color", theme_cache.icon_hover_color); dir_next->add_theme_color_override("icon_focus_color", theme_cache.icon_focus_color); dir_next->add_theme_color_override("icon_color_pressed", theme_cache.icon_pressed_color); dir_next->end_bulk_theme_override(); @@ -671,8 +671,8 @@ void FileDialog::update_file_list() { item = dir_access->get_next(); } - dirs.sort_custom<NaturalNoCaseComparator>(); - files.sort_custom<NaturalNoCaseComparator>(); + dirs.sort_custom<FileNoCaseComparator>(); + files.sort_custom<FileNoCaseComparator>(); while (!dirs.is_empty()) { String &dir_name = dirs.front()->get(); diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp index 056872a4fe..8bce5c0caa 100644 --- a/scene/gui/graph_edit.cpp +++ b/scene/gui/graph_edit.cpp @@ -181,8 +181,7 @@ void GraphEditMinimap::gui_input(const Ref<InputEvent> &p_ev) { if (is_resizing) { // Prevent setting minimap wider than GraphEdit. Vector2 new_minimap_size; - new_minimap_size.width = MIN(get_size().width - mm->get_relative().x, ge->get_size().width - 2.0 * minimap_padding.x); - new_minimap_size.height = MIN(get_size().height - mm->get_relative().y, ge->get_size().height - 2.0 * minimap_padding.y); + new_minimap_size = (get_size() - mm->get_relative()).min(ge->get_size() - 2.0 * minimap_padding); ge->set_minimap_size(new_minimap_size); queue_redraw(); diff --git a/scene/gui/graph_element.cpp b/scene/gui/graph_element.cpp index 7fa5b0ceec..9eb9578b2c 100644 --- a/scene/gui/graph_element.cpp +++ b/scene/gui/graph_element.cpp @@ -74,8 +74,7 @@ Size2 GraphElement::get_minimum_size() const { Size2i size = child->get_combined_minimum_size(); - minsize.width = MAX(minsize.width, size.width); - minsize.height = MAX(minsize.height, size.height); + minsize = minsize.max(size); } return minsize; diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp index 8eb455d0ac..2ce12794a7 100644 --- a/scene/gui/menu_bar.cpp +++ b/scene/gui/menu_bar.cpp @@ -236,12 +236,12 @@ void MenuBar::bind_global_menu() { RID submenu_rid = popups[i]->bind_global_menu(); if (!popups[i]->is_system_menu()) { int index = nmenu->add_submenu_item(main_menu, menu_cache[i].name, submenu_rid, global_menu_tag + "#" + itos(i), global_start_idx + i); - menu_cache.write[i].global_index = index; + menu_cache.write[i].submenu_rid = submenu_rid; nmenu->set_item_hidden(main_menu, index, menu_cache[i].hidden); nmenu->set_item_disabled(main_menu, index, menu_cache[i].disabled); nmenu->set_item_tooltip(main_menu, index, menu_cache[i].tooltip); } else { - menu_cache.write[i].global_index = -1; + menu_cache.write[i].submenu_rid = RID(); } } } @@ -257,11 +257,14 @@ void MenuBar::unbind_global_menu() { Vector<PopupMenu *> popups = _get_popups(); for (int i = menu_cache.size() - 1; i >= 0; i--) { if (!popups[i]->is_system_menu()) { - popups[i]->unbind_global_menu(); - if (menu_cache[i].global_index >= 0) { - nmenu->remove_item(main_menu, menu_cache[i].global_index); + if (menu_cache[i].submenu_rid.is_valid()) { + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[i].submenu_rid); + if (item_idx >= 0) { + nmenu->remove_item(main_menu, item_idx); + } } - menu_cache.write[i].global_index = -1; + popups[i]->unbind_global_menu(); + menu_cache.write[i].submenu_rid = RID(); } } @@ -292,8 +295,11 @@ void MenuBar::_notification(int p_what) { RID main_menu = is_global ? nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID) : RID(); for (int i = 0; i < menu_cache.size(); i++) { shape(menu_cache.write[i]); - if (is_global && menu_cache[i].global_index >= 0) { - nmenu->set_item_text(main_menu, menu_cache[i].global_index, atr(menu_cache[i].name)); + if (is_global && menu_cache[i].submenu_rid.is_valid()) { + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[i].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_text(main_menu, item_idx, atr(menu_cache[i].name)); + } } } } break; @@ -500,8 +506,11 @@ void MenuBar::_refresh_menu_names() { if (!popups[i]->has_meta("_menu_name") && String(popups[i]->get_name()) != get_menu_title(i)) { menu_cache.write[i].name = popups[i]->get_name(); shape(menu_cache.write[i]); - if (is_global && menu_cache[i].global_index >= 0) { - nmenu->set_item_text(main_menu, menu_cache[i].global_index, atr(menu_cache[i].name)); + if (is_global && menu_cache[i].submenu_rid.is_valid()) { + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[i].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_text(main_menu, item_idx, atr(menu_cache[i].name)); + } } } } @@ -554,8 +563,8 @@ void MenuBar::add_child_notify(Node *p_child) { RID submenu_rid = pm->bind_global_menu(); if (!pm->is_system_menu()) { - int index = nmenu->add_submenu_item(main_menu, atr(menu.name), submenu_rid, global_menu_tag + "#" + itos(menu_cache.size() - 1), _find_global_start_index() + menu_cache.size() - 1); - menu_cache.write[menu_cache.size() - 1].global_index = index; + nmenu->add_submenu_item(main_menu, atr(menu.name), submenu_rid, global_menu_tag + "#" + itos(menu_cache.size() - 1), _find_global_start_index() + menu_cache.size() - 1); + menu_cache.write[menu_cache.size() - 1].submenu_rid = submenu_rid; } } update_minimum_size(); @@ -589,13 +598,14 @@ void MenuBar::move_child_notify(Node *p_child) { RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); int global_start = _find_global_start_index(); - if (menu.global_index >= 0) { - nmenu->remove_item(main_menu, menu.global_index); + if (menu.submenu_rid.is_valid()) { + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu.submenu_rid); + if (item_idx >= 0) { + nmenu->remove_item(main_menu, item_idx); + } } if (new_idx != -1) { - RID submenu_rid = pm->bind_global_menu(); - int index = nmenu->add_submenu_item(main_menu, atr(menu.name), submenu_rid, global_menu_tag + "#" + itos(new_idx), global_start + new_idx); - menu_cache.write[new_idx].global_index = index; + nmenu->add_submenu_item(main_menu, atr(menu.name), menu.submenu_rid, global_menu_tag + "#" + itos(new_idx), global_start + new_idx); } } } @@ -611,20 +621,22 @@ void MenuBar::remove_child_notify(Node *p_child) { int idx = get_menu_idx_from_control(pm); - menu_cache.remove_at(idx); - if (!global_menu_tag.is_empty()) { if (!pm->is_system_menu()) { - pm->unbind_global_menu(); - if (menu_cache[idx].global_index >= 0) { + if (menu_cache[idx].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->remove_item(main_menu, menu_cache[idx].global_index); - menu_cache.write[idx].global_index = -1; + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[idx].submenu_rid); + if (item_idx >= 0) { + nmenu->remove_item(main_menu, item_idx); + } } + pm->unbind_global_menu(); } } + menu_cache.remove_at(idx); + p_child->remove_meta("_menu_name"); p_child->remove_meta("_menu_tooltip"); @@ -817,10 +829,13 @@ void MenuBar::set_menu_title(int p_menu, const String &p_title) { } menu_cache.write[p_menu].name = p_title; shape(menu_cache.write[p_menu]); - if (!global_menu_tag.is_empty() && menu_cache[p_menu].global_index >= 0) { + if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->set_item_text(main_menu, menu_cache[p_menu].global_index, atr(menu_cache[p_menu].name)); + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[p_menu].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_text(main_menu, item_idx, atr(menu_cache[p_menu].name)); + } } update_minimum_size(); } @@ -835,10 +850,13 @@ void MenuBar::set_menu_tooltip(int p_menu, const String &p_tooltip) { PopupMenu *pm = get_menu_popup(p_menu); pm->set_meta("_menu_tooltip", p_tooltip); menu_cache.write[p_menu].tooltip = p_tooltip; - if (!global_menu_tag.is_empty() && menu_cache[p_menu].global_index >= 0) { + if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->set_item_tooltip(main_menu, menu_cache[p_menu].global_index, p_tooltip); + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[p_menu].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_tooltip(main_menu, item_idx, p_tooltip); + } } } @@ -850,10 +868,13 @@ String MenuBar::get_menu_tooltip(int p_menu) const { void MenuBar::set_menu_disabled(int p_menu, bool p_disabled) { ERR_FAIL_INDEX(p_menu, menu_cache.size()); menu_cache.write[p_menu].disabled = p_disabled; - if (!global_menu_tag.is_empty() && menu_cache[p_menu].global_index >= 0) { + if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->set_item_disabled(main_menu, menu_cache[p_menu].global_index, p_disabled); + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[p_menu].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_disabled(main_menu, item_idx, p_disabled); + } } } @@ -865,10 +886,13 @@ bool MenuBar::is_menu_disabled(int p_menu) const { void MenuBar::set_menu_hidden(int p_menu, bool p_hidden) { ERR_FAIL_INDEX(p_menu, menu_cache.size()); menu_cache.write[p_menu].hidden = p_hidden; - if (!global_menu_tag.is_empty() && menu_cache[p_menu].global_index >= 0) { + if (!global_menu_tag.is_empty() && menu_cache[p_menu].submenu_rid.is_valid()) { NativeMenu *nmenu = NativeMenu::get_singleton(); RID main_menu = nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); - nmenu->set_item_hidden(main_menu, menu_cache[p_menu].global_index, p_hidden); + int item_idx = nmenu->find_item_index_with_submenu(main_menu, menu_cache[p_menu].submenu_rid); + if (item_idx >= 0) { + nmenu->set_item_hidden(main_menu, item_idx, p_hidden); + } } update_minimum_size(); } diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h index 631b791e1b..04f6afc2fa 100644 --- a/scene/gui/menu_bar.h +++ b/scene/gui/menu_bar.h @@ -55,7 +55,7 @@ class MenuBar : public Control { Ref<TextLine> text_buf; bool hidden = false; bool disabled = false; - int global_index = -1; + RID submenu_rid; Menu(const String &p_name) { name = p_name; diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp index 306ef4936f..ef85919859 100644 --- a/scene/gui/panel_container.cpp +++ b/scene/gui/panel_container.cpp @@ -44,8 +44,7 @@ Size2 PanelContainer::get_minimum_size() const { } Size2 minsize = c->get_combined_minimum_size(); - ms.width = MAX(ms.width, minsize.width); - ms.height = MAX(ms.height, minsize.height); + ms = ms.max(minsize); } if (theme_cache.panel_style.is_valid()) { diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 0c5a882044..0927404947 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -224,8 +224,7 @@ Size2 PopupPanel::_get_contents_minimum_size() const { } Size2 cms = c->get_combined_minimum_size(); - ms.x = MAX(cms.x, ms.x); - ms.y = MAX(cms.y, ms.y); + ms = cms.max(ms); } return ms + theme_cache.panel_style->get_minimum_size(); diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp index c66b30f130..b2617e6fc7 100644 --- a/scene/gui/progress_bar.cpp +++ b/scene/gui/progress_bar.cpp @@ -35,15 +35,13 @@ Size2 ProgressBar::get_minimum_size() const { Size2 minimum_size = theme_cache.background_style->get_minimum_size(); - minimum_size.height = MAX(minimum_size.height, theme_cache.fill_style->get_minimum_size().height); - minimum_size.width = MAX(minimum_size.width, theme_cache.fill_style->get_minimum_size().width); + minimum_size = minimum_size.max(theme_cache.fill_style->get_minimum_size()); if (show_percentage) { String txt = "100%"; TextLine tl = TextLine(txt, theme_cache.font, theme_cache.font_size); minimum_size.height = MAX(minimum_size.height, theme_cache.background_style->get_minimum_size().height + tl.get_size().y); } else { // this is needed, else the progressbar will collapse - minimum_size.width = MAX(minimum_size.width, 1); - minimum_size.height = MAX(minimum_size.height, 1); + minimum_size = minimum_size.max(Size2(1, 1)); } return minimum_size; } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index cb7ccb583e..1baf71dd07 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -951,7 +951,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o case ITEM_IMAGE: { ItemImage *img = static_cast<ItemImage *>(it); if (img->pad) { - Size2 pad_size = Size2(MIN(rect.size.x, img->image->get_width()), MIN(rect.size.y, img->image->get_height())); + Size2 pad_size = rect.size.min(img->image->get_size()); Vector2 pad_off = (rect.size - pad_size) / 2; img->image->draw_rect(ci, Rect2(p_ofs + rect.position + off + pad_off, pad_size), false, img->color); } else { diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index 89d308de3f..1447d2f002 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -56,8 +56,7 @@ Size2 ScrollContainer::get_minimum_size() const { Size2 child_min_size = c->get_combined_minimum_size(); - largest_child_min_size.x = MAX(largest_child_min_size.x, child_min_size.x); - largest_child_min_size.y = MAX(largest_child_min_size.y, child_min_size.y); + largest_child_min_size = largest_child_min_size.max(child_min_size); } if (horizontal_scroll_mode == SCROLL_MODE_DISABLED) { diff --git a/scene/gui/subviewport_container.cpp b/scene/gui/subviewport_container.cpp index 0d33774e20..f6cfe6ab18 100644 --- a/scene/gui/subviewport_container.cpp +++ b/scene/gui/subviewport_container.cpp @@ -45,8 +45,7 @@ Size2 SubViewportContainer::get_minimum_size() const { } Size2 minsize = c->get_size(); - ms.width = MAX(ms.width, minsize.width); - ms.height = MAX(ms.height, minsize.height); + ms = ms.max(minsize); } return ms; diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 741b38a35a..df3c9631f9 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -871,8 +871,7 @@ Size2 TabContainer::get_minimum_size() const { } Size2 cms = c->get_combined_minimum_size(); - largest_child_min_size.x = MAX(largest_child_min_size.x, cms.x); - largest_child_min_size.y = MAX(largest_child_min_size.y, cms.y); + largest_child_min_size = largest_child_min_size.max(cms); } ms.y += largest_child_min_size.y; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 2d7a66d4c0..a7cd18e1a8 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1113,7 +1113,7 @@ void TextEdit::_notification(int p_what) { Vector<Vector2> sel = TS->shaped_text_get_selection(rid, sel_from, sel_to); // Show selection at the end of line. - if (line < get_selection_to_line(c)) { + if (line_wrap_index == line_wrap_amount && line < get_selection_to_line(c)) { if (rtl) { sel.push_back(Vector2(-char_w, 0)); } else { @@ -1123,7 +1123,7 @@ void TextEdit::_notification(int p_what) { } for (int j = 0; j < sel.size(); j++) { - Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, Math::ceil(sel[j].y - sel[j].x), row_height); + Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, Math::ceil(sel[j].y) - sel[j].x, row_height); if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) { continue; } @@ -2115,7 +2115,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { } if (is_shortcut_keys_enabled()) { - // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, + // SELECT ALL, SELECT WORD UNDER CARET, ADD SELECTION FOR NEXT OCCURRENCE, SKIP SELECTION FOR NEXT OCCURRENCE, // CLEAR CARETS AND SELECTIONS, CUT, COPY, PASTE. if (k->is_action("ui_text_select_all", true)) { select_all(); @@ -2132,6 +2132,11 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) { accept_event(); return; } + if (k->is_action("ui_text_skip_selection_for_next_occurrence", true)) { + skip_selection_for_next_occurrence(); + accept_event(); + return; + } if (k->is_action("ui_text_clear_carets_and_selection", true)) { // Since the default shortcut is ESC, accepts the event only if it's actually performed. if (_clear_carets_and_selection()) { @@ -5185,6 +5190,54 @@ void TextEdit::add_selection_for_next_occurrence() { } } +void TextEdit::skip_selection_for_next_occurrence() { + if (!selecting_enabled) { + return; + } + + if (text.size() == 1 && text[0].length() == 0) { + return; + } + + // Always use the last caret, to correctly search for + // the next occurrence that comes after this caret. + int caret = get_caret_count() - 1; + + // Supports getting the text under caret without selecting it. + // It allows to use this shortcut to simply jump to the next (under caret) word. + // Due to const and &(reference) presence, ternary operator is a way to avoid errors and warnings. + const String &searched_text = has_selection(caret) ? get_selected_text(caret) : get_word_under_caret(caret); + + int column = (has_selection(caret) ? get_selection_from_column(caret) : get_caret_column(caret)) + 1; + int line = get_caret_line(caret); + + const Point2i next_occurrence = search(searched_text, SEARCH_MATCH_CASE, line, column); + + if (next_occurrence.x == -1 || next_occurrence.y == -1) { + return; + } + + int to_column = (has_selection(caret) ? get_selection_to_column(caret) : get_caret_column(caret)) + 1; + int end = next_occurrence.x + (to_column - column); + int new_caret = add_caret(next_occurrence.y, end); + + if (new_caret != -1) { + select(next_occurrence.y, next_occurrence.x, next_occurrence.y, end, new_caret); + adjust_viewport_to_caret(new_caret); + merge_overlapping_carets(); + } + + // Deselect word under previous caret. + if (has_selection(caret)) { + select_word_under_caret(caret); + } + + // Remove previous caret. + if (get_caret_count() > 1) { + remove_caret(caret); + } +} + void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret) { ERR_FAIL_INDEX(p_caret, carets.size()); if (!selecting_enabled) { @@ -6351,6 +6404,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all); ClassDB::bind_method(D_METHOD("select_word_under_caret", "caret_index"), &TextEdit::select_word_under_caret, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("add_selection_for_next_occurrence"), &TextEdit::add_selection_for_next_occurrence); + ClassDB::bind_method(D_METHOD("skip_selection_for_next_occurrence"), &TextEdit::skip_selection_for_next_occurrence); ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column", "caret_index"), &TextEdit::select, DEFVAL(0)); ClassDB::bind_method(D_METHOD("has_selection", "caret_index"), &TextEdit::has_selection, DEFVAL(-1)); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index b8e30c7900..1099295d3b 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -890,6 +890,7 @@ public: void select_all(); void select_word_under_caret(int p_caret = -1); void add_selection_for_next_occurrence(); + void skip_selection_for_next_occurrence(); void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret = 0); bool has_selection(int p_caret = -1) const; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index dcbb25c41d..0b197c8c02 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -103,8 +103,8 @@ bool TextureButton::has_point(const Point2 &p_point) const { point *= scale; // finally, we need to check if the point is inside a rectangle with a position >= 0,0 and a size <= mask_size - rect.position = Point2(MAX(0, _texture_region.position.x), MAX(0, _texture_region.position.y)); - rect.size = Size2(MIN(mask_size.x, _texture_region.size.x), MIN(mask_size.y, _texture_region.size.y)); + rect.position = Point2().max(_texture_region.position); + rect.size = mask_size.min(_texture_region.size); } if (!rect.has_point(point)) { diff --git a/scene/gui/texture_progress_bar.cpp b/scene/gui/texture_progress_bar.cpp index 248260a7d2..5261cbe3eb 100644 --- a/scene/gui/texture_progress_bar.cpp +++ b/scene/gui/texture_progress_bar.cpp @@ -249,8 +249,7 @@ Point2 TextureProgressBar::get_relative_center() { p += rad_center_off; p.x /= progress->get_width(); p.y /= progress->get_height(); - p.x = CLAMP(p.x, 0, 1); - p.y = CLAMP(p.y, 0, 1); + p = p.clamp(Point2(), Point2(1, 1)); return p; } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 7842fc5fc0..8c544dcacf 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -3868,6 +3868,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) { } if (!root || (!root->get_first_child() && hide_root)) { + emit_signal(SNAME("empty_clicked"), get_local_mouse_position(), mb->get_button_index()); break; } diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index 2d0da075ba..56aa453407 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -336,6 +336,19 @@ void CanvasItem::_notification(int p_what) { get_parent()->connect(SNAME("child_order_changed"), callable_mp(get_viewport(), &Viewport::canvas_parent_mark_dirty).bind(get_parent()), CONNECT_REFERENCE_COUNTED); } + // If using physics interpolation, reset for this node only, + // as a helper, as in most cases, users will want items reset when + // adding to the tree. + // In cases where they move immediately after adding, + // there will be little cost in having two resets as these are cheap, + // and it is worth it for convenience. + // Do not propagate to children, as each child of an added branch + // receives its own NOTIFICATION_ENTER_TREE, and this would + // cause unnecessary duplicate resets. + if (is_physics_interpolated_and_enabled()) { + notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION); + } + } break; case NOTIFICATION_EXIT_TREE: { ERR_MAIN_THREAD_GUARD; @@ -360,6 +373,12 @@ void CanvasItem::_notification(int p_what) { } } break; + case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: { + if (is_visible_in_tree() && is_physics_interpolated()) { + RenderingServer::get_singleton()->canvas_item_reset_physics_interpolation(canvas_item); + } + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { ERR_MAIN_THREAD_GUARD; @@ -921,6 +940,10 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) { } } +void CanvasItem::_physics_interpolated_changed() { + RenderingServer::get_singleton()->canvas_item_set_interpolated(canvas_item, is_physics_interpolated()); +} + Rect2 CanvasItem::get_viewport_rect() const { ERR_READ_THREAD_GUARD_V(Rect2()); ERR_FAIL_COND_V(!is_inside_tree(), Rect2()); @@ -1378,14 +1401,17 @@ void CanvasItem::_refresh_texture_filter_cache() const { } } +void CanvasItem::_update_self_texture_filter(RS::CanvasItemTextureFilter p_texture_filter) { + RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), p_texture_filter); + queue_redraw(); +} + void CanvasItem::_update_texture_filter_changed(bool p_propagate) { if (!is_inside_tree()) { return; } _refresh_texture_filter_cache(); - - RS::get_singleton()->canvas_item_set_default_texture_filter(get_canvas_item(), texture_filter_cache); - queue_redraw(); + _update_self_texture_filter(texture_filter_cache); if (p_propagate) { for (CanvasItem *E : children_items) { @@ -1429,14 +1455,18 @@ void CanvasItem::_refresh_texture_repeat_cache() const { } } +void CanvasItem::_update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat) { + RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), p_texture_repeat); + queue_redraw(); +} + void CanvasItem::_update_texture_repeat_changed(bool p_propagate) { if (!is_inside_tree()) { return; } _refresh_texture_repeat_cache(); + _update_self_texture_repeat(texture_repeat_cache); - RS::get_singleton()->canvas_item_set_default_texture_repeat(get_canvas_item(), texture_repeat_cache); - queue_redraw(); if (p_propagate) { for (CanvasItem *E : children_items) { if (!E->top_level && E->texture_repeat == TEXTURE_REPEAT_PARENT_NODE) { diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 03b01f7ef7..8cec086ca6 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -140,6 +140,8 @@ private: void _notify_transform(CanvasItem *p_node); + virtual void _physics_interpolated_changed() override; + static CanvasItem *current_item_drawn; friend class Viewport; void _refresh_texture_repeat_cache() const; @@ -150,6 +152,9 @@ private: void _notify_transform_deferred(); protected: + virtual void _update_self_texture_repeat(RS::CanvasItemTextureRepeat p_texture_repeat); + virtual void _update_self_texture_filter(RS::CanvasItemTextureFilter p_texture_filter); + _FORCE_INLINE_ void _notify_transform() { _notify_transform(this); if (is_inside_tree() && !block_transform_notify && notify_local_transform) { diff --git a/scene/main/node.compat.inc b/scene/main/node.compat.inc new file mode 100644 index 0000000000..69ece1a40d --- /dev/null +++ b/scene/main/node.compat.inc @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* node.compat.inc */ +/**************************************************************************/ +/* 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 DISABLE_DEPRECATED + +void Node::_replace_by_bind_compat_89992(Node *p_node, bool p_keep_data) { + replace_by(p_node, p_keep_data, true); +} + +void Node::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::_replace_by_bind_compat_89992, DEFVAL(false)); +} + +#endif diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 906c397b5c..11c200064e 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -29,6 +29,7 @@ /**************************************************************************/ #include "node.h" +#include "node.compat.inc" #include "core/config/project_settings.h" #include "core/core_string_names.h" @@ -99,6 +100,14 @@ void Node::_notification(int p_notification) { } } + if (data.physics_interpolation_mode == PHYSICS_INTERPOLATION_MODE_INHERIT) { + bool interpolate = true; // Root node default is for interpolation to be on. + if (data.parent) { + interpolate = data.parent->is_physics_interpolated(); + } + _propagate_physics_interpolated(interpolate); + } + // Update auto translate mode. if (data.auto_translate_mode == AUTO_TRANSLATE_MODE_INHERIT && !data.parent) { ERR_PRINT("The root node can't be set to Inherit auto translate mode, reverting to Always instead."); @@ -395,6 +404,36 @@ void Node::_propagate_exit_tree() { data.depth = -1; } +void Node::_propagate_physics_interpolated(bool p_interpolated) { + switch (data.physics_interpolation_mode) { + case PHYSICS_INTERPOLATION_MODE_INHERIT: + // Keep the parent p_interpolated. + break; + case PHYSICS_INTERPOLATION_MODE_OFF: { + p_interpolated = false; + } break; + case PHYSICS_INTERPOLATION_MODE_ON: { + p_interpolated = true; + } break; + } + + // No change? No need to propagate further. + if (data.physics_interpolated == p_interpolated) { + return; + } + + data.physics_interpolated = p_interpolated; + + // Allow a call to the RenderingServer etc. in derived classes. + _physics_interpolated_changed(); + + data.blocked++; + for (KeyValue<StringName, Node *> &K : data.children) { + K.value->_propagate_physics_interpolated(p_interpolated); + } + data.blocked--; +} + void Node::move_child(Node *p_child, int p_index) { ERR_FAIL_COND_MSG(data.inside_tree && !Thread::is_main_thread(), "Moving child node positions inside the SceneTree is only allowed from the main thread. Use call_deferred(\"move_child\",child,index)."); ERR_FAIL_NULL(p_child); @@ -507,6 +546,8 @@ void Node::move_child_notify(Node *p_child) { void Node::owner_changed_notify() { } +void Node::_physics_interpolated_changed() {} + void Node::set_physics_process(bool p_process) { ERR_THREAD_GUARD if (data.physics_process == p_process) { @@ -821,6 +862,42 @@ bool Node::_can_process(bool p_paused) const { } } +void Node::set_physics_interpolation_mode(PhysicsInterpolationMode p_mode) { + ERR_THREAD_GUARD + if (data.physics_interpolation_mode == p_mode) { + return; + } + + data.physics_interpolation_mode = p_mode; + + bool interpolate = true; // Default for root node. + + switch (p_mode) { + case PHYSICS_INTERPOLATION_MODE_INHERIT: { + if (is_inside_tree() && data.parent) { + interpolate = data.parent->is_physics_interpolated(); + } + } break; + case PHYSICS_INTERPOLATION_MODE_OFF: { + interpolate = false; + } break; + case PHYSICS_INTERPOLATION_MODE_ON: { + interpolate = true; + } break; + } + + // If swapping from interpolated to non-interpolated, use this as an extra means to cause a reset. + if (is_physics_interpolated() && !interpolate) { + reset_physics_interpolation(); + } + + _propagate_physics_interpolated(interpolate); +} + +void Node::reset_physics_interpolation() { + propagate_notification(NOTIFICATION_RESET_PHYSICS_INTERPOLATION); +} + bool Node::_is_enabled() const { ProcessMode process_mode; @@ -1679,23 +1756,14 @@ Node *Node::get_node_or_null(const NodePath &p_path) const { } } else if (name.is_node_unique_name()) { - if (current->data.owned_unique_nodes.size()) { - // Has unique nodes in ownership - Node **unique = current->data.owned_unique_nodes.getptr(name); - if (!unique) { - return nullptr; - } - next = *unique; - } else if (current->data.owner) { - Node **unique = current->data.owner->data.owned_unique_nodes.getptr(name); - if (!unique) { - return nullptr; - } - next = *unique; - } else { + Node **unique = current->data.owned_unique_nodes.getptr(name); + if (!unique && current->data.owner) { + unique = current->data.owner->data.owned_unique_nodes.getptr(name); + } + if (!unique) { return nullptr; } - + next = *unique; } else { next = nullptr; const Node *const *node = current->data.children.getptr(name); @@ -1823,7 +1891,7 @@ void Node::reparent(Node *p_parent, bool p_keep_global_transform) { Node *check = to_visit[to_visit.size() - 1]; to_visit.resize(to_visit.size() - 1); - for (int i = 0; i < check->get_child_count(); i++) { + for (int i = 0; i < check->get_child_count(false); i++) { Node *child = check->get_child(i, false); to_visit.push_back(child); if (child->data.owner == owner_temp) { @@ -2737,24 +2805,6 @@ Node *Node::_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap) c } } else { - // If property points to a node which is owned by a node we are duplicating, update its path. - if (value.get_type() == Variant::OBJECT) { - Node *property_node = Object::cast_to<Node>(value); - if (property_node && is_ancestor_of(property_node)) { - value = current_node->get_node_or_null(get_path_to(property_node)); - } - } else if (value.get_type() == Variant::ARRAY) { - Array arr = value; - if (arr.get_typed_builtin() == Variant::OBJECT) { - for (int i = 0; i < arr.size(); i++) { - Node *property_node = Object::cast_to<Node>(arr[i]); - if (property_node && is_ancestor_of(property_node)) { - arr[i] = current_node->get_node_or_null(get_path_to(property_node)); - } - } - value = arr; - } - } current_node->set(name, value); } } @@ -2771,6 +2821,8 @@ Node *Node::duplicate(int p_flags) const { _duplicate_signals(this, dupe); } + _duplicate_properties_node(this, this, dupe); + return dupe; } @@ -2792,6 +2844,8 @@ Node *Node::duplicate_from_editor(HashMap<const Node *, Node *> &r_duplimap, con // if the emitter node comes later in tree order than the receiver _duplicate_signals(this, dupe); + _duplicate_properties_node(this, this, dupe); + return dupe; } @@ -2844,6 +2898,44 @@ void Node::remap_nested_resources(Ref<Resource> p_resource, const HashMap<Ref<Re } #endif +// Duplicates properties that store a Node. +// This has to be called after nodes have been duplicated since +// only then do we get a full picture of how the duplicated node tree looks like. +void Node::_duplicate_properties_node(const Node *p_root, const Node *p_original, Node *p_copy) const { + List<PropertyInfo> props; + p_copy->get_property_list(&props); + for (const PropertyInfo &E : props) { + if (!(E.usage & PROPERTY_USAGE_STORAGE)) { + continue; + } + String name = E.name; + Variant value = p_original->get(name).duplicate(true); + if (value.get_type() == Variant::OBJECT) { + Node *property_node = Object::cast_to<Node>(value); + if (property_node && (p_root == property_node || p_root->is_ancestor_of(property_node))) { + value = p_copy->get_node_or_null(p_original->get_path_to(property_node)); + p_copy->set(name, value); + } + } else if (value.get_type() == Variant::ARRAY) { + Array arr = value; + if (arr.get_typed_builtin() == Variant::OBJECT) { + for (int i = 0; i < arr.size(); i++) { + Node *property_node = Object::cast_to<Node>(arr[i]); + if (property_node && (p_root == property_node || p_root->is_ancestor_of(property_node))) { + arr[i] = p_copy->get_node_or_null(p_original->get_path_to(property_node)); + } + } + value = arr; + p_copy->set(name, value); + } + } + } + + for (int i = 0; i < p_copy->get_child_count(); i++) { + _duplicate_properties_node(p_root, p_original->get_child(i), p_copy->get_child(i)); + } +} + // Duplication of signals must happen after all the node descendants have been copied, // because re-targeting of connections from some descendant to another is not possible // if the emitter node comes later in tree order than the receiver @@ -2914,7 +3006,7 @@ static void find_owned_by(Node *p_by, Node *p_node, List<Node *> *p_owned) { } } -void Node::replace_by(Node *p_node, bool p_keep_groups) { +void Node::replace_by(Node *p_node, bool p_keep_groups, bool p_keep_children) { ERR_THREAD_GUARD ERR_FAIL_NULL(p_node); ERR_FAIL_COND(p_node->data.parent); @@ -2935,13 +3027,13 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) { _replace_connections_target(p_node); if (data.owner) { - for (int i = 0; i < get_child_count(); i++) { - find_owned_by(data.owner, get_child(i), &owned_by_owner); + if (p_keep_children) { + for (int i = 0; i < get_child_count(); i++) { + find_owned_by(data.owner, get_child(i), &owned_by_owner); + } } - _clean_up_owner(); } - Node *parent = data.parent; int index_in_parent = get_index(false); @@ -2953,31 +3045,33 @@ void Node::replace_by(Node *p_node, bool p_keep_groups) { emit_signal(SNAME("replacing_by"), p_node); - while (get_child_count()) { - Node *child = get_child(0); - remove_child(child); - if (!child->is_owned_by_parent()) { - // add the custom children to the p_node - Node *child_owner = child->get_owner() == this ? p_node : child->get_owner(); - child->set_owner(nullptr); - p_node->add_child(child); - child->set_owner(child_owner); + if (p_keep_children) { + while (get_child_count()) { + Node *child = get_child(0); + remove_child(child); + if (!child->is_owned_by_parent()) { + // add the custom children to the p_node + Node *child_owner = child->get_owner() == this ? p_node : child->get_owner(); + child->set_owner(nullptr); + p_node->add_child(child); + child->set_owner(child_owner); + } } - } - p_node->set_owner(owner); - for (Node *E : owned) { - if (E->data.owner != p_node) { - E->set_owner(p_node); + for (Node *E : owned) { + if (E->data.owner != p_node) { + E->set_owner(p_node); + } } - } - for (Node *E : owned_by_owner) { - if (E->data.owner != owner) { - E->set_owner(owner); + for (Node *E : owned_by_owner) { + if (E->data.owner != owner) { + E->set_owner(owner); + } } } + p_node->set_owner(owner); p_node->set_scene_file_path(get_scene_file_path()); } @@ -3489,6 +3583,12 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("set_physics_process_internal", "enable"), &Node::set_physics_process_internal); ClassDB::bind_method(D_METHOD("is_physics_processing_internal"), &Node::is_physics_processing_internal); + ClassDB::bind_method(D_METHOD("set_physics_interpolation_mode", "mode"), &Node::set_physics_interpolation_mode); + ClassDB::bind_method(D_METHOD("get_physics_interpolation_mode"), &Node::get_physics_interpolation_mode); + ClassDB::bind_method(D_METHOD("is_physics_interpolated"), &Node::is_physics_interpolated); + ClassDB::bind_method(D_METHOD("is_physics_interpolated_and_enabled"), &Node::is_physics_interpolated_and_enabled); + ClassDB::bind_method(D_METHOD("reset_physics_interpolation"), &Node::reset_physics_interpolation); + ClassDB::bind_method(D_METHOD("set_auto_translate_mode", "mode"), &Node::set_auto_translate_mode); ClassDB::bind_method(D_METHOD("get_auto_translate_mode"), &Node::get_auto_translate_mode); @@ -3498,7 +3598,7 @@ void Node::_bind_methods() { ClassDB::bind_method(D_METHOD("create_tween"), &Node::create_tween); ClassDB::bind_method(D_METHOD("duplicate", "flags"), &Node::duplicate, DEFVAL(DUPLICATE_USE_INSTANTIATION | DUPLICATE_SIGNALS | DUPLICATE_GROUPS | DUPLICATE_SCRIPTS)); - ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups"), &Node::replace_by, DEFVAL(false)); + ClassDB::bind_method(D_METHOD("replace_by", "node", "keep_groups", "keep_children"), &Node::replace_by, DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("set_scene_instance_load_placeholder", "load_placeholder"), &Node::set_scene_instance_load_placeholder); ClassDB::bind_method(D_METHOD("get_scene_instance_load_placeholder"), &Node::get_scene_instance_load_placeholder); @@ -3594,6 +3694,7 @@ void Node::_bind_methods() { BIND_CONSTANT(NOTIFICATION_POST_ENTER_TREE); BIND_CONSTANT(NOTIFICATION_DISABLED); BIND_CONSTANT(NOTIFICATION_ENABLED); + BIND_CONSTANT(NOTIFICATION_RESET_PHYSICS_INTERPOLATION); BIND_CONSTANT(NOTIFICATION_EDITOR_PRE_SAVE); BIND_CONSTANT(NOTIFICATION_EDITOR_POST_SAVE); @@ -3633,6 +3734,10 @@ void Node::_bind_methods() { BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES_PHYSICS); BIND_BITFIELD_FLAG(FLAG_PROCESS_THREAD_MESSAGES_ALL); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_INHERIT); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_ON); + BIND_ENUM_CONSTANT(PHYSICS_INTERPOLATION_MODE_OFF); + BIND_ENUM_CONSTANT(DUPLICATE_SIGNALS); BIND_ENUM_CONSTANT(DUPLICATE_GROUPS); BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS); @@ -3674,6 +3779,9 @@ void Node::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_group_order"), "set_process_thread_group_order", "get_process_thread_group_order"); ADD_PROPERTY(PropertyInfo(Variant::INT, "process_thread_messages", PROPERTY_HINT_FLAGS, "Process,Physics Process"), "set_process_thread_messages", "get_process_thread_messages"); + ADD_GROUP("Physics Interpolation", "physics_interpolation_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "physics_interpolation_mode", PROPERTY_HINT_ENUM, "Inherit,Off,On"), "set_physics_interpolation_mode", "get_physics_interpolation_mode"); + ADD_GROUP("Auto Translate", "auto_translate_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "auto_translate_mode", PROPERTY_HINT_ENUM, "Inherit,Always,Disabled"), "set_auto_translate_mode", "get_auto_translate_mode"); @@ -3708,6 +3816,35 @@ String Node::_get_name_num_separator() { Node::Node() { orphan_node_count++; + + // Default member initializer for bitfield is a C++20 extension, so: + + data.process_mode = PROCESS_MODE_INHERIT; + data.physics_interpolation_mode = PHYSICS_INTERPOLATION_MODE_INHERIT; + + data.physics_process = false; + data.process = false; + + data.physics_process_internal = false; + data.process_internal = false; + + data.input = false; + data.shortcut_input = false; + data.unhandled_input = false; + data.unhandled_key_input = false; + + data.physics_interpolated = false; + + data.parent_owned = false; + data.in_constructor = true; + data.use_placeholder = false; + + data.display_folded = false; + data.editable_instance = false; + + data.inside_tree = false; + data.ready_notified = false; // This is a small hack, so if a node is added during _ready() to the tree, it correctly gets the _ready() notification. + data.ready_first = true; } Node::~Node() { diff --git a/scene/main/node.h b/scene/main/node.h index 57a7278e73..99def10338 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -66,7 +66,9 @@ protected: }; public: - enum ProcessMode { + // N.B. Any enum stored as a bitfield should be specified as UNSIGNED to work around + // some compilers trying to store it as signed, and requiring 1 more bit than necessary. + enum ProcessMode : unsigned int { PROCESS_MODE_INHERIT, // same as parent node PROCESS_MODE_PAUSABLE, // process only if not paused PROCESS_MODE_WHEN_PAUSED, // process only if paused @@ -86,6 +88,12 @@ public: FLAG_PROCESS_THREAD_MESSAGES_ALL = 3, }; + enum PhysicsInterpolationMode : unsigned int { + PHYSICS_INTERPOLATION_MODE_INHERIT, + PHYSICS_INTERPOLATION_MODE_ON, + PHYSICS_INTERPOLATION_MODE_OFF, + }; + enum DuplicateFlags { DUPLICATE_SIGNALS = 1, DUPLICATE_GROUPS = 2, @@ -170,9 +178,7 @@ private: int blocked = 0; // Safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed. StringName name; SceneTree *tree = nullptr; - bool inside_tree = false; - bool ready_notified = false; // This is a small hack, so if a node is added during _ready() to the tree, it correctly gets the _ready() notification. - bool ready_first = true; + #ifdef TOOLS_ENABLED NodePath import_path; // Path used when imported, used by scene editors to keep tracking. #endif @@ -184,7 +190,6 @@ private: List<Node *>::Element *OW = nullptr; // Owned element. List<Node *> owned; - ProcessMode process_mode = PROCESS_MODE_INHERIT; Node *process_owner = nullptr; ProcessThreadGroup process_thread_group = PROCESS_THREAD_GROUP_INHERIT; Node *process_thread_group_owner = nullptr; @@ -196,26 +201,39 @@ private: Variant rpc_config; // Variables used to properly sort the node when processing, ignored otherwise. - // TODO: Should move all the stuff below to bits. - bool physics_process = false; - bool process = false; int process_priority = 0; int physics_process_priority = 0; - bool physics_process_internal = false; - bool process_internal = false; + // Keep bitpacked values together to get better packing. + ProcessMode process_mode : 3; + PhysicsInterpolationMode physics_interpolation_mode : 2; + + bool physics_process : 1; + bool process : 1; + + bool physics_process_internal : 1; + bool process_internal : 1; + + bool input : 1; + bool shortcut_input : 1; + bool unhandled_input : 1; + bool unhandled_key_input : 1; - bool input = false; - bool shortcut_input = false; - bool unhandled_input = false; - bool unhandled_key_input = false; + // Physics interpolation can be turned on and off on a per node basis. + // This only takes effect when the SceneTree (or project setting) physics interpolation + // is switched on. + bool physics_interpolated : 1; - bool parent_owned = false; - bool in_constructor = true; - bool use_placeholder = false; + bool parent_owned : 1; + bool in_constructor : 1; + bool use_placeholder : 1; - bool display_folded = false; - bool editable_instance = false; + bool display_folded : 1; + bool editable_instance : 1; + + bool inside_tree : 1; + bool ready_notified : 1; + bool ready_first : 1; AutoTranslateMode auto_translate_mode = AUTO_TRANSLATE_MODE_INHERIT; mutable bool is_auto_translating = true; @@ -243,10 +261,12 @@ private: void _propagate_ready(); void _propagate_exit_tree(); void _propagate_after_exit_tree(); + void _propagate_physics_interpolated(bool p_interpolated); void _propagate_process_owner(Node *p_owner, int p_pause_notification, int p_enabled_notification); void _propagate_groups_dirty(); Array _get_node_and_resource(const NodePath &p_path); + void _duplicate_properties_node(const Node *p_root, const Node *p_original, Node *p_copy) const; void _duplicate_signals(const Node *p_original, Node *p_copy) const; Node *_duplicate(int p_flags, HashMap<const Node *, Node *> *r_duplimap = nullptr) const; @@ -290,11 +310,18 @@ private: Variant _call_thread_safe_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error); protected: +#ifndef DISABLE_DEPRECATED + void _replace_by_bind_compat_89992(Node *p_node, bool p_keep_data = false); + static void _bind_compatibility_methods(); +#endif // DISABLE_DEPRECATED + void _block() { data.blocked++; } void _unblock() { data.blocked--; } void _notification(int p_notification); + virtual void _physics_interpolated_changed(); + virtual void add_child_notify(Node *p_child); virtual void remove_child_notify(Node *p_child); virtual void move_child_notify(Node *p_child); @@ -339,7 +366,7 @@ protected: public: enum { - // you can make your own, but don't use the same numbers as other notifications in other nodes + // You can make your own, but don't use the same numbers as other notifications in other nodes. NOTIFICATION_ENTER_TREE = 10, NOTIFICATION_EXIT_TREE = 11, NOTIFICATION_MOVED_IN_PARENT = 12, @@ -360,8 +387,8 @@ public: NOTIFICATION_POST_ENTER_TREE = 27, NOTIFICATION_DISABLED = 28, NOTIFICATION_ENABLED = 29, - //keep these linked to node - + NOTIFICATION_RESET_PHYSICS_INTERPOLATION = 2001, // A GodotSpace Odyssey. + // Keep these linked to Node. NOTIFICATION_WM_MOUSE_ENTER = 1002, NOTIFICATION_WM_MOUSE_EXIT = 1003, NOTIFICATION_WM_WINDOW_FOCUS_IN = 1004, @@ -607,12 +634,19 @@ public: return binds; } - void replace_by(Node *p_node, bool p_keep_data = false); + void replace_by(Node *p_node, bool p_keep_groups = false, bool p_keep_children = true); void set_process_mode(ProcessMode p_mode); ProcessMode get_process_mode() const; bool can_process() const; bool can_process_notification(int p_what) const; + + void set_physics_interpolation_mode(PhysicsInterpolationMode p_mode); + PhysicsInterpolationMode get_physics_interpolation_mode() const { return data.physics_interpolation_mode; } + _FORCE_INLINE_ bool is_physics_interpolated() const { return data.physics_interpolated; } + _FORCE_INLINE_ bool is_physics_interpolated_and_enabled() const { return is_inside_tree() && get_tree()->is_physics_interpolation_enabled() && is_physics_interpolated(); } + void reset_physics_interpolation(); + bool is_enabled() const; bool is_ready() const; @@ -742,6 +776,7 @@ VARIANT_ENUM_CAST(Node::ProcessMode); VARIANT_ENUM_CAST(Node::ProcessThreadGroup); VARIANT_BITFIELD_CAST(Node::ProcessThreadMessages); VARIANT_ENUM_CAST(Node::InternalMode); +VARIANT_ENUM_CAST(Node::PhysicsInterpolationMode); VARIANT_ENUM_CAST(Node::AutoTranslateMode); typedef HashSet<Node *, Node::Comparator> NodeSet; diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index cb16f425b5..0c77a60af6 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -451,6 +451,30 @@ void SceneTree::initialize() { root->_set_tree(this); } +void SceneTree::set_physics_interpolation_enabled(bool p_enabled) { + // We never want interpolation in the editor. + if (Engine::get_singleton()->is_editor_hint()) { + p_enabled = false; + } + + if (p_enabled == _physics_interpolation_enabled) { + return; + } + + _physics_interpolation_enabled = p_enabled; + RenderingServer::get_singleton()->set_physics_interpolation_enabled(p_enabled); +} + +bool SceneTree::is_physics_interpolation_enabled() const { + return _physics_interpolation_enabled; +} + +void SceneTree::iteration_prepare() { + if (_physics_interpolation_enabled) { + RenderingServer::get_singleton()->tick(); + } +} + bool SceneTree::physics_process(double p_time) { root_lock++; @@ -1606,6 +1630,9 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("get_frame"), &SceneTree::get_frame); ClassDB::bind_method(D_METHOD("quit", "exit_code"), &SceneTree::quit, DEFVAL(EXIT_SUCCESS)); + ClassDB::bind_method(D_METHOD("set_physics_interpolation_enabled", "enabled"), &SceneTree::set_physics_interpolation_enabled); + ClassDB::bind_method(D_METHOD("is_physics_interpolation_enabled"), &SceneTree::is_physics_interpolation_enabled); + ClassDB::bind_method(D_METHOD("queue_delete", "obj"), &SceneTree::queue_delete); MethodInfo mi; @@ -1657,6 +1684,7 @@ void SceneTree::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "set_current_scene", "get_current_scene"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", PROPERTY_USAGE_NONE), "", "get_root"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "multiplayer_poll"), "set_multiplayer_poll_enabled", "is_multiplayer_poll_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "physics_interpolation"), "set_physics_interpolation_enabled", "is_physics_interpolation_enabled"); ADD_SIGNAL(MethodInfo("tree_changed")); ADD_SIGNAL(MethodInfo("tree_process_mode_changed")); //editor only signal, but due to API hash it can't be removed in run-time @@ -1748,6 +1776,8 @@ SceneTree::SceneTree() { root->set_as_audio_listener_3d(true); #endif // _3D_DISABLED + set_physics_interpolation_enabled(GLOBAL_DEF("physics/common/physics_interpolation", false)); + // Initialize network state. set_multiplayer(MultiplayerAPI::create_default_interface()); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index a7515f0243..603438cc5f 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -139,6 +139,8 @@ private: HashMap<StringName, Group> group_map; bool _quit = false; + bool _physics_interpolation_enabled = false; + StringName tree_changed_name = "tree_changed"; StringName node_added_name = "node_added"; StringName node_removed_name = "node_removed"; @@ -313,6 +315,8 @@ public: virtual void initialize() override; + virtual void iteration_prepare() override; + virtual bool physics_process(double p_time) override; virtual bool process(double p_time) override; @@ -425,6 +429,9 @@ public: void set_disable_node_threading(bool p_disable); //default texture settings + void set_physics_interpolation_enabled(bool p_enabled); + bool is_physics_interpolation_enabled() const; + SceneTree(); ~SceneTree(); }; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index c8d2d71c2a..4e1d2b3983 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -2747,8 +2747,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { Size2i min_size = gui.currently_dragged_subwindow->get_min_size(); Size2i min_size_clamped = gui.currently_dragged_subwindow->get_clamped_minimum_size(); - min_size_clamped.x = MAX(min_size_clamped.x, 1); - min_size_clamped.y = MAX(min_size_clamped.y, 1); + min_size_clamped = min_size_clamped.max(Size2i(1, 1)); Rect2i r = gui.subwindow_resize_from_rect; @@ -2809,8 +2808,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) { Size2i max_size = gui.currently_dragged_subwindow->get_max_size(); if ((max_size.x > 0 || max_size.y > 0) && (max_size.x >= min_size.x && max_size.y >= min_size.y)) { - max_size.x = MAX(max_size.x, 1); - max_size.y = MAX(max_size.y, 1); + max_size = max_size.max(Size2i(1, 1)); if (r.size.x > max_size.x) { r.size.x = max_size.x; @@ -4843,6 +4841,7 @@ void Viewport::_bind_methods() { BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_VISIBLE); BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_SHADOW); + BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_CANVAS); BIND_ENUM_CONSTANT(RENDER_INFO_TYPE_MAX); BIND_ENUM_CONSTANT(DEBUG_DRAW_DISABLED); diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 29ccdc5426..21832a454c 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -138,6 +138,7 @@ public: enum RenderInfoType { RENDER_INFO_TYPE_VISIBLE, RENDER_INFO_TYPE_SHADOW, + RENDER_INFO_TYPE_CANVAS, RENDER_INFO_TYPE_MAX }; diff --git a/scene/main/window.cpp b/scene/main/window.cpp index 6632dd9033..586a88ea85 100644 --- a/scene/main/window.cpp +++ b/scene/main/window.cpp @@ -1033,8 +1033,7 @@ void Window::_update_window_size() { } if (embedder) { - size.x = MAX(size.x, 1); - size.y = MAX(size.y, 1); + size = size.max(Size2i(1, 1)); embedder->_sub_window_update(this); } else if (window_id != DisplayServer::INVALID_WINDOW_ID) { @@ -1214,7 +1213,7 @@ void Window::set_force_native(bool p_force_native) { return; } force_native = p_force_native; - if (is_visible()) { + if (is_visible() && !is_in_edited_scene_root()) { WARN_PRINT("Can't change \"force_native\" while a window is displayed. Consider hiding window before changing this value."); } } @@ -1225,7 +1224,7 @@ bool Window::get_force_native() const { Viewport *Window::get_embedder() const { ERR_READ_THREAD_GUARD_V(nullptr); - if (force_native && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SUBWINDOWS)) { + if (force_native && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_SUBWINDOWS) && !is_in_edited_scene_root()) { return nullptr; } @@ -1545,8 +1544,7 @@ Size2 Window::_get_contents_minimum_size() const { Point2i pos = c->get_position(); Size2i min = c->get_combined_minimum_size(); - max.x = MAX(pos.x + min.x, max.x); - max.y = MAX(pos.y + min.y, max.y); + max = max.max(pos + min); } } @@ -1703,7 +1701,7 @@ void Window::popup_centered_clamped(const Size2i &p_size, float p_fallback_ratio Vector2i size_ratio = parent_rect.size * p_fallback_ratio; Rect2i popup_rect; - popup_rect.size = Vector2i(MIN(size_ratio.x, expected_size.x), MIN(size_ratio.y, expected_size.y)); + popup_rect.size = size_ratio.min(expected_size); popup_rect.size = _clamp_window_size(popup_rect.size); if (parent_rect != Rect2()) { diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 3583dace2a..b6efd30f63 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -77,6 +77,7 @@ #include "scene/2d/skeleton_2d.h" #include "scene/2d/sprite_2d.h" #include "scene/2d/tile_map.h" +#include "scene/2d/tile_map_layer.h" #include "scene/2d/touch_screen_button.h" #include "scene/2d/visible_on_screen_notifier_2d.h" #include "scene/animation/animation_blend_space_1d.h" @@ -813,7 +814,7 @@ void register_scene_types() { GDREGISTER_CLASS(TileMapPattern); GDREGISTER_CLASS(TileData); GDREGISTER_CLASS(TileMap); - GDREGISTER_ABSTRACT_CLASS(TileMapLayerGroup); + GDREGISTER_CLASS(TileMapLayer); GDREGISTER_CLASS(Parallax2D); GDREGISTER_CLASS(ParallaxBackground); GDREGISTER_CLASS(ParallaxLayer); diff --git a/scene/resources/2d/polygon_path_finder.cpp b/scene/resources/2d/polygon_path_finder.cpp index 617a53f0a3..3aa292431d 100644 --- a/scene/resources/2d/polygon_path_finder.cpp +++ b/scene/resources/2d/polygon_path_finder.cpp @@ -64,8 +64,7 @@ void PolygonPathFinder::setup(const Vector<Vector2> &p_points, const Vector<int> points.write[i].pos = p_points[i]; points.write[i].penalty = 0; - outside_point.x = i == 0 ? p_points[0].x : (MAX(p_points[i].x, outside_point.x)); - outside_point.y = i == 0 ? p_points[0].y : (MAX(p_points[i].y, outside_point.y)); + outside_point = i == 0 ? p_points[0] : p_points[i].max(outside_point); if (i == 0) { bounds.position = points[i].pos; diff --git a/scene/resources/2d/tile_set.cpp b/scene/resources/2d/tile_set.cpp index d09723d765..6ae97944e0 100644 --- a/scene/resources/2d/tile_set.cpp +++ b/scene/resources/2d/tile_set.cpp @@ -4650,7 +4650,7 @@ Ref<Texture2D> TileSetAtlasSource::get_texture() const { void TileSetAtlasSource::set_margins(Vector2i p_margins) { if (p_margins.x < 0 || p_margins.y < 0) { WARN_PRINT("Atlas source margins should be positive."); - margins = Vector2i(MAX(0, p_margins.x), MAX(0, p_margins.y)); + margins = p_margins.max(Vector2i()); } else { margins = p_margins; } @@ -4666,7 +4666,7 @@ Vector2i TileSetAtlasSource::get_margins() const { void TileSetAtlasSource::set_separation(Vector2i p_separation) { if (p_separation.x < 0 || p_separation.y < 0) { WARN_PRINT("Atlas source separation should be positive."); - separation = Vector2i(MAX(0, p_separation.x), MAX(0, p_separation.y)); + separation = p_separation.max(Vector2i()); } else { separation = p_separation; } @@ -4682,7 +4682,7 @@ Vector2i TileSetAtlasSource::get_separation() const { void TileSetAtlasSource::set_texture_region_size(Vector2i p_tile_size) { if (p_tile_size.x <= 0 || p_tile_size.y <= 0) { WARN_PRINT("Atlas source tile_size should be strictly positive."); - texture_region_size = Vector2i(MAX(1, p_tile_size.x), MAX(1, p_tile_size.y)); + texture_region_size = p_tile_size.max(Vector2i(1, 1)); } else { texture_region_size = p_tile_size; } @@ -6918,6 +6918,7 @@ void TileData::_bind_methods() { ClassDB::bind_method(D_METHOD("get_terrain"), &TileData::get_terrain); ClassDB::bind_method(D_METHOD("set_terrain_peering_bit", "peering_bit", "terrain"), &TileData::set_terrain_peering_bit); ClassDB::bind_method(D_METHOD("get_terrain_peering_bit", "peering_bit"), &TileData::get_terrain_peering_bit); + ClassDB::bind_method(D_METHOD("is_valid_terrain_peering_bit", "peering_bit"), &TileData::is_valid_terrain_peering_bit); // Navigation ClassDB::bind_method(D_METHOD("set_navigation_polygon", "layer_id", "navigation_polygon"), &TileData::set_navigation_polygon); diff --git a/scene/resources/3d/height_map_shape_3d.cpp b/scene/resources/3d/height_map_shape_3d.cpp index 35c905bd43..5b55b66152 100644 --- a/scene/resources/3d/height_map_shape_3d.cpp +++ b/scene/resources/3d/height_map_shape_3d.cpp @@ -30,6 +30,7 @@ #include "height_map_shape_3d.h" +#include "core/io/image.h" #include "servers/physics_server_3d.h" Vector<Vector3> HeightMapShape3D::get_debug_mesh_lines() const { @@ -187,6 +188,104 @@ real_t HeightMapShape3D::get_max_height() const { return max_height; } +void HeightMapShape3D::update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max) { + ERR_FAIL_COND_MSG(p_image.is_null(), "Heightmap update image requires a valid Image reference."); + ERR_FAIL_COND_MSG(p_image->get_format() != Image::FORMAT_RF && p_image->get_format() != Image::FORMAT_RH && p_image->get_format() != Image::FORMAT_R8, "Heightmap update image requires Image in format FORMAT_RF (32 bit), FORMAT_RH (16 bit), or FORMAT_R8 (8 bit)."); + ERR_FAIL_COND_MSG(p_image->get_width() < 2, "Heightmap update image requires a minimum Image width of 2."); + ERR_FAIL_COND_MSG(p_image->get_height() < 2, "Heightmap update image requires a minimum Image height of 2."); + ERR_FAIL_COND_MSG(p_height_min > p_height_max, "Heightmap update image requires height_max to be greater than height_min."); + + map_width = p_image->get_width(); + map_depth = p_image->get_height(); + map_data.resize(map_width * map_depth); + + real_t new_min_height = FLT_MAX; + real_t new_max_height = -FLT_MAX; + + float remap_height_min = float(p_height_min); + float remap_height_max = float(p_height_max); + + real_t *map_data_ptrw = map_data.ptrw(); + + switch (p_image->get_format()) { + case Image::FORMAT_RF: { + const float *image_data_ptr = (float *)p_image->get_data().ptr(); + + for (int i = 0; i < map_data.size(); i++) { + float pixel_value = image_data_ptr[i]; + + DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0); + + real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max); + + if (height_value < new_min_height) { + new_min_height = height_value; + } + if (height_value > new_max_height) { + new_max_height = height_value; + } + + map_data_ptrw[i] = height_value; + } + + } break; + + case Image::FORMAT_RH: { + const uint16_t *image_data_ptr = (uint16_t *)p_image->get_data().ptr(); + + for (int i = 0; i < map_data.size(); i++) { + float pixel_value = Math::half_to_float(image_data_ptr[i]); + + DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0); + + real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max); + + if (height_value < new_min_height) { + new_min_height = height_value; + } + if (height_value > new_max_height) { + new_max_height = height_value; + } + + map_data_ptrw[i] = height_value; + } + + } break; + + case Image::FORMAT_R8: { + const uint8_t *image_data_ptr = (uint8_t *)p_image->get_data().ptr(); + + for (int i = 0; i < map_data.size(); i++) { + float pixel_value = float(image_data_ptr[i] / 255.0); + + DEV_ASSERT(pixel_value >= 0.0 && pixel_value <= 1.0); + + real_t height_value = Math::remap(pixel_value, 0.0f, 1.0f, remap_height_min, remap_height_max); + + if (height_value < new_min_height) { + new_min_height = height_value; + } + if (height_value > new_max_height) { + new_max_height = height_value; + } + + map_data_ptrw[i] = height_value; + } + + } break; + + default: { + return; + } + } + + min_height = new_min_height; + max_height = new_max_height; + + _update_shape(); + emit_changed(); +} + void HeightMapShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_map_width", "width"), &HeightMapShape3D::set_map_width); ClassDB::bind_method(D_METHOD("get_map_width"), &HeightMapShape3D::get_map_width); @@ -197,6 +296,8 @@ void HeightMapShape3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_min_height"), &HeightMapShape3D::get_min_height); ClassDB::bind_method(D_METHOD("get_max_height"), &HeightMapShape3D::get_max_height); + ClassDB::bind_method(D_METHOD("update_map_data_from_image", "image", "height_min", "height_max"), &HeightMapShape3D::update_map_data_from_image); + ADD_PROPERTY(PropertyInfo(Variant::INT, "map_width", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_width", "get_map_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "map_depth", PROPERTY_HINT_RANGE, "0.001,100,0.001,or_greater"), "set_map_depth", "get_map_depth"); ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "map_data"), "set_map_data", "get_map_data"); diff --git a/scene/resources/3d/height_map_shape_3d.h b/scene/resources/3d/height_map_shape_3d.h index 363d9ec0e9..33ba9c4472 100644 --- a/scene/resources/3d/height_map_shape_3d.h +++ b/scene/resources/3d/height_map_shape_3d.h @@ -33,6 +33,8 @@ #include "scene/resources/3d/shape_3d.h" +class Image; + class HeightMapShape3D : public Shape3D { GDCLASS(HeightMapShape3D, Shape3D); @@ -57,6 +59,8 @@ public: real_t get_min_height() const; real_t get_max_height() const; + void update_map_data_from_image(const Ref<Image> &p_image, real_t p_height_min, real_t p_height_max); + virtual Vector<Vector3> get_debug_mesh_lines() const override; virtual real_t get_enclosing_radius() const override; diff --git a/scene/resources/3d/primitive_meshes.cpp b/scene/resources/3d/primitive_meshes.cpp index c2b2a6d68b..ee772f960a 100644 --- a/scene/resources/3d/primitive_meshes.cpp +++ b/scene/resources/3d/primitive_meshes.cpp @@ -2845,10 +2845,8 @@ void TextMesh::_generate_glyph_mesh_data(const GlyphMeshKey &p_key, const Glyph for (int j = 0; j < gl_data.contours[i].size(); j++) { int next = (j + 1 == gl_data.contours[i].size()) ? 0 : (j + 1); - gl_data.min_p.x = MIN(gl_data.min_p.x, gl_data.contours[i][j].point.x); - gl_data.min_p.y = MIN(gl_data.min_p.y, gl_data.contours[i][j].point.y); - gl_data.max_p.x = MAX(gl_data.max_p.x, gl_data.contours[i][j].point.x); - gl_data.max_p.y = MAX(gl_data.max_p.y, gl_data.contours[i][j].point.y); + gl_data.min_p = gl_data.min_p.min(gl_data.contours[i][j].point); + gl_data.max_p = gl_data.max_p.max(gl_data.contours[i][j].point); length += (gl_data.contours[i][next].point - gl_data.contours[i][j].point).length(); inp.GetPoint(j) = gl_data.contours[i][j].point; diff --git a/scene/resources/animation.h b/scene/resources/animation.h index d3df8d03e5..c72327e464 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -75,6 +75,7 @@ public: LOOP_PINGPONG, }; + // LoopedFlag is used in Animataion to "process the keys at both ends correct". enum LoopedFlag { LOOPED_FLAG_NONE, LOOPED_FLAG_END, @@ -187,6 +188,7 @@ private: }; /* BEZIER TRACK */ + struct BezierKey { Vector2 in_handle; // Relative (x always <0) Vector2 out_handle; // Relative (x always >0) @@ -223,7 +225,7 @@ private: } }; - /* AUDIO TRACK */ + /* ANIMATION TRACK */ struct AnimationTrack : public Track { Vector<TKey<StringName>> values; diff --git a/scene/resources/compressed_texture.h b/scene/resources/compressed_texture.h index 5297d79cfe..439f7c097e 100644 --- a/scene/resources/compressed_texture.h +++ b/scene/resources/compressed_texture.h @@ -113,10 +113,10 @@ public: class ResourceFormatLoaderCompressedTexture2D : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; class CompressedTextureLayered : public TextureLayered { @@ -178,10 +178,10 @@ public: class ResourceFormatLoaderCompressedTextureLayered : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; class CompressedTexture2DArray : public CompressedTextureLayered { @@ -264,10 +264,10 @@ public: class ResourceFormatLoaderCompressedTexture3D : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; #endif // COMPRESSED_TEXTURE_H diff --git a/scene/resources/navigation_polygon.cpp b/scene/resources/navigation_polygon.cpp index e830153330..274b13a487 100644 --- a/scene/resources/navigation_polygon.cpp +++ b/scene/resources/navigation_polygon.cpp @@ -251,8 +251,7 @@ void NavigationPolygon::make_polygons_from_outlines() { } const Vector2 *r = ol.ptr(); for (int j = 0; j < olsize; j++) { - outside_point.x = MAX(r[j].x, outside_point.x); - outside_point.y = MAX(r[j].y, outside_point.y); + outside_point = outside_point.max(r[j]); } } diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h index 02898ce984..c05b7a24e1 100644 --- a/scene/resources/resource_format_text.h +++ b/scene/resources/resource_format_text.h @@ -139,17 +139,17 @@ public: class ResourceFormatLoaderText : public ResourceFormatLoader { public: static ResourceFormatLoaderText *singleton; - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const; - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes); - - virtual String get_resource_type(const String &p_path) const; - virtual String get_resource_script_class(const String &p_path) const; - virtual ResourceUID::ID get_resource_uid(const String &p_path) const; - virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false); - virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map); + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual void get_classes_used(const String &p_path, HashSet<StringName> *r_classes) override; + + virtual String get_resource_type(const String &p_path) const override; + virtual String get_resource_script_class(const String &p_path) const override; + virtual ResourceUID::ID get_resource_uid(const String &p_path) const override; + virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false) override; + virtual Error rename_dependencies(const String &p_path, const HashMap<String, String> &p_map) override; static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path); @@ -199,10 +199,10 @@ public: class ResourceFormatSaverText : public ResourceFormatSaver { public: static ResourceFormatSaverText *singleton; - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid); - virtual bool recognize(const Ref<Resource> &p_resource) const; - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual Error set_uid(const String &p_path, ResourceUID::ID p_uid) override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; ResourceFormatSaverText(); }; diff --git a/scene/resources/shader.h b/scene/resources/shader.h index ca889940ef..921143c219 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -96,17 +96,17 @@ VARIANT_ENUM_CAST(Shader::Mode); class ResourceFormatLoaderShader : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; class ResourceFormatSaverShader : public ResourceFormatSaver { public: - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; - virtual bool recognize(const Ref<Resource> &p_resource) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; }; #endif // SHADER_H diff --git a/scene/resources/shader_include.h b/scene/resources/shader_include.h index a8949b327e..9fb4271623 100644 --- a/scene/resources/shader_include.h +++ b/scene/resources/shader_include.h @@ -58,17 +58,17 @@ public: class ResourceFormatLoaderShaderInclude : public ResourceFormatLoader { public: - virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual bool handles_type(const String &p_type) const; - virtual String get_resource_type(const String &p_path) const; + virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override; + virtual void get_recognized_extensions(List<String> *p_extensions) const override; + virtual bool handles_type(const String &p_type) const override; + virtual String get_resource_type(const String &p_path) const override; }; class ResourceFormatSaverShaderInclude : public ResourceFormatSaver { public: - virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0); - virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const; - virtual bool recognize(const Ref<Resource> &p_resource) const; + virtual Error save(const Ref<Resource> &p_resource, const String &p_path, uint32_t p_flags = 0) override; + virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override; + virtual bool recognize(const Ref<Resource> &p_resource) const override; }; #endif // SHADER_INCLUDE_H diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index c7c2ddbb18..5cd9ec7ad0 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -4710,68 +4710,61 @@ String VisualShaderNodeExpression::get_expression() const { return expression; } +bool VisualShaderNodeExpression::_is_valid_identifier_char(char32_t p_c) const { + return p_c == '_' || (p_c >= 'A' && p_c <= 'Z') || (p_c >= 'a' && p_c <= 'z') || (p_c >= '0' && p_c <= '9'); +} + +String VisualShaderNodeExpression::_replace_port_names(const Vector<Pair<String, String>> &p_pairs, const String &p_expression) const { + String _expression = p_expression; + + for (const Pair<String, String> &pair : p_pairs) { + String from = pair.first; + String to = pair.second; + int search_idx = 0; + int len = from.length(); + + while (true) { + int index = _expression.find(from, search_idx); + if (index == -1) { + break; + } + + int left_index = index - 1; + int right_index = index + len; + bool left_correct = left_index <= 0 || !_is_valid_identifier_char(_expression[left_index]); + bool right_correct = right_index >= _expression.length() || !_is_valid_identifier_char(_expression[right_index]); + + if (left_correct && right_correct) { + _expression = _expression.erase(index, len); + _expression = _expression.insert(index, to); + + search_idx = index + to.length(); + } else { + search_idx = index + len; + } + } + } + + return _expression; +} + String VisualShaderNodeExpression::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const { String _expression = expression; _expression = _expression.insert(0, "\n"); _expression = _expression.replace("\n", "\n "); - static Vector<String> pre_symbols; - if (pre_symbols.is_empty()) { - pre_symbols.push_back(" "); - pre_symbols.push_back(","); - pre_symbols.push_back(";"); - pre_symbols.push_back("{"); - pre_symbols.push_back("["); - pre_symbols.push_back("]"); - pre_symbols.push_back("("); - pre_symbols.push_back(" "); - pre_symbols.push_back("-"); - pre_symbols.push_back("*"); - pre_symbols.push_back("/"); - pre_symbols.push_back("+"); - pre_symbols.push_back("="); - pre_symbols.push_back("&"); - pre_symbols.push_back("|"); - pre_symbols.push_back("!"); - } - - static Vector<String> post_symbols; - if (post_symbols.is_empty()) { - post_symbols.push_back(" "); - post_symbols.push_back("\n"); - post_symbols.push_back(","); - post_symbols.push_back(";"); - post_symbols.push_back("}"); - post_symbols.push_back("["); - post_symbols.push_back("]"); - post_symbols.push_back(")"); - post_symbols.push_back(" "); - post_symbols.push_back("."); - post_symbols.push_back("-"); - post_symbols.push_back("*"); - post_symbols.push_back("/"); - post_symbols.push_back("+"); - post_symbols.push_back("="); - post_symbols.push_back("&"); - post_symbols.push_back("|"); - post_symbols.push_back("!"); - } - + Vector<Pair<String, String>> input_port_names; for (int i = 0; i < get_input_port_count(); i++) { - for (int j = 0; j < pre_symbols.size(); j++) { - for (int k = 0; k < post_symbols.size(); k++) { - _expression = _expression.replace(pre_symbols[j] + get_input_port_name(i) + post_symbols[k], pre_symbols[j] + p_input_vars[i] + post_symbols[k]); - } - } + input_port_names.push_back(Pair<String, String>(get_input_port_name(i), p_input_vars[i])); } + _expression = _replace_port_names(input_port_names, _expression); + + Vector<Pair<String, String>> output_port_names; for (int i = 0; i < get_output_port_count(); i++) { - for (int j = 0; j < pre_symbols.size(); j++) { - for (int k = 0; k < post_symbols.size(); k++) { - _expression = _expression.replace(pre_symbols[j] + get_output_port_name(i) + post_symbols[k], pre_symbols[j] + p_output_vars[i] + post_symbols[k]); - } - } + output_port_names.push_back(Pair<String, String>(get_output_port_name(i), p_output_vars[i])); } + _expression = _replace_port_names(output_port_names, _expression); String output_initializer; diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 09ea9a8890..f02ada7ee8 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -819,6 +819,10 @@ public: class VisualShaderNodeExpression : public VisualShaderNodeGroupBase { GDCLASS(VisualShaderNodeExpression, VisualShaderNodeGroupBase); +private: + bool _is_valid_identifier_char(char32_t p_c) const; + String _replace_port_names(const Vector<Pair<String, String>> &p_pairs, const String &p_expression) const; + protected: String expression = ""; diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp index e4c469b752..c45f52ec9e 100644 --- a/scene/theme/default_theme.cpp +++ b/scene/theme/default_theme.cpp @@ -936,8 +936,6 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const theme->set_stylebox("separator", "VSeparator", separator_vertical); theme->set_icon("close", "Icons", icons["close"]); - theme->set_font("normal", "Fonts", Ref<Font>()); - theme->set_font("large", "Fonts", Ref<Font>()); theme->set_constant("separation", "HSeparator", Math::round(4 * scale)); theme->set_constant("separation", "VSeparator", Math::round(4 * scale)); diff --git a/servers/SCsub b/servers/SCsub index 2e4430f030..736bed68ec 100644 --- a/servers/SCsub +++ b/servers/SCsub @@ -7,7 +7,6 @@ env.servers_sources = [] env.add_source_files(env.servers_sources, "audio_server.cpp") env.add_source_files(env.servers_sources, "camera_server.cpp") env.add_source_files(env.servers_sources, "display_server.cpp") -env.add_source_files(env.servers_sources, "native_menu.cpp") env.add_source_files(env.servers_sources, "navigation_server_2d.cpp") env.add_source_files(env.servers_sources, "navigation_server_3d.cpp") env.add_source_files(env.servers_sources, "physics_server_2d.cpp") @@ -19,6 +18,7 @@ env.add_source_files(env.servers_sources, "text_server.cpp") SConscript("audio/SCsub") SConscript("camera/SCsub") SConscript("debugger/SCsub") +SConscript("display/SCsub") SConscript("extensions/SCsub") SConscript("movie_writer/SCsub") SConscript("navigation/SCsub") diff --git a/servers/audio/effects/audio_effect_hard_limiter.cpp b/servers/audio/effects/audio_effect_hard_limiter.cpp new file mode 100644 index 0000000000..e717557af2 --- /dev/null +++ b/servers/audio/effects/audio_effect_hard_limiter.cpp @@ -0,0 +1,161 @@ +/**************************************************************************/ +/* audio_effect_hard_limiter.cpp */ +/**************************************************************************/ +/* 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. */ +/**************************************************************************/ + +#include "audio_effect_hard_limiter.h" + +#include "servers/audio_server.h" + +void AudioEffectHardLimiterInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) { + float sample_rate = AudioServer::get_singleton()->get_mix_rate(); + + float ceiling = Math::db_to_linear(base->ceiling); + float release = base->release; + float attack = base->attack; + float pre_gain = Math::db_to_linear(base->pre_gain); + + for (int i = 0; i < p_frame_count; i++) { + float sample_left = p_src_frames[i].left; + float sample_right = p_src_frames[i].right; + + sample_left *= pre_gain; + sample_right *= pre_gain; + + float largest_sample = MAX(ABS(sample_left), ABS(sample_right)); + + release_factor = MAX(0.0, release_factor - 1.0 / sample_rate); + release_factor = MIN(release_factor, release); + + if (release_factor > 0.0) { + gain = Math::lerp(gain_target, 1.0f, 1.0f - release_factor / release); + } + + if (largest_sample * gain > ceiling) { + gain_target = ceiling / largest_sample; + release_factor = release; + attack_factor = attack; + } + + // Lerp gain over attack time to avoid distortion. + attack_factor = MAX(0.0f, attack_factor - 1.0f / sample_rate); + if (attack_factor > 0.0) { + gain = Math::lerp(gain_target, gain, 1.0f - attack_factor / attack); + } + + int bucket_id = gain_bucket_cursor / gain_bucket_size; + + // If first item within the current bucket, reset the bucket. + if (gain_bucket_cursor % gain_bucket_size == 0) { + gain_buckets[bucket_id] = 1.0f; + } + + gain_buckets[bucket_id] = MIN(gain_buckets[bucket_id], gain); + + gain_bucket_cursor = (gain_bucket_cursor + 1) % gain_samples_to_store; + + for (int j = 0; j < (int)gain_buckets.size(); j++) { + gain = MIN(gain, gain_buckets[j]); + } + + // Introduce latency by grabbing the AudioFrame stored previously, + // then overwrite it with current audioframe, then update circular + // buffer cursor. + float dst_buffer_left = sample_buffer_left[sample_cursor]; + float dst_buffer_right = sample_buffer_right[sample_cursor]; + + sample_buffer_left[sample_cursor] = sample_left; + sample_buffer_right[sample_cursor] = sample_right; + + sample_cursor = (sample_cursor + 1) % sample_buffer_left.size(); + + p_dst_frames[i].left = dst_buffer_left * gain; + p_dst_frames[i].right = dst_buffer_right * gain; + } +} + +Ref<AudioEffectInstance> AudioEffectHardLimiter::instantiate() { + Ref<AudioEffectHardLimiterInstance> ins; + ins.instantiate(); + ins->base = Ref<AudioEffectHardLimiter>(this); + + float mix_rate = AudioServer::get_singleton()->get_mix_rate(); + + for (int i = 0; i < (int)Math::ceil(mix_rate * attack) + 1; i++) { + ins->sample_buffer_left.push_back(0.0f); + ins->sample_buffer_right.push_back(0.0f); + } + + ins->gain_samples_to_store = (int)Math::ceil(mix_rate * (attack + sustain) + 1); + ins->gain_bucket_size = (int)(mix_rate * attack); + + for (int i = 0; i < ins->gain_samples_to_store; i += ins->gain_bucket_size) { + ins->gain_buckets.push_back(1.0f); + } + + return ins; +} + +void AudioEffectHardLimiter::set_ceiling_db(float p_ceiling) { + ceiling = p_ceiling; +} + +float AudioEffectHardLimiter::get_ceiling_db() const { + return ceiling; +} + +float AudioEffectHardLimiter::get_pre_gain_db() const { + return pre_gain; +} + +void AudioEffectHardLimiter::set_pre_gain_db(const float p_pre_gain) { + pre_gain = p_pre_gain; +} + +float AudioEffectHardLimiter::get_release() const { + return release; +} + +void AudioEffectHardLimiter::set_release(const float p_release) { + release = p_release; +} + +void AudioEffectHardLimiter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_ceiling_db", "ceiling"), &AudioEffectHardLimiter::set_ceiling_db); + ClassDB::bind_method(D_METHOD("get_ceiling_db"), &AudioEffectHardLimiter::get_ceiling_db); + + ClassDB::bind_method(D_METHOD("set_pre_gain_db", "p_pre_gain"), &AudioEffectHardLimiter::set_pre_gain_db); + ClassDB::bind_method(D_METHOD("get_pre_gain_db"), &AudioEffectHardLimiter::get_pre_gain_db); + + ClassDB::bind_method(D_METHOD("set_release", "p_release"), &AudioEffectHardLimiter::set_release); + ClassDB::bind_method(D_METHOD("get_release"), &AudioEffectHardLimiter::get_release); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pre_gain_db", PROPERTY_HINT_RANGE, "-24,24,0.01,suffix:dB"), "set_pre_gain_db", "get_pre_gain_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ceiling_db", PROPERTY_HINT_RANGE, "-24,0.0,0.01,suffix:dB"), "set_ceiling_db", "get_ceiling_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "release", PROPERTY_HINT_RANGE, "0.01,3,0.01"), "set_release", "get_release"); +} diff --git a/servers/audio/effects/audio_effect_hard_limiter.h b/servers/audio/effects/audio_effect_hard_limiter.h new file mode 100644 index 0000000000..7e28480797 --- /dev/null +++ b/servers/audio/effects/audio_effect_hard_limiter.h @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* audio_effect_hard_limiter.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 AUDIO_EFFECT_HARD_LIMITER_H +#define AUDIO_EFFECT_HARD_LIMITER_H + +#include "servers/audio/audio_effect.h" + +class AudioEffectHardLimiter; + +class AudioEffectHardLimiterInstance : public AudioEffectInstance { + GDCLASS(AudioEffectHardLimiterInstance, AudioEffectInstance); + friend class AudioEffectHardLimiter; + Ref<AudioEffectHardLimiter> base; + +private: + int sample_cursor = 0; + + float release_factor = 0; + float attack_factor = 0; + float gain = 1; + float gain_target = 1; + + LocalVector<float> sample_buffer_left; + LocalVector<float> sample_buffer_right; + + int gain_samples_to_store = 0; + int gain_bucket_cursor = 0; + int gain_bucket_size = 0; + LocalVector<float> gain_buckets; + +public: + virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) override; +}; + +class AudioEffectHardLimiter : public AudioEffect { + GDCLASS(AudioEffectHardLimiter, AudioEffect); + + friend class AudioEffectHardLimiterInstance; + float pre_gain = 0.0f; + float ceiling = -0.3f; + float sustain = 0.02f; + float release = 0.1f; + const float attack = 0.002; + +protected: + static void _bind_methods(); + +public: + void set_ceiling_db(float p_ceiling); + float get_ceiling_db() const; + + void set_release(float p_release); + float get_release() const; + + void set_pre_gain_db(float p_pre_gain); + float get_pre_gain_db() const; + + Ref<AudioEffectInstance> instantiate() override; +}; + +#endif // AUDIO_EFFECT_HARD_LIMITER_H diff --git a/servers/display/SCsub b/servers/display/SCsub new file mode 100644 index 0000000000..86681f9c74 --- /dev/null +++ b/servers/display/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/native_menu.cpp b/servers/display/native_menu.cpp index d1894ba6c3..ca46560c7c 100644 --- a/servers/native_menu.cpp +++ b/servers/display/native_menu.cpp @@ -68,6 +68,7 @@ void NativeMenu::_bind_methods() { ClassDB::bind_method(D_METHOD("find_item_index_with_text", "rid", "text"), &NativeMenu::find_item_index_with_text); ClassDB::bind_method(D_METHOD("find_item_index_with_tag", "rid", "tag"), &NativeMenu::find_item_index_with_tag); + ClassDB::bind_method(D_METHOD("find_item_index_with_submenu", "rid", "submenu_rid"), &NativeMenu::find_item_index_with_submenu); ClassDB::bind_method(D_METHOD("is_item_checked", "rid", "idx"), &NativeMenu::is_item_checked); ClassDB::bind_method(D_METHOD("is_item_checkable", "rid", "idx"), &NativeMenu::is_item_checkable); @@ -263,6 +264,19 @@ int NativeMenu::find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) return -1; } +int NativeMenu::find_item_index_with_submenu(const RID &p_rid, const RID &p_submenu_rid) const { + if (!has_menu(p_rid) || !has_menu(p_submenu_rid)) { + return -1; + } + int count = get_item_count(p_rid); + for (int i = 0; i < count; i++) { + if (p_submenu_rid == get_item_submenu(p_rid, i)) { + return i; + } + } + return -1; +} + bool NativeMenu::is_item_checked(const RID &p_rid, int p_idx) const { WARN_PRINT("Global menus are not supported on this platform."); return false; diff --git a/servers/native_menu.h b/servers/display/native_menu.h index f65e193972..2bc061a216 100644 --- a/servers/native_menu.h +++ b/servers/display/native_menu.h @@ -102,6 +102,7 @@ public: virtual int find_item_index_with_text(const RID &p_rid, const String &p_text) const; virtual int find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) const; + virtual int find_item_index_with_submenu(const RID &p_rid, const RID &p_submenu_rid) const; virtual bool is_item_checked(const RID &p_rid, int p_idx) const; virtual bool is_item_checkable(const RID &p_rid, int p_idx) const; diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 72228c25f2..9ceb6909fe 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -645,22 +645,22 @@ void DisplayServer::enable_for_stealing_focus(OS::ProcessID pid) { Error DisplayServer::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); - return OK; + return ERR_UNAVAILABLE; } Error DisplayServer::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); - return OK; + return ERR_UNAVAILABLE; } Error DisplayServer::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); - return OK; + return ERR_UNAVAILABLE; } Error DisplayServer::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); - return OK; + return ERR_UNAVAILABLE; } int DisplayServer::keyboard_get_layout_count() const { @@ -1014,6 +1014,8 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_SCREEN_CAPTURE); BIND_ENUM_CONSTANT(FEATURE_STATUS_INDICATOR); BIND_ENUM_CONSTANT(FEATURE_NATIVE_HELP); + BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_INPUT); + BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE); BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); diff --git a/servers/display_server.h b/servers/display_server.h index 85b791ca69..f1a98c2c17 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -36,7 +36,7 @@ #include "core/os/os.h" #include "core/variant/callable.h" -#include "native_menu.h" +#include "display/native_menu.h" class Texture2D; class Image; @@ -140,6 +140,8 @@ public: FEATURE_SCREEN_CAPTURE, FEATURE_STATUS_INDICATOR, FEATURE_NATIVE_HELP, + FEATURE_NATIVE_DIALOG_INPUT, + FEATURE_NATIVE_DIALOG_FILE, }; virtual bool has_feature(Feature p_feature) const = 0; diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index a8e36a615f..c12659fe7a 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -235,6 +235,7 @@ NavigationServer3D::NavigationServer3D() { GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true); GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true); + GLOBAL_DEF("navigation/baking/use_crash_prevention_checks", true); GLOBAL_DEF("navigation/baking/thread_model/baking_use_multiple_threads", true); GLOBAL_DEF("navigation/baking/thread_model/baking_use_high_priority_threads", true); diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp index 872d26aff6..ea389ff59c 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -2016,9 +2016,7 @@ void GodotHeightMapShape3D::_get_cell(const Vector3 &p_point, int &r_x, int &r_y Vector3 pos_local = shape_aabb.position + local_origin; Vector3 clamped_point(p_point); - clamped_point.x = CLAMP(p_point.x, pos_local.x, pos_local.x + shape_aabb.size.x); - clamped_point.y = CLAMP(p_point.y, pos_local.y, pos_local.y + shape_aabb.size.y); - clamped_point.z = CLAMP(p_point.z, pos_local.z, pos_local.z + shape_aabb.size.z); + clamped_point = p_point.clamp(pos_local, pos_local + shape_aabb.size); r_x = (clamped_point.x < 0.0) ? (clamped_point.x - 0.5) : (clamped_point.x + 0.5); r_y = (clamped_point.y < 0.0) ? (clamped_point.y - 0.5) : (clamped_point.y + 0.5); diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index 46b6689533..9a6ba776b4 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -655,7 +655,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: //this took about a week to get right.. //but is it right? who knows at this point.. - ERR_FAIL_INDEX_V(p_parameters.max_collisions, PhysicsServer3D::MotionResult::MAX_COLLISIONS, false); + ERR_FAIL_COND_V(p_parameters.max_collisions < 0 || p_parameters.max_collisions > PhysicsServer3D::MotionResult::MAX_COLLISIONS, false); if (r_result) { *r_result = PhysicsServer3D::MotionResult(); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 15d43ff5dd..f56ef11c14 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -985,6 +985,9 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_DAMPING); BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY); BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT); + BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_STIFFNESS); + BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_DAMPING); + BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LOWER_LIMIT); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_UPPER_LIMIT); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS); @@ -994,11 +997,18 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_ERP); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT); + BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS); + BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_DAMPING); + BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT); + BIND_ENUM_CONSTANT(G6DOF_JOINT_MAX); BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT); BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT); + BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING); + BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING); BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_MOTOR); BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR); + BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_MAX); ClassDB::bind_method(D_METHOD("joint_get_type", "joint"), &PhysicsServer3D::joint_get_type); diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 4e49129941..c03c0b7a40 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -43,6 +43,7 @@ #include "audio/effects/audio_effect_distortion.h" #include "audio/effects/audio_effect_eq.h" #include "audio/effects/audio_effect_filter.h" +#include "audio/effects/audio_effect_hard_limiter.h" #include "audio/effects/audio_effect_limiter.h" #include "audio/effects/audio_effect_panner.h" #include "audio/effects/audio_effect_phaser.h" @@ -56,11 +57,11 @@ #include "camera/camera_feed.h" #include "camera_server.h" #include "debugger/servers_debugger.h" +#include "display/native_menu.h" #include "display_server.h" #include "movie_writer/movie_writer.h" #include "movie_writer/movie_writer_mjpeg.h" #include "movie_writer/movie_writer_pngwav.h" -#include "native_menu.h" #include "rendering/renderer_compositor.h" #include "rendering/renderer_rd/framebuffer_cache_rd.h" #include "rendering/renderer_rd/storage_rd/render_data_rd.h" @@ -210,6 +211,7 @@ void register_server_types() { GDREGISTER_CLASS(AudioEffectDelay); GDREGISTER_CLASS(AudioEffectCompressor); GDREGISTER_CLASS(AudioEffectLimiter); + GDREGISTER_CLASS(AudioEffectHardLimiter); GDREGISTER_CLASS(AudioEffectPitchShift); GDREGISTER_CLASS(AudioEffectPhaser); diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 8e342375f8..e32164ea98 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -32,6 +32,7 @@ #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" +#include "core/math/transform_interpolator.h" #include "renderer_viewport.h" #include "rendering_server_default.h" #include "rendering_server_globals.h" @@ -81,7 +82,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2 if (r_items) { r_items[r_index] = child_items[i]; child_items[i]->ysort_xform = p_transform; - child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.columns[2]); + child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform_curr.columns[2]); child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr; child_items[i]->ysort_modulate = p_modulate; child_items[i]->ysort_index = r_index; @@ -98,7 +99,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2 r_index++; if (child_items[i]->sort_y) { - _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z); + _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform_curr, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z); } } } @@ -244,7 +245,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 } } - Transform2D xform = ci->xform; + Transform2D final_xform; + if (!_interpolation_data.interpolation_enabled || !ci->interpolated) { + final_xform = ci->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, final_xform, f); + } + Transform2D parent_xform = p_parent_xform; Point2 repeat_size = p_repeat_size; @@ -258,19 +266,19 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 ci->repeat_times = repeat_times; if (repeat_size.x || repeat_size.y) { - rect.size += repeat_size * repeat_times / ci->xform.get_scale(); + rect.size += repeat_size * repeat_times / final_xform.get_scale(); rect.position -= repeat_size * (repeat_times / 2); } } if (snapping_2d_transforms_to_pixel) { - xform.columns[2] = xform.columns[2].round(); + final_xform.columns[2] = final_xform.columns[2].round(); parent_xform.columns[2] = parent_xform.columns[2].round(); } - xform = parent_xform * xform; + final_xform = parent_xform * final_xform; - Rect2 global_rect = xform.xform(rect); + Rect2 global_rect = final_xform.xform(rect); global_rect.position += p_clip_rect.position; if (ci->use_parent_material && p_material_owner) { @@ -324,7 +332,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 child_item_count = ci->ysort_children_count + 1; child_items = (Item **)alloca(child_item_count * sizeof(Item *)); - ci->ysort_xform = ci->xform.affine_inverse(); + ci->ysort_xform = final_xform.affine_inverse(); ci->ysort_pos = Vector2(); ci->ysort_modulate = Color(1, 1, 1, 1); ci->ysort_index = 0; @@ -337,7 +345,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 sorter.sort(child_items, child_item_count); for (i = 0; i < child_item_count; i++) { - _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times); + _cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; @@ -347,7 +355,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 canvas_group_from = r_z_last_list[zidx]; } - _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); + _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; @@ -361,14 +369,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 if (!child_items[i]->behind && !use_canvas_group) { continue; } - _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times); + _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times); } - _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); + _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); for (int i = 0; i < child_item_count; i++) { if (child_items[i]->behind || use_canvas_group) { continue; } - _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times); + _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times); } } } @@ -512,7 +520,16 @@ void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_NULL(canvas_item); - canvas_item->xform = p_transform; + if (_interpolation_data.interpolation_enabled && canvas_item->interpolated) { + if (!canvas_item->on_interpolate_transform_list) { + _interpolation_data.canvas_item_transform_update_list_curr->push_back(p_item); + canvas_item->on_interpolate_transform_list = true; + } else { + DEV_ASSERT(_interpolation_data.canvas_item_transform_update_list_curr->size() > 0); + } + } + + canvas_item->xform_curr = p_transform; } void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) { @@ -1622,6 +1639,26 @@ bool RendererCanvasCull::canvas_item_get_debug_redraw() const { return debug_redraw; } +void RendererCanvasCull::canvas_item_set_interpolated(RID p_item, bool p_interpolated) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_NULL(canvas_item); + canvas_item->interpolated = p_interpolated; +} + +void RendererCanvasCull::canvas_item_reset_physics_interpolation(RID p_item) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_NULL(canvas_item); + canvas_item->xform_prev = canvas_item->xform_curr; +} + +// Useful especially for origin shifting. +void RendererCanvasCull::canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_NULL(canvas_item); + canvas_item->xform_prev = p_transform * canvas_item->xform_prev; + canvas_item->xform_curr = p_transform * canvas_item->xform_curr; +} + void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_NULL(canvas_item); @@ -1720,7 +1757,16 @@ void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_NULL(clight); - clight->xform = p_transform; + if (_interpolation_data.interpolation_enabled && clight->interpolated) { + if (!clight->on_interpolate_transform_list) { + _interpolation_data.canvas_light_transform_update_list_curr->push_back(p_light); + clight->on_interpolate_transform_list = true; + } else { + DEV_ASSERT(_interpolation_data.canvas_light_transform_update_list_curr->size() > 0); + } + } + + clight->xform_curr = p_transform; } void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) { @@ -1839,6 +1885,25 @@ void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smo clight->shadow_smooth = p_smooth; } +void RendererCanvasCull::canvas_light_set_interpolated(RID p_light, bool p_interpolated) { + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); + ERR_FAIL_NULL(clight); + clight->interpolated = p_interpolated; +} + +void RendererCanvasCull::canvas_light_reset_physics_interpolation(RID p_light) { + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); + ERR_FAIL_NULL(clight); + clight->xform_prev = clight->xform_curr; +} + +void RendererCanvasCull::canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) { + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); + ERR_FAIL_NULL(clight); + clight->xform_prev = p_transform * clight->xform_prev; + clight->xform_curr = p_transform * clight->xform_curr; +} + RID RendererCanvasCull::canvas_light_occluder_allocate() { return canvas_light_occluder_owner.allocate_rid(); } @@ -1911,7 +1976,16 @@ void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, con RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_NULL(occluder); - occluder->xform = p_xform; + if (_interpolation_data.interpolation_enabled && occluder->interpolated) { + if (!occluder->on_interpolate_transform_list) { + _interpolation_data.canvas_light_occluder_transform_update_list_curr->push_back(p_occluder); + occluder->on_interpolate_transform_list = true; + } else { + DEV_ASSERT(_interpolation_data.canvas_light_occluder_transform_update_list_curr->size() > 0); + } + } + + occluder->xform_curr = p_xform; } void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) { @@ -1921,6 +1995,25 @@ void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, in occluder->light_mask = p_mask; } +void RendererCanvasCull::canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); + ERR_FAIL_NULL(occluder); + occluder->interpolated = p_interpolated; +} + +void RendererCanvasCull::canvas_light_occluder_reset_physics_interpolation(RID p_occluder) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); + ERR_FAIL_NULL(occluder); + occluder->xform_prev = occluder->xform_curr; +} + +void RendererCanvasCull::canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); + ERR_FAIL_NULL(occluder); + occluder->xform_prev = p_transform * occluder->xform_prev; + occluder->xform_curr = p_transform * occluder->xform_curr; +} + RID RendererCanvasCull::canvas_occluder_polygon_allocate() { return canvas_light_occluder_polygon_owner.allocate_rid(); } @@ -2075,6 +2168,7 @@ bool RendererCanvasCull::free(RID p_rid) { } else if (canvas_item_owner.owns(p_rid)) { Item *canvas_item = canvas_item_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(canvas_item, true); + _interpolation_data.notify_free_canvas_item(p_rid, *canvas_item); if (canvas_item->parent.is_valid()) { if (canvas_owner.owns(canvas_item->parent)) { @@ -2114,6 +2208,7 @@ bool RendererCanvasCull::free(RID p_rid) { } else if (canvas_light_owner.owns(p_rid)) { RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(canvas_light, true); + _interpolation_data.notify_free_canvas_light(p_rid, *canvas_light); if (canvas_light->canvas.is_valid()) { Canvas *canvas = canvas_owner.get_or_null(canvas_light->canvas); @@ -2129,6 +2224,7 @@ bool RendererCanvasCull::free(RID p_rid) { } else if (canvas_light_occluder_owner.owns(p_rid)) { RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(occluder, true); + _interpolation_data.notify_free_canvas_light_occluder(p_rid, *occluder); if (occluder->polygon.is_valid()) { LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon); @@ -2186,6 +2282,81 @@ void RendererCanvasCull::finalize() { _free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon"); } +void RendererCanvasCull::tick() { + if (_interpolation_data.interpolation_enabled) { + update_interpolation_tick(true); + } +} + +void RendererCanvasCull::update_interpolation_tick(bool p_process) { +#define GODOT_UPDATE_INTERPOLATION_TICK(m_list_prev, m_list_curr, m_type, m_owner_list) \ + /* Detect any that were on the previous transform list that are no longer active. */ \ + for (unsigned int n = 0; n < _interpolation_data.m_list_prev->size(); n++) { \ + const RID &rid = (*_interpolation_data.m_list_prev)[n]; \ + m_type *item = m_owner_list.get_or_null(rid); \ + /* no longer active? (either the instance deleted or no longer being transformed) */ \ + if (item && !item->on_interpolate_transform_list) { \ + item->xform_prev = item->xform_curr; \ + } \ + } \ + /* and now for any in the transform list (being actively interpolated), */ \ + /* keep the previous transform value up to date and ready for next tick */ \ + if (p_process) { \ + for (unsigned int n = 0; n < _interpolation_data.m_list_curr->size(); n++) { \ + const RID &rid = (*_interpolation_data.m_list_curr)[n]; \ + m_type *item = m_owner_list.get_or_null(rid); \ + if (item) { \ + item->xform_prev = item->xform_curr; \ + item->on_interpolate_transform_list = false; \ + } \ + } \ + } \ + SWAP(_interpolation_data.m_list_curr, _interpolation_data.m_list_prev); \ + _interpolation_data.m_list_curr->clear(); + + GODOT_UPDATE_INTERPOLATION_TICK(canvas_item_transform_update_list_prev, canvas_item_transform_update_list_curr, Item, canvas_item_owner); + GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_transform_update_list_prev, canvas_light_transform_update_list_curr, RendererCanvasRender::Light, canvas_light_owner); + GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_occluder_transform_update_list_prev, canvas_light_occluder_transform_update_list_curr, RendererCanvasRender::LightOccluderInstance, canvas_light_occluder_owner); + +#undef GODOT_UPDATE_INTERPOLATION_TICK +} + +void RendererCanvasCull::InterpolationData::notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item) { + r_canvas_item.on_interpolate_transform_list = false; + + if (!interpolation_enabled) { + return; + } + + // If the instance was on any of the lists, remove. + canvas_item_transform_update_list_curr->erase_multiple_unordered(p_rid); + canvas_item_transform_update_list_prev->erase_multiple_unordered(p_rid); +} + +void RendererCanvasCull::InterpolationData::notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light) { + r_canvas_light.on_interpolate_transform_list = false; + + if (!interpolation_enabled) { + return; + } + + // If the instance was on any of the lists, remove. + canvas_light_transform_update_list_curr->erase_multiple_unordered(p_rid); + canvas_light_transform_update_list_prev->erase_multiple_unordered(p_rid); +} + +void RendererCanvasCull::InterpolationData::notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder) { + r_canvas_light_occluder.on_interpolate_transform_list = false; + + if (!interpolation_enabled) { + return; + } + + // If the instance was on any of the lists, remove. + canvas_light_occluder_transform_update_list_curr->erase_multiple_unordered(p_rid); + canvas_light_occluder_transform_update_list_prev->erase_multiple_unordered(p_rid); +} + RendererCanvasCull::RendererCanvasCull() { z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index d733a7bed2..961506ca28 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -271,6 +271,10 @@ public: void canvas_item_set_debug_redraw(bool p_enabled); bool canvas_item_get_debug_redraw() const; + void canvas_item_set_interpolated(RID p_item, bool p_interpolated); + void canvas_item_reset_physics_interpolation(RID p_item); + void canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform); + RID canvas_light_allocate(); void canvas_light_initialize(RID p_rid); @@ -297,6 +301,10 @@ public: void canvas_light_set_shadow_color(RID p_light, const Color &p_color); void canvas_light_set_shadow_smooth(RID p_light, float p_smooth); + void canvas_light_set_interpolated(RID p_light, bool p_interpolated); + void canvas_light_reset_physics_interpolation(RID p_light); + void canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform); + RID canvas_light_occluder_allocate(); void canvas_light_occluder_initialize(RID p_rid); @@ -307,6 +315,10 @@ public: void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform); void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask); + void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated); + void canvas_light_occluder_reset_physics_interpolation(RID p_occluder); + void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform); + RID canvas_occluder_polygon_allocate(); void canvas_occluder_polygon_initialize(RID p_rid); @@ -336,6 +348,32 @@ public: void finalize(); + /* INTERPOLATION */ + + void tick(); + void update_interpolation_tick(bool p_process = true); + void set_physics_interpolation_enabled(bool p_enabled) { _interpolation_data.interpolation_enabled = p_enabled; } + + struct InterpolationData { + void notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item); + void notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light); + void notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder); + + LocalVector<RID> canvas_item_transform_update_lists[2]; + LocalVector<RID> *canvas_item_transform_update_list_curr = &canvas_item_transform_update_lists[0]; + LocalVector<RID> *canvas_item_transform_update_list_prev = &canvas_item_transform_update_lists[1]; + + LocalVector<RID> canvas_light_transform_update_lists[2]; + LocalVector<RID> *canvas_light_transform_update_list_curr = &canvas_light_transform_update_lists[0]; + LocalVector<RID> *canvas_light_transform_update_list_prev = &canvas_light_transform_update_lists[1]; + + LocalVector<RID> canvas_light_occluder_transform_update_lists[2]; + LocalVector<RID> *canvas_light_occluder_transform_update_list_curr = &canvas_light_occluder_transform_update_lists[0]; + LocalVector<RID> *canvas_light_occluder_transform_update_list_prev = &canvas_light_occluder_transform_update_lists[1]; + + bool interpolation_enabled = false; + } _interpolation_data; + RendererCanvasCull(); ~RendererCanvasCull(); }; diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index cf8f6dcb2e..4a56548932 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -51,9 +51,12 @@ public: }; struct Light { - bool enabled; + bool enabled : 1; + bool on_interpolate_transform_list : 1; + bool interpolated : 1; Color color; - Transform2D xform; + Transform2D xform_curr; + Transform2D xform_prev; float height; float energy; float scale; @@ -97,6 +100,8 @@ public: Light() { version = 0; enabled = true; + on_interpolate_transform_list = false; + interpolated = true; color = Color(1, 1, 1); shadow_color = Color(0, 0, 0, 0); height = 0; @@ -307,11 +312,17 @@ public: Rect2 rect; }; - Transform2D xform; - bool clip; - bool visible; - bool behind; - bool update_when_visible; + // For interpolation we store the current local xform, + // and the previous xform from the previous tick. + Transform2D xform_curr; + Transform2D xform_prev; + + bool clip : 1; + bool visible : 1; + bool behind : 1; + bool update_when_visible : 1; + bool on_interpolate_transform_list : 1; + bool interpolated : 1; struct CanvasGroup { RS::CanvasGroupMode mode; @@ -472,6 +483,8 @@ public: texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; repeat_source = false; + on_interpolate_transform_list = false; + interpolated = true; } virtual ~Item() { clear(); @@ -487,12 +500,15 @@ public: virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0; struct LightOccluderInstance { - bool enabled; + bool enabled : 1; + bool on_interpolate_transform_list : 1; + bool interpolated : 1; RID canvas; RID polygon; RID occluder; Rect2 aabb_cache; - Transform2D xform; + Transform2D xform_curr; + Transform2D xform_prev; Transform2D xform_cache; int light_mask; bool sdf_collision; @@ -502,6 +518,8 @@ public: LightOccluderInstance() { enabled = true; + on_interpolate_transform_list = false; + interpolated = false; sdf_collision = false; next = nullptr; light_mask = 1; diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index abbe04b5b2..1568867663 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -583,7 +583,7 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, p_rect); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); if (p_secondary.is_valid()) { @@ -982,7 +982,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, p_region); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer))); RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); RD::get_singleton()->draw_list_set_push_constant(draw_list, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp index a57a65fd5a..017ad41fdc 100644 --- a/servers/rendering/renderer_rd/effects/debug_effects.cpp +++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp @@ -282,7 +282,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj // And draw our frustum. RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect); RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); @@ -326,7 +326,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj rect.size.x *= atlas_rect_norm.size.x; rect.size.y *= atlas_rect_norm.size.y; - draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); + draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect); pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); diff --git a/servers/rendering/renderer_rd/effects/fsr2.cpp b/servers/rendering/renderer_rd/effects/fsr2.cpp index bebbf51d51..925352a7d1 100644 --- a/servers/rendering/renderer_rd/effects/fsr2.cpp +++ b/servers/rendering/renderer_rd/effects/fsr2.cpp @@ -527,6 +527,7 @@ FSR2Effect::FSR2Effect() { "\n#define FFX_GLSL 1\n" "\n#define FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS 1\n" "\n#define FFX_FSR2_OPTION_HDR_COLOR_INPUT 1\n" + "\n#define FFX_FSR2_OPTION_INVERTED_DEPTH 1\n" "\n#define FFX_FSR2_OPTION_GODOT_REACTIVE_MASK_CLAMP 1\n" "\n#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS 1\n"; @@ -808,7 +809,7 @@ FSR2Effect::~FSR2Effect() { FSR2Context *FSR2Effect::create_context(Size2i p_internal_size, Size2i p_target_size) { FSR2Context *context = memnew(RendererRD::FSR2Context); - context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE; + context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE | FFX_FSR2_ENABLE_DEPTH_INVERTED; context->fsr_desc.maxRenderSize.width = p_internal_size.x; context->fsr_desc.maxRenderSize.height = p_internal_size.y; context->fsr_desc.displaySize.width = p_target_size.x; diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp index bdd687d9f4..3db82c8fbd 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.cpp +++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp @@ -483,8 +483,12 @@ void SSEffects::downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uin downsample_uniform_set = uniform_set_cache->get_cache_vec(shader, 2, u_depths); } - float depth_linearize_mul = -p_projection.columns[3][2] * 0.5; - float depth_linearize_add = p_projection.columns[2][2]; + Projection correction; + correction.set_depth_correction(false); + Projection temp = correction * p_projection; + + float depth_linearize_mul = -temp.columns[3][2]; + float depth_linearize_add = temp.columns[2][2]; if (depth_linearize_mul * depth_linearize_add < 0) { depth_linearize_add = -depth_linearize_add; } diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 1d144bedcf..48537a97d9 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -509,9 +509,7 @@ Vector3i Fog::_point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_position.z = Math::pow(float(fog_position.z), float(1.0 / volumetric_fog_detail_spread)); fog_position = fog_position * fog_size - Vector3(0.5, 0.5, 0.5); - fog_position.x = CLAMP(fog_position.x, 0.0, fog_size.x); - fog_position.y = CLAMP(fog_position.y, 0.0, fog_size.y); - fog_position.z = CLAMP(fog_position.z, 0.0, fog_size.z); + fog_position = fog_position.clamp(Vector3(), fog_size); return Vector3i(fog_position); } @@ -680,8 +678,8 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P max = Vector3i(1, 1, 1); for (int j = 0; j < 8; j++) { - min = Vector3i(MIN(min.x, points[j].x), MIN(min.y, points[j].y), MIN(min.z, points[j].z)); - max = Vector3i(MAX(max.x, points[j].x), MAX(max.y, points[j].y), MAX(max.z, points[j].z)); + min = min.min(points[j]); + max = max.max(points[j]); } kernel_size = max - min; diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index 78214ede0b..c7752f8a86 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -3407,7 +3407,7 @@ void GI::init(SkyRD *p_sky) { RD::PipelineDepthStencilState ds; ds.enable_depth_test = true; ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + ds.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; voxel_gi_debug_shader_version_pipelines[i].setup(voxel_gi_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); } @@ -3575,7 +3575,7 @@ void GI::init(SkyRD *p_sky) { RD::PipelineDepthStencilState ds; ds.enable_depth_test = true; ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + ds.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; for (int i = 0; i < SDFGIShader::PROBE_DEBUG_MAX; i++) { // TODO check if version is enabled @@ -3810,8 +3810,13 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor rbgi->scene_data_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SceneData)); } + Projection correction; + correction.set_depth_correction(false); + for (uint32_t v = 0; v < p_view_count; v++) { - RendererRD::MaterialStorage::store_camera(p_projections[v].inverse(), scene_data.inv_projection[v]); + Projection temp = correction * p_projections[v]; + + RendererRD::MaterialStorage::store_camera(temp.inverse(), scene_data.inv_projection[v]); scene_data.eye_offset[v][0] = p_eye_offsets[v].x; scene_data.eye_offset[v][1] = p_eye_offsets[v].y; scene_data.eye_offset[v][2] = p_eye_offsets[v].z; diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index 41609dc74d..27c07f23fa 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -141,7 +141,7 @@ void SkyRD::SkyShaderData::set_code(const String &p_code) { for (int i = 0; i < SKY_VERSION_MAX; i++) { RD::PipelineDepthStencilState depth_stencil_state; depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) { RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i); @@ -1174,6 +1174,7 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con } Projection correction; + correction.set_depth_correction(false, true); correction.add_jitter_offset(p_jitter); sky_scene_state.view_count = p_view_count; @@ -1184,10 +1185,12 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con for (uint32_t i = 0; i < p_view_count; i++) { Projection view_inv_projection = (correction * p_view_projections[i]).inverse(); if (p_view_count > 1) { + // Reprojection is used when we need to have things in combined space. RendererRD::MaterialStorage::store_camera(p_cam_projection * view_inv_projection, sky_scene_state.ubo.combined_reprojection[i]); } else { + // This is unused so just reset to identity. Projection ident; - RendererRD::MaterialStorage::store_camera(correction, sky_scene_state.ubo.combined_reprojection[i]); + RendererRD::MaterialStorage::store_camera(ident, sky_scene_state.ubo.combined_reprojection[i]); } RendererRD::MaterialStorage::store_camera(view_inv_projection, sky_scene_state.ubo.view_inv_projections[i]); 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 33bb5459f2..0e69ad99b8 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -546,6 +546,8 @@ void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_lis VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MULTIVIEW); VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS); VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MOTION_VECTORS); + VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_SEPARATE_SPECULAR | COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS); + VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_TRANSPARENT | COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS); default: { ERR_FAIL_MSG("Invalid color pass flag combination " + itos(p_params->color_pass_flags)); } @@ -1130,6 +1132,7 @@ void RenderForwardClustered::_update_sdfgi(RenderDataRD *p_render_data) { } if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { + RENDER_TIMESTAMP("Render SDFGI"); Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); float exposure_normalization = 1.0; @@ -1401,7 +1404,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } } - //cube shadows are rendered in their own way + RENDER_TIMESTAMP("Render OmniLight Shadows"); + // Cube shadows are rendered in their own way. for (const int &index : p_render_data->cube_shadows) { _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); } @@ -1457,6 +1461,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo // drawcalls per eye/view. It will all sync up at the barrier. if (p_use_ssao || p_use_ssil) { + RENDER_TIMESTAMP("Prepare Depth for SSAO/SSIL"); // Convert our depth buffer data to linear data in for (uint32_t v = 0; v < rb->get_view_count(); v++) { ss_effects->downsample_depth(rb, v, p_render_data->scene_data->view_projection[v]); @@ -1472,6 +1477,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } } + RENDER_TIMESTAMP("Pre Opaque Render"); + if (current_cluster_builder) { // Note: when rendering stereoscopic (multiview) we are using our combined frustum projection to create // our cluster data. We use reprojection in the shader to adjust for our left/right eye. @@ -1504,6 +1511,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } if (rb_data.is_valid()) { + RENDER_TIMESTAMP("Update Volumetric Fog"); bool directional_shadows = RendererRD::LightStorage::get_singleton()->has_directional_shadows(directional_light_count); _update_volumetric_fog(rb, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes); } @@ -1965,6 +1973,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co WARN_PRINT_ONCE("Pre opaque rendering effects can't access resolved depth buffers."); } + RENDER_TIMESTAMP("Process Pre Opaque Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_OPAQUE, p_render_data); } @@ -1976,6 +1985,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, normal_roughness_views, rb_data.is_valid() && rb_data->has_voxelgi() ? rb_data->get_voxelgi() : RID()); + RENDER_TIMESTAMP("Render Opaque Pass"); + RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count; @@ -1986,8 +1997,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass); - RENDER_TIMESTAMP("Render Opaque Pass"); - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, samplers, true); { @@ -2012,7 +2021,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co uint32_t opaque_color_pass_flags = using_motion_pass ? (color_pass_flags & ~COLOR_PASS_FLAG_MOTION_VECTORS) : color_pass_flags; RID opaque_framebuffer = using_motion_pass ? rb_data->get_color_pass_fb(opaque_color_pass_flags) : color_framebuffer; RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, opaque_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count, 0, spec_constant_base_flags); - _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0); + _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0); } RD::get_singleton()->draw_command_end_label(); @@ -2051,6 +2060,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } + RENDER_TIMESTAMP("Process Post Opaque Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_OPAQUE, p_render_data); } @@ -2111,6 +2121,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } { + RENDER_TIMESTAMP("Process Post Sky Compositor Effects"); // Don't need to check for depth or color resolve here, we've already triggered it. _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_SKY, p_render_data); } @@ -2188,6 +2199,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } + RENDER_TIMESTAMP("Process Pre Transparent Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); } @@ -2232,6 +2244,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); { + RENDER_TIMESTAMP("Process Post Transparent Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_TRANSPARENT, p_render_data); } @@ -2627,7 +2640,7 @@ void RenderForwardClustered::_render_shadow_end() { for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from); - _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect); + _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect); } RD::get_singleton()->draw_command_end_label(); @@ -2727,7 +2740,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } @@ -2777,7 +2790,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance Color(0, 0, 0, 0), Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); const int uv_offset_count = 9; static const Vector2 uv_offsets[uv_offset_count] = { @@ -2883,7 +2896,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu } RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, 0, true, false, rp_uniform_set, false); - _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2()); + _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, Rect2()); } RD::get_singleton()->draw_command_end_label(); @@ -4263,7 +4276,7 @@ RenderForwardClustered::RenderForwardClustered() { sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 12af8822b4..1f12d92754 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -379,7 +379,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { template <PassMode p_pass_mode, uint32_t p_color_pass_flags = 0> _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); void _update_instance_data_buffer(RenderListType p_render_list); void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); 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 0b504eca0a..209fabeddf 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 @@ -260,7 +260,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { if (depth_test != DEPTH_TEST_DISABLED) { depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; } bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable")); @@ -827,7 +827,7 @@ void fragment() { sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } } 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 ac93aca6bb..b54f511d05 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -984,7 +984,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0); RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); if (copy_canvas) { @@ -1385,7 +1385,7 @@ void RenderForwardMobile::_render_shadow_end() { for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from); - _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect); + _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect); } RD::get_singleton()->draw_command_end_label(); @@ -1437,7 +1437,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c Color(0, 0, 0, 0), Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } @@ -1483,7 +1483,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *> Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); const int uv_offset_count = 9; static const Vector2 uv_offsets[uv_offset_count] = { @@ -2835,6 +2835,11 @@ RenderForwardMobile::~RenderForwardMobile() { for (const RID &rid : scene_state.uniform_buffers) { RD::get_singleton()->free(rid); } + for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) { + if (scene_state.instance_buffer[i].is_valid()) { + RD::get_singleton()->free(scene_state.instance_buffer[i]); + } + } RD::get_singleton()->free(scene_state.lightmap_buffer); RD::get_singleton()->free(scene_state.lightmap_capture_buffer); memdelete_arr(scene_state.lightmap_captures); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 5c02204627..f29503e5ec 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -350,7 +350,7 @@ private: template <PassMode p_pass_mode> _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); RenderList render_list[RENDER_LIST_MAX]; 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 95ba76a707..a2f112669c 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 @@ -271,7 +271,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { if (depth_test != DEPTH_TEST_DISABLED) { depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; } @@ -731,7 +731,7 @@ void fragment() { sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 673afc53e5..6f56711151 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -34,6 +34,7 @@ #include "core/math/geometry_2d.h" #include "core/math/math_defs.h" #include "core/math/math_funcs.h" +#include "core/math/transform_interpolator.h" #include "renderer_compositor_rd.h" #include "servers/rendering/renderer_rd/storage_rd/material_storage.h" #include "servers/rendering/renderer_rd/storage_rd/particles_storage.h" @@ -427,7 +428,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform; if (p_offset.x || p_offset.y) { - base_transform *= Transform2D(0, p_offset / p_item->xform.get_scale()); + base_transform *= Transform2D(0, p_offset / p_item->xform_curr.get_scale()); // TODO: Interpolate or explain why not needed. } Transform2D draw_transform; @@ -1366,7 +1367,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p ERR_CONTINUE(!clight); } - 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 + Transform2D final_xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !l->interpolated) { + final_xform = l->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(l->xform_prev, l->xform_curr, final_xform, f); + } + // Convert light position to canvas coordinates, as all computation is done in canvas coordinates to avoid precision loss. + Vector2 canvas_light_pos = p_canvas_transform.xform(final_xform.get_origin()); state.light_uniforms[index].position[0] = canvas_light_pos.x; state.light_uniforms[index].position[1] = canvas_light_pos.y; diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl index fe770ac065..48c1b0a3f6 100644 --- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl @@ -32,9 +32,9 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh; float get_depth_at_pos(vec2 uv) { float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + depth = -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); } return depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl index 947aa793d9..2010b58474 100644 --- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl @@ -53,9 +53,9 @@ layout(set = 2, binding = 0) uniform sampler2D original_weight; float get_depth_at_pos(vec2 uv) { float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + depth = -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); } return depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl index e77d0de719..3fb93dda35 100644 --- a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl @@ -77,8 +77,8 @@ void main() { float depth_fix = 1.0 / dot(normal, unorm); depth = 2.0 * depth - 1.0; - float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - depth = (linear_depth * depth_fix) / params.z_far; - + float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); + // linear_depth equal to view space depth + depth = (params.z_far - linear_depth * depth_fix) / params.z_far; gl_FragDepth = depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl index 51caa67d3c..d9e21b8cd1 100644 --- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl @@ -98,9 +98,9 @@ void main() { // unproject our Z value so we can use it directly. depth = depth * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0; + depth = -(depth * (params.camera_z_far - params.camera_z_near) - (params.camera_z_far + params.camera_z_near)) / 2.0; } else { - depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near)); + depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near + depth * (params.camera_z_far - params.camera_z_near)); } depth = -depth; } diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl index 80ed34cda1..480172f9dc 100644 --- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl @@ -174,9 +174,9 @@ vec3 reconstruct_position(ivec2 screen_pos) { pos.z = pos.z * 2.0 - 1.0; if (params.orthogonal) { - pos.z = ((pos.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + pos.z = -(pos.z * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - pos.z * (params.z_far - params.z_near)); + pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + pos.z * (params.z_far - params.z_near)); } pos.z = -pos.z; diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl index 4e5b11aed8..35457a2482 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl @@ -25,7 +25,7 @@ params; void main() { vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0)); uv_interp = base_arr[gl_VertexIndex]; - gl_Position = vec4(uv_interp, 1.0, 1.0); + gl_Position = vec4(uv_interp, 0.0, 1.0); } #[fragment] @@ -158,7 +158,7 @@ vec3 interleaved_gradient_noise(vec2 pos) { vec4 volumetric_fog_process(vec2 screen_uv) { #ifdef USE_MULTIVIEW - vec4 reprojected = sky_scene_data.combined_reprojection[ViewIndex] * (vec4(screen_uv * 2.0 - 1.0, 1.0, 1.0) * sky_scene_data.z_far); + vec4 reprojected = sky_scene_data.combined_reprojection[ViewIndex] * vec4(screen_uv * 2.0 - 1.0, 0.0, 1.0); // Unproject at the far plane vec3 fog_pos = vec3(reprojected.xy / reprojected.w, 1.0) * 0.5 + 0.5; #else vec3 fog_pos = vec3(screen_uv, 1.0); @@ -187,9 +187,11 @@ void main() { vec3 cube_normal; #ifdef USE_MULTIVIEW // In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject. - vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 1.0, 1.0); + vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 0.0, 1.0); // unproject at the far plane vec4 unprojected = sky_scene_data.view_inv_projections[ViewIndex] * unproject; cube_normal = unprojected.xyz / unprojected.w; + + // Unproject will give us the position between the eyes, need to re-offset cube_normal += sky_scene_data.view_eye_offsets[ViewIndex].xyz; #else cube_normal.z = -1.0; diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl index 57b9a4c320..d0cfe6a3b8 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -416,7 +416,7 @@ void main() { } float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r; - float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * INV_FOG_FADE); + float shadow = exp(min(0.0, (pssm_coord.z - depth)) * z_range * INV_FOG_FADE); shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance @@ -519,7 +519,7 @@ void main() { float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; - shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE)); + shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (pos.z - depth)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE)); } total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g) * omni_lights.data[light_index].volumetric_fog_energy; } @@ -597,7 +597,7 @@ void main() { float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; - shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE)); + shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (pos.z - depth)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE)); } total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g) * spot_lights.data[light_index].volumetric_fog_energy; } diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 6eae64c04e..359d7799e5 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -487,8 +487,8 @@ void vertex_shader(vec3 vertex_input, #ifdef MODE_RENDER_DEPTH if (scene_data.pancake_shadows) { - if (gl_Position.z <= 0.00001) { - gl_Position.z = 0.00001; + if (gl_Position.z >= 0.9999) { + gl_Position.z = 0.9999; } } #endif diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 259edc63a0..c26313092b 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -475,8 +475,8 @@ void main() { #ifdef MODE_RENDER_DEPTH if (scene_data.pancake_shadows) { - if (gl_Position.z <= 0.00001) { - gl_Position.z = 0.00001; + if (gl_Position.z >= 0.9999) { + gl_Position.z = 0.9999; } } #endif // MODE_RENDER_DEPTH diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index e9722bad1f..47e6fe5873 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -454,7 +454,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { vec3 v0 = abs(basis_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); vec3 tangent = normalize(cross(v0, basis_normal)); vec3 bitangent = normalize(cross(tangent, basis_normal)); - float z_norm = shadow_len * omni_lights.data[idx].inv_radius; + float z_norm = 1.0 - shadow_len * omni_lights.data[idx].inv_radius; tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; @@ -479,7 +479,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), pos.xy, 0.0).r; - if (d < z_norm) { + if (d > z_norm) { blocker_average += d; blocker_count += 1.0; } @@ -488,11 +488,11 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { if (blocker_count > 0.0) { //blockers found, do soft shadow blocker_average /= blocker_count; - float penumbra = (z_norm - blocker_average) / blocker_average; + float penumbra = (z_norm + blocker_average) / blocker_average; tangent *= penumbra; bitangent *= penumbra; - z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; + z_norm += omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; shadow = 0.0; for (uint i = 0; i < sc_penumbra_shadow_samples; i++) { @@ -536,6 +536,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { vec2 pos = shadow_sample.xy / shadow_sample.z; float depth = shadow_len - omni_lights.data[idx].shadow_bias; depth *= omni_lights.data[idx].inv_radius; + depth = 1.0 - depth; shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth), omni_lights.data[idx].shadow_opacity); } @@ -706,7 +707,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { vec4 v = vec4(vertex + normal_bias, 1.0); vec4 splane = (spot_lights.data[idx].shadow_matrix * v); - splane.z -= spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius); + splane.z += spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius); splane /= splane.w; float shadow; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index cf8c29e624..d1ff9fc362 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -668,7 +668,9 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light->directional_blend_splits; for (int j = 0; j < 4; j++) { Rect2 atlas_rect = light_instance->shadow_transform[j].atlas_rect; - Projection matrix = light_instance->shadow_transform[j].camera; + Projection correction; + correction.set_depth_correction(false, true, false); + Projection matrix = correction * light_instance->shadow_transform[j].camera; float split = light_instance->shadow_transform[MIN(limit, j)].split; Projection bias; @@ -967,7 +969,9 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged Projection bias; bias.set_light_bias(); - Projection cm = light_instance->shadow_transform[0].camera; + Projection correction; + correction.set_depth_correction(false, true, false); + Projection cm = correction * light_instance->shadow_transform[0].camera; Projection shadow_mtx = bias * cm * modelview; RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrix); diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index e78b8de4db..c9c7c53d04 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -1388,6 +1388,11 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) { } } void ParticlesStorage::update_particles() { + if (!particle_update_list.first()) { + return; + } + + RENDER_TIMESTAMP("Update GPUParticles"); uint32_t frame = RSG::rasterizer->get_frame_number(); bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0; while (particle_update_list.first()) { 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 8dc74820e2..c5d74d395f 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 @@ -128,6 +128,13 @@ void RenderSceneBuffersRD::cleanup() { free_named_texture(E.value); } named_textures.clear(); + + // Clear weight_buffer / blur textures. + for (const WeightBuffers &weight_buffer : weight_buffers) { + if (weight_buffer.weight.is_valid()) { + RD::get_singleton()->free(weight_buffer.weight); + } + } } void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_config) { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index dd94982f1a..f3ce432495 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -3637,8 +3637,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) { } rt->process_size = size * scale / 100; - rt->process_size.x = MAX(rt->process_size.x, 1); - rt->process_size.y = MAX(rt->process_size.y, 1); + rt->process_size = rt->process_size.max(Size2i(1, 1)); tformat.format = RD::DATA_FORMAT_R16G16_SINT; tformat.width = rt->process_size.width; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index aa69cd8539..b33de9d6f4 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1720,6 +1720,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { idata.base_rid = p_instance->base; idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1; idata.visibility_index = p_instance->visibility_index; + idata.occlusion_timeout = 0; for (Instance *E : p_instance->visibility_dependencies) { Instance *dep_instance = E; @@ -2775,7 +2776,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul #define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check<false>(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0) #define VIS_PARENT_CHECK (_visibility_parent_check(cull_data, idata)) #define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check) -#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near)) +#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near, cull_data.scenario->instance_data[i].occlusion_timeout)) if (!HIDDEN_BY_VISIBILITY_CHECKS) { if ((LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) || (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_ALL_CULLING)) { @@ -3567,43 +3568,47 @@ void RendererSceneCull::render_probes() { bool busy = false; - while (ref_probe) { - SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); - RID base = ref_probe->self()->owner->base; + if (ref_probe) { + RENDER_TIMESTAMP("Render ReflectionProbes"); - switch (RSG::light_storage->reflection_probe_get_update_mode(base)) { - case RS::REFLECTION_PROBE_UPDATE_ONCE: { - if (busy) { //already rendering something - break; - } + while (ref_probe) { + SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); + RID base = ref_probe->self()->owner->base; - bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); - if (done) { - done_list.push_back(ref_probe); - } else { - ref_probe->self()->render_step++; - } + switch (RSG::light_storage->reflection_probe_get_update_mode(base)) { + case RS::REFLECTION_PROBE_UPDATE_ONCE: { + if (busy) { // Already rendering something. + break; + } - busy = true; //do not render another one of this kind - } break; - case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { - int step = 0; - bool done = false; - while (!done) { - done = _render_reflection_probe_step(ref_probe->self()->owner, step); - step++; - } + bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); + if (done) { + done_list.push_back(ref_probe); + } else { + ref_probe->self()->render_step++; + } - done_list.push_back(ref_probe); - } break; - } + busy = true; // Do not render another one of this kind. + } break; + case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { + int step = 0; + bool done = false; + while (!done) { + done = _render_reflection_probe_step(ref_probe->self()->owner, step); + step++; + } - ref_probe = next; - } + done_list.push_back(ref_probe); + } break; + } + + ref_probe = next; + } - // Now remove from our list - for (SelfList<InstanceReflectionProbeData> *rp : done_list) { - reflection_probe_render_list.remove(rp); + // Now remove from our list + for (SelfList<InstanceReflectionProbeData> *rp : done_list) { + reflection_probe_render_list.remove(rp); + } } /* VOXEL GIS */ @@ -4252,6 +4257,7 @@ RendererSceneCull::RendererSceneCull() { indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame"); thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances"); thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)WorkerThreadPool::get_singleton()->get_thread_count()); //make sure there is at least one thread per CPU + RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = GLOBAL_GET("rendering/occlusion_culling/jitter_projection"); dummy_occlusion_culling = memnew(RendererSceneOcclusionCull); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 341ba0e3b0..0039d14475 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -286,6 +286,13 @@ public: Instance *instance = nullptr; int32_t parent_array_index = -1; int32_t visibility_index = -1; + + // Each time occlusion culling determines an instance is visible, + // set this to occlusion_frame plus some delay. + // Once the timeout is reached, allow the instance to be occlusion culled. + // This creates a delay for occlusion culling, which prevents flickering + // when jittering the raster occlusion projection. + uint64_t occlusion_timeout = 0; }; struct InstanceVisibilityData { diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp index c4f0177c73..1f0239411a 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.cpp +++ b/servers/rendering/renderer_scene_occlusion_cull.cpp @@ -43,6 +43,8 @@ const Vector3 RendererSceneOcclusionCull::HZBuffer::corners[8] = { Vector3(1, 1, 1) }; +bool RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = false; + bool RendererSceneOcclusionCull::HZBuffer::is_empty() const { return sizes.is_empty(); } @@ -66,6 +68,8 @@ void RendererSceneOcclusionCull::HZBuffer::clear() { } void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) { + occlusion_buffer_size = p_size; + if (p_size == Size2i()) { clear(); return; @@ -124,6 +128,9 @@ void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) { } void RendererSceneOcclusionCull::HZBuffer::update_mips() { + // Keep this up to date as a local to be used for occlusion timers. + occlusion_frame = Engine::get_singleton()->get_frames_drawn(); + if (sizes.is_empty()) { return; } diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index 565b393094..5adba5dc6a 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -53,19 +53,15 @@ public: PackedByteArray debug_data; float debug_tex_range = 0.0f; - public: - bool is_empty() const; - virtual void clear(); - virtual void resize(const Size2i &p_size); - - void update_mips(); + uint64_t occlusion_frame = 0; + Size2i occlusion_buffer_size; - _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const { + _FORCE_INLINE_ bool _is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const { if (is_empty()) { return false; } - Vector3 closest_point = Vector3(CLAMP(p_cam_position.x, p_bounds[0], p_bounds[3]), CLAMP(p_cam_position.y, p_bounds[1], p_bounds[4]), CLAMP(p_cam_position.z, p_bounds[2], p_bounds[5])); + Vector3 closest_point = p_cam_position.clamp(Vector3(p_bounds[0], p_bounds[1], p_bounds[2]), Vector3(p_bounds[3], p_bounds[4], p_bounds[5])); if (closest_point == p_cam_position) { return false; @@ -154,7 +150,47 @@ public: return !visible; } + public: + static bool occlusion_jitter_enabled; + + bool is_empty() const; + virtual void clear(); + virtual void resize(const Size2i &p_size); + + void update_mips(); + + // Thin wrapper around _is_occluded(), + // allowing occlusion timers to delay the disappearance + // of objects to prevent flickering when using jittering. + _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near, uint64_t &r_occlusion_timeout) const { + bool occluded = _is_occluded(p_bounds, p_cam_position, p_cam_inv_transform, p_cam_projection, p_near); + + // Special case, temporal jitter disabled, + // so we don't use occlusion timers. + if (!occlusion_jitter_enabled) { + return occluded; + } + + if (!occluded) { +//#define DEBUG_RASTER_OCCLUSION_JITTER +#ifdef DEBUG_RASTER_OCCLUSION_JITTER + r_occlusion_timeout = occlusion_frame + 1; +#else + r_occlusion_timeout = occlusion_frame + 9; +#endif + } else if (r_occlusion_timeout) { + // Regular timeout, allow occlusion culling + // to proceed as normal after the delay. + if (occlusion_frame >= r_occlusion_timeout) { + r_occlusion_timeout = 0; + } + } + + return occluded && !r_occlusion_timeout; + } + RID get_debug_texture(); + const Size2i &get_occlusion_buffer_size() const { return occlusion_buffer_size; } virtual ~HZBuffer(){}; }; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index baa198626c..bafabf16b8 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -31,6 +31,7 @@ #include "renderer_viewport.h" #include "core/config/project_settings.h" +#include "core/math/transform_interpolator.h" #include "core/object/worker_thread_pool.h" #include "renderer_canvas_cull.h" #include "renderer_scene_cull.h" @@ -339,7 +340,14 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (!F->enabled) { continue; } - F->xform_cache = xf * F->xform; + + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) { + F->xform_cache = xf * F->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f); + F->xform_cache = xf * F->xform_cache; + } if (sdf_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) { F->next = occluders; @@ -378,7 +386,14 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { Vector2 offset = tsize / 2.0; cl->rect_cache = Rect2(-offset + cl->texture_offset, tsize); - cl->xform_cache = xf * cl->xform; + + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) { + cl->xform_cache = xf * cl->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f); + cl->xform_cache = xf * cl->xform_cache; + } if (clip_rect.intersects_transformed(cl->xform_cache, cl->rect_cache)) { cl->filter_next_ptr = lights; @@ -386,7 +401,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 = xf * cl->xform * scale; + cl->light_shader_xform = cl->xform_cache * scale; if (cl->use_shadow) { cl->shadows_next_ptr = lights_with_shadow; if (lights_with_shadow == nullptr) { @@ -406,7 +421,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (cl->enabled) { cl->filter_next_ptr = directional_lights; directional_lights = cl; - cl->xform_cache = xf * cl->xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) { + cl->xform_cache = xf * cl->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f); + cl->xform_cache = xf * cl->xform_cache; + } cl->xform_cache.columns[2] = Vector2(); //translation is pointless if (cl->use_shadow) { cl->shadows_next_ptr = directional_lights_with_shadow; @@ -441,7 +462,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (!F->enabled) { continue; } - F->xform_cache = xf * F->xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) { + F->xform_cache = xf * F->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f); + F->xform_cache = xf * F->xform_cache; + } if (shadow_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) { F->next = occluders; occluders = F; @@ -521,7 +548,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (!F->enabled) { continue; } - F->xform_cache = xf * F->xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) { + F->xform_cache = xf * F->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f); + F->xform_cache = xf * F->xform_cache; + } Transform2D localizer = F->xform_cache.affine_inverse(); for (int j = 0; j < point_count; j++) { diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 9a898a2fca..c8277024cf 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1103,7 +1103,7 @@ private: public: DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color()); - DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color); void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline); diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index b4c539dcff..5bf0ab0ba6 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -80,6 +80,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { uint64_t time_usec = OS::get_singleton()->get_ticks_usec(); + RENDER_TIMESTAMP("Prepare Render Frame"); RSG::scene->update(); //update scenes stuff before updating instances frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0; @@ -370,6 +371,16 @@ void RenderingServerDefault::_thread_loop() { _finish(); } +/* INTERPOLATION */ + +void RenderingServerDefault::tick() { + RSG::canvas->tick(); +} + +void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) { + RSG::canvas->set_physics_interpolation_enabled(p_enabled); +} + /* EVENT QUEUING */ void RenderingServerDefault::sync() { diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 99fd683e1d..139624c777 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -926,6 +926,10 @@ public: FUNC1(canvas_item_set_debug_redraw, bool) FUNC0RC(bool, canvas_item_get_debug_redraw) + FUNC2(canvas_item_set_interpolated, RID, bool) + FUNC1(canvas_item_reset_physics_interpolation, RID) + FUNC2(canvas_item_transform_physics_interpolation, RID, const Transform2D &) + FUNCRIDSPLIT(canvas_light) FUNC2(canvas_light_set_mode, RID, CanvasLightMode) @@ -952,6 +956,10 @@ public: FUNC2(canvas_light_set_shadow_color, RID, const Color &) FUNC2(canvas_light_set_shadow_smooth, RID, float) + FUNC2(canvas_light_set_interpolated, RID, bool) + FUNC1(canvas_light_reset_physics_interpolation, RID) + FUNC2(canvas_light_transform_physics_interpolation, RID, const Transform2D &) + FUNCRIDSPLIT(canvas_light_occluder) FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID) FUNC2(canvas_light_occluder_set_enabled, RID, bool) @@ -960,6 +968,10 @@ public: FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &) FUNC2(canvas_light_occluder_set_light_mask, RID, int) + FUNC2(canvas_light_occluder_set_interpolated, RID, bool) + FUNC1(canvas_light_occluder_reset_physics_interpolation, RID) + FUNC2(canvas_light_occluder_transform_physics_interpolation, RID, const Transform2D &) + FUNCRIDSPLIT(canvas_occluder_polygon) FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool) @@ -1021,6 +1033,11 @@ public: } } + /* INTERPOLATION */ + + virtual void tick() override; + virtual void set_physics_interpolation_enabled(bool p_enabled) override; + /* EVENT QUEUING */ virtual void request_frame_drawn_callback(const Callable &p_callable) override; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 1ed0424839..994f6ad8b4 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -3219,6 +3219,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_set_modulate", "item", "color"), &RenderingServer::canvas_item_set_modulate); ClassDB::bind_method(D_METHOD("canvas_item_set_self_modulate", "item", "color"), &RenderingServer::canvas_item_set_self_modulate); ClassDB::bind_method(D_METHOD("canvas_item_set_draw_behind_parent", "item", "enabled"), &RenderingServer::canvas_item_set_draw_behind_parent); + ClassDB::bind_method(D_METHOD("canvas_item_set_interpolated", "item", "interpolated"), &RenderingServer::canvas_item_set_interpolated); + ClassDB::bind_method(D_METHOD("canvas_item_reset_physics_interpolation", "item"), &RenderingServer::canvas_item_reset_physics_interpolation); + ClassDB::bind_method(D_METHOD("canvas_item_transform_physics_interpolation", "item", "transform"), &RenderingServer::canvas_item_transform_physics_interpolation); /* Primitives */ @@ -3302,6 +3305,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_color", "light", "color"), &RenderingServer::canvas_light_set_shadow_color); ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_smooth", "light", "smooth"), &RenderingServer::canvas_light_set_shadow_smooth); ClassDB::bind_method(D_METHOD("canvas_light_set_blend_mode", "light", "mode"), &RenderingServer::canvas_light_set_blend_mode); + ClassDB::bind_method(D_METHOD("canvas_light_set_interpolated", "light", "interpolated"), &RenderingServer::canvas_light_set_interpolated); + ClassDB::bind_method(D_METHOD("canvas_light_reset_physics_interpolation", "light"), &RenderingServer::canvas_light_reset_physics_interpolation); + ClassDB::bind_method(D_METHOD("canvas_light_transform_physics_interpolation", "light", "transform"), &RenderingServer::canvas_light_transform_physics_interpolation); BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_POINT); BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_DIRECTIONAL); @@ -3324,6 +3330,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_as_sdf_collision", "occluder", "enable"), &RenderingServer::canvas_light_occluder_set_as_sdf_collision); ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_transform", "occluder", "transform"), &RenderingServer::canvas_light_occluder_set_transform); ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_light_mask", "occluder", "mask"), &RenderingServer::canvas_light_occluder_set_light_mask); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_interpolated", "occluder", "interpolated"), &RenderingServer::canvas_light_occluder_set_interpolated); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_reset_physics_interpolation", "occluder"), &RenderingServer::canvas_light_occluder_reset_physics_interpolation); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_transform_physics_interpolation", "occluder", "transform"), &RenderingServer::canvas_light_occluder_transform_physics_interpolation); /* CANVAS LIGHT OCCLUDER POLYGON */ diff --git a/servers/rendering_server.h b/servers/rendering_server.h index a67ae0a66c..a3a77bc57b 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -1476,6 +1476,10 @@ public: virtual void canvas_item_set_debug_redraw(bool p_enabled) = 0; virtual bool canvas_item_get_debug_redraw() const = 0; + virtual void canvas_item_set_interpolated(RID p_item, bool p_interpolated) = 0; + virtual void canvas_item_reset_physics_interpolation(RID p_item) = 0; + virtual void canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) = 0; + /* CANVAS LIGHT */ virtual RID canvas_light_create() = 0; @@ -1523,6 +1527,10 @@ public: virtual void canvas_light_set_shadow_color(RID p_light, const Color &p_color) = 0; virtual void canvas_light_set_shadow_smooth(RID p_light, float p_smooth) = 0; + virtual void canvas_light_set_interpolated(RID p_light, bool p_interpolated) = 0; + virtual void canvas_light_reset_physics_interpolation(RID p_light) = 0; + virtual void canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) = 0; + /* CANVAS LIGHT OCCLUDER */ virtual RID canvas_light_occluder_create() = 0; @@ -1533,6 +1541,10 @@ public: virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0; virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0; + virtual void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) = 0; + virtual void canvas_light_occluder_reset_physics_interpolation(RID p_occluder) = 0; + virtual void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) = 0; + /* CANVAS LIGHT OCCLUDER POLYGON */ virtual RID canvas_occluder_polygon_create() = 0; @@ -1604,6 +1616,11 @@ public: virtual void free(RID p_rid) = 0; // Free RIDs associated with the rendering server. + /* INTERPOLATION */ + + virtual void tick() = 0; + virtual void set_physics_interpolation_enabled(bool p_enabled) = 0; + /* EVENT QUEUING */ virtual void request_frame_drawn_callback(const Callable &p_callable) = 0; diff --git a/tests/core/io/test_marshalls.h b/tests/core/io/test_marshalls.h index 3c0ba611c6..de8d6e1406 100644 --- a/tests/core/io/test_marshalls.h +++ b/tests/core/io/test_marshalls.h @@ -160,7 +160,7 @@ TEST_CASE("[Marshalls] NIL Variant encoding") { uint8_t buffer[4]; CHECK(encode_variant(variant, buffer, r_len) == OK); - CHECK_MESSAGE(r_len == 4, "Length == 4 bytes for Variant::Type"); + CHECK_MESSAGE(r_len == 4, "Length == 4 bytes for header"); CHECK_MESSAGE(buffer[0] == 0x00, "Variant::NIL"); CHECK(buffer[1] == 0x00); CHECK(buffer[2] == 0x00); @@ -174,7 +174,7 @@ TEST_CASE("[Marshalls] INT 32 bit Variant encoding") { uint8_t buffer[8]; CHECK(encode_variant(variant, buffer, r_len) == OK); - CHECK_MESSAGE(r_len == 8, "Length == 4 bytes for Variant::Type + 4 bytes for int32_t"); + CHECK_MESSAGE(r_len == 8, "Length == 4 bytes for header + 4 bytes for int32_t"); CHECK_MESSAGE(buffer[0] == 0x02, "Variant::INT"); CHECK(buffer[1] == 0x00); CHECK(buffer[2] == 0x00); @@ -192,10 +192,10 @@ TEST_CASE("[Marshalls] INT 64 bit Variant encoding") { uint8_t buffer[12]; CHECK(encode_variant(variant, buffer, r_len) == OK); - CHECK_MESSAGE(r_len == 12, "Length == 4 bytes for Variant::Type + 8 bytes for int64_t"); + CHECK_MESSAGE(r_len == 12, "Length == 4 bytes for header + 8 bytes for int64_t"); CHECK_MESSAGE(buffer[0] == 0x02, "Variant::INT"); CHECK(buffer[1] == 0x00); - CHECK_MESSAGE(buffer[2] == 0x01, "ENCODE_FLAG_64"); + CHECK_MESSAGE(buffer[2] == 0x01, "HEADER_DATA_FLAG_64"); CHECK(buffer[3] == 0x00); // Check value CHECK(buffer[4] == 0xef); @@ -214,7 +214,7 @@ TEST_CASE("[Marshalls] FLOAT single precision Variant encoding") { uint8_t buffer[8]; CHECK(encode_variant(variant, buffer, r_len) == OK); - CHECK_MESSAGE(r_len == 8, "Length == 4 bytes for Variant::Type + 4 bytes for float"); + CHECK_MESSAGE(r_len == 8, "Length == 4 bytes for header + 4 bytes for float"); CHECK_MESSAGE(buffer[0] == 0x03, "Variant::FLOAT"); CHECK(buffer[1] == 0x00); CHECK(buffer[2] == 0x00); @@ -232,10 +232,10 @@ TEST_CASE("[Marshalls] FLOAT double precision Variant encoding") { uint8_t buffer[12]; CHECK(encode_variant(variant, buffer, r_len) == OK); - CHECK_MESSAGE(r_len == 12, "Length == 4 bytes for Variant::Type + 8 bytes for double"); + CHECK_MESSAGE(r_len == 12, "Length == 4 bytes for header + 8 bytes for double"); CHECK_MESSAGE(buffer[0] == 0x03, "Variant::FLOAT"); CHECK(buffer[1] == 0x00); - CHECK_MESSAGE(buffer[2] == 0x01, "ENCODE_FLAG_64"); + CHECK_MESSAGE(buffer[2] == 0x01, "HEADER_DATA_FLAG_64"); CHECK(buffer[3] == 0x00); // Check value CHECK(buffer[4] == 0x55); @@ -292,7 +292,7 @@ TEST_CASE("[Marshalls] INT 64 bit Variant decoding") { Variant variant; int r_len; uint8_t buffer[] = { - 0x02, 0x00, 0x01, 0x00, // Variant::INT & ENCODE_FLAG_64 + 0x02, 0x00, 0x01, 0x00, // Variant::INT, HEADER_DATA_FLAG_64 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0xf1 // value }; @@ -318,7 +318,7 @@ TEST_CASE("[Marshalls] FLOAT double precision Variant decoding") { Variant variant; int r_len; uint8_t buffer[] = { - 0x03, 0x00, 0x01, 0x00, // Variant::FLOAT & ENCODE_FLAG_64 + 0x03, 0x00, 0x01, 0x00, // Variant::FLOAT, HEADER_DATA_FLAG_64 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xd5, 0x3f // value }; @@ -326,6 +326,66 @@ TEST_CASE("[Marshalls] FLOAT double precision Variant decoding") { CHECK(r_len == 12); CHECK(variant == Variant(0.33333333333333333)); } + +TEST_CASE("[Marshalls] Typed array encoding") { + int r_len; + Array array; + array.set_typed(Variant::INT, StringName(), Ref<Script>()); + array.push_back(Variant(uint64_t(0x0f123456789abcdef))); + uint8_t buffer[24]; + + CHECK(encode_variant(array, buffer, r_len) == OK); + CHECK_MESSAGE(r_len == 24, "Length == 4 bytes for header + 4 bytes for array type + 4 bytes for array size + 12 bytes for element"); + CHECK_MESSAGE(buffer[0] == 0x1c, "Variant::ARRAY"); + CHECK(buffer[1] == 0x00); + CHECK_MESSAGE(buffer[2] == 0x01, "HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN"); + CHECK(buffer[3] == 0x00); + // Check array type. + CHECK_MESSAGE(buffer[4] == 0x02, "Variant::INT"); + CHECK(buffer[5] == 0x00); + CHECK(buffer[6] == 0x00); + CHECK(buffer[7] == 0x00); + // Check array size. + CHECK(buffer[8] == 0x01); + CHECK(buffer[9] == 0x00); + CHECK(buffer[10] == 0x00); + CHECK(buffer[11] == 0x00); + // Check element type. + CHECK_MESSAGE(buffer[12] == 0x02, "Variant::INT"); + CHECK(buffer[13] == 0x00); + CHECK_MESSAGE(buffer[14] == 0x01, "HEADER_DATA_FLAG_64"); + CHECK(buffer[15] == 0x00); + // Check element value. + CHECK(buffer[16] == 0xef); + CHECK(buffer[17] == 0xcd); + CHECK(buffer[18] == 0xab); + CHECK(buffer[19] == 0x89); + CHECK(buffer[20] == 0x67); + CHECK(buffer[21] == 0x45); + CHECK(buffer[22] == 0x23); + CHECK(buffer[23] == 0xf1); +} + +TEST_CASE("[Marshalls] Typed array decoding") { + Variant variant; + int r_len; + uint8_t buffer[] = { + 0x1c, 0x00, 0x01, 0x00, // Variant::ARRAY, HEADER_DATA_FIELD_TYPED_ARRAY_BUILTIN + 0x02, 0x00, 0x00, 0x00, // Array type (Variant::INT). + 0x01, 0x00, 0x00, 0x00, // Array size. + 0x02, 0x00, 0x01, 0x00, // Element type (Variant::INT, HEADER_DATA_FLAG_64). + 0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0xf1, // Element value. + }; + + CHECK(decode_variant(variant, buffer, 24, &r_len) == OK); + CHECK(r_len == 24); + CHECK(variant.get_type() == Variant::ARRAY); + Array array = variant; + CHECK(array.get_typed_builtin() == Variant::INT); + CHECK(array.size() == 1); + CHECK(array[0] == Variant(uint64_t(0x0f123456789abcdef))); +} + } // namespace TestMarshalls #endif // TEST_MARSHALLS_H diff --git a/tests/core/string/test_string.h b/tests/core/string/test_string.h index da742d0183..64f03e5879 100644 --- a/tests/core/string/test_string.h +++ b/tests/core/string/test_string.h @@ -336,6 +336,16 @@ TEST_CASE("[String] Natural compare function test") { CHECK(a.naturalnocasecmp_to("img10.png") < 0); } +TEST_CASE("[String] File compare function test") { + String a = "_img2.png"; + String b = "img2.png"; + + CHECK(a.nocasecmp_to("img10.png") > 0); + CHECK_MESSAGE(a.filenocasecmp_to("img10.png") < 0, "Should sort before letters."); + CHECK_MESSAGE(a.filenocasecmp_to(".img10.png") > 0, "Should sort after period."); + CHECK(b.filenocasecmp_to("img3.png") < 0); +} + TEST_CASE("[String] hex_encode_buffer") { static const uint8_t u8str[] = { 0x45, 0xE3, 0x81, 0x8A, 0x8F, 0xE3 }; String s = String::hex_encode_buffer(u8str, 6); diff --git a/tests/create_test.py b/tests/create_test.py index 4d1f1d656e..deb53aca20 100644 --- a/tests/create_test.py +++ b/tests/create_test.py @@ -101,7 +101,7 @@ TEST_CASE("[{name_pascal_case}] Example test case") {{ if args.invasive: print("Trying to insert include directive in test_main.cpp...") - with open("test_main.cpp", "r") as file: + with open("test_main.cpp", "r", encoding="utf-8") as file: contents = file.read() match = re.search(r'#include "tests.*\n', contents) diff --git a/tests/python_build/test_gles3_builder.py b/tests/python_build/test_gles3_builder.py index 861e0b84c4..6f16139eb9 100644 --- a/tests/python_build/test_gles3_builder.py +++ b/tests/python_build/test_gles3_builder.py @@ -17,15 +17,15 @@ def test_gles3_builder(shader_files, builder, header_struct): builder(shader_files["path_input"], "drivers/gles3/shader_gles3.h", "GLES3", header_data=header) - with open(shader_files["path_expected_parts"], "r") as f: + with open(shader_files["path_expected_parts"], "r", encoding="utf-8") as f: expected_parts = json.load(f) assert expected_parts == header.__dict__ - with open(shader_files["path_output"], "r") as f: + with open(shader_files["path_output"], "r", encoding="utf-8") as f: actual_output = f.read() assert actual_output - with open(shader_files["path_expected_full"], "r") as f: + with open(shader_files["path_expected_full"], "r", encoding="utf-8") as f: expected_output = f.read() assert actual_output == expected_output diff --git a/tests/python_build/test_glsl_builder.py b/tests/python_build/test_glsl_builder.py index b9dcef48ac..348ef8441c 100644 --- a/tests/python_build/test_glsl_builder.py +++ b/tests/python_build/test_glsl_builder.py @@ -23,15 +23,15 @@ def test_glsl_builder(shader_files, builder, header_struct): header = header_struct() builder(shader_files["path_input"], header_data=header) - with open(shader_files["path_expected_parts"], "r") as f: + with open(shader_files["path_expected_parts"], "r", encoding="utf-8") as f: expected_parts = json.load(f) assert expected_parts == header.__dict__ - with open(shader_files["path_output"], "r") as f: + with open(shader_files["path_output"], "r", encoding="utf-8") as f: actual_output = f.read() assert actual_output - with open(shader_files["path_expected_full"], "r") as f: + with open(shader_files["path_expected_full"], "r", encoding="utf-8") as f: expected_output = f.read() assert actual_output == expected_output diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index 8f603c698d..8577dd7148 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -802,6 +802,153 @@ TEST_CASE("[SceneTree][TextEdit] text entry") { CHECK(text_edit->get_selected_text(3) == "test"); } + SUBCASE("[TextEdit] skip selection for next occurrence") { + text_edit->set_text("\ntest other_test\nrandom test\nword test word nonrandom"); + text_edit->set_caret_column(0); + text_edit->set_caret_line(1); + + // Without selection on the current caret, the caret as 'jumped' to the next occurrence of the word under the caret. + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); + CHECK_FALSE(text_edit->has_selection(0)); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 13); + + // Repeating previous action. + // This time caret is in 'other_test' (other_|test) + // so the searched term will be 'other_test' or not just 'test' + // => no occurrence, as a side effect, the caret will move to start of the term. + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); + CHECK_FALSE(text_edit->has_selection(0)); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 7); + + // Repeating action again should do nothing now + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); + CHECK_FALSE(text_edit->has_selection(0)); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 7); + + // Moving back to the first 'test' occurrence. + text_edit->set_caret_column(0); + text_edit->set_caret_line(1); + + // But this time, create a selection of it. + text_edit->add_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 1); + CHECK(text_edit->get_selection_from_column(0) == 0); + CHECK(text_edit->get_selection_to_line(0) == 1); + CHECK(text_edit->get_selection_to_column(0) == 4); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 4); + + // Then, skipping it, but this time, selection has been made on the next occurrence. + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 1); + CHECK(text_edit->get_selection_from_column(0) == 13); + CHECK(text_edit->get_selection_to_line(0) == 1); + CHECK(text_edit->get_selection_to_column(0) == 17); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 17); + + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 2); + CHECK(text_edit->get_selection_from_column(0) == 9); + CHECK(text_edit->get_selection_to_line(0) == 2); + CHECK(text_edit->get_selection_to_column(0) == 13); + CHECK(text_edit->get_caret_line(0) == 2); + CHECK(text_edit->get_caret_column(0) == 13); + + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 3); + CHECK(text_edit->get_selection_from_column(0) == 5); + CHECK(text_edit->get_selection_to_line(0) == 3); + CHECK(text_edit->get_selection_to_column(0) == 9); + CHECK(text_edit->get_caret_line(0) == 3); + CHECK(text_edit->get_caret_column(0) == 9); + + // Last skip, we are back to the first occurrence. + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 1); + CHECK(text_edit->get_selection_from_column(0) == 0); + CHECK(text_edit->get_selection_to_line(0) == 1); + CHECK(text_edit->get_selection_to_column(0) == 4); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 4); + + // Adding first occurrence to selections/carets list + // and select occurrence on 'other_test'. + text_edit->add_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 2); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + + CHECK(text_edit->has_selection(1)); + CHECK(text_edit->get_selected_text(1) == "test"); + CHECK(text_edit->get_selection_from_line(1) == 1); + CHECK(text_edit->get_selection_from_column(1) == 13); + CHECK(text_edit->get_selection_to_line(1) == 1); + CHECK(text_edit->get_selection_to_column(1) == 17); + CHECK(text_edit->get_caret_line(1) == 1); + CHECK(text_edit->get_caret_column(1) == 17); + + // We don't want this occurrence. + // Let's skip it. + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 2); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + + CHECK(text_edit->get_selected_text(1) == "test"); + CHECK(text_edit->get_selection_from_line(1) == 2); + CHECK(text_edit->get_selection_from_column(1) == 9); + CHECK(text_edit->get_selection_to_line(1) == 2); + CHECK(text_edit->get_selection_to_column(1) == 13); + CHECK(text_edit->get_caret_line(1) == 2); + CHECK(text_edit->get_caret_column(1) == 13); + + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 2); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + + CHECK(text_edit->get_selected_text(1) == "test"); + CHECK(text_edit->get_selection_from_line(1) == 3); + CHECK(text_edit->get_selection_from_column(1) == 5); + CHECK(text_edit->get_selection_to_line(1) == 3); + CHECK(text_edit->get_selection_to_column(1) == 9); + CHECK(text_edit->get_caret_line(1) == 3); + CHECK(text_edit->get_caret_column(1) == 9); + + // We are back the first occurrence. + text_edit->skip_selection_for_next_occurrence(); + CHECK(text_edit->get_caret_count() == 1); + CHECK(text_edit->has_selection(0)); + CHECK(text_edit->get_selected_text(0) == "test"); + CHECK(text_edit->get_selection_from_line(0) == 1); + CHECK(text_edit->get_selection_from_column(0) == 0); + CHECK(text_edit->get_selection_to_line(0) == 1); + CHECK(text_edit->get_selection_to_column(0) == 4); + CHECK(text_edit->get_caret_line(0) == 1); + CHECK(text_edit->get_caret_column(0) == 4); + } + SUBCASE("[TextEdit] deselect on focus loss") { text_edit->set_text("test"); diff --git a/thirdparty/README.md b/thirdparty/README.md index d86c14cd14..be386a3920 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -172,13 +172,15 @@ Files extracted from upstream source: ## embree - Upstream: https://github.com/embree/embree -- Version: 3.13.5 (698442324ccddd11725fb8875275dc1384f7fb40, 2022) +- Version: 4.3.1 (daa8de0e714e18ad5e5c9841b67c1950d9c91c51, 2024) - License: Apache 2.0 Files extracted from upstream: - All `.cpp` files listed in `modules/raycast/godot_update_embree.py` - All header files in the directories listed in `modules/raycast/godot_update_embree.py` +- All config files listed in `modules/raycast/godot_update_embree.py` +- `LICENSE.txt` The `modules/raycast/godot_update_embree.py` script can be used to pull the relevant files from the latest Embree release and apply some automatic changes. @@ -540,7 +542,7 @@ File extracted from upstream release tarball: ## meshoptimizer - Upstream: https://github.com/zeux/meshoptimizer -- Version: git (c21d3be6ddf627f8ca852ba4b6db9903b0557858, 2023) +- Version: 0.20 (c21d3be6ddf627f8ca852ba4b6db9903b0557858, 2023) - License: MIT Files extracted from upstream repository: @@ -860,7 +862,7 @@ instead of `miniz.h` as an external dependency. ## thorvg - Upstream: https://github.com/thorvg/thorvg -- Version: 0.12.7 (cddae9966cbb48c431ea17c262d6f48393206fd7, 2024) +- Version: 0.12.9 (afa6d8499bd49141d99d5e40a4620bd9f6bc0467, 2024) - License: MIT Files extracted from upstream source: diff --git a/thirdparty/embree/LICENSE.txt b/thirdparty/embree/LICENSE.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/thirdparty/embree/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/thirdparty/embree/common/algorithms/parallel_any_of.h b/thirdparty/embree/common/algorithms/parallel_any_of.h index a64e4a1889..a95c1f6490 100644 --- a/thirdparty/embree/common/algorithms/parallel_any_of.h +++ b/thirdparty/embree/common/algorithms/parallel_any_of.h @@ -12,7 +12,8 @@ namespace embree template<typename Index, class UnaryPredicate> __forceinline bool parallel_any_of (Index first, Index last, UnaryPredicate pred) { - bool ret = false; + std::atomic_bool ret; + ret = false; #if defined(TASKING_TBB) #if TBB_INTERFACE_VERSION >= 12002 diff --git a/thirdparty/embree/common/algorithms/parallel_for.h b/thirdparty/embree/common/algorithms/parallel_for.h index 6d411e4852..fd5213e70a 100644 --- a/thirdparty/embree/common/algorithms/parallel_for.h +++ b/thirdparty/embree/common/algorithms/parallel_for.h @@ -5,7 +5,7 @@ #include "../tasking/taskscheduler.h" #include "../sys/array.h" -#include "../math/math.h" +#include "../math/emath.h" #include "../math/range.h" namespace embree @@ -14,17 +14,17 @@ namespace embree template<typename Index, typename Func> __forceinline void parallel_for( const Index N, const Func& func) { -#if defined(TASKING_INTERNAL) +#if defined(TASKING_INTERNAL) && !defined(TASKING_TBB) if (N) { + TaskScheduler::TaskGroupContext context; TaskScheduler::spawn(Index(0),N,Index(1),[&] (const range<Index>& r) { assert(r.size() == 1); func(r.begin()); - }); - if (!TaskScheduler::wait()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + },&context); + TaskScheduler::wait(); + if (context.cancellingException != nullptr) { + std::rethrow_exception(context.cancellingException); + } } #elif defined(TASKING_TBB) #if TBB_INTERFACE_VERSION >= 12002 @@ -33,19 +33,13 @@ namespace embree func(i); },context); if (context.is_group_execution_cancelled()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + throw std::runtime_error("task cancelled"); #else tbb::parallel_for(Index(0),N,Index(1),[&](Index i) { func(i); }); if (tbb::task::self().is_cancelled()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + throw std::runtime_error("task cancelled"); #endif #elif defined(TASKING_PPL) @@ -62,13 +56,13 @@ namespace embree __forceinline void parallel_for( const Index first, const Index last, const Index minStepSize, const Func& func) { assert(first <= last); -#if defined(TASKING_INTERNAL) - TaskScheduler::spawn(first,last,minStepSize,func); - if (!TaskScheduler::wait()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- +#if defined(TASKING_INTERNAL) && !defined(TASKING_TBB) + TaskScheduler::TaskGroupContext context; + TaskScheduler::spawn(first,last,minStepSize,func,&context); + TaskScheduler::wait(); + if (context.cancellingException != nullptr) { + std::rethrow_exception(context.cancellingException); + } #elif defined(TASKING_TBB) #if TBB_INTERFACE_VERSION >= 12002 @@ -77,19 +71,13 @@ namespace embree func(range<Index>(r.begin(),r.end())); },context); if (context.is_group_execution_cancelled()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + throw std::runtime_error("task cancelled"); #else tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) { func(range<Index>(r.begin(),r.end())); }); if (tbb::task::self().is_cancelled()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + throw std::runtime_error("task cancelled"); #endif #elif defined(TASKING_PPL) @@ -121,19 +109,13 @@ namespace embree func(i); },tbb::simple_partitioner(),context); if (context.is_group_execution_cancelled()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + throw std::runtime_error("task cancelled"); #else tbb::parallel_for(Index(0),N,Index(1),[&](Index i) { func(i); },tbb::simple_partitioner()); if (tbb::task::self().is_cancelled()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + throw std::runtime_error("task cancelled"); #endif } @@ -148,19 +130,13 @@ namespace embree func(i); },ap,context); if (context.is_group_execution_cancelled()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + throw std::runtime_error("task cancelled"); #else tbb::parallel_for(Index(0),N,Index(1),[&](Index i) { func(i); },ap); if (tbb::task::self().is_cancelled()) - // -- GODOT start -- - // throw std::runtime_error("task cancelled"); - abort(); - // -- GODOT end -- + throw std::runtime_error("task cancelled"); #endif } diff --git a/thirdparty/embree/common/algorithms/parallel_partition.h b/thirdparty/embree/common/algorithms/parallel_partition.h index a1cbdc8e04..53d4d6f0db 100644 --- a/thirdparty/embree/common/algorithms/parallel_partition.h +++ b/thirdparty/embree/common/algorithms/parallel_partition.h @@ -175,8 +175,8 @@ namespace embree /* calculate all left and right ranges that are on the wrong global side */ size_t numMisplacedRangesLeft = 0; size_t numMisplacedRangesRight = 0; - size_t numMisplacedItemsLeft = 0; - size_t numMisplacedItemsRight = 0; + size_t numMisplacedItemsLeft MAYBE_UNUSED = 0; + size_t numMisplacedItemsRight MAYBE_UNUSED = 0; for (size_t i=0; i<numTasks; i++) { diff --git a/thirdparty/embree/common/algorithms/parallel_reduce.h b/thirdparty/embree/common/algorithms/parallel_reduce.h index cd0078f2e6..51ec0a6405 100644 --- a/thirdparty/embree/common/algorithms/parallel_reduce.h +++ b/thirdparty/embree/common/algorithms/parallel_reduce.h @@ -43,7 +43,7 @@ namespace embree template<typename Index, typename Value, typename Func, typename Reduction> __forceinline Value parallel_reduce( const Index first, const Index last, const Index minStepSize, const Value& identity, const Func& func, const Reduction& reduction ) { -#if defined(TASKING_INTERNAL) +#if defined(TASKING_INTERNAL) && !defined(TASKING_TBB) /* fast path for small number of iterations */ Index taskCount = (last-first+minStepSize-1)/minStepSize; diff --git a/thirdparty/embree/common/lexers/stream.h b/thirdparty/embree/common/lexers/stream.h index a40c15f8eb..9ad72af4e6 100644 --- a/thirdparty/embree/common/lexers/stream.h +++ b/thirdparty/embree/common/lexers/stream.h @@ -6,7 +6,7 @@ #include "../sys/platform.h" #include "../sys/ref.h" #include "../sys/filename.h" -#include "../sys/string.h" +#include "../sys/estring.h" #include <vector> #include <iostream> @@ -122,17 +122,16 @@ namespace embree class FileStream : public Stream<int> { public: - - FileStream (FILE* file, const std::string& name = "file") - : file(file), lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(name))) {} - FileStream (const FileName& fileName) : lineNumber(1), colNumber(0), charNumber(0), name(std::shared_ptr<std::string>(new std::string(fileName.str()))) { - file = fopen(fileName.c_str(),"r"); - if (file == nullptr) THROW_RUNTIME_ERROR("cannot open file " + fileName.str()); + if (ifs) ifs.close(); + ifs.open(fileName.str()); + if (!ifs.is_open()) THROW_RUNTIME_ERROR("cannot open file " + fileName.str()); + } + ~FileStream() { + if (ifs) ifs.close(); } - ~FileStream() { if (file) fclose(file); } public: ParseLocation location() { @@ -140,14 +139,15 @@ namespace embree } int next() { - int c = fgetc(file); + int c = ifs.get(); if (c == '\n') { lineNumber++; colNumber = 0; } else if (c != '\r') colNumber++; charNumber++; return c; } + private: - FILE* file; + std::ifstream ifs; ssize_t lineNumber; /// the line number the token is from ssize_t colNumber; /// the character number in the current line ssize_t charNumber; /// the character in the file diff --git a/thirdparty/embree/common/lexers/stringstream.cpp b/thirdparty/embree/common/lexers/stringstream.cpp index a037869506..c93da0b420 100644 --- a/thirdparty/embree/common/lexers/stringstream.cpp +++ b/thirdparty/embree/common/lexers/stringstream.cpp @@ -41,7 +41,9 @@ namespace embree int c = cin->get(); // -- GODOT start -- // if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input"); - if (!isValidChar(c)) abort(); + if (!isValidChar(c)) { + abort(); + } // -- GODOT end -- str.push_back((char)c); } diff --git a/thirdparty/embree/common/lexers/tokenstream.cpp b/thirdparty/embree/common/lexers/tokenstream.cpp index 6ed6f2045a..fe9de641db 100644 --- a/thirdparty/embree/common/lexers/tokenstream.cpp +++ b/thirdparty/embree/common/lexers/tokenstream.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "tokenstream.h" -#include "../math/math.h" +#include "../math/emath.h" namespace embree { diff --git a/thirdparty/embree/common/math/affinespace.h b/thirdparty/embree/common/math/affinespace.h index 9d4a0f0846..f3e5404639 100644 --- a/thirdparty/embree/common/math/affinespace.h +++ b/thirdparty/embree/common/math/affinespace.h @@ -337,7 +337,7 @@ namespace embree if (D) *D = sqrtf(D_x); return true; } - + __forceinline void AffineSpace3fa_store_unaligned(const AffineSpace3fa &source, AffineSpace3fa* ptr) { Vec3fa::storeu(&ptr->l.vx, source.l.vx); diff --git a/thirdparty/embree/common/math/bbox.h b/thirdparty/embree/common/math/bbox.h index e4eb3df9a4..651b29a8fe 100644 --- a/thirdparty/embree/common/math/bbox.h +++ b/thirdparty/embree/common/math/bbox.h @@ -56,6 +56,11 @@ namespace embree return BBox(min(a.lower, b.lower), max(a.upper, b.upper)); } + /*! intersects two boxes */ + __forceinline static const BBox intersect (const BBox& a, const BBox& b) { + return BBox(max(a.lower, b.lower), min(a.upper, b.upper)); + } + /*! enlarge box by some scaling factor */ __forceinline BBox enlarge_by(const float a) const { return BBox(lower - T(a)*abs(lower), upper + T(a)*abs(upper)); diff --git a/thirdparty/embree/common/math/col3.h b/thirdparty/embree/common/math/col3.h index 3f50c04393..4576bc517d 100644 --- a/thirdparty/embree/common/math/col3.h +++ b/thirdparty/embree/common/math/col3.h @@ -3,7 +3,7 @@ #pragma once -#include "math.h" +#include "emath.h" namespace embree { diff --git a/thirdparty/embree/common/math/col4.h b/thirdparty/embree/common/math/col4.h index 788508516b..4ef916cc3a 100644 --- a/thirdparty/embree/common/math/col4.h +++ b/thirdparty/embree/common/math/col4.h @@ -3,7 +3,7 @@ #pragma once -#include "math.h" +#include "emath.h" namespace embree { diff --git a/thirdparty/embree/common/math/color.h b/thirdparty/embree/common/math/color.h index e62e4ad2a4..8b28ff9447 100644 --- a/thirdparty/embree/common/math/color.h +++ b/thirdparty/embree/common/math/color.h @@ -3,6 +3,10 @@ #pragma once +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) +# include "color_sycl.h" +#else + #include "constants.h" #include "col3.h" #include "col4.h" @@ -64,6 +68,10 @@ namespace embree d.b = (unsigned char)(s[2]); d.a = (unsigned char)(s[3]); } + __forceinline void set(float &f) const + { + f = 0.2126f*r+0.7125f*g+0.0722f*b; // sRGB luminance. + } //////////////////////////////////////////////////////////////////////////////// /// Constants @@ -256,3 +264,5 @@ namespace embree return cout << "(" << a.r << ", " << a.g << ", " << a.b << ")"; } } + +#endif diff --git a/thirdparty/embree/common/math/color_sycl.h b/thirdparty/embree/common/math/color_sycl.h new file mode 100644 index 0000000000..41b89ddecc --- /dev/null +++ b/thirdparty/embree/common/math/color_sycl.h @@ -0,0 +1,219 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "constants.h" +#include "col3.h" +#include "col4.h" + +#include "../simd/sse.h" + +namespace embree +{ + //////////////////////////////////////////////////////////////////////////////// + /// SSE RGBA Color Class + //////////////////////////////////////////////////////////////////////////////// + + struct Color4 + { + struct { float r,g,b,a; }; + + //////////////////////////////////////////////////////////////////////////////// + /// Construction + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Color4 () {} + //__forceinline Color4 ( const __m128 a ) : m128(a) {} + + __forceinline explicit Color4 (const float v) : r(v), g(v), b(v), a(v) {} + __forceinline Color4 (const float r, const float g, const float b, const float a) : r(r), g(g), b(b), a(a) {} + + __forceinline explicit Color4 ( const Col3uc& other ) : r(other.r/255.0f), g(other.g/255.0f), b(other.b/255.0f), a(1.0f) {} + __forceinline explicit Color4 ( const Col3f& other ) : r(other.r), g(other.g), b(other.b), a(1.0f) {} + __forceinline explicit Color4 ( const Col4uc& other ) : r(other.r/255.0f), g(other.g/255.0f), b(other.b/255.0f), a(other.a/255.0f) {} + __forceinline explicit Color4 ( const Col4f& other ) : r(other.r), g(other.g), b(other.b), a(other.a) {} + + //__forceinline Color4 ( const Color4& other ) : m128(other.m128) {} + //__forceinline Color4& operator=( const Color4& other ) { m128 = other.m128; return *this; } + + //__forceinline operator const __m128&() const { return m128; } + //__forceinline operator __m128&() { return m128; } + + //////////////////////////////////////////////////////////////////////////////// + /// Set + //////////////////////////////////////////////////////////////////////////////// + + __forceinline void set(Col3f& d) const { d.r = r; d.g = g; d.b = b; } + __forceinline void set(Col4f& d) const { d.r = r; d.g = g; d.b = b; d.a = a; } + + __forceinline void set(Col3uc& d) const + { + d.r = (unsigned char)(clamp(r)*255.0f); + d.g = (unsigned char)(clamp(g)*255.0f); + d.b = (unsigned char)(clamp(b)*255.0f); + } + + __forceinline void set(Col4uc& d) const + { + d.r = (unsigned char)(clamp(r)*255.0f); + d.g = (unsigned char)(clamp(g)*255.0f); + d.b = (unsigned char)(clamp(b)*255.0f); + d.a = (unsigned char)(clamp(a)*255.0f); + } + __forceinline void set(float &f) const + { + f = 0.2126f*r+0.7125f*g+0.0722f*b; // sRGB luminance. + } + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Color4( ZeroTy ) : r(0.0f), g(0.0f), b(0.0f), a(0.0f) {} + __forceinline Color4( OneTy ) : r(1.0f), g(1.0f), b(1.0f), a(1.0f) {} + //__forceinline Color4( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {} + //__forceinline Color4( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {} + }; + + //////////////////////////////////////////////////////////////////////////////// + /// SSE RGB Color Class + //////////////////////////////////////////////////////////////////////////////// + + struct Color + { + struct { float r,g,b; }; + + //////////////////////////////////////////////////////////////////////////////// + /// Construction + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Color () {} + //__forceinline Color ( const __m128 a ) : m128(a) {} + + __forceinline explicit Color (const float v) : r(v), g(v), b(v) {} + __forceinline Color (const float r, const float g, const float b) : r(r), g(g), b(b) {} + + //__forceinline Color ( const Color& other ) : m128(other.m128) {} + //__forceinline Color& operator=( const Color& other ) { m128 = other.m128; return *this; } + + //__forceinline Color ( const Color4& other ) : m128(other.m128) {} + //__forceinline Color& operator=( const Color4& other ) { m128 = other.m128; return *this; } + + //__forceinline operator const __m128&() const { return m128; } + //__forceinline operator __m128&() { return m128; } + + //////////////////////////////////////////////////////////////////////////////// + /// Set + //////////////////////////////////////////////////////////////////////////////// + + __forceinline void set(Col3f& d) const { d.r = r; d.g = g; d.b = b; } + __forceinline void set(Col4f& d) const { d.r = r; d.g = g; d.b = b; d.a = 1.0f; } + +#if 0 + __forceinline void set(Col3uc& d) const + { + vfloat4 s = clamp(vfloat4(m128))*255.0f; + d.r = (unsigned char)(s[0]); + d.g = (unsigned char)(s[1]); + d.b = (unsigned char)(s[2]); + } + __forceinline void set(Col4uc& d) const + { + vfloat4 s = clamp(vfloat4(m128))*255.0f; + d.r = (unsigned char)(s[0]); + d.g = (unsigned char)(s[1]); + d.b = (unsigned char)(s[2]); + d.a = 255; + } +#endif + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Color( ZeroTy ) : r(0.0f), g(0.0f), b(0.0f) {} + __forceinline Color( OneTy ) : r(1.0f), g(1.0f), b(1.0f) {} + //__forceinline Color( PosInfTy ) : m128(_mm_set1_ps(pos_inf)) {} + //__forceinline Color( NegInfTy ) : m128(_mm_set1_ps(neg_inf)) {} + }; + + //////////////////////////////////////////////////////////////////////////////// + /// Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline const Color operator +( const Color& a ) { return a; } + __forceinline const Color operator -( const Color& a ) { return Color(-a.r, -a.g, -a.b); } + __forceinline const Color abs ( const Color& a ) { return Color(abs(a.r), abs(a.g), abs(a.b)); } + __forceinline const Color rcp ( const Color& a ) { return Color(1.0f/a.r, 1.0f/a.g, 1.0f/a.b); } + __forceinline const Color rsqrt( const Color& a ) { return Color(1.0f/sqrt(a.r), 1.0f/sqrt(a.g), 1.0f/sqrt(a.b)); } + __forceinline const Color sqrt ( const Color& a ) { return Color(sqrt(a.r), sqrt(a.g), sqrt(a.b)); } + + //////////////////////////////////////////////////////////////////////////////// + /// Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline const Color operator +( const Color& a, const Color& b ) { return Color(a.r+b.r, a.g+b.g, a.b+b.b); } + __forceinline const Color operator -( const Color& a, const Color& b ) { return Color(a.r-b.r, a.g-b.g, a.b-b.b); } + __forceinline const Color operator *( const Color& a, const Color& b ) { return Color(a.r*b.r, a.g*b.g, a.b*b.b); } + __forceinline const Color operator *( const Color& a, const float b ) { return a * Color(b); } + __forceinline const Color operator *( const float a, const Color& b ) { return Color(a) * b; } + __forceinline const Color operator /( const Color& a, const Color& b ) { return a * rcp(b); } + __forceinline const Color operator /( const Color& a, const float b ) { return a * rcp(b); } + + __forceinline const Color min( const Color& a, const Color& b ) { return Color(min(a.r,b.r), min(a.g,b.g), min(a.b,b.b)); } + __forceinline const Color max( const Color& a, const Color& b ) { return Color(max(a.r,b.r), max(a.g,b.g), max(a.b,b.b)); } + + //////////////////////////////////////////////////////////////////////////////// + /// Assignment Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline const Color operator+=(Color& a, const Color& b) { return a = a + b; } + __forceinline const Color operator-=(Color& a, const Color& b) { return a = a - b; } + __forceinline const Color operator*=(Color& a, const Color& b) { return a = a * b; } + __forceinline const Color operator/=(Color& a, const Color& b) { return a = a / b; } + __forceinline const Color operator*=(Color& a, const float b ) { return a = a * b; } + __forceinline const Color operator/=(Color& a, const float b ) { return a = a / b; } + + //////////////////////////////////////////////////////////////////////////////// + /// Reductions + //////////////////////////////////////////////////////////////////////////////// + + __forceinline float reduce_add(const Color& v) { return v.r+v.g+v.b; } + __forceinline float reduce_mul(const Color& v) { return v.r*v.g*v.b; } + __forceinline float reduce_min(const Color& v) { return min(v.r,v.g,v.b); } + __forceinline float reduce_max(const Color& v) { return max(v.r,v.g,v.b); } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline bool operator ==( const Color& a, const Color& b ) { return a.r == b.r && a.g == b.g && a.b == b.b; } + __forceinline bool operator !=( const Color& a, const Color& b ) { return a.r != b.r || a.g != b.g || a.b != b.b; } + __forceinline bool operator < ( const Color& a, const Color& b ) { + if (a.r != b.r) return a.r < b.r; + if (a.g != b.g) return a.g < b.g; + if (a.b != b.b) return a.b < b.b; + return false; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Select + //////////////////////////////////////////////////////////////////////////////// + + __forceinline const Color select( bool s, const Color& t, const Color& f ) { + return s ? t : f; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Special Operators + //////////////////////////////////////////////////////////////////////////////// + + /*! computes luminance of a color */ + __forceinline float luminance (const Color& a) { return madd(0.212671f,a.r,madd(0.715160f,a.g,0.072169f*a.b)); } + + /*! output operator */ + inline std::ostream& operator<<(std::ostream& cout, const Color& a) { + return cout << "(" << a.r << ", " << a.g << ", " << a.b << ")"; + } +} diff --git a/thirdparty/embree/common/math/math.h b/thirdparty/embree/common/math/emath.h index 7930c17727..22a89a7669 100644 --- a/thirdparty/embree/common/math/math.h +++ b/thirdparty/embree/common/math/emath.h @@ -8,6 +8,10 @@ #include "constants.h" #include <cmath> +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) +# include "math_sycl.h" +#else + #if defined(__ARM_NEON) #include "../simd/arm/emulation.h" #else @@ -44,6 +48,9 @@ namespace embree __forceinline int toInt (const float& a) { return int(a); } __forceinline float toFloat(const int& a) { return float(a); } + __forceinline int asInt (const float& a) { return *((int*)&a); } + __forceinline float asFloat(const int& a) { return *((float*)&a); } + #if defined(__WIN32__) __forceinline bool finite ( const float x ) { return _finite(x) != 0; } #endif @@ -351,7 +358,11 @@ __forceinline float nmsub ( const float a, const float b, const float c) { retur __forceinline int select(bool s, int t, int f) { return s ? t : f; } __forceinline float select(bool s, float t, float f) { return s ? t : f; } - __forceinline bool all(bool s) { return s; } + __forceinline bool none(bool s) { return !s; } + __forceinline bool all (bool s) { return s; } + __forceinline bool any (bool s) { return s; } + + __forceinline unsigned movemask (bool s) { return (unsigned)s; } __forceinline float lerp(const float v0, const float v1, const float t) { return madd(1.0f-t,v0,t*v1); @@ -453,3 +464,5 @@ __forceinline float nmsub ( const float a, const float b, const float c) { retur return x | (y << 1) | (z << 2); } } + +#endif diff --git a/thirdparty/embree/common/math/lbbox.h b/thirdparty/embree/common/math/lbbox.h index 2b397a05c8..7619199780 100644 --- a/thirdparty/embree/common/math/lbbox.h +++ b/thirdparty/embree/common/math/lbbox.h @@ -179,6 +179,48 @@ namespace embree bounds1 = b1; } + /*! calculates the linear bounds for target_time_range of primitive with it's time_range_in and bounds */ + __forceinline LBBox(const BBox1f& time_range_in, const LBBox<T> lbounds, const BBox1f& target_time_range) + { + const BBox3f bounds0 = lbounds.bounds0; + const BBox3f bounds1 = lbounds.bounds1; + + /* normalize global target_time_range to local time_range_in */ + const BBox1f time_range((target_time_range.lower-time_range_in.lower)/time_range_in.size(), + (target_time_range.upper-time_range_in.lower)/time_range_in.size()); + + const BBox1f clipped_time_range(max(0.0f,time_range.lower), min(1.0f,time_range.upper)); + + /* compute bounds at begin and end of clipped time range */ + BBox<T> b0 = lerp(bounds0,bounds1,clipped_time_range.lower); + BBox<T> b1 = lerp(bounds0,bounds1,clipped_time_range.upper); + + /* make sure that b0 is properly bounded at time_range_in.lower */ + { + const BBox<T> bt = lerp(b0, b1, (0.0f - time_range.lower) / time_range.size()); + const T dlower = min(bounds0.lower-bt.lower, T(zero)); + const T dupper = max(bounds0.upper-bt.upper, T(zero)); + b0.lower += dlower; b1.lower += dlower; + b0.upper += dupper; b1.upper += dupper; + } + + /* make sure that b1 is properly bounded at time_range_in.upper */ + { + const BBox<T> bt = lerp(b0, b1, (1.0f - time_range.lower) / time_range.size()); + const T dlower = min(bounds1.lower-bt.lower, T(zero)); + const T dupper = max(bounds1.upper-bt.upper, T(zero)); + b0.lower += dlower; b1.lower += dlower; + b0.upper += dupper; b1.upper += dupper; + } + + this->bounds0 = b0; + this->bounds1 = b1; + } + + /*! calculates the linear bounds for target_time_range of primitive with it's time_range_in and bounds */ + __forceinline LBBox(const BBox1f& time_range_in, const BBox<T>& bounds0, const BBox<T>& bounds1, const BBox1f& target_time_range) + : LBBox(time_range_in,LBBox(bounds0,bounds1),target_time_range) {} + public: __forceinline bool empty() const { diff --git a/thirdparty/embree/common/math/linearspace2.h b/thirdparty/embree/common/math/linearspace2.h index 184ee695fb..e58f61ea6b 100644 --- a/thirdparty/embree/common/math/linearspace2.h +++ b/thirdparty/embree/common/math/linearspace2.h @@ -18,6 +18,7 @@ namespace embree /*! default matrix constructor */ __forceinline LinearSpace2 ( ) {} + __forceinline LinearSpace2 ( const LinearSpace2& other ) { vx = other.vx; vy = other.vy; } __forceinline LinearSpace2& operator=( const LinearSpace2& other ) { vx = other.vx; vy = other.vy; return *this; } diff --git a/thirdparty/embree/common/math/linearspace3.h b/thirdparty/embree/common/math/linearspace3.h index 9eaa2cc2bb..f6d2318fa0 100644 --- a/thirdparty/embree/common/math/linearspace3.h +++ b/thirdparty/embree/common/math/linearspace3.h @@ -19,6 +19,7 @@ namespace embree /*! default matrix constructor */ __forceinline LinearSpace3 ( ) {} + __forceinline LinearSpace3 ( const LinearSpace3& other ) { vx = other.vx; vy = other.vy; vz = other.vz; } __forceinline LinearSpace3& operator=( const LinearSpace3& other ) { vx = other.vx; vy = other.vy; vz = other.vz; return *this; } @@ -90,17 +91,20 @@ namespace embree Vector vx,vy,vz; }; +#if !defined(__SYCL_DEVICE_ONLY__) + /*! compute transposed matrix */ template<> __forceinline const LinearSpace3<Vec3fa> LinearSpace3<Vec3fa>::transposed() const { vfloat4 rx,ry,rz; transpose((vfloat4&)vx,(vfloat4&)vy,(vfloat4&)vz,vfloat4(zero),rx,ry,rz); return LinearSpace3<Vec3fa>(Vec3fa(rx),Vec3fa(ry),Vec3fa(rz)); } - +#endif + template<typename T> __forceinline const LinearSpace3<T> transposed(const LinearSpace3<T>& xfm) { return xfm.transposed(); } - + //////////////////////////////////////////////////////////////////////////////// // Unary Operators //////////////////////////////////////////////////////////////////////////////// diff --git a/thirdparty/embree/common/math/math_sycl.h b/thirdparty/embree/common/math/math_sycl.h new file mode 100644 index 0000000000..ffb047569c --- /dev/null +++ b/thirdparty/embree/common/math/math_sycl.h @@ -0,0 +1,279 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../sys/platform.h" +#include "../sys/intrinsics.h" +#include "constants.h" +#include <cmath> + +namespace embree +{ + __forceinline bool isvalid ( const float& v ) { + return (v > -FLT_LARGE) & (v < +FLT_LARGE); + } + + __forceinline int cast_f2i(float f) { + return __builtin_bit_cast(int,f); + } + + __forceinline float cast_i2f(int i) { + return __builtin_bit_cast(float,i); + } + + __forceinline int toInt (const float& a) { return int(a); } + __forceinline float toFloat(const int& a) { return float(a); } + + __forceinline float asFloat(const int a) { return __builtin_bit_cast(float,a); } + __forceinline int asInt (const float a) { return __builtin_bit_cast(int,a); } + + //__forceinline bool finite ( const float x ) { return _finite(x) != 0; } + __forceinline float sign ( const float x ) { return x<0?-1.0f:1.0f; } + __forceinline float sqr ( const float x ) { return x*x; } + + __forceinline float rcp ( const float x ) { + return sycl::native::recip(x); + } + + __forceinline float signmsk(const float a) { return asFloat(asInt(a) & 0x80000000); } + //__forceinline float signmsk ( const float x ) { + // return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(0x80000000)))); + //} + //__forceinline float xorf( const float x, const float y ) { + // return _mm_cvtss_f32(_mm_xor_ps(_mm_set_ss(x),_mm_set_ss(y))); + //} + //__forceinline float andf( const float x, const unsigned y ) { + // return _mm_cvtss_f32(_mm_and_ps(_mm_set_ss(x),_mm_castsi128_ps(_mm_set1_epi32(y)))); + //} + + __forceinline float rsqrt( const float x ) { + return sycl::rsqrt(x); + } + + //__forceinline float nextafter(float x, float y) { if ((x<y) == (x>0)) return x*(1.1f+float(ulp)); else return x*(0.9f-float(ulp)); } + //__forceinline double nextafter(double x, double y) { return _nextafter(x, y); } + //__forceinline int roundf(float f) { return (int)(f + 0.5f); } + + __forceinline float abs ( const float x ) { return sycl::fabs(x); } + __forceinline float acos ( const float x ) { return sycl::acos(x); } + __forceinline float asin ( const float x ) { return sycl::asin(x); } + __forceinline float atan ( const float x ) { return sycl::atan(x); } + __forceinline float atan2( const float y, const float x ) { return sycl::atan2(y, x); } + __forceinline float cos ( const float x ) { return sycl::cos(x); } + __forceinline float cosh ( const float x ) { return sycl::cosh(x); } + __forceinline float exp ( const float x ) { return sycl::exp(x); } + __forceinline float fmod ( const float x, const float y ) { return sycl::fmod(x, y); } + __forceinline float log ( const float x ) { return sycl::log(x); } + __forceinline float log10( const float x ) { return sycl::log10(x); } + __forceinline float pow ( const float x, const float y ) { return sycl::pow(x, y); } + __forceinline float sin ( const float x ) { return sycl::sin(x); } + __forceinline float sinh ( const float x ) { return sycl::sinh(x); } + __forceinline float sqrt ( const float x ) { return sycl::sqrt(x); } + __forceinline float tan ( const float x ) { return sycl::tan(x); } + __forceinline float tanh ( const float x ) { return sycl::tanh(x); } + __forceinline float floor( const float x ) { return sycl::floor(x); } + __forceinline float ceil ( const float x ) { return sycl::ceil(x); } + __forceinline float frac ( const float x ) { return x-floor(x); } + + //__forceinline double abs ( const double x ) { return ::fabs(x); } + //__forceinline double sign ( const double x ) { return x<0?-1.0:1.0; } + //__forceinline double acos ( const double x ) { return ::acos (x); } + //__forceinline double asin ( const double x ) { return ::asin (x); } + //__forceinline double atan ( const double x ) { return ::atan (x); } + //__forceinline double atan2( const double y, const double x ) { return ::atan2(y, x); } + //__forceinline double cos ( const double x ) { return ::cos (x); } + //__forceinline double cosh ( const double x ) { return ::cosh (x); } + //__forceinline double exp ( const double x ) { return ::exp (x); } + //__forceinline double fmod ( const double x, const double y ) { return ::fmod (x, y); } + //__forceinline double log ( const double x ) { return ::log (x); } + //__forceinline double log10( const double x ) { return ::log10(x); } + //__forceinline double pow ( const double x, const double y ) { return ::pow (x, y); } + //__forceinline double rcp ( const double x ) { return 1.0/x; } + //__forceinline double rsqrt( const double x ) { return 1.0/::sqrt(x); } + //__forceinline double sin ( const double x ) { return ::sin (x); } + //__forceinline double sinh ( const double x ) { return ::sinh (x); } + //__forceinline double sqr ( const double x ) { return x*x; } + //__forceinline double sqrt ( const double x ) { return ::sqrt (x); } + //__forceinline double tan ( const double x ) { return ::tan (x); } + //__forceinline double tanh ( const double x ) { return ::tanh (x); } + //__forceinline double floor( const double x ) { return ::floor (x); } + //__forceinline double ceil ( const double x ) { return ::ceil (x); } + +/* +#if defined(__SSE4_1__) + __forceinline float mini(float a, float b) { + const __m128i ai = _mm_castps_si128(_mm_set_ss(a)); + const __m128i bi = _mm_castps_si128(_mm_set_ss(b)); + const __m128i ci = _mm_min_epi32(ai,bi); + return _mm_cvtss_f32(_mm_castsi128_ps(ci)); + } +#endif + +#if defined(__SSE4_1__) + __forceinline float maxi(float a, float b) { + const __m128i ai = _mm_castps_si128(_mm_set_ss(a)); + const __m128i bi = _mm_castps_si128(_mm_set_ss(b)); + const __m128i ci = _mm_max_epi32(ai,bi); + return _mm_cvtss_f32(_mm_castsi128_ps(ci)); + } +#endif +*/ + + template<typename T> + __forceinline T twice(const T& a) { return a+a; } + + __forceinline int min(int a, int b) { return sycl::min(a,b); } + __forceinline unsigned min(unsigned a, unsigned b) { return sycl::min(a,b); } + __forceinline int64_t min(int64_t a, int64_t b) { return sycl::min(a,b); } + __forceinline float min(float a, float b) { return sycl::fmin(a,b); } + __forceinline double min(double a, double b) { return sycl::fmin(a,b); } +#if defined(__X86_64__) + __forceinline size_t min(size_t a, size_t b) { return sycl::min(a,b); } +#endif + + template<typename T> __forceinline T min(const T& a, const T& b, const T& c) { return min(min(a,b),c); } + template<typename T> __forceinline T min(const T& a, const T& b, const T& c, const T& d) { return min(min(a,b),min(c,d)); } + template<typename T> __forceinline T min(const T& a, const T& b, const T& c, const T& d, const T& e) { return min(min(min(a,b),min(c,d)),e); } + +// template<typename T> __forceinline T mini(const T& a, const T& b, const T& c) { return mini(mini(a,b),c); } +// template<typename T> __forceinline T mini(const T& a, const T& b, const T& c, const T& d) { return mini(mini(a,b),mini(c,d)); } +// template<typename T> __forceinline T mini(const T& a, const T& b, const T& c, const T& d, const T& e) { return mini(mini(mini(a,b),mini(c,d)),e); } + + __forceinline int max(int a, int b) { return sycl::max(a,b); } + __forceinline unsigned max(unsigned a, unsigned b) { return sycl::max(a,b); } + __forceinline int64_t max(int64_t a, int64_t b) { return sycl::max(a,b); } + __forceinline float max(float a, float b) { return sycl::fmax(a,b); } + __forceinline double max(double a, double b) { return sycl::fmax(a,b); } +#if defined(__X86_64__) + __forceinline size_t max(size_t a, size_t b) { return sycl::max(a,b); } +#endif + + template<typename T> __forceinline T max(const T& a, const T& b, const T& c) { return max(max(a,b),c); } + template<typename T> __forceinline T max(const T& a, const T& b, const T& c, const T& d) { return max(max(a,b),max(c,d)); } + template<typename T> __forceinline T max(const T& a, const T& b, const T& c, const T& d, const T& e) { return max(max(max(a,b),max(c,d)),e); } + +// template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c) { return maxi(maxi(a,b),c); } +// template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c, const T& d) { return maxi(maxi(a,b),maxi(c,d)); } +// template<typename T> __forceinline T maxi(const T& a, const T& b, const T& c, const T& d, const T& e) { return maxi(maxi(maxi(a,b),maxi(c,d)),e); } + + template<typename T> __forceinline T clamp(const T& x, const T& lower = T(zero), const T& upper = T(one)) { return max(min(x,upper),lower); } + template<typename T> __forceinline T clampz(const T& x, const T& upper) { return max(T(zero), min(x,upper)); } + + template<typename T> __forceinline T deg2rad ( const T& x ) { return x * T(1.74532925199432957692e-2f); } + template<typename T> __forceinline T rad2deg ( const T& x ) { return x * T(5.72957795130823208768e1f); } + template<typename T> __forceinline T sin2cos ( const T& x ) { return sqrt(max(T(zero),T(one)-x*x)); } + template<typename T> __forceinline T cos2sin ( const T& x ) { return sin2cos(x); } + + __forceinline float madd ( const float a, const float b, const float c) { return +sycl::fma(+a,b,+c); } + __forceinline float msub ( const float a, const float b, const float c) { return +sycl::fma(+a,b,-c); } + __forceinline float nmadd ( const float a, const float b, const float c) { return +sycl::fma(-a,b,+c); } + __forceinline float nmsub ( const float a, const float b, const float c) { return -sycl::fma(+a,b,+c); } + + /*! random functions */ +/* + template<typename T> T random() { return T(0); } + template<> __forceinline int random() { return int(rand()); } + template<> __forceinline uint32_t random() { return uint32_t(rand()) ^ (uint32_t(rand()) << 16); } + template<> __forceinline float random() { return rand()/float(RAND_MAX); } + template<> __forceinline double random() { return rand()/double(RAND_MAX); } +*/ + + /*! selects */ + __forceinline bool select(bool s, bool t , bool f) { return s ? t : f; } + __forceinline int select(bool s, int t, int f) { return s ? t : f; } + __forceinline float select(bool s, float t, float f) { return s ? t : f; } + + __forceinline bool none(bool s) { return !s; } + __forceinline bool all (bool s) { return s; } + __forceinline bool any (bool s) { return s; } + + __forceinline unsigned movemask (bool s) { return (unsigned)s; } + + __forceinline float lerp(const float v0, const float v1, const float t) { + return madd(1.0f-t,v0,t*v1); + } + + template<typename T> + __forceinline T lerp2(const float x0, const float x1, const float x2, const float x3, const T& u, const T& v) { + return madd((1.0f-u),madd((1.0f-v),T(x0),v*T(x2)),u*madd((1.0f-v),T(x1),v*T(x3))); + } + + /*! exchange */ + template<typename T> __forceinline void xchg ( T& a, T& b ) { const T tmp = a; a = b; b = tmp; } + + /* load/store */ + template<typename Ty> struct mem; + + template<> struct mem<float> { + static __forceinline float load (bool mask, const void* ptr) { return mask ? *(float*)ptr : 0.0f; } + static __forceinline float loadu(bool mask, const void* ptr) { return mask ? *(float*)ptr : 0.0f; } + + static __forceinline void store (bool mask, void* ptr, const float v) { if (mask) *(float*)ptr = v; } + static __forceinline void storeu(bool mask, void* ptr, const float v) { if (mask) *(float*)ptr = v; } + }; + + /*! bit reverse operation */ + template<class T> + __forceinline T bitReverse(const T& vin) + { + T v = vin; + v = ((v >> 1) & 0x55555555) | ((v & 0x55555555) << 1); + v = ((v >> 2) & 0x33333333) | ((v & 0x33333333) << 2); + v = ((v >> 4) & 0x0F0F0F0F) | ((v & 0x0F0F0F0F) << 4); + v = ((v >> 8) & 0x00FF00FF) | ((v & 0x00FF00FF) << 8); + v = ( v >> 16 ) | ( v << 16); + return v; + } + + /*! bit interleave operation */ + template<class T> + __forceinline T bitInterleave(const T& xin, const T& yin, const T& zin) + { + T x = xin, y = yin, z = zin; + x = (x | (x << 16)) & 0x030000FF; + x = (x | (x << 8)) & 0x0300F00F; + x = (x | (x << 4)) & 0x030C30C3; + x = (x | (x << 2)) & 0x09249249; + + y = (y | (y << 16)) & 0x030000FF; + y = (y | (y << 8)) & 0x0300F00F; + y = (y | (y << 4)) & 0x030C30C3; + y = (y | (y << 2)) & 0x09249249; + + z = (z | (z << 16)) & 0x030000FF; + z = (z | (z << 8)) & 0x0300F00F; + z = (z | (z << 4)) & 0x030C30C3; + z = (z | (z << 2)) & 0x09249249; + + return x | (y << 1) | (z << 2); + } + + /*! bit interleave operation for 64bit data types*/ + template<class T> + __forceinline T bitInterleave64(const T& xin, const T& yin, const T& zin){ + T x = xin & 0x1fffff; + T y = yin & 0x1fffff; + T z = zin & 0x1fffff; + + x = (x | x << 32) & 0x1f00000000ffff; + x = (x | x << 16) & 0x1f0000ff0000ff; + x = (x | x << 8) & 0x100f00f00f00f00f; + x = (x | x << 4) & 0x10c30c30c30c30c3; + x = (x | x << 2) & 0x1249249249249249; + + y = (y | y << 32) & 0x1f00000000ffff; + y = (y | y << 16) & 0x1f0000ff0000ff; + y = (y | y << 8) & 0x100f00f00f00f00f; + y = (y | y << 4) & 0x10c30c30c30c30c3; + y = (y | y << 2) & 0x1249249249249249; + + z = (z | z << 32) & 0x1f00000000ffff; + z = (z | z << 16) & 0x1f0000ff0000ff; + z = (z | z << 8) & 0x100f00f00f00f00f; + z = (z | z << 4) & 0x10c30c30c30c30c3; + z = (z | z << 2) & 0x1249249249249249; + + return x | (y << 1) | (z << 2); + } +} diff --git a/thirdparty/embree/common/math/range.h b/thirdparty/embree/common/math/range.h index 909fadb995..f397615ea2 100644 --- a/thirdparty/embree/common/math/range.h +++ b/thirdparty/embree/common/math/range.h @@ -4,7 +4,7 @@ #pragma once #include "../sys/platform.h" -#include "../math/math.h" +#include "../math/emath.h" namespace embree { diff --git a/thirdparty/embree/common/math/vec2.h b/thirdparty/embree/common/math/vec2.h index f6d98ffa0d..4e641ec249 100644 --- a/thirdparty/embree/common/math/vec2.h +++ b/thirdparty/embree/common/math/vec2.h @@ -3,7 +3,7 @@ #pragma once -#include "math.h" +#include "emath.h" namespace embree { @@ -34,7 +34,7 @@ namespace embree __forceinline Vec2( const T& x, const T& y ) : x(x), y(y) {} __forceinline Vec2( const Vec2& other ) { x = other.x; y = other.y; } - __forceinline Vec2( const Vec2fa& other ); + Vec2( const Vec2fa& other ); template<typename T1> __forceinline Vec2( const Vec2<T1>& a ) : x(T(a.x)), y(T(a.y)) {} template<typename T1> __forceinline Vec2& operator =( const Vec2<T1>& other ) { x = other.x; y = other.y; return *this; } @@ -232,4 +232,5 @@ namespace embree #if defined(__AVX512F__) template<> __forceinline Vec2<vfloat16>::Vec2(const Vec2fa& a) : x(a.x), y(a.y) {} #endif + } diff --git a/thirdparty/embree/common/math/vec2fa.h b/thirdparty/embree/common/math/vec2fa.h index 4f222894c2..d57e549e68 100644 --- a/thirdparty/embree/common/math/vec2fa.h +++ b/thirdparty/embree/common/math/vec2fa.h @@ -4,7 +4,12 @@ #pragma once #include "../sys/alloc.h" -#include "math.h" +#include "emath.h" + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) +# include "vec2fa_sycl.h" +#else + #include "../simd/sse.h" namespace embree @@ -316,3 +321,5 @@ namespace embree typedef Vec2fa Vec2fa_t; } + +#endif diff --git a/thirdparty/embree/common/math/vec2fa_sycl.h b/thirdparty/embree/common/math/vec2fa_sycl.h new file mode 100644 index 0000000000..62d62bdd01 --- /dev/null +++ b/thirdparty/embree/common/math/vec2fa_sycl.h @@ -0,0 +1,270 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../sys/alloc.h" +#include "emath.h" +#include "../simd/sse.h" + +namespace embree +{ + struct Vec3fa; + + //////////////////////////////////////////////////////////////////////////////// + /// SSE Vec2fa Type + //////////////////////////////////////////////////////////////////////////////// + + struct __aligned(16) Vec2fa + { + //ALIGNED_STRUCT_(16); + + typedef float Scalar; + enum { N = 2 }; + struct { float x,y; }; + + //////////////////////////////////////////////////////////////////////////////// + /// Constructors, Assignment & Cast Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec2fa( ) {} + //__forceinline Vec2fa( const __m128 a ) : m128(a) {} + explicit Vec2fa(const Vec3fa& a); + + __forceinline explicit Vec2fa( const vfloat<4>& a ) { + x = a[0]; + y = a[1]; + } + + __forceinline Vec2fa ( const Vec2<float>& other ) { x = other.x; y = other.y; } + __forceinline Vec2fa& operator =( const Vec2<float>& other ) { x = other.x; y = other.y; return *this; } + + __forceinline Vec2fa ( const Vec2fa& other ) { x = other.x; y = other.y; } + __forceinline Vec2fa& operator =( const Vec2fa& other ) { x = other.x; y = other.y; return *this; } + + __forceinline explicit Vec2fa( const float a ) : x(a), y(a) {} + __forceinline Vec2fa( const float x, const float y) : x(x), y(y) {} + + //__forceinline explicit Vec2fa( const __m128i a ) : m128(_mm_cvtepi32_ps(a)) {} + + //__forceinline operator const __m128&() const { return m128; } + //__forceinline operator __m128&() { return m128; } + + //////////////////////////////////////////////////////////////////////////////// + /// Loads and Stores + //////////////////////////////////////////////////////////////////////////////// + + static __forceinline Vec2fa load( const void* const a ) { + const float* ptr = (const float*)a; + return Vec2fa(ptr[0],ptr[1]); + } + + static __forceinline Vec2fa loadu( const void* const a ) { + const float* ptr = (const float*)a; + return Vec2fa(ptr[0],ptr[1]); + } + + static __forceinline void storeu ( void* a, const Vec2fa& v ) { + float* ptr = (float*)a; + ptr[0] = v.x; ptr[1] = v.y; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec2fa( ZeroTy ) : x(0.0f), y(0.0f) {} + __forceinline Vec2fa( OneTy ) : x(1.0f), y(1.0f) {} + __forceinline Vec2fa( PosInfTy ) : x(+INFINITY), y(+INFINITY) {} + __forceinline Vec2fa( NegInfTy ) : x(-INFINITY), y(-INFINITY) {} + + //////////////////////////////////////////////////////////////////////////////// + /// Array Access + //////////////////////////////////////////////////////////////////////////////// + + //__forceinline const float& operator []( const size_t index ) const { assert(index < 2); return (&x)[index]; } + //__forceinline float& operator []( const size_t index ) { assert(index < 2); return (&x)[index]; } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec2fa operator +( const Vec2fa& a ) { return a; } + __forceinline Vec2fa operator -( const Vec2fa& a ) { return Vec2fa(-a.x,-a.y); } + __forceinline Vec2fa abs ( const Vec2fa& a ) { return Vec2fa(sycl::fabs(a.x),sycl::fabs(a.y)); } + __forceinline Vec2fa sign ( const Vec2fa& a ) { return Vec2fa(sycl::sign(a.x),sycl::sign(a.y)); } + + //__forceinline Vec2fa rcp ( const Vec2fa& a ) { return Vec2fa(sycl::recip(a.x),sycl::recip(a.y)); } + __forceinline Vec2fa rcp ( const Vec2fa& a ) { return Vec2fa(__sycl_std::__invoke_native_recip<float>(a.x),__sycl_std::__invoke_native_recip<float>(a.y)); } + __forceinline Vec2fa sqrt ( const Vec2fa& a ) { return Vec2fa(sycl::sqrt(a.x),sycl::sqrt(a.y)); } + __forceinline Vec2fa sqr ( const Vec2fa& a ) { return Vec2fa(a.x*a.x,a.y*a.y); } + + __forceinline Vec2fa rsqrt( const Vec2fa& a ) { return Vec2fa(sycl::rsqrt(a.x),sycl::rsqrt(a.y)); } + + __forceinline Vec2fa zero_fix(const Vec2fa& a) { + const float x = sycl::fabs(a.x) < min_rcp_input ? min_rcp_input : a.x; + const float y = sycl::fabs(a.y) < min_rcp_input ? min_rcp_input : a.y; + return Vec2fa(x,y); + } + __forceinline Vec2fa rcp_safe(const Vec2fa& a) { + return rcp(zero_fix(a)); + } + __forceinline Vec2fa log ( const Vec2fa& a ) { + return Vec2fa(sycl::log(a.x),sycl::log(a.y)); + } + + __forceinline Vec2fa exp ( const Vec2fa& a ) { + return Vec2fa(sycl::exp(a.x),sycl::exp(a.y)); + } + + //////////////////////////////////////////////////////////////////////////////// + /// Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec2fa operator +( const Vec2fa& a, const Vec2fa& b ) { return Vec2fa(a.x+b.x, a.y+b.y); } + __forceinline Vec2fa operator -( const Vec2fa& a, const Vec2fa& b ) { return Vec2fa(a.x-b.x, a.y-b.y); } + __forceinline Vec2fa operator *( const Vec2fa& a, const Vec2fa& b ) { return Vec2fa(a.x*b.x, a.y*b.y); } + __forceinline Vec2fa operator *( const Vec2fa& a, const float b ) { return a * Vec2fa(b); } + __forceinline Vec2fa operator *( const float a, const Vec2fa& b ) { return Vec2fa(a) * b; } + __forceinline Vec2fa operator /( const Vec2fa& a, const Vec2fa& b ) { return Vec2fa(a.x/b.x, a.y/b.y); } + __forceinline Vec2fa operator /( const Vec2fa& a, const float b ) { return Vec2fa(a.x/b, a.y/b); } + __forceinline Vec2fa operator /( const float a, const Vec2fa& b ) { return Vec2fa(a/b.x, a/b.y); } + + __forceinline Vec2fa min( const Vec2fa& a, const Vec2fa& b ) { + return Vec2fa(sycl::fmin(a.x,b.x), sycl::fmin(a.y,b.y)); + } + __forceinline Vec2fa max( const Vec2fa& a, const Vec2fa& b ) { + return Vec2fa(sycl::fmax(a.x,b.x), sycl::fmax(a.y,b.y)); + } + +/* +#if defined(__SSE4_1__) + __forceinline Vec2fa mini(const Vec2fa& a, const Vec2fa& b) { + const vint4 ai = _mm_castps_si128(a); + const vint4 bi = _mm_castps_si128(b); + const vint4 ci = _mm_min_epi32(ai,bi); + return _mm_castsi128_ps(ci); + } +#endif + +#if defined(__SSE4_1__) + __forceinline Vec2fa maxi(const Vec2fa& a, const Vec2fa& b) { + const vint4 ai = _mm_castps_si128(a); + const vint4 bi = _mm_castps_si128(b); + const vint4 ci = _mm_max_epi32(ai,bi); + return _mm_castsi128_ps(ci); + } +#endif + + __forceinline Vec2fa pow ( const Vec2fa& a, const float& b ) { + return Vec2fa(powf(a.x,b),powf(a.y,b)); + } +*/ + + //////////////////////////////////////////////////////////////////////////////// + /// Ternary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec2fa madd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return Vec2fa(madd(a.x,b.x,c.x), madd(a.y,b.y,c.y)); } + __forceinline Vec2fa msub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return Vec2fa(msub(a.x,b.x,c.x), msub(a.y,b.y,c.y)); } + __forceinline Vec2fa nmadd ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return Vec2fa(nmadd(a.x,b.x,c.x), nmadd(a.y,b.y,c.y)); } + __forceinline Vec2fa nmsub ( const Vec2fa& a, const Vec2fa& b, const Vec2fa& c) { return Vec2fa(nmsub(a.x,b.x,c.x), nmsub(a.y,b.y,c.y)); } + + __forceinline Vec2fa madd ( const float a, const Vec2fa& b, const Vec2fa& c) { return madd(Vec2fa(a),b,c); } + __forceinline Vec2fa msub ( const float a, const Vec2fa& b, const Vec2fa& c) { return msub(Vec2fa(a),b,c); } + __forceinline Vec2fa nmadd ( const float a, const Vec2fa& b, const Vec2fa& c) { return nmadd(Vec2fa(a),b,c); } + __forceinline Vec2fa nmsub ( const float a, const Vec2fa& b, const Vec2fa& c) { return nmsub(Vec2fa(a),b,c); } + + //////////////////////////////////////////////////////////////////////////////// + /// Assignment Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec2fa& operator +=( Vec2fa& a, const Vec2fa& b ) { return a = a + b; } + __forceinline Vec2fa& operator -=( Vec2fa& a, const Vec2fa& b ) { return a = a - b; } + __forceinline Vec2fa& operator *=( Vec2fa& a, const Vec2fa& b ) { return a = a * b; } + __forceinline Vec2fa& operator *=( Vec2fa& a, const float b ) { return a = a * b; } + __forceinline Vec2fa& operator /=( Vec2fa& a, const Vec2fa& b ) { return a = a / b; } + __forceinline Vec2fa& operator /=( Vec2fa& a, const float b ) { return a = a / b; } + + //////////////////////////////////////////////////////////////////////////////// + /// Reductions + //////////////////////////////////////////////////////////////////////////////// + + __forceinline float reduce_add(const Vec2fa& v) { return v.x+v.y; } + __forceinline float reduce_mul(const Vec2fa& v) { return v.x*v.y; } + __forceinline float reduce_min(const Vec2fa& v) { return sycl::fmin(v.x,v.y); } + __forceinline float reduce_max(const Vec2fa& v) { return sycl::fmax(v.x,v.y); } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline bool operator ==( const Vec2fa& a, const Vec2fa& b ) { return a.x == b.x && a.y == b.y; } + __forceinline bool operator !=( const Vec2fa& a, const Vec2fa& b ) { return a.x != b.x || a.y != b.y; } + + //////////////////////////////////////////////////////////////////////////////// + /// Euclidian Space Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline float dot ( const Vec2fa& a, const Vec2fa& b ) { + return reduce_add(a*b); + } + + __forceinline Vec2fa cross ( const Vec2fa& a ) { + return Vec2fa(-a.y,a.x); + } + + __forceinline float sqr_length ( const Vec2fa& a ) { return dot(a,a); } + __forceinline float rcp_length ( const Vec2fa& a ) { return rsqrt(dot(a,a)); } + __forceinline float rcp_length2( const Vec2fa& a ) { return rcp(dot(a,a)); } + __forceinline float length ( const Vec2fa& a ) { return sqrt(dot(a,a)); } + __forceinline Vec2fa normalize( const Vec2fa& a ) { return a*rsqrt(dot(a,a)); } + __forceinline float distance ( const Vec2fa& a, const Vec2fa& b ) { return length(a-b); } + + //////////////////////////////////////////////////////////////////////////////// + /// Select + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec2fa select( bool s, const Vec2fa& t, const Vec2fa& f ) { + return Vec2fa(s ? t.x : f.x, s ? t.y : f.y); + } + + __forceinline Vec2fa lerp(const Vec2fa& v0, const Vec2fa& v1, const float t) { + return madd(1.0f-t,v0,t*v1); + } + + __forceinline int maxDim ( const Vec2fa& a ) + { + const Vec2fa b = abs(a); + if (b.x > b.y) return 0; + else return 1; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Rounding Functions + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec2fa trunc( const Vec2fa& a ) { return Vec2fa(sycl::trunc(a.x),sycl::trunc(a.y)); } + __forceinline Vec2fa floor( const Vec2fa& a ) { return Vec2fa(sycl::floor(a.x),sycl::floor(a.y)); } + __forceinline Vec2fa ceil ( const Vec2fa& a ) { return Vec2fa(sycl::ceil (a.x),sycl::ceil (a.y)); } + + //////////////////////////////////////////////////////////////////////////////// + /// Output Operators + //////////////////////////////////////////////////////////////////////////////// + + inline embree_ostream operator<<(embree_ostream cout, const Vec2fa& a) { + return cout << "(" << a.x << ", " << a.y << ")"; + } + + /*template<> + __forceinline vfloat_impl<4>::vfloat_impl(const Vec2fa& a) + { + v = 0; + const unsigned int lid = get_sub_group_local_id(); + if (lid == 0) v = a.x; + if (lid == 1) v = a.y; + }*/ + + typedef Vec2fa Vec2fa_t; +} diff --git a/thirdparty/embree/common/math/vec3.h b/thirdparty/embree/common/math/vec3.h index 254f6c4011..d5e78befe8 100644 --- a/thirdparty/embree/common/math/vec3.h +++ b/thirdparty/embree/common/math/vec3.h @@ -3,7 +3,7 @@ #pragma once -#include "math.h" +#include "emath.h" namespace embree { @@ -286,6 +286,8 @@ namespace embree template<> __forceinline Vec3<float>::Vec3(const Vec3fa& a) { x = a.x; y = a.y; z = a.z; } +#if !defined(__SYCL_DEVICE_ONLY__) + #if defined(__AVX__) template<> __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) { x = a.x; y = a.y; z = a.z; @@ -333,4 +335,23 @@ namespace embree #if defined(__AVX512F__) template<> __forceinline Vec3<vfloat16>::Vec3(const Vec3fa& a) : x(a.x), y(a.y), z(a.z) {} #endif + +#else + +#if defined(__SSE__) + template<> __forceinline Vec3<vfloat4>::Vec3(const Vec3fa& a) { + x = a.x; y = a.y; z = a.z; + } +#endif +#if defined(__AVX__) + template<> __forceinline Vec3<vfloat8>::Vec3(const Vec3fa& a) { + x = a.x; y = a.y; z = a.z; + } +#endif +#if defined(__AVX512F__) + template<> __forceinline Vec3<vfloat16>::Vec3(const Vec3fa& a) { + x = a.x; y = a.y; z = a.z; + } +#endif +#endif } diff --git a/thirdparty/embree/common/math/vec3ba.h b/thirdparty/embree/common/math/vec3ba.h index a021b522dc..bf24a2a3b6 100644 --- a/thirdparty/embree/common/math/vec3ba.h +++ b/thirdparty/embree/common/math/vec3ba.h @@ -4,7 +4,12 @@ #pragma once #include "../sys/alloc.h" -#include "math.h" +#include "emath.h" + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) +# include "vec3ba_sycl.h" +#else + #include "../simd/sse.h" namespace embree @@ -118,3 +123,5 @@ namespace embree return cout << "(" << (a.x ? "1" : "0") << ", " << (a.y ? "1" : "0") << ", " << (a.z ? "1" : "0") << ")"; } } + +#endif diff --git a/thirdparty/embree/common/math/vec3ba_sycl.h b/thirdparty/embree/common/math/vec3ba_sycl.h new file mode 100644 index 0000000000..a2fa13de6c --- /dev/null +++ b/thirdparty/embree/common/math/vec3ba_sycl.h @@ -0,0 +1,115 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../sys/alloc.h" +#include "emath.h" +#include "../simd/sse.h" + +namespace embree +{ + //////////////////////////////////////////////////////////////////////////////// + /// SSE Vec3ba Type + //////////////////////////////////////////////////////////////////////////////// + + struct __aligned(16) Vec3ba + { + //ALIGNED_STRUCT_(16); + + struct { bool x,y,z; }; + + typedef bool Scalar; + enum { N = 3 }; + + //////////////////////////////////////////////////////////////////////////////// + /// Constructors, Assignment & Cast Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ba( ) {} + //__forceinline Vec3ba( const __m128 input ) : m128(input) {} + + __forceinline Vec3ba( const Vec3ba& other ) : x(other.x), y(other.y), z(other.z) {} + __forceinline Vec3ba& operator =(const Vec3ba& other) { x = other.x; y = other.y; z = other.z; return *this; } + + __forceinline explicit Vec3ba( bool a ) : x(a), y(a), z(a) {} + __forceinline Vec3ba( bool a, bool b, bool c) : x(a), y(b), z(c) {} + + //__forceinline operator const __m128&() const { return m128; } + //__forceinline operator __m128&() { return m128; } + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ba( FalseTy ) : x(false), y(false), z(false) {} + __forceinline Vec3ba( TrueTy ) : x(true), y(true), z(true) {} + + //////////////////////////////////////////////////////////////////////////////// + /// Array Access + //////////////////////////////////////////////////////////////////////////////// + + //__forceinline const int& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; } + //__forceinline int& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; } + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ba operator !( const Vec3ba& a ) { return Vec3ba(!a.x,!a.y,!a.z); } + + //////////////////////////////////////////////////////////////////////////////// + /// Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ba operator &( const Vec3ba& a, const Vec3ba& b ) { return Vec3ba(a.x & b.x, a.y & b.y, a.z & b.z); } + __forceinline Vec3ba operator |( const Vec3ba& a, const Vec3ba& b ) { return Vec3ba(a.x | b.x, a.y | b.y, a.z | b.z); } + __forceinline Vec3ba operator ^( const Vec3ba& a, const Vec3ba& b ) { return Vec3ba(a.x != b.x, a.y != b.y, a.z != b.z); } + + //////////////////////////////////////////////////////////////////////////////// + /// Assignment Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ba& operator &=( Vec3ba& a, const Vec3ba& b ) { return a = a & b; } + __forceinline Vec3ba& operator |=( Vec3ba& a, const Vec3ba& b ) { return a = a | b; } + __forceinline Vec3ba& operator ^=( Vec3ba& a, const Vec3ba& b ) { return a = a ^ b; } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + Select + //////////////////////////////////////////////////////////////////////////////// + + __forceinline bool operator ==( const Vec3ba& a, const Vec3ba& b ) { + return a.x == b.x && a.y == b.y && a.z == b.z; + } + __forceinline bool operator !=( const Vec3ba& a, const Vec3ba& b ) { + return a.x != b.x || a.y != b.y || a.z != b.z; + } +/* + __forceinline bool operator < ( const Vec3ba& a, const Vec3ba& b ) { + if (a.x != b.x) return a.x < b.x; + if (a.y != b.y) return a.y < b.y; + if (a.z != b.z) return a.z < b.z; + return false; + } +*/ + //////////////////////////////////////////////////////////////////////////////// + /// Reduction Operations + //////////////////////////////////////////////////////////////////////////////// + + __forceinline bool reduce_and( const Vec3ba& a ) { return a.x & a.y & a.z; } + __forceinline bool reduce_or ( const Vec3ba& a ) { return a.x | a.y | a.z; } + + __forceinline bool all ( const Vec3ba& b ) { return reduce_and(b); } + __forceinline bool any ( const Vec3ba& b ) { return reduce_or(b); } + __forceinline bool none ( const Vec3ba& b ) { return !reduce_or(b); } + + //////////////////////////////////////////////////////////////////////////////// + /// Output Operators + //////////////////////////////////////////////////////////////////////////////// + + inline embree_ostream operator<<(embree_ostream cout, const Vec3ba& a) { + return cout; + } +} diff --git a/thirdparty/embree/common/math/vec3fa.h b/thirdparty/embree/common/math/vec3fa.h index 8564cf6d10..967e75da74 100644 --- a/thirdparty/embree/common/math/vec3fa.h +++ b/thirdparty/embree/common/math/vec3fa.h @@ -4,7 +4,12 @@ #pragma once #include "../sys/alloc.h" -#include "math.h" +#include "emath.h" + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) +# include "vec3fa_sycl.h" +#else + #include "../simd/sse.h" namespace embree @@ -441,7 +446,6 @@ namespace embree //__forceinline Vec3fx& operator =( const Vec3<float>& other ) { m128 = _mm_set_ps(0, other.z, other.y, other.x); return *this; } __forceinline Vec3fx ( const Vec3fx& other ) { m128 = other.m128; } - __forceinline Vec3fx& operator =( const Vec3fx& other ) { m128 = other.m128; return *this; } __forceinline explicit Vec3fx( const float a ) : m128(_mm_set1_ps(a)) {} @@ -783,3 +787,5 @@ namespace embree typedef Vec3fx Vec3ff; } + +#endif diff --git a/thirdparty/embree/common/math/vec3fa_sycl.h b/thirdparty/embree/common/math/vec3fa_sycl.h new file mode 100644 index 0000000000..5fdb00ab99 --- /dev/null +++ b/thirdparty/embree/common/math/vec3fa_sycl.h @@ -0,0 +1,617 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../sys/alloc.h" +#include "emath.h" +#include "../simd/sse.h" + +namespace embree +{ + //////////////////////////////////////////////////////////////////////////////// + /// SSE Vec3fa Type + //////////////////////////////////////////////////////////////////////////////// + + struct __aligned(16) Vec3fa + { + //ALIGNED_STRUCT_(16); + + typedef float Scalar; + enum { N = 3 }; + struct { float x,y,z, do_not_use; }; + + //////////////////////////////////////////////////////////////////////////////// + /// Constructors, Assignment & Cast Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fa( ) {} + //__forceinline Vec3fa( const __m128 a ) : m128(a) {} + //__forceinline explicit Vec3fa(const vfloat4& a) : x(a[0]), y(a[1]), z(a[2]) {} + + __forceinline Vec3fa ( const Vec3<float>& other ) { x = other.x; y = other.y; z = other.z; } + //__forceinline Vec3fa& operator =( const Vec3<float>& other ) { x = other.x; y = other.y; z = other.z; return *this; } + + __forceinline Vec3fa ( const Vec3fa& other ) { x = other.x; y = other.y; z = other.z; } + __forceinline Vec3fa& operator =( const Vec3fa& other ) { x = other.x; y = other.y; z = other.z; return *this; } + + __forceinline explicit Vec3fa( const float a ) : x(a), y(a), z(a) {} + __forceinline Vec3fa( const float x, const float y, const float z) : x(x), y(y), z(z) {} + + __forceinline explicit Vec3fa( const Vec3ia& a ) : x((float)a.x), y((float)a.y), z((float)a.z) {} + + //__forceinline operator const __m128&() const { return m128; } + //__forceinline operator __m128&() { return m128; } + __forceinline operator vfloat4() const { return vfloat4(x,y,z,0.0f); } // FIXME: we should not need this!! + + //friend __forceinline Vec3fa copy_a( const Vec3fa& a, const Vec3fa& b ) { Vec3fa c = a; c.a = b.a; return c; } + + //////////////////////////////////////////////////////////////////////////////// + /// Loads and Stores + //////////////////////////////////////////////////////////////////////////////// + + static __forceinline Vec3fa load( const void* const a ) { + const float* ptr = (const float*)a; + return Vec3fa(ptr[0],ptr[1],ptr[2]); + } + + static __forceinline Vec3fa loadu( const void* const a ) { + const float* ptr = (const float*)a; + return Vec3fa(ptr[0],ptr[1],ptr[2]); + } + + static __forceinline void storeu ( void* a, const Vec3fa& v ) { + float* ptr = (float*)a; + ptr[0] = v.x; ptr[1] = v.y; ptr[2] = v.z; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fa( ZeroTy ) : x(0.0f), y(0.0f), z(0.0f) {} + __forceinline Vec3fa( OneTy ) : x(1.0f), y(1.0f), z(1.0f) {} + __forceinline Vec3fa( PosInfTy ) : x(+INFINITY), y(+INFINITY), z(+INFINITY) {} + __forceinline Vec3fa( NegInfTy ) : x(-INFINITY), y(-INFINITY), z(-INFINITY) {} + + //////////////////////////////////////////////////////////////////////////////// + /// Array Access + //////////////////////////////////////////////////////////////////////////////// + + __forceinline const float& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; } + __forceinline float& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fa operator +( const Vec3fa& a ) { return a; } + __forceinline Vec3fa operator -( const Vec3fa& a ) { return Vec3fa(-a.x,-a.y,-a.z); } + __forceinline Vec3fa abs ( const Vec3fa& a ) { return Vec3fa(sycl::fabs(a.x),sycl::fabs(a.y),sycl::fabs(a.z)); } + __forceinline Vec3fa sign ( const Vec3fa& a ) { return Vec3fa(sycl::sign(a.x),sycl::sign(a.y),sycl::sign(a.z)); } + + //__forceinline Vec3fa rcp ( const Vec3fa& a ) { return Vec3fa(sycl::recip(a.x),sycl::recip(a.y),sycl::recip(a.z)); } + __forceinline Vec3fa rcp ( const Vec3fa& a ) { return Vec3fa(__sycl_std::__invoke_native_recip<float>(a.x),__sycl_std::__invoke_native_recip<float>(a.y),__sycl_std::__invoke_native_recip<float>(a.z)); } + __forceinline Vec3fa sqrt ( const Vec3fa& a ) { return Vec3fa(sycl::sqrt(a.x),sycl::sqrt(a.y),sycl::sqrt(a.z)); } + __forceinline Vec3fa sqr ( const Vec3fa& a ) { return Vec3fa(a.x*a.x,a.y*a.y,a.z*a.z); } + + __forceinline Vec3fa rsqrt( const Vec3fa& a ) { return Vec3fa(sycl::rsqrt(a.x),sycl::rsqrt(a.y),sycl::rsqrt(a.z)); } + + __forceinline Vec3fa zero_fix(const Vec3fa& a) { + const float x = sycl::fabs(a.x) < min_rcp_input ? min_rcp_input : a.x; + const float y = sycl::fabs(a.y) < min_rcp_input ? min_rcp_input : a.y; + const float z = sycl::fabs(a.z) < min_rcp_input ? min_rcp_input : a.z; + return Vec3fa(x,y,z); + } + __forceinline Vec3fa rcp_safe(const Vec3fa& a) { + return rcp(zero_fix(a)); + } + __forceinline Vec3fa log ( const Vec3fa& a ) { + return Vec3fa(sycl::log(a.x),sycl::log(a.y),sycl::log(a.z)); + } + + __forceinline Vec3fa exp ( const Vec3fa& a ) { + return Vec3fa(sycl::exp(a.x),sycl::exp(a.y),sycl::exp(a.z)); + } + + //////////////////////////////////////////////////////////////////////////////// + /// Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fa operator +( const Vec3fa& a, const Vec3fa& b ) { return Vec3fa(a.x+b.x, a.y+b.y, a.z+b.z); } + __forceinline Vec3fa operator -( const Vec3fa& a, const Vec3fa& b ) { return Vec3fa(a.x-b.x, a.y-b.y, a.z-b.z); } + __forceinline Vec3fa operator *( const Vec3fa& a, const Vec3fa& b ) { return Vec3fa(a.x*b.x, a.y*b.y, a.z*b.z); } + __forceinline Vec3fa operator *( const Vec3fa& a, const float b ) { return a * Vec3fa(b); } + __forceinline Vec3fa operator *( const float a, const Vec3fa& b ) { return Vec3fa(a) * b; } + __forceinline Vec3fa operator /( const Vec3fa& a, const Vec3fa& b ) { return Vec3fa(a.x/b.x, a.y/b.y, a.z/b.z); } + __forceinline Vec3fa operator /( const Vec3fa& a, const float b ) { return Vec3fa(a.x/b, a.y/b, a.z/b); } + __forceinline Vec3fa operator /( const float a, const Vec3fa& b ) { return Vec3fa(a/b.x, a/b.y, a/b.z); } + + __forceinline Vec3fa min( const Vec3fa& a, const Vec3fa& b ) { + return Vec3fa(sycl::fmin(a.x,b.x), sycl::fmin(a.y,b.y), sycl::fmin(a.z,b.z)); + } + __forceinline Vec3fa max( const Vec3fa& a, const Vec3fa& b ) { + return Vec3fa(sycl::fmax(a.x,b.x), sycl::fmax(a.y,b.y), sycl::fmax(a.z,b.z)); + } + +/* +#if defined(__SSE4_1__) + __forceinline Vec3fa mini(const Vec3fa& a, const Vec3fa& b) { + const vint4 ai = _mm_castps_si128(a); + const vint4 bi = _mm_castps_si128(b); + const vint4 ci = _mm_min_epi32(ai,bi); + return _mm_castsi128_ps(ci); + } +#endif + +#if defined(__SSE4_1__) + __forceinline Vec3fa maxi(const Vec3fa& a, const Vec3fa& b) { + const vint4 ai = _mm_castps_si128(a); + const vint4 bi = _mm_castps_si128(b); + const vint4 ci = _mm_max_epi32(ai,bi); + return _mm_castsi128_ps(ci); + } +#endif +*/ + __forceinline Vec3fa pow ( const Vec3fa& a, const float& b ) { + return Vec3fa(powf(a.x,b),powf(a.y,b),powf(a.z,b)); + } + + //////////////////////////////////////////////////////////////////////////////// + /// Ternary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fa madd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return Vec3fa(madd(a.x,b.x,c.x), madd(a.y,b.y,c.y), madd(a.z,b.z,c.z)); } + __forceinline Vec3fa msub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return Vec3fa(msub(a.x,b.x,c.x), msub(a.y,b.y,c.y), msub(a.z,b.z,c.z)); } + __forceinline Vec3fa nmadd ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return Vec3fa(nmadd(a.x,b.x,c.x), nmadd(a.y,b.y,c.y), nmadd(a.z,b.z,c.z)); } + __forceinline Vec3fa nmsub ( const Vec3fa& a, const Vec3fa& b, const Vec3fa& c) { return Vec3fa(nmsub(a.x,b.x,c.x), nmsub(a.y,b.y,c.y), nmsub(a.z,b.z,c.z)); } + + __forceinline Vec3fa madd ( const float a, const Vec3fa& b, const Vec3fa& c) { return madd(Vec3fa(a),b,c); } + __forceinline Vec3fa msub ( const float a, const Vec3fa& b, const Vec3fa& c) { return msub(Vec3fa(a),b,c); } + __forceinline Vec3fa nmadd ( const float a, const Vec3fa& b, const Vec3fa& c) { return nmadd(Vec3fa(a),b,c); } + __forceinline Vec3fa nmsub ( const float a, const Vec3fa& b, const Vec3fa& c) { return nmsub(Vec3fa(a),b,c); } + + //////////////////////////////////////////////////////////////////////////////// + /// Assignment Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fa& operator +=( Vec3fa& a, const Vec3fa& b ) { return a = a + b; } + __forceinline Vec3fa& operator -=( Vec3fa& a, const Vec3fa& b ) { return a = a - b; } + __forceinline Vec3fa& operator *=( Vec3fa& a, const Vec3fa& b ) { return a = a * b; } + __forceinline Vec3fa& operator *=( Vec3fa& a, const float b ) { return a = a * b; } + __forceinline Vec3fa& operator /=( Vec3fa& a, const Vec3fa& b ) { return a = a / b; } + __forceinline Vec3fa& operator /=( Vec3fa& a, const float b ) { return a = a / b; } + + //////////////////////////////////////////////////////////////////////////////// + /// Reductions + //////////////////////////////////////////////////////////////////////////////// + + __forceinline float reduce_add(const Vec3fa& v) { return v.x+v.y+v.z; } + __forceinline float reduce_mul(const Vec3fa& v) { return v.x*v.y*v.z; } + __forceinline float reduce_min(const Vec3fa& v) { return sycl::fmin(sycl::fmin(v.x,v.y),v.z); } + __forceinline float reduce_max(const Vec3fa& v) { return sycl::fmax(sycl::fmax(v.x,v.y),v.z); } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline bool operator ==( const Vec3fa& a, const Vec3fa& b ) { return a.x == b.x && a.y == b.y && a.z == b.z; } + __forceinline bool operator !=( const Vec3fa& a, const Vec3fa& b ) { return a.x != b.x || a.y != b.y || a.z != b.z; } + + __forceinline Vec3ba eq_mask( const Vec3fa& a, const Vec3fa& b ) { return Vec3ba(a.x == b.x, a.y == b.y, a.z == b.z); } + __forceinline Vec3ba neq_mask(const Vec3fa& a, const Vec3fa& b ) { return Vec3ba(a.x != b.x, a.y != b.y, a.z != b.z); } + __forceinline Vec3ba lt_mask( const Vec3fa& a, const Vec3fa& b ) { return Vec3ba(a.x < b.x, a.y < b.y, a.z < b.z); } + __forceinline Vec3ba le_mask( const Vec3fa& a, const Vec3fa& b ) { return Vec3ba(a.x <= b.x, a.y <= b.y, a.z <= b.z); } + __forceinline Vec3ba gt_mask( const Vec3fa& a, const Vec3fa& b ) { return Vec3ba(a.x > b.x, a.y > b.y, a.z > b.z); } + __forceinline Vec3ba ge_mask( const Vec3fa& a, const Vec3fa& b ) { return Vec3ba(a.x >= b.x, a.y >= b.y, a.z >= b.z); } + + __forceinline bool isvalid ( const Vec3fa& v ) { + return all(gt_mask(v,Vec3fa(-FLT_LARGE)) & lt_mask(v,Vec3fa(+FLT_LARGE))); + } + + __forceinline bool is_finite ( const Vec3fa& a ) { + return all(ge_mask(a,Vec3fa(-FLT_MAX)) & le_mask(a,Vec3fa(+FLT_MAX))); + } + + //////////////////////////////////////////////////////////////////////////////// + /// Euclidian Space Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline float dot ( const Vec3fa& a, const Vec3fa& b ) { + return reduce_add(a*b); + } + + __forceinline Vec3fa cross ( const Vec3fa& a, const Vec3fa& b ) { + return Vec3fa(msub(a.y,b.z,a.z*b.y), msub(a.z,b.x,a.x*b.z), msub(a.x,b.y,a.y*b.x)); + } + + __forceinline float sqr_length ( const Vec3fa& a ) { return dot(a,a); } + __forceinline float rcp_length ( const Vec3fa& a ) { return rsqrt(dot(a,a)); } + __forceinline float rcp_length2( const Vec3fa& a ) { return rcp(dot(a,a)); } + __forceinline float length ( const Vec3fa& a ) { return sqrt(dot(a,a)); } + __forceinline Vec3fa normalize( const Vec3fa& a ) { return a*rsqrt(dot(a,a)); } + __forceinline float distance ( const Vec3fa& a, const Vec3fa& b ) { return length(a-b); } + __forceinline float halfArea ( const Vec3fa& d ) { return madd(d.x,(d.y+d.z),d.y*d.z); } + __forceinline float area ( const Vec3fa& d ) { return 2.0f*halfArea(d); } + + __forceinline Vec3fa normalize_safe( const Vec3fa& a ) { + const float d = dot(a,a); if (unlikely(d == 0.0f)) return a; else return a*rsqrt(d); + } + + /*! differentiated normalization */ + __forceinline Vec3fa dnormalize(const Vec3fa& p, const Vec3fa& dp) + { + const float pp = dot(p,p); + const float pdp = dot(p,dp); + return (pp*dp-pdp*p)*rcp(pp)*rsqrt(pp); + } + + //////////////////////////////////////////////////////////////////////////////// + /// Select + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fa select( bool s, const Vec3fa& t, const Vec3fa& f ) { + return Vec3fa(s ? t.x : f.x, s ? t.y : f.y, s ? t.z : f.z); + } + + __forceinline Vec3fa select( const Vec3ba& s, const Vec3fa& t, const Vec3fa& f ) { + return Vec3fa(s.x ? t.x : f.x, s.y ? t.y : f.y, s.z ? t.z : f.z); + } + + __forceinline Vec3fa lerp(const Vec3fa& v0, const Vec3fa& v1, const float t) { + return madd(1.0f-t,v0,t*v1); + } + + __forceinline int maxDim ( const Vec3fa& a ) + { + const Vec3fa b = abs(a); + if (b.x > b.y) { + if (b.x > b.z) return 0; else return 2; + } else { + if (b.y > b.z) return 1; else return 2; + } + } + + //////////////////////////////////////////////////////////////////////////////// + /// Rounding Functions + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fa trunc( const Vec3fa& a ) { return Vec3fa(sycl::trunc(a.x),sycl::trunc(a.y),sycl::trunc(a.z)); } + __forceinline Vec3fa floor( const Vec3fa& a ) { return Vec3fa(sycl::floor(a.x),sycl::floor(a.y),sycl::floor(a.z)); } + __forceinline Vec3fa ceil ( const Vec3fa& a ) { return Vec3fa(sycl::ceil (a.x),sycl::ceil (a.y),sycl::ceil (a.z)); } + + //////////////////////////////////////////////////////////////////////////////// + /// Output Operators + //////////////////////////////////////////////////////////////////////////////// + + inline embree_ostream operator<<(embree_ostream cout, const Vec3fa& a) { + return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")"; + } + + __forceinline Vec2fa::Vec2fa(const Vec3fa& a) + : x(a.x), y(a.y) {} + + __forceinline Vec3ia::Vec3ia( const Vec3fa& a ) + : x((int)a.x), y((int)a.y), z((int)a.z) {} + + typedef Vec3fa Vec3fa_t; + + + + //////////////////////////////////////////////////////////////////////////////// + /// SSE Vec3fx Type + //////////////////////////////////////////////////////////////////////////////// + + struct __aligned(16) Vec3fx + { + //ALIGNED_STRUCT_(16); + + typedef float Scalar; + enum { N = 3 }; + struct { float x,y,z; union { int a; unsigned u; float w; }; }; + + //////////////////////////////////////////////////////////////////////////////// + /// Constructors, Assignment & Cast Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fx( ) {} + //__forceinline Vec3fx( const __m128 a ) : m128(a) {} + __forceinline explicit Vec3fx(const vfloat4& a) : x(a[0]), y(a[1]), z(a[2]), w(a[3]) {} + + __forceinline explicit Vec3fx(const Vec3fa& v) : x(v.x), y(v.y), z(v.z), w(0.0f) {} + __forceinline operator Vec3fa() const { return Vec3fa(x,y,z); } + + __forceinline explicit Vec3fx ( const Vec3<float>& other ) { x = other.x; y = other.y; z = other.z; } + //__forceinline Vec3fx& operator =( const Vec3<float>& other ) { x = other.x; y = other.y; z = other.z; return *this; } + + //__forceinline Vec3fx ( const Vec3fx& other ) { *(sycl::float4*)this = *(const sycl::float4*)&other; } + //__forceinline Vec3fx& operator =( const Vec3fx& other ) { *(sycl::float4*)this = *(const sycl::float4*)&other; return *this; } + + __forceinline explicit Vec3fx( const float a ) : x(a), y(a), z(a), w(a) {} + __forceinline Vec3fx( const float x, const float y, const float z) : x(x), y(y), z(z), w(z) {} + + __forceinline Vec3fx( const Vec3fa& other, const int a1) : x(other.x), y(other.y), z(other.z), a(a1) {} + __forceinline Vec3fx( const Vec3fa& other, const unsigned a1) : x(other.x), y(other.y), z(other.z), u(a1) {} + __forceinline Vec3fx( const Vec3fa& other, const float w1) : x(other.x), y(other.y), z(other.z), w(w1) {} + + //__forceinline Vec3fx( const float x, const float y, const float z, const int a) : x(x), y(y), z(z), a(a) {} // not working properly! + //__forceinline Vec3fx( const float x, const float y, const float z, const unsigned a) : x(x), y(y), z(z), u(a) {} // not working properly! + __forceinline Vec3fx( const float x, const float y, const float z, const float w) : x(x), y(y), z(z), w(w) {} + + __forceinline explicit Vec3fx( const Vec3ia& a ) : x((float)a.x), y((float)a.y), z((float)a.z), w(0.0f) {} + + //__forceinline operator const __m128&() const { return m128; } + //__forceinline operator __m128&() { return m128; } + __forceinline operator vfloat4() const { return vfloat4(x,y,z,w); } + + //friend __forceinline Vec3fx copy_a( const Vec3fx& a, const Vec3fx& b ) { Vec3fx c = a; c.a = b.a; return c; } + + //////////////////////////////////////////////////////////////////////////////// + /// Loads and Stores + //////////////////////////////////////////////////////////////////////////////// + + static __forceinline Vec3fx load( const void* const a ) { + const float* ptr = (const float*)a; + return Vec3fx(ptr[0],ptr[1],ptr[2],ptr[3]); + } + + static __forceinline Vec3fx loadu( const void* const a ) { + const float* ptr = (const float*)a; + return Vec3fx(ptr[0],ptr[1],ptr[2],ptr[3]); + } + + static __forceinline void storeu ( void* a, const Vec3fx& v ) { + float* ptr = (float*)a; + ptr[0] = v.x; ptr[1] = v.y; ptr[2] = v.z; ptr[3] = v.w; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fx( ZeroTy ) : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {} + __forceinline Vec3fx( OneTy ) : x(1.0f), y(1.0f), z(1.0f), w(1.0f) {} + __forceinline Vec3fx( PosInfTy ) : x(+INFINITY), y(+INFINITY), z(+INFINITY), w(+INFINITY) {} + __forceinline Vec3fx( NegInfTy ) : x(-INFINITY), y(-INFINITY), z(-INFINITY), w(-INFINITY) {} + + //////////////////////////////////////////////////////////////////////////////// + /// Array Access + //////////////////////////////////////////////////////////////////////////////// + + __forceinline const float& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; } + __forceinline float& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fx operator +( const Vec3fx& a ) { return a; } + __forceinline Vec3fx operator -( const Vec3fx& a ) { return Vec3fx(-a.x,-a.y,-a.z,-a.w); } + __forceinline Vec3fx abs ( const Vec3fx& a ) { return Vec3fx(sycl::fabs(a.x),sycl::fabs(a.y),sycl::fabs(a.z),sycl::fabs(a.w)); } + __forceinline Vec3fx sign ( const Vec3fx& a ) { return Vec3fx(sycl::sign(a.x),sycl::sign(a.y),sycl::sign(a.z),sycl::sign(a.z)); } + + //__forceinline Vec3fx rcp ( const Vec3fx& a ) { return Vec3fx(sycl::recip(a.x),sycl::recip(a.y),sycl::recip(a.z)); } + __forceinline Vec3fx rcp ( const Vec3fx& a ) { return Vec3fx(__sycl_std::__invoke_native_recip<float>(a.x),__sycl_std::__invoke_native_recip<float>(a.y),__sycl_std::__invoke_native_recip<float>(a.z),__sycl_std::__invoke_native_recip<float>(a.w)); } + __forceinline Vec3fx sqrt ( const Vec3fx& a ) { return Vec3fx(sycl::sqrt(a.x),sycl::sqrt(a.y),sycl::sqrt(a.z),sycl::sqrt(a.w)); } + __forceinline Vec3fx sqr ( const Vec3fx& a ) { return Vec3fx(a.x*a.x,a.y*a.y,a.z*a.z,a.w*a.w); } + + __forceinline Vec3fx rsqrt( const Vec3fx& a ) { return Vec3fx(sycl::rsqrt(a.x),sycl::rsqrt(a.y),sycl::rsqrt(a.z),sycl::rsqrt(a.w)); } + + __forceinline Vec3fx zero_fix(const Vec3fx& a) { + const float x = sycl::fabs(a.x) < min_rcp_input ? min_rcp_input : a.x; + const float y = sycl::fabs(a.y) < min_rcp_input ? min_rcp_input : a.y; + const float z = sycl::fabs(a.z) < min_rcp_input ? min_rcp_input : a.z; + return Vec3fx(x,y,z); + } + __forceinline Vec3fx rcp_safe(const Vec3fx& a) { + return rcp(zero_fix(a)); + } + __forceinline Vec3fx log ( const Vec3fx& a ) { + return Vec3fx(sycl::log(a.x),sycl::log(a.y),sycl::log(a.z)); + } + + __forceinline Vec3fx exp ( const Vec3fx& a ) { + return Vec3fx(sycl::exp(a.x),sycl::exp(a.y),sycl::exp(a.z)); + } + + //////////////////////////////////////////////////////////////////////////////// + /// Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fx operator +( const Vec3fx& a, const Vec3fx& b ) { return Vec3fx(a.x+b.x, a.y+b.y, a.z+b.z, a.w+b.w); } + __forceinline Vec3fx operator -( const Vec3fx& a, const Vec3fx& b ) { return Vec3fx(a.x-b.x, a.y-b.y, a.z-b.z, a.w-b.w); } + __forceinline Vec3fx operator *( const Vec3fx& a, const Vec3fx& b ) { return Vec3fx(a.x*b.x, a.y*b.y, a.z*b.z, a.w*b.w); } + __forceinline Vec3fx operator *( const Vec3fx& a, const float b ) { return a * Vec3fx(b); } + __forceinline Vec3fx operator *( const float a, const Vec3fx& b ) { return Vec3fx(a) * b; } + __forceinline Vec3fx operator /( const Vec3fx& a, const Vec3fx& b ) { return Vec3fx(a.x/b.x, a.y/b.y, a.z/b.z, a.w/b.w); } + __forceinline Vec3fx operator /( const Vec3fx& a, const float b ) { return Vec3fx(a.x/b, a.y/b, a.z/b, a.w/b); } + __forceinline Vec3fx operator /( const float a, const Vec3fx& b ) { return Vec3fx(a/b.x, a/b.y, a/b.z, a/b.w); } + + __forceinline Vec3fx min( const Vec3fx& a, const Vec3fx& b ) { + return Vec3fx(sycl::fmin(a.x,b.x), sycl::fmin(a.y,b.y), sycl::fmin(a.z,b.z), sycl::fmin(a.w,b.w)); + } + __forceinline Vec3fx max( const Vec3fx& a, const Vec3fx& b ) { + return Vec3fx(sycl::fmax(a.x,b.x), sycl::fmax(a.y,b.y), sycl::fmax(a.z,b.z), sycl::fmax(a.w,b.w)); + } + +/* +#if defined(__SSE4_1__) + __forceinline Vec3fx mini(const Vec3fx& a, const Vec3fx& b) { + const vint4 ai = _mm_castps_si128(a); + const vint4 bi = _mm_castps_si128(b); + const vint4 ci = _mm_min_epi32(ai,bi); + return _mm_castsi128_ps(ci); + } +#endif + +#if defined(__SSE4_1__) + __forceinline Vec3fx maxi(const Vec3fx& a, const Vec3fx& b) { + const vint4 ai = _mm_castps_si128(a); + const vint4 bi = _mm_castps_si128(b); + const vint4 ci = _mm_max_epi32(ai,bi); + return _mm_castsi128_ps(ci); + } +#endif + + __forceinline Vec3fx pow ( const Vec3fx& a, const float& b ) { + return Vec3fx(powf(a.x,b),powf(a.y,b),powf(a.z,b)); + } +*/ + + //////////////////////////////////////////////////////////////////////////////// + /// Ternary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fx madd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return Vec3fx(madd(a.x,b.x,c.x), madd(a.y,b.y,c.y), madd(a.z,b.z,c.z), madd(a.w,b.w,c.w)); } + __forceinline Vec3fx msub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return Vec3fx(msub(a.x,b.x,c.x), msub(a.y,b.y,c.y), msub(a.z,b.z,c.z), msub(a.w,b.w,c.w)); } + __forceinline Vec3fx nmadd ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return Vec3fx(nmadd(a.x,b.x,c.x), nmadd(a.y,b.y,c.y), nmadd(a.z,b.z,c.z), nmadd(a.w,b.w,c.w)); } + __forceinline Vec3fx nmsub ( const Vec3fx& a, const Vec3fx& b, const Vec3fx& c) { return Vec3fx(nmsub(a.x,b.x,c.x), nmsub(a.y,b.y,c.y), nmsub(a.z,b.z,c.z), nmsub(a.w,b.w,c.w)); } + + __forceinline Vec3fx madd ( const float a, const Vec3fx& b, const Vec3fx& c) { return madd(Vec3fx(a),b,c); } + __forceinline Vec3fx msub ( const float a, const Vec3fx& b, const Vec3fx& c) { return msub(Vec3fx(a),b,c); } + __forceinline Vec3fx nmadd ( const float a, const Vec3fx& b, const Vec3fx& c) { return nmadd(Vec3fx(a),b,c); } + __forceinline Vec3fx nmsub ( const float a, const Vec3fx& b, const Vec3fx& c) { return nmsub(Vec3fx(a),b,c); } + + //////////////////////////////////////////////////////////////////////////////// + /// Assignment Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fx& operator +=( Vec3fx& a, const Vec3fx& b ) { return a = a + b; } + __forceinline Vec3fx& operator -=( Vec3fx& a, const Vec3fx& b ) { return a = a - b; } + __forceinline Vec3fx& operator *=( Vec3fx& a, const Vec3fx& b ) { return a = a * b; } + __forceinline Vec3fx& operator *=( Vec3fx& a, const float b ) { return a = a * b; } + __forceinline Vec3fx& operator /=( Vec3fx& a, const Vec3fx& b ) { return a = a / b; } + __forceinline Vec3fx& operator /=( Vec3fx& a, const float b ) { return a = a / b; } + + //////////////////////////////////////////////////////////////////////////////// + /// Reductions + //////////////////////////////////////////////////////////////////////////////// + + __forceinline float reduce_add(const Vec3fx& v) { return v.x+v.y+v.z; } + __forceinline float reduce_mul(const Vec3fx& v) { return v.x*v.y*v.z; } + __forceinline float reduce_min(const Vec3fx& v) { return sycl::fmin(sycl::fmin(v.x,v.y),v.z); } + __forceinline float reduce_max(const Vec3fx& v) { return sycl::fmax(sycl::fmax(v.x,v.y),v.z); } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline bool operator ==( const Vec3fx& a, const Vec3fx& b ) { return a.x == b.x && a.y == b.y && a.z == b.z; } + __forceinline bool operator !=( const Vec3fx& a, const Vec3fx& b ) { return a.x != b.x || a.y != b.y || a.z != b.z; } + + __forceinline Vec3ba eq_mask( const Vec3fx& a, const Vec3fx& b ) { return Vec3ba(a.x == b.x, a.y == b.y, a.z == b.z); } + __forceinline Vec3ba neq_mask(const Vec3fx& a, const Vec3fx& b ) { return Vec3ba(a.x != b.x, a.y != b.y, a.z != b.z); } + __forceinline Vec3ba lt_mask( const Vec3fx& a, const Vec3fx& b ) { return Vec3ba(a.x < b.x, a.y < b.y, a.z < b.z); } + __forceinline Vec3ba le_mask( const Vec3fx& a, const Vec3fx& b ) { return Vec3ba(a.x <= b.x, a.y <= b.y, a.z <= b.z); } + __forceinline Vec3ba gt_mask( const Vec3fx& a, const Vec3fx& b ) { return Vec3ba(a.x > b.x, a.y > b.y, a.z > b.z); } + __forceinline Vec3ba ge_mask( const Vec3fx& a, const Vec3fx& b ) { return Vec3ba(a.x >= b.x, a.y >= b.y, a.z >= b.z); } + + __forceinline bool isvalid ( const Vec3fx& v ) { + return all(gt_mask(v,Vec3fx(-FLT_LARGE)) & lt_mask(v,Vec3fx(+FLT_LARGE))); + } + + __forceinline bool is_finite ( const Vec3fx& a ) { + return all(ge_mask(a,Vec3fx(-FLT_MAX)) & le_mask(a,Vec3fx(+FLT_MAX))); + } + + __forceinline bool isvalid4 ( const Vec3fx& v ) { + const bool valid_x = v.x >= -FLT_LARGE & v.x <= +FLT_LARGE; + const bool valid_y = v.y >= -FLT_LARGE & v.y <= +FLT_LARGE; + const bool valid_z = v.z >= -FLT_LARGE & v.z <= +FLT_LARGE; + const bool valid_w = v.w >= -FLT_LARGE & v.w <= +FLT_LARGE; + return valid_x & valid_y & valid_z & valid_w; + } + + __forceinline bool is_finite4 ( const Vec3fx& v ) { + const bool finite_x = v.x >= -FLT_MAX & v.x <= +FLT_MAX; + const bool finite_y = v.y >= -FLT_MAX & v.y <= +FLT_MAX; + const bool finite_z = v.z >= -FLT_MAX & v.z <= +FLT_MAX; + const bool finite_w = v.w >= -FLT_MAX & v.w <= +FLT_MAX; + return finite_x & finite_y & finite_z & finite_w; + } + + //////////////////////////////////////////////////////////////////////////////// + /// Euclidian Space Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline float dot ( const Vec3fx& a, const Vec3fx& b ) { + return reduce_add(a*b); + } + + __forceinline Vec3fx cross ( const Vec3fx& a, const Vec3fx& b ) { + return Vec3fx(msub(a.y,b.z,a.z*b.y), msub(a.z,b.x,a.x*b.z), msub(a.x,b.y,a.y*b.x)); + } + + __forceinline float sqr_length ( const Vec3fx& a ) { return dot(a,a); } + __forceinline float rcp_length ( const Vec3fx& a ) { return rsqrt(dot(a,a)); } + __forceinline float rcp_length2( const Vec3fx& a ) { return rcp(dot(a,a)); } + __forceinline float length ( const Vec3fx& a ) { return sqrt(dot(a,a)); } + __forceinline Vec3fx normalize( const Vec3fx& a ) { return a*rsqrt(dot(a,a)); } + __forceinline float distance ( const Vec3fx& a, const Vec3fx& b ) { return length(a-b); } + __forceinline float halfArea ( const Vec3fx& d ) { return madd(d.x,(d.y+d.z),d.y*d.z); } + __forceinline float area ( const Vec3fx& d ) { return 2.0f*halfArea(d); } + + __forceinline Vec3fx normalize_safe( const Vec3fx& a ) { + const float d = dot(a,a); if (unlikely(d == 0.0f)) return a; else return a*rsqrt(d); + } + + /*! differentiated normalization */ + __forceinline Vec3fx dnormalize(const Vec3fx& p, const Vec3fx& dp) + { + const float pp = dot(p,p); + const float pdp = dot(p,dp); + return (pp*dp-pdp*p)*rcp(pp)*rsqrt(pp); + } + + //////////////////////////////////////////////////////////////////////////////// + /// Select + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fx select( bool s, const Vec3fx& t, const Vec3fx& f ) { + return Vec3fx(s ? t.x : f.x, s ? t.y : f.y, s ? t.z : f.z, s ? t.w : f.w); + } + + __forceinline Vec3fx select( const Vec3ba& s, const Vec3fx& t, const Vec3fx& f ) { + return Vec3fx(s.x ? t.x : f.x, s.y ? t.y : f.y, s.z ? t.z : f.z); + } + + __forceinline Vec3fx lerp(const Vec3fx& v0, const Vec3fx& v1, const float t) { + return madd(1.0f-t,v0,t*v1); + } + + __forceinline int maxDim ( const Vec3fx& a ) + { + const Vec3fx b = abs(a); + if (b.x > b.y) { + if (b.x > b.z) return 0; else return 2; + } else { + if (b.y > b.z) return 1; else return 2; + } + } + + //////////////////////////////////////////////////////////////////////////////// + /// Rounding Functions + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3fx trunc( const Vec3fx& a ) { return Vec3fx(sycl::trunc(a.x),sycl::trunc(a.y),sycl::trunc(a.z),sycl::trunc(a.w)); } + __forceinline Vec3fx floor( const Vec3fx& a ) { return Vec3fx(sycl::floor(a.x),sycl::floor(a.y),sycl::floor(a.z),sycl::floor(a.w)); } + __forceinline Vec3fx ceil ( const Vec3fx& a ) { return Vec3fx(sycl::ceil (a.x),sycl::ceil (a.y),sycl::ceil (a.z),sycl::ceil (a.w)); } + + //////////////////////////////////////////////////////////////////////////////// + /// Output Operators + //////////////////////////////////////////////////////////////////////////////// + + inline embree_ostream operator<<(embree_ostream cout, const Vec3fx& a) { + return cout << "(" << a.x << ", " << a.y << ", " << a.z << "," << a.w << ")"; + } + + typedef Vec3fx Vec3ff; + + //__forceinline Vec2fa::Vec2fa(const Vec3fx& a) + // : x(a.x), y(a.y) {} + + //__forceinline Vec3ia::Vec3ia( const Vec3fx& a ) + // : x((int)a.x), y((int)a.y), z((int)a.z) {} +} diff --git a/thirdparty/embree/common/math/vec3ia.h b/thirdparty/embree/common/math/vec3ia.h index d4cc3125cd..1472fe9135 100644 --- a/thirdparty/embree/common/math/vec3ia.h +++ b/thirdparty/embree/common/math/vec3ia.h @@ -4,7 +4,12 @@ #pragma once #include "../sys/alloc.h" -#include "math.h" +#include "emath.h" + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) +# include "vec3ia_sycl.h" +#else + #include "../simd/sse.h" namespace embree @@ -194,3 +199,5 @@ namespace embree return cout << "(" << a.x << ", " << a.y << ", " << a.z << ")"; } } + +#endif diff --git a/thirdparty/embree/common/math/vec3ia_sycl.h b/thirdparty/embree/common/math/vec3ia_sycl.h new file mode 100644 index 0000000000..5a3d396373 --- /dev/null +++ b/thirdparty/embree/common/math/vec3ia_sycl.h @@ -0,0 +1,178 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../sys/alloc.h" +#include "emath.h" +#include "../simd/sse.h" + +namespace embree +{ + //////////////////////////////////////////////////////////////////////////////// + /// SSE Vec3ia Type + //////////////////////////////////////////////////////////////////////////////// + + struct __aligned(16) Vec3ia + { + ALIGNED_STRUCT_(16); + + struct { int x,y,z; }; + + typedef int Scalar; + enum { N = 3 }; + + //////////////////////////////////////////////////////////////////////////////// + /// Constructors, Assignment & Cast Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ia( ) {} + //__forceinline Vec3ia( const __m128i a ) : m128(a) {} + + __forceinline Vec3ia( const Vec3ia& other ) : x(other.x), y(other.y), z(other.z) {} + __forceinline Vec3ia& operator =(const Vec3ia& other) { x = other.x; y = other.y; z = other.z; return *this; } + + __forceinline explicit Vec3ia( const int a ) : x(a), y(a), z(a) {} + __forceinline Vec3ia( const int x, const int y, const int z) : x(x), y(y), z(z) {} + //__forceinline explicit Vec3ia( const __m128 a ) : m128(_mm_cvtps_epi32(a)) {} + __forceinline explicit Vec3ia(const vint4& a) : x(a[0]), y(a[1]), z(a[2]) {} + + __forceinline explicit Vec3ia( const Vec3fa& a ); + + //__forceinline operator const __m128i&() const { return m128; } + //__forceinline operator __m128i&() { return m128; } + __forceinline operator vint4() const { return vint4(x,y,z,z); } + + //////////////////////////////////////////////////////////////////////////////// + /// Constants + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ia( ZeroTy ) : x(0), y(0), z(0) {} + __forceinline Vec3ia( OneTy ) : x(1), y(1), z(1) {} + __forceinline Vec3ia( PosInfTy ) : x(0x7FFFFFFF), y(0x7FFFFFFF), z(0x7FFFFFFF) {} + __forceinline Vec3ia( NegInfTy ) : x(0x80000000), y(0x80000000), z(0x80000000) {} + + //////////////////////////////////////////////////////////////////////////////// + /// Array Access + //////////////////////////////////////////////////////////////////////////////// + + __forceinline const int& operator []( const size_t index ) const { assert(index < 3); return (&x)[index]; } + __forceinline int& operator []( const size_t index ) { assert(index < 3); return (&x)[index]; } + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// Unary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ia operator +( const Vec3ia& a ) { return Vec3ia(+a.x,+a.y,+a.z); } + __forceinline Vec3ia operator -( const Vec3ia& a ) { return Vec3ia(-a.x,-a.y,-a.z); } + __forceinline Vec3ia abs ( const Vec3ia& a ) { return Vec3ia(sycl::abs(a.x),sycl::abs(a.y),sycl::abs(a.z)); } + + //////////////////////////////////////////////////////////////////////////////// + /// Binary Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ia operator +( const Vec3ia& a, const Vec3ia& b ) { return Vec3ia(a.x+b.x, a.y+b.y, a.z+b.z); } + __forceinline Vec3ia operator +( const Vec3ia& a, const int b ) { return a+Vec3ia(b); } + __forceinline Vec3ia operator +( const int a, const Vec3ia& b ) { return Vec3ia(a)+b; } + + __forceinline Vec3ia operator -( const Vec3ia& a, const Vec3ia& b ) { return Vec3ia(a.x-b.x, a.y-b.y, a.z-b.z); } + __forceinline Vec3ia operator -( const Vec3ia& a, const int b ) { return a-Vec3ia(b); } + __forceinline Vec3ia operator -( const int a, const Vec3ia& b ) { return Vec3ia(a)-b; } + + __forceinline Vec3ia operator *( const Vec3ia& a, const Vec3ia& b ) { return Vec3ia(a.x*b.x, a.y*b.y, a.z*b.z); } + __forceinline Vec3ia operator *( const Vec3ia& a, const int b ) { return a * Vec3ia(b); } + __forceinline Vec3ia operator *( const int a, const Vec3ia& b ) { return Vec3ia(a) * b; } + + __forceinline Vec3ia operator &( const Vec3ia& a, const Vec3ia& b ) { return Vec3ia(a.x&b.x, a.y&b.y, a.z&b.z); } + __forceinline Vec3ia operator &( const Vec3ia& a, const int b ) { return a & Vec3ia(b); } + __forceinline Vec3ia operator &( const int a, const Vec3ia& b ) { return Vec3ia(a) & b; } + + __forceinline Vec3ia operator |( const Vec3ia& a, const Vec3ia& b ) { return Vec3ia(a.x|b.x, a.y|b.y, a.z|b.z); } + __forceinline Vec3ia operator |( const Vec3ia& a, const int b ) { return a | Vec3ia(b); } + __forceinline Vec3ia operator |( const int a, const Vec3ia& b ) { return Vec3ia(a) | b; } + + __forceinline Vec3ia operator ^( const Vec3ia& a, const Vec3ia& b ) { return Vec3ia(a.x^b.x, a.y^b.y, a.z^b.z); } + __forceinline Vec3ia operator ^( const Vec3ia& a, const int b ) { return a ^ Vec3ia(b); } + __forceinline Vec3ia operator ^( const int a, const Vec3ia& b ) { return Vec3ia(a) ^ b; } + + __forceinline Vec3ia operator <<( const Vec3ia& a, const int n ) { return Vec3ia(a.x<<n, a.y<<n, a.z<<n); } + __forceinline Vec3ia operator >>( const Vec3ia& a, const int n ) { return Vec3ia(a.x>>n, a.y>>n, a.z>>n); } + + __forceinline Vec3ia sll ( const Vec3ia& a, const int b ) { return Vec3ia(a.x<<b, a.y<<b, a.z<<b); } + __forceinline Vec3ia sra ( const Vec3ia& a, const int b ) { return Vec3ia(a.x>>b, a.y>>b, a.z>>b); } + __forceinline Vec3ia srl ( const Vec3ia& a, const int b ) { return Vec3ia(unsigned(a.x)>>b, unsigned(a.y)>>b, unsigned(a.z)>>b); } + + //////////////////////////////////////////////////////////////////////////////// + /// Assignment Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ia& operator +=( Vec3ia& a, const Vec3ia& b ) { return a = a + b; } + __forceinline Vec3ia& operator +=( Vec3ia& a, const int& b ) { return a = a + b; } + + __forceinline Vec3ia& operator -=( Vec3ia& a, const Vec3ia& b ) { return a = a - b; } + __forceinline Vec3ia& operator -=( Vec3ia& a, const int& b ) { return a = a - b; } + + __forceinline Vec3ia& operator *=( Vec3ia& a, const Vec3ia& b ) { return a = a * b; } + __forceinline Vec3ia& operator *=( Vec3ia& a, const int& b ) { return a = a * b; } + + __forceinline Vec3ia& operator &=( Vec3ia& a, const Vec3ia& b ) { return a = a & b; } + __forceinline Vec3ia& operator &=( Vec3ia& a, const int& b ) { return a = a & b; } + + __forceinline Vec3ia& operator |=( Vec3ia& a, const Vec3ia& b ) { return a = a | b; } + __forceinline Vec3ia& operator |=( Vec3ia& a, const int& b ) { return a = a | b; } + + __forceinline Vec3ia& operator <<=( Vec3ia& a, const int& b ) { return a = a << b; } + __forceinline Vec3ia& operator >>=( Vec3ia& a, const int& b ) { return a = a >> b; } + + //////////////////////////////////////////////////////////////////////////////// + /// Reductions + //////////////////////////////////////////////////////////////////////////////// + + __forceinline int reduce_add(const Vec3ia& v) { return v.x+v.y+v.z; } + __forceinline int reduce_mul(const Vec3ia& v) { return v.x*v.y*v.z; } + __forceinline int reduce_min(const Vec3ia& v) { return sycl::min(sycl::min(v.x,v.y),v.z); } + __forceinline int reduce_max(const Vec3ia& v) { return sycl::max(sycl::max(v.x,v.y),v.z); } + + //////////////////////////////////////////////////////////////////////////////// + /// Comparison Operators + //////////////////////////////////////////////////////////////////////////////// + + __forceinline bool operator ==( const Vec3ia& a, const Vec3ia& b ) { return a.x == b.x & a.y == b.y & a.z == b.z; } + __forceinline bool operator !=( const Vec3ia& a, const Vec3ia& b ) { return a.x != b.x & a.y != b.y & a.z != b.z; } + +/* + __forceinline bool operator < ( const Vec3ia& a, const Vec3ia& b ) { + if (a.x != b.x) return a.x < b.x; + if (a.y != b.y) return a.y < b.y; + if (a.z != b.z) return a.z < b.z; + return false; + } +*/ + __forceinline Vec3ba eq_mask( const Vec3ia& a, const Vec3ia& b ) { return Vec3ba(a.x == b.x, a.y == b.y, a.z == b.z); } + __forceinline Vec3ba lt_mask( const Vec3ia& a, const Vec3ia& b ) { return Vec3ba(a.x < b.x, a.y < b.y, a.z < b.z); } + __forceinline Vec3ba gt_mask( const Vec3ia& a, const Vec3ia& b ) { return Vec3ba(a.x > b.x, a.y > b.y, a.z > b.z); } + + //////////////////////////////////////////////////////////////////////////////// + /// Select + //////////////////////////////////////////////////////////////////////////////// + + __forceinline Vec3ia select( const Vec3ba& m, const Vec3ia& t, const Vec3ia& f ) { + const int x = m.x ? t.x : f.x; + const int y = m.y ? t.y : f.y; + const int z = m.z ? t.z : f.z; + return Vec3ia(x,y,z); + } + + __forceinline Vec3ia min( const Vec3ia& a, const Vec3ia& b ) { return Vec3ia(sycl::min(a.x,b.x), sycl::min(a.y,b.y), sycl::min(a.z,b.z)); } + __forceinline Vec3ia max( const Vec3ia& a, const Vec3ia& b ) { return Vec3ia(sycl::max(a.x,b.x), sycl::max(a.y,b.y), sycl::max(a.z,b.z)); } + + //////////////////////////////////////////////////////////////////////////////// + /// Output Operators + //////////////////////////////////////////////////////////////////////////////// + + inline embree_ostream operator<<(embree_ostream cout, const Vec3ia& a) { + return cout; + } +} diff --git a/thirdparty/embree/common/math/vec4.h b/thirdparty/embree/common/math/vec4.h index 10c53f47b4..5647859257 100644 --- a/thirdparty/embree/common/math/vec4.h +++ b/thirdparty/embree/common/math/vec4.h @@ -3,7 +3,7 @@ #pragma once -#include "math.h" +#include "emath.h" #include "vec3.h" namespace embree @@ -221,6 +221,8 @@ namespace embree { template<> __forceinline Vec4<float>::Vec4( const Vec3fx& a ) { x = a.x; y = a.y; z = a.z; w = a.w; } +#if !defined(__SYCL_DEVICE_ONLY__) + #if defined(__AVX__) template<> __forceinline Vec4<vfloat4>::Vec4( const Vec3fx& a ) { x = a.x; y = a.y; z = a.z; w = a.w; @@ -240,4 +242,25 @@ namespace embree #if defined(__AVX512F__) template<> __forceinline Vec4<vfloat16>::Vec4( const Vec3fx& a ) : x(a.x), y(a.y), z(a.z), w(a.w) {} #endif + +#else + +#if defined(__SSE__) + template<> __forceinline Vec4<vfloat4>::Vec4(const Vec3fx& a) { + x = a.x; y = a.y; z = a.z; w = a.w; + } +#endif +#if defined(__AVX__) + template<> __forceinline Vec4<vfloat8>::Vec4(const Vec3fx& a) { + x = a.x; y = a.y; z = a.z; w = a.w; + } +#endif +#if defined(__AVX512F__) + template<> __forceinline Vec4<vfloat16>::Vec4(const Vec3fx& a) { + x = a.x; y = a.y; z = a.z; w = a.w; + } +#endif + +#endif } + diff --git a/thirdparty/embree/common/simd/arm/emulation.h b/thirdparty/embree/common/simd/arm/emulation.h index 4327298019..8eea1ffe71 100644 --- a/thirdparty/embree/common/simd/arm/emulation.h +++ b/thirdparty/embree/common/simd/arm/emulation.h @@ -34,6 +34,7 @@ __forceinline __m128 _mm_broadcast_ss (float const * mem_addr) #define _MM_SET_EXCEPTION_MASK(x) // #define _MM_SET_FLUSH_ZERO_MODE(x) +/* __forceinline int _mm_getcsr() { return 0; @@ -43,6 +44,7 @@ __forceinline void _mm_mfence() { __sync_synchronize(); } +*/ __forceinline __m128i _mm_load4epu8_epi32(__m128i *ptr) { diff --git a/thirdparty/embree/common/simd/arm/sse2neon.h b/thirdparty/embree/common/simd/arm/sse2neon.h index 43416662d7..b18d41e783 100644 --- a/thirdparty/embree/common/simd/arm/sse2neon.h +++ b/thirdparty/embree/common/simd/arm/sse2neon.h @@ -4,8 +4,6 @@ // This header file provides a simple API translation layer // between SSE intrinsics to their corresponding Arm/Aarch64 NEON versions // -// This header file does not yet translate all of the SSE intrinsics. -// // Contributors to this work are: // John W. Ratcliff <jratcliffscarab@gmail.com> // Brandon Rowlett <browlett@nvidia.com> @@ -13,8 +11,8 @@ // Eric van Beurden <evanbeurden@nvidia.com> // Alexander Potylitsin <apotylitsin@nvidia.com> // Hasindu Gamaarachchi <hasindu2008@gmail.com> -// Jim Huang <jserv@biilabs.io> -// Mark Cheng <marktwtn@biilabs.io> +// Jim Huang <jserv@ccns.ncku.edu.tw> +// Mark Cheng <marktwtn@gmail.com> // Malcolm James MacLeod <malcolm@gulden.com> // Devin Hussey (easyaspi314) <husseydevin@gmail.com> // Sebastian Pop <spop@amazon.com> @@ -22,9 +20,12 @@ // Danila Kutenin <danilak@google.com> // François Turban (JishinMaster) <francois.turban@gmail.com> // Pei-Hsuan Hung <afcidk@gmail.com> -// Yang-Hao Yuan <yanghau@biilabs.io> +// Yang-Hao Yuan <yuanyanghau@gmail.com> // Syoyo Fujita <syoyo@lighttransport.com> // Brecht Van Lommel <brecht@blender.org> +// Jonathan Hue <jhue@adobe.com> +// Cuda Chen <clh960524@gmail.com> +// Aymen Qader <aymen.qader@arm.com> /* * sse2neon is freely redistributable under the MIT License. @@ -54,7 +55,7 @@ * This would slow down the computation a bit, but gives consistent result with * x86 SSE. (e.g. would solve a hole or NaN pixel in the rendering result) */ -/* _mm_min_ps and _mm_max_ps */ +/* _mm_min|max_ps|ss|pd|sd */ #ifndef SSE2NEON_PRECISE_MINMAX #define SSE2NEON_PRECISE_MINMAX (0) #endif @@ -91,9 +92,61 @@ #define _sse2neon_unlikely(x) (x) #endif +/* C language does not allow initializing a variable with a function call. */ +#ifdef __cplusplus +#define _sse2neon_const static const +#else +#define _sse2neon_const const +#endif + #include <stdint.h> #include <stdlib.h> +#if defined(_WIN32) +/* Definitions for _mm_{malloc,free} are provided by <malloc.h> + * from both MinGW-w64 and MSVC. + */ +#define SSE2NEON_ALLOC_DEFINED +#endif + +/* If using MSVC */ +#ifdef _MSC_VER +#include <intrin.h> +#if (defined(_M_AMD64) || defined(__x86_64__)) || \ + (defined(_M_ARM) || defined(__arm__)) +#define SSE2NEON_HAS_BITSCAN64 +#endif +#endif + +/* Compiler barrier */ +#define SSE2NEON_BARRIER() \ + do { \ + __asm__ __volatile__("" ::: "memory"); \ + (void) 0; \ + } while (0) + +/* Memory barriers + * __atomic_thread_fence does not include a compiler barrier; instead, + * the barrier is part of __atomic_load/__atomic_store's "volatile-like" + * semantics. + */ +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) +#include <stdatomic.h> +#endif + +FORCE_INLINE void _sse2neon_smp_mb(void) +{ + SSE2NEON_BARRIER(); +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ + !defined(__STDC_NO_ATOMICS__) + atomic_thread_fence(memory_order_seq_cst); +#elif defined(__GNUC__) || defined(__clang__) + __atomic_thread_fence(__ATOMIC_SEQ_CST); +#else + /* FIXME: MSVC support */ +#endif +} + /* Architecture-specific build options */ /* FIXME: #pragma GCC push_options is only available on GCC */ #if defined(__GNUC__) @@ -114,27 +167,70 @@ #pragma GCC push_options #pragma GCC target("+simd") #endif +#elif __ARM_ARCH == 8 +#if !defined(__ARM_NEON) || !defined(__ARM_NEON__) +#error \ + "You must enable NEON instructions (e.g. -mfpu=neon-fp-armv8) to use SSE2NEON." +#endif +#if !defined(__clang__) +#pragma GCC push_options +#endif #else #error "Unsupported target. Must be either ARMv7-A+NEON or ARMv8-A." #endif #endif #include <arm_neon.h> +#if !defined(__aarch64__) && (__ARM_ARCH == 8) +#if defined __has_include && __has_include(<arm_acle.h>) +#include <arm_acle.h> +#endif +#endif + +/* Apple Silicon cache lines are double of what is commonly used by Intel, AMD + * and other Arm microarchtectures use. + * From sysctl -a on Apple M1: + * hw.cachelinesize: 128 + */ +#if defined(__APPLE__) && (defined(__aarch64__) || defined(__arm64__)) +#define SSE2NEON_CACHELINE_SIZE 128 +#else +#define SSE2NEON_CACHELINE_SIZE 64 +#endif /* Rounding functions require either Aarch64 instructions or libm failback */ #if !defined(__aarch64__) #include <math.h> #endif +/* On ARMv7, some registers, such as PMUSERENR and PMCCNTR, are read-only + * or even not accessible in user mode. + * To write or access to these registers in user mode, + * we have to perform syscall instead. + */ +#if !defined(__aarch64__) +#include <sys/time.h> +#endif + /* "__has_builtin" can be used to query support for built-in functions * provided by gcc/clang and other compilers that support it. */ #ifndef __has_builtin /* GCC prior to 10 or non-clang compilers */ /* Compatibility with gcc <= 9 */ -#if __GNUC__ <= 9 +#if defined(__GNUC__) && (__GNUC__ <= 9) #define __has_builtin(x) HAS##x #define HAS__builtin_popcount 1 #define HAS__builtin_popcountll 1 + +// __builtin_shuffle introduced in GCC 4.7.0 +#if (__GNUC__ >= 5) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 7)) +#define HAS__builtin_shuffle 1 +#else +#define HAS__builtin_shuffle 0 +#endif + +#define HAS__builtin_shufflevector 0 +#define HAS__builtin_nontemporal_store 0 #else #define __has_builtin(x) 0 #endif @@ -159,6 +255,26 @@ #define _MM_SHUFFLE(fp3, fp2, fp1, fp0) \ (((fp3) << 6) | ((fp2) << 4) | ((fp1) << 2) | ((fp0))) +#if __has_builtin(__builtin_shufflevector) +#define _sse2neon_shuffle(type, a, b, ...) \ + __builtin_shufflevector(a, b, __VA_ARGS__) +#elif __has_builtin(__builtin_shuffle) +#define _sse2neon_shuffle(type, a, b, ...) \ + __extension__({ \ + type tmp = {__VA_ARGS__}; \ + __builtin_shuffle(a, b, tmp); \ + }) +#endif + +#ifdef _sse2neon_shuffle +#define vshuffle_s16(a, b, ...) _sse2neon_shuffle(int16x4_t, a, b, __VA_ARGS__) +#define vshuffleq_s16(a, b, ...) _sse2neon_shuffle(int16x8_t, a, b, __VA_ARGS__) +#define vshuffle_s32(a, b, ...) _sse2neon_shuffle(int32x2_t, a, b, __VA_ARGS__) +#define vshuffleq_s32(a, b, ...) _sse2neon_shuffle(int32x4_t, a, b, __VA_ARGS__) +#define vshuffle_s64(a, b, ...) _sse2neon_shuffle(int64x1_t, a, b, __VA_ARGS__) +#define vshuffleq_s64(a, b, ...) _sse2neon_shuffle(int64x2_t, a, b, __VA_ARGS__) +#endif + /* Rounding mode macros. */ #define _MM_FROUND_TO_NEAREST_INT 0x00 #define _MM_FROUND_TO_NEG_INF 0x01 @@ -166,6 +282,13 @@ #define _MM_FROUND_TO_ZERO 0x03 #define _MM_FROUND_CUR_DIRECTION 0x04 #define _MM_FROUND_NO_EXC 0x08 +#define _MM_FROUND_RAISE_EXC 0x00 +#define _MM_FROUND_NINT (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_FLOOR (_MM_FROUND_TO_NEG_INF | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_CEIL (_MM_FROUND_TO_POS_INF | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_TRUNC (_MM_FROUND_TO_ZERO | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_RINT (_MM_FROUND_CUR_DIRECTION | _MM_FROUND_RAISE_EXC) +#define _MM_FROUND_NEARBYINT (_MM_FROUND_CUR_DIRECTION | _MM_FROUND_NO_EXC) #define _MM_ROUND_NEAREST 0x0000 #define _MM_ROUND_DOWN 0x2000 #define _MM_ROUND_UP 0x4000 @@ -198,10 +321,17 @@ typedef float64x2_t __m128d; /* 128-bit vector containing 2 doubles */ #else typedef float32x4_t __m128d; #endif -// Note: upstream sse2neon declares __m128i as int64x2_t. However, there's -// many places within embree that assume __m128i can be indexed as a -// 4 element u32. -typedef int32x4_t __m128i; /* 128-bit vector containing integers */ +typedef int64x2_t __m128i; /* 128-bit vector containing integers */ + +// __int64 is defined in the Intrinsics Guide which maps to different datatype +// in different data model +#if !(defined(_WIN32) || defined(_WIN64) || defined(__int64)) +#if (defined(__x86_64__) || defined(__i386__)) +#define __int64 long long +#else +#define __int64 int64_t +#endif +#endif /* type-safe casting between types */ @@ -233,28 +363,28 @@ typedef int32x4_t __m128i; /* 128-bit vector containing integers */ #define vreinterpretq_s32_m128(x) vreinterpretq_s32_f32(x) #define vreinterpretq_s64_m128(x) vreinterpretq_s64_f32(x) -#define vreinterpretq_m128i_s8(x) vreinterpretq_s32_s8(x) -#define vreinterpretq_m128i_s16(x) vreinterpretq_s32_s16(x) -#define vreinterpretq_m128i_s32(x) (x) -#define vreinterpretq_m128i_s64(x) vreinterpretq_s32_s64(x) +#define vreinterpretq_m128i_s8(x) vreinterpretq_s64_s8(x) +#define vreinterpretq_m128i_s16(x) vreinterpretq_s64_s16(x) +#define vreinterpretq_m128i_s32(x) vreinterpretq_s64_s32(x) +#define vreinterpretq_m128i_s64(x) (x) -#define vreinterpretq_m128i_u8(x) vreinterpretq_s32_u8(x) -#define vreinterpretq_m128i_u16(x) vreinterpretq_s32_u16(x) -#define vreinterpretq_m128i_u32(x) vreinterpretq_s32_u32(x) -#define vreinterpretq_m128i_u64(x) vreinterpretq_s32_u64(x) +#define vreinterpretq_m128i_u8(x) vreinterpretq_s64_u8(x) +#define vreinterpretq_m128i_u16(x) vreinterpretq_s64_u16(x) +#define vreinterpretq_m128i_u32(x) vreinterpretq_s64_u32(x) +#define vreinterpretq_m128i_u64(x) vreinterpretq_s64_u64(x) -#define vreinterpretq_f32_m128i(x) vreinterpretq_f32_s32(x) -#define vreinterpretq_f64_m128i(x) vreinterpretq_f64_s32(x) +#define vreinterpretq_f32_m128i(x) vreinterpretq_f32_s64(x) +#define vreinterpretq_f64_m128i(x) vreinterpretq_f64_s64(x) -#define vreinterpretq_s8_m128i(x) vreinterpretq_s8_s32(x) -#define vreinterpretq_s16_m128i(x) vreinterpretq_s16_s32(x) -#define vreinterpretq_s32_m128i(x) (x) -#define vreinterpretq_s64_m128i(x) vreinterpretq_s64_s32(x) +#define vreinterpretq_s8_m128i(x) vreinterpretq_s8_s64(x) +#define vreinterpretq_s16_m128i(x) vreinterpretq_s16_s64(x) +#define vreinterpretq_s32_m128i(x) vreinterpretq_s32_s64(x) +#define vreinterpretq_s64_m128i(x) (x) -#define vreinterpretq_u8_m128i(x) vreinterpretq_u8_s32(x) -#define vreinterpretq_u16_m128i(x) vreinterpretq_u16_s32(x) -#define vreinterpretq_u32_m128i(x) vreinterpretq_u32_s32(x) -#define vreinterpretq_u64_m128i(x) vreinterpretq_u64_s32(x) +#define vreinterpretq_u8_m128i(x) vreinterpretq_u8_s64(x) +#define vreinterpretq_u16_m128i(x) vreinterpretq_u16_s64(x) +#define vreinterpretq_u32_m128i(x) vreinterpretq_u32_s64(x) +#define vreinterpretq_u64_m128i(x) vreinterpretq_u64_s64(x) #define vreinterpret_m64_s8(x) vreinterpret_s64_s8(x) #define vreinterpret_m64_s16(x) vreinterpret_s64_s16(x) @@ -394,7 +524,7 @@ FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t, uint8_t); // Older gcc does not define vld1q_u8_x4 type #if defined(__GNUC__) && !defined(__clang__) && \ - ((__GNUC__ <= 10 && defined(__arm__)) || \ + ((__GNUC__ <= 12 && defined(__arm__)) || \ (__GNUC__ == 10 && __GNUC_MINOR__ < 3 && defined(__aarch64__)) || \ (__GNUC__ <= 9 && defined(__aarch64__))) FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p) @@ -414,6 +544,57 @@ FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p) } #endif +#if !defined(__aarch64__) +/* emulate vaddv u8 variant */ +FORCE_INLINE uint8_t _sse2neon_vaddv_u8(uint8x8_t v8) +{ + const uint64x1_t v1 = vpaddl_u32(vpaddl_u16(vpaddl_u8(v8))); + return vget_lane_u8(vreinterpret_u8_u64(v1), 0); +} +#else +// Wraps vaddv_u8 +FORCE_INLINE uint8_t _sse2neon_vaddv_u8(uint8x8_t v8) +{ + return vaddv_u8(v8); +} +#endif + +#if !defined(__aarch64__) +/* emulate vaddvq u8 variant */ +FORCE_INLINE uint8_t _sse2neon_vaddvq_u8(uint8x16_t a) +{ + uint8x8_t tmp = vpadd_u8(vget_low_u8(a), vget_high_u8(a)); + uint8_t res = 0; + for (int i = 0; i < 8; ++i) + res += tmp[i]; + return res; +} +#else +// Wraps vaddvq_u8 +FORCE_INLINE uint8_t _sse2neon_vaddvq_u8(uint8x16_t a) +{ + return vaddvq_u8(a); +} +#endif + +#if !defined(__aarch64__) +/* emulate vaddvq u16 variant */ +FORCE_INLINE uint16_t _sse2neon_vaddvq_u16(uint16x8_t a) +{ + uint32x4_t m = vpaddlq_u16(a); + uint64x2_t n = vpaddlq_u32(m); + uint64x1_t o = vget_low_u64(n) + vget_high_u64(n); + + return vget_lane_u32((uint32x2_t) o, 0); +} +#else +// Wraps vaddvq_u16 +FORCE_INLINE uint16_t _sse2neon_vaddvq_u16(uint16x8_t a) +{ + return vaddvq_u16(a); +} +#endif + /* Function Naming Conventions * The naming convention of SSE intrinsics is straightforward. A generic SSE * intrinsic function is given as follows: @@ -491,16 +672,12 @@ FORCE_INLINE uint8x16x4_t _sse2neon_vld1q_u8_x4(const uint8_t *p) +------+------+------+------+------+------+-------------+ */ -/* Constants for use with _mm_prefetch. */ +/* Constants for use with _mm_prefetch. */ enum _mm_hint { - _MM_HINT_NTA = 0, /* load data to L1 and L2 cache, mark it as NTA */ - _MM_HINT_T0 = 1, /* load data to L1 and L2 cache */ - _MM_HINT_T1 = 2, /* load data to L2 cache only */ - _MM_HINT_T2 = 3, /* load data to L2 cache only, mark it as NTA */ - _MM_HINT_ENTA = 4, /* exclusive version of _MM_HINT_NTA */ - _MM_HINT_ET0 = 5, /* exclusive version of _MM_HINT_T0 */ - _MM_HINT_ET1 = 6, /* exclusive version of _MM_HINT_T1 */ - _MM_HINT_ET2 = 7 /* exclusive version of _MM_HINT_T2 */ + _MM_HINT_NTA = 0, /* load data to L1 and L2 cache, mark it as NTA */ + _MM_HINT_T0 = 1, /* load data to L1 and L2 cache */ + _MM_HINT_T1 = 2, /* load data to L2 cache only */ + _MM_HINT_T2 = 3, /* load data to L2 cache only, mark it as NTA */ }; // The bit field mapping to the FPCR(floating-point control register) @@ -661,7 +838,8 @@ FORCE_INLINE void _sse2neon_kadd_f32(float *sum, float *c, float y) *sum = t; } -#if defined(__ARM_FEATURE_CRYPTO) +#if defined(__ARM_FEATURE_CRYPTO) && \ + (defined(__aarch64__) || __has_builtin(__builtin_arm_crypto_vmullp64)) // Wraps vmull_p64 FORCE_INLINE uint64x2_t _sse2neon_vmull_p64(uint64x1_t _a, uint64x1_t _b) { @@ -970,6 +1148,11 @@ FORCE_INLINE __m128i _mm_shuffle_epi_3332(__m128i a) vreinterpretq_m128i_s16(ret); \ }) +/* MMX */ + +//_mm_empty is a no-op on arm +FORCE_INLINE void _mm_empty(void) {} + /* SSE */ // Adds the four single-precision, floating-point values of a and b. @@ -1035,7 +1218,7 @@ FORCE_INLINE __m128 _mm_andnot_ps(__m128 a, __m128 b) // dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_avg_pu16 FORCE_INLINE __m64 _mm_avg_pu16(__m64 a, __m64 b) { return vreinterpret_m64_u16( @@ -1050,7 +1233,7 @@ FORCE_INLINE __m64 _mm_avg_pu16(__m64 a, __m64 b) // dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_avg_pu8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_avg_pu8 FORCE_INLINE __m64 _mm_avg_pu8(__m64 a, __m64 b) { return vreinterpret_m64_u8( @@ -1333,7 +1516,7 @@ FORCE_INLINE int _mm_comineq_ss(__m128 a, __m128 b) // dst[95:64] := a[95:64] // dst[127:96] := a[127:96] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_pi2ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvt_pi2ps FORCE_INLINE __m128 _mm_cvt_pi2ps(__m128 a, __m64 b) { return vreinterpretq_m128_f32( @@ -1349,10 +1532,10 @@ FORCE_INLINE __m128 _mm_cvt_pi2ps(__m128 a, __m64 b) // dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ps2pi +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvt_ps2pi FORCE_INLINE __m64 _mm_cvt_ps2pi(__m128 a) { -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) return vreinterpret_m64_s32( vget_low_s32(vcvtnq_s32_f32(vrndiq_f32(vreinterpretq_f32_m128(a))))); #else @@ -1368,7 +1551,7 @@ FORCE_INLINE __m64 _mm_cvt_ps2pi(__m128 a) // dst[31:0] := Convert_Int32_To_FP32(b[31:0]) // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_si2ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvt_si2ss FORCE_INLINE __m128 _mm_cvt_si2ss(__m128 a, int b) { return vreinterpretq_m128_f32( @@ -1377,10 +1560,10 @@ FORCE_INLINE __m128 _mm_cvt_si2ss(__m128 a, int b) // Convert the lower single-precision (32-bit) floating-point element in a to a // 32-bit integer, and store the result in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_ss2si +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvt_ss2si FORCE_INLINE int _mm_cvt_ss2si(__m128 a) { -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) return vgetq_lane_s32(vcvtnq_s32_f32(vrndiq_f32(vreinterpretq_f32_m128(a))), 0); #else @@ -1399,7 +1582,7 @@ FORCE_INLINE int _mm_cvt_ss2si(__m128 a) // dst[m+31:m] := Convert_Int16_To_FP32(a[i+15:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi16_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpi16_ps FORCE_INLINE __m128 _mm_cvtpi16_ps(__m64 a) { return vreinterpretq_m128_f32( @@ -1415,7 +1598,7 @@ FORCE_INLINE __m128 _mm_cvtpi16_ps(__m64 a) // dst[95:64] := a[95:64] // dst[127:96] := a[127:96] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpi32_ps FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b) { return vreinterpretq_m128_f32( @@ -1425,7 +1608,7 @@ FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b) // Convert packed signed 32-bit integers in a to packed single-precision // (32-bit) floating-point elements, store the results in the lower 2 elements -// of dst, then covert the packed signed 32-bit integers in b to +// of dst, then convert the packed signed 32-bit integers in b to // single-precision (32-bit) floating-point element, and store the results in // the upper 2 elements of dst. // @@ -1434,7 +1617,7 @@ FORCE_INLINE __m128 _mm_cvtpi32_ps(__m128 a, __m64 b) // dst[95:64] := Convert_Int32_To_FP32(b[31:0]) // dst[127:96] := Convert_Int32_To_FP32(b[63:32]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32x2_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpi32x2_ps FORCE_INLINE __m128 _mm_cvtpi32x2_ps(__m64 a, __m64 b) { return vreinterpretq_m128_f32(vcvtq_f32_s32( @@ -1450,7 +1633,7 @@ FORCE_INLINE __m128 _mm_cvtpi32x2_ps(__m64 a, __m64 b) // dst[m+31:m] := Convert_Int8_To_FP32(a[i+7:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi8_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpi8_ps FORCE_INLINE __m128 _mm_cvtpi8_ps(__m64 a) { return vreinterpretq_m128_f32(vcvtq_f32_s32( @@ -1472,23 +1655,11 @@ FORCE_INLINE __m128 _mm_cvtpi8_ps(__m64 a) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_pi16 FORCE_INLINE __m64 _mm_cvtps_pi16(__m128 a) { - const __m128 i16Min = _mm_set_ps1((float) INT16_MIN); - const __m128 i16Max = _mm_set_ps1((float) INT16_MAX); - const __m128 i32Max = _mm_set_ps1((float) INT32_MAX); - const __m128i maxMask = _mm_castps_si128( - _mm_and_ps(_mm_cmpge_ps(a, i16Max), _mm_cmple_ps(a, i32Max))); - const __m128i betweenMask = _mm_castps_si128( - _mm_and_ps(_mm_cmpgt_ps(a, i16Min), _mm_cmplt_ps(a, i16Max))); - const __m128i minMask = _mm_cmpeq_epi32(_mm_or_si128(maxMask, betweenMask), - _mm_setzero_si128()); - __m128i max = _mm_and_si128(maxMask, _mm_set1_epi32(INT16_MAX)); - __m128i min = _mm_and_si128(minMask, _mm_set1_epi32(INT16_MIN)); - __m128i cvt = _mm_and_si128(betweenMask, _mm_cvtps_epi32(a)); - __m128i res32 = _mm_or_si128(_mm_or_si128(max, min), cvt); - return vreinterpret_m64_s16(vmovn_s32(vreinterpretq_s32_m128i(res32))); + return vreinterpret_m64_s16( + vqmovn_s32(vreinterpretq_s32_m128i(_mm_cvtps_epi32(a)))); } // Convert packed single-precision (32-bit) floating-point elements in a to @@ -1499,7 +1670,7 @@ FORCE_INLINE __m64 _mm_cvtps_pi16(__m128 a) // dst[i+31:i] := Convert_FP32_To_Int32(a[i+31:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_pi32 #define _mm_cvtps_pi32(a) _mm_cvt_ps2pi(a) // Convert packed single-precision (32-bit) floating-point elements in a to @@ -1517,28 +1688,11 @@ FORCE_INLINE __m64 _mm_cvtps_pi16(__m128 a) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_pi8 FORCE_INLINE __m64 _mm_cvtps_pi8(__m128 a) { - const __m128 i8Min = _mm_set_ps1((float) INT8_MIN); - const __m128 i8Max = _mm_set_ps1((float) INT8_MAX); - const __m128 i32Max = _mm_set_ps1((float) INT32_MAX); - const __m128i maxMask = _mm_castps_si128( - _mm_and_ps(_mm_cmpge_ps(a, i8Max), _mm_cmple_ps(a, i32Max))); - const __m128i betweenMask = _mm_castps_si128( - _mm_and_ps(_mm_cmpgt_ps(a, i8Min), _mm_cmplt_ps(a, i8Max))); - const __m128i minMask = _mm_cmpeq_epi32(_mm_or_si128(maxMask, betweenMask), - _mm_setzero_si128()); - __m128i max = _mm_and_si128(maxMask, _mm_set1_epi32(INT8_MAX)); - __m128i min = _mm_and_si128(minMask, _mm_set1_epi32(INT8_MIN)); - __m128i cvt = _mm_and_si128(betweenMask, _mm_cvtps_epi32(a)); - __m128i res32 = _mm_or_si128(_mm_or_si128(max, min), cvt); - int16x4_t res16 = vmovn_s32(vreinterpretq_s32_m128i(res32)); - int8x8_t res8 = vmovn_s16(vcombine_s16(res16, res16)); - uint32_t bitMask[2] = {0xFFFFFFFF, 0}; - int8x8_t mask = vreinterpret_s8_u32(vld1_u32(bitMask)); - - return vreinterpret_m64_s8(vorr_s8(vand_s8(mask, res8), vdup_n_s8(0))); + return vreinterpret_m64_s8(vqmovn_s16( + vcombine_s16(vreinterpret_s16_m64(_mm_cvtps_pi16(a)), vdup_n_s16(0)))); } // Convert packed unsigned 16-bit integers in a to packed single-precision @@ -1550,7 +1704,7 @@ FORCE_INLINE __m64 _mm_cvtps_pi8(__m128 a) // dst[m+31:m] := Convert_UInt16_To_FP32(a[i+15:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu16_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpu16_ps FORCE_INLINE __m128 _mm_cvtpu16_ps(__m64 a) { return vreinterpretq_m128_f32( @@ -1567,7 +1721,7 @@ FORCE_INLINE __m128 _mm_cvtpu16_ps(__m64 a) // dst[m+31:m] := Convert_UInt8_To_FP32(a[i+7:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpu8_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpu8_ps FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a) { return vreinterpretq_m128_f32(vcvtq_f32_u32( @@ -1581,7 +1735,7 @@ FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a) // dst[31:0] := Convert_Int32_To_FP32(b[31:0]) // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi32_ss #define _mm_cvtsi32_ss(a, b) _mm_cvt_si2ss(a, b) // Convert the signed 64-bit integer b to a single-precision (32-bit) @@ -1591,7 +1745,7 @@ FORCE_INLINE __m128 _mm_cvtpu8_ps(__m64 a) // dst[31:0] := Convert_Int64_To_FP32(b[63:0]) // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi64_ss FORCE_INLINE __m128 _mm_cvtsi64_ss(__m128 a, int64_t b) { return vreinterpretq_m128_f32( @@ -1602,7 +1756,7 @@ FORCE_INLINE __m128 _mm_cvtsi64_ss(__m128 a, int64_t b) // // dst[31:0] := a[31:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_f32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtss_f32 FORCE_INLINE float _mm_cvtss_f32(__m128 a) { return vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); @@ -1613,7 +1767,7 @@ FORCE_INLINE float _mm_cvtss_f32(__m128 a) // // dst[31:0] := Convert_FP32_To_Int32(a[31:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtss_si32 #define _mm_cvtss_si32(a) _mm_cvt_ss2si(a) // Convert the lower single-precision (32-bit) floating-point element in a to a @@ -1621,10 +1775,10 @@ FORCE_INLINE float _mm_cvtss_f32(__m128 a) // // dst[63:0] := Convert_FP32_To_Int64(a[31:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtss_si64 FORCE_INLINE int64_t _mm_cvtss_si64(__m128 a) { -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) return (int64_t) vgetq_lane_f32(vrndiq_f32(vreinterpretq_f32_m128(a)), 0); #else float32_t data = vgetq_lane_f32( @@ -1641,7 +1795,7 @@ FORCE_INLINE int64_t _mm_cvtss_si64(__m128 a) // dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ps2pi +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtt_ps2pi FORCE_INLINE __m64 _mm_cvtt_ps2pi(__m128 a) { return vreinterpret_m64_s32( @@ -1653,7 +1807,7 @@ FORCE_INLINE __m64 _mm_cvtt_ps2pi(__m128 a) // // dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_ss2si +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtt_ss2si FORCE_INLINE int _mm_cvtt_ss2si(__m128 a) { return vgetq_lane_s32(vcvtq_s32_f32(vreinterpretq_f32_m128(a)), 0); @@ -1667,7 +1821,7 @@ FORCE_INLINE int _mm_cvtt_ss2si(__m128 a) // dst[i+31:i] := Convert_FP32_To_Int32_Truncate(a[i+31:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttps_pi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttps_pi32 #define _mm_cvttps_pi32(a) _mm_cvtt_ps2pi(a) // Convert the lower single-precision (32-bit) floating-point element in a to a @@ -1675,7 +1829,7 @@ FORCE_INLINE int _mm_cvtt_ss2si(__m128 a) // // dst[31:0] := Convert_FP32_To_Int32_Truncate(a[31:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttss_si32 #define _mm_cvttss_si32(a) _mm_cvtt_ss2si(a) // Convert the lower single-precision (32-bit) floating-point element in a to a @@ -1683,7 +1837,7 @@ FORCE_INLINE int _mm_cvtt_ss2si(__m128 a) // // dst[63:0] := Convert_FP32_To_Int64_Truncate(a[31:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttss_si64 FORCE_INLINE int64_t _mm_cvttss_si64(__m128 a) { return (int64_t) vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); @@ -1725,21 +1879,23 @@ FORCE_INLINE __m128 _mm_div_ss(__m128 a, __m128 b) // Extract a 16-bit integer from a, selected with imm8, and store the result in // the lower element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_extract_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_extract_pi16 #define _mm_extract_pi16(a, imm) \ (int32_t) vget_lane_u16(vreinterpret_u16_m64(a), (imm)) // Free aligned memory that was allocated with _mm_malloc. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_free +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_free +#if !defined(SSE2NEON_ALLOC_DEFINED) FORCE_INLINE void _mm_free(void *addr) { free(addr); } +#endif // Macro: Get the flush zero bits from the MXCSR control and status register. // The flush zero may contain any of the following flags: _MM_FLUSH_ZERO_ON or // _MM_FLUSH_ZERO_OFF -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_GET_FLUSH_ZERO_MODE +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_MM_GET_FLUSH_ZERO_MODE FORCE_INLINE unsigned int _sse2neon_mm_get_flush_zero_mode() { union { @@ -1752,9 +1908,9 @@ FORCE_INLINE unsigned int _sse2neon_mm_get_flush_zero_mode() } r; #if defined(__aarch64__) - asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ #else - asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ #endif return r.field.bit24 ? _MM_FLUSH_ZERO_ON : _MM_FLUSH_ZERO_OFF; @@ -1763,7 +1919,7 @@ FORCE_INLINE unsigned int _sse2neon_mm_get_flush_zero_mode() // Macro: Get the rounding mode bits from the MXCSR control and status register. // The rounding mode may contain any of the following flags: _MM_ROUND_NEAREST, // _MM_ROUND_DOWN, _MM_ROUND_UP, _MM_ROUND_TOWARD_ZERO -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_GET_ROUNDING_MODE +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_MM_GET_ROUNDING_MODE FORCE_INLINE unsigned int _MM_GET_ROUNDING_MODE() { union { @@ -1776,9 +1932,9 @@ FORCE_INLINE unsigned int _MM_GET_ROUNDING_MODE() } r; #if defined(__aarch64__) - asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ #else - asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ #endif if (r.field.bit22) { @@ -1790,7 +1946,7 @@ FORCE_INLINE unsigned int _MM_GET_ROUNDING_MODE() // Copy a to dst, and insert the 16-bit integer i into dst at the location // specified by imm8. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_insert_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_insert_pi16 #define _mm_insert_pi16(a, b, imm) \ __extension__({ \ vreinterpret_m64_s16( \ @@ -1812,7 +1968,7 @@ FORCE_INLINE __m128 _mm_load_ps(const float *p) // dst[95:64] := MEM[mem_addr+31:mem_addr] // dst[127:96] := MEM[mem_addr+31:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_ps1 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_load_ps1 #define _mm_load_ps1 _mm_load1_ps // Loads an single - precision, floating - point value into the low word and @@ -1873,7 +2029,7 @@ FORCE_INLINE __m128 _mm_loadl_pi(__m128 a, __m64 const *p) // dst[95:64] := MEM[mem_addr+63:mem_addr+32] // dst[127:96] := MEM[mem_addr+31:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadr_ps FORCE_INLINE __m128 _mm_loadr_ps(const float *p) { float32x4_t v = vrev64q_f32(vld1q_f32(p)); @@ -1894,7 +2050,7 @@ FORCE_INLINE __m128 _mm_loadu_ps(const float *p) // dst[15:0] := MEM[mem_addr+15:mem_addr] // dst[MAX:16] := 0 // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadu_si16 FORCE_INLINE __m128i _mm_loadu_si16(const void *p) { return vreinterpretq_m128i_s16( @@ -1906,7 +2062,7 @@ FORCE_INLINE __m128i _mm_loadu_si16(const void *p) // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[MAX:64] := 0 // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadu_si64 FORCE_INLINE __m128i _mm_loadu_si64(const void *p) { return vreinterpretq_m128i_s64( @@ -1916,6 +2072,7 @@ FORCE_INLINE __m128i _mm_loadu_si64(const void *p) // Allocate aligned blocks of memory. // https://software.intel.com/en-us/ // cpp-compiler-developer-guide-and-reference-allocating-and-freeing-aligned-memory-blocks +#if !defined(SSE2NEON_ALLOC_DEFINED) FORCE_INLINE void *_mm_malloc(size_t size, size_t align) { void *ptr; @@ -1927,11 +2084,12 @@ FORCE_INLINE void *_mm_malloc(size_t size, size_t align) return ptr; return NULL; } +#endif // Conditionally store 8-bit integer elements from a into memory using mask // (elements are not stored when the highest bit is not set in the corresponding // element) and a non-temporal memory hint. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskmove_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maskmove_si64 FORCE_INLINE void _mm_maskmove_si64(__m64 a, __m64 mask, char *mem_addr) { int8x8_t shr_mask = vshr_n_s8(vreinterpret_s8_m64(mask), 7); @@ -1945,7 +2103,7 @@ FORCE_INLINE void _mm_maskmove_si64(__m64 a, __m64 mask, char *mem_addr) // Conditionally store 8-bit integer elements from a into memory using mask // (elements are not stored when the highest bit is not set in the corresponding // element) and a non-temporal memory hint. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_maskmovq +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_maskmovq #define _m_maskmovq(a, mask, mem_addr) _mm_maskmove_si64(a, mask, mem_addr) // Compare packed signed 16-bit integers in a and b, and store packed maximum @@ -1956,7 +2114,7 @@ FORCE_INLINE void _mm_maskmove_si64(__m64 a, __m64 mask, char *mem_addr) // dst[i+15:i] := MAX(a[i+15:i], b[i+15:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_pi16 FORCE_INLINE __m64 _mm_max_pi16(__m64 a, __m64 b) { return vreinterpret_m64_s16( @@ -1971,7 +2129,7 @@ FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b) #if SSE2NEON_PRECISE_MINMAX float32x4_t _a = vreinterpretq_f32_m128(a); float32x4_t _b = vreinterpretq_f32_m128(b); - return vbslq_f32(vcltq_f32(_b, _a), _a, _b); + return vreinterpretq_m128_f32(vbslq_f32(vcgtq_f32(_a, _b), _a, _b)); #else return vreinterpretq_m128_f32( vmaxq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); @@ -1986,7 +2144,7 @@ FORCE_INLINE __m128 _mm_max_ps(__m128 a, __m128 b) // dst[i+7:i] := MAX(a[i+7:i], b[i+7:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pu8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_pu8 FORCE_INLINE __m64 _mm_max_pu8(__m64 a, __m64 b) { return vreinterpret_m64_u8( @@ -2011,7 +2169,7 @@ FORCE_INLINE __m128 _mm_max_ss(__m128 a, __m128 b) // dst[i+15:i] := MIN(a[i+15:i], b[i+15:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_min_pi16 FORCE_INLINE __m64 _mm_min_pi16(__m64 a, __m64 b) { return vreinterpret_m64_s16( @@ -2026,7 +2184,7 @@ FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b) #if SSE2NEON_PRECISE_MINMAX float32x4_t _a = vreinterpretq_f32_m128(a); float32x4_t _b = vreinterpretq_f32_m128(b); - return vbslq_f32(vcltq_f32(_a, _b), _a, _b); + return vreinterpretq_m128_f32(vbslq_f32(vcltq_f32(_a, _b), _a, _b)); #else return vreinterpretq_m128_f32( vminq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(b))); @@ -2041,7 +2199,7 @@ FORCE_INLINE __m128 _mm_min_ps(__m128 a, __m128 b) // dst[i+7:i] := MIN(a[i+7:i], b[i+7:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pu8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_min_pu8 FORCE_INLINE __m64 _mm_min_pu8(__m64 a, __m64 b) { return vreinterpret_m64_u8( @@ -2095,7 +2253,7 @@ FORCE_INLINE __m128 _mm_movelh_ps(__m128 __A, __m128 __B) // Create mask from the most significant bit of each 8-bit element in a, and // store the result in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movemask_pi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_movemask_pi8 FORCE_INLINE int _mm_movemask_pi8(__m64 a) { uint8x8_t input = vreinterpret_u8_m64(a); @@ -2159,7 +2317,7 @@ FORCE_INLINE __m128 _mm_mul_ps(__m128 a, __m128 b) // dst[31:0] := a[31:0] * b[31:0] // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mul_ss FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_mul_ps(a, b)); @@ -2168,7 +2326,7 @@ FORCE_INLINE __m128 _mm_mul_ss(__m128 a, __m128 b) // Multiply the packed unsigned 16-bit integers in a and b, producing // intermediate 32-bit integers, and store the high 16 bits of the intermediate // integers in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_pu16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhi_pu16 FORCE_INLINE __m64 _mm_mulhi_pu16(__m64 a, __m64 b) { return vreinterpret_m64_u16(vshrn_n_u32( @@ -2192,7 +2350,7 @@ FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b) // dst[i+7:i] := (a[i+7:i] + b[i+7:i] + 1) >> 1 // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgb +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pavgb #define _m_pavgb(a, b) _mm_avg_pu8(a, b) // Average packed unsigned 16-bit integers in a and b, and store the results in @@ -2203,74 +2361,87 @@ FORCE_INLINE __m128 _mm_or_ps(__m128 a, __m128 b) // dst[i+15:i] := (a[i+15:i] + b[i+15:i] + 1) >> 1 // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pavgw +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pavgw #define _m_pavgw(a, b) _mm_avg_pu16(a, b) // Extract a 16-bit integer from a, selected with imm8, and store the result in // the lower element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pextrw +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pextrw #define _m_pextrw(a, imm) _mm_extract_pi16(a, imm) // Copy a to dst, and insert the 16-bit integer i into dst at the location // specified by imm8. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_pinsrw +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=m_pinsrw #define _m_pinsrw(a, i, imm) _mm_insert_pi16(a, i, imm) // Compare packed signed 16-bit integers in a and b, and store packed maximum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxsw +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pmaxsw #define _m_pmaxsw(a, b) _mm_max_pi16(a, b) // Compare packed unsigned 8-bit integers in a and b, and store packed maximum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmaxub +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pmaxub #define _m_pmaxub(a, b) _mm_max_pu8(a, b) // Compare packed signed 16-bit integers in a and b, and store packed minimum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminsw +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pminsw #define _m_pminsw(a, b) _mm_min_pi16(a, b) // Compare packed unsigned 8-bit integers in a and b, and store packed minimum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pminub +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pminub #define _m_pminub(a, b) _mm_min_pu8(a, b) // Create mask from the most significant bit of each 8-bit element in a, and // store the result in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmovmskb +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pmovmskb #define _m_pmovmskb(a) _mm_movemask_pi8(a) // Multiply the packed unsigned 16-bit integers in a and b, producing // intermediate 32-bit integers, and store the high 16 bits of the intermediate // integers in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pmulhuw +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pmulhuw #define _m_pmulhuw(a, b) _mm_mulhi_pu16(a, b) -// Loads one cache line of data from address p to a location closer to the -// processor. https://msdn.microsoft.com/en-us/library/84szxsww(v=vs.100).aspx -FORCE_INLINE void _mm_prefetch(const void *p, int i) +// Fetch the line of data from memory that contains address p to a location in +// the cache heirarchy specified by the locality hint i. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_prefetch +FORCE_INLINE void _mm_prefetch(char const *p, int i) { - (void) i; - __builtin_prefetch(p); + switch (i) { + case _MM_HINT_NTA: + __builtin_prefetch(p, 0, 0); + break; + case _MM_HINT_T0: + __builtin_prefetch(p, 0, 3); + break; + case _MM_HINT_T1: + __builtin_prefetch(p, 0, 2); + break; + case _MM_HINT_T2: + __builtin_prefetch(p, 0, 1); + break; + } } // Compute the absolute differences of packed unsigned 8-bit integers in a and // b, then horizontally sum each consecutive 8 differences to produce four // unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low // 16 bits of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=m_psadbw +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=m_psadbw #define _m_psadbw(a, b) _mm_sad_pu8(a, b) // Shuffle 16-bit integers in a using the control in imm8, and store the results // in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_m_pshufw +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_m_pshufw #define _m_pshufw(a, imm) _mm_shuffle_pi16(a, imm) // Compute the approximate reciprocal of packed single-precision (32-bit) // floating-point elements in a, and store the results in dst. The maximum // relative error for this approximation is less than 1.5*2^-12. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_rcp_ps FORCE_INLINE __m128 _mm_rcp_ps(__m128 in) { float32x4_t recip = vrecpeq_f32(vreinterpretq_f32_m128(in)); @@ -2290,7 +2461,7 @@ FORCE_INLINE __m128 _mm_rcp_ps(__m128 in) // dst[31:0] := (1.0 / a[31:0]) // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_rcp_ss FORCE_INLINE __m128 _mm_rcp_ss(__m128 a) { return _mm_move_ss(a, _mm_rcp_ps(a)); @@ -2317,7 +2488,7 @@ FORCE_INLINE __m128 _mm_rsqrt_ps(__m128 in) // (32-bit) floating-point element in a, store the result in the lower element // of dst, and copy the upper 3 packed elements from a to the upper elements of // dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_rsqrt_ss FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in) { return vsetq_lane_f32(vgetq_lane_f32(_mm_rsqrt_ps(in), 0), in, 0); @@ -2327,7 +2498,7 @@ FORCE_INLINE __m128 _mm_rsqrt_ss(__m128 in) // b, then horizontally sum each consecutive 8 differences to produce four // unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low // 16 bits of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_pu8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_pu8 FORCE_INLINE __m64 _mm_sad_pu8(__m64 a, __m64 b) { uint64x1_t t = vpaddl_u32(vpaddl_u16( @@ -2339,7 +2510,7 @@ FORCE_INLINE __m64 _mm_sad_pu8(__m64 a, __m64 b) // Macro: Set the flush zero bits of the MXCSR control and status register to // the value in unsigned 32-bit integer a. The flush zero may contain any of the // following flags: _MM_FLUSH_ZERO_ON or _MM_FLUSH_ZERO_OFF -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_SET_FLUSH_ZERO_MODE +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_MM_SET_FLUSH_ZERO_MODE FORCE_INLINE void _sse2neon_mm_set_flush_zero_mode(unsigned int flag) { // AArch32 Advanced SIMD arithmetic always uses the Flush-to-zero setting, @@ -2354,17 +2525,17 @@ FORCE_INLINE void _sse2neon_mm_set_flush_zero_mode(unsigned int flag) } r; #if defined(__aarch64__) - asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ #else - asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ #endif r.field.bit24 = (flag & _MM_FLUSH_ZERO_MASK) == _MM_FLUSH_ZERO_ON; #if defined(__aarch64__) - asm volatile("msr FPCR, %0" ::"r"(r)); /* write */ + __asm__ __volatile__("msr FPCR, %0" ::"r"(r)); /* write */ #else - asm volatile("vmsr FPSCR, %0" ::"r"(r)); /* write */ + __asm__ __volatile__("vmsr FPSCR, %0" ::"r"(r)); /* write */ #endif } @@ -2387,7 +2558,7 @@ FORCE_INLINE __m128 _mm_set_ps1(float _w) // the value in unsigned 32-bit integer a. The rounding mode may contain any of // the following flags: _MM_ROUND_NEAREST, _MM_ROUND_DOWN, _MM_ROUND_UP, // _MM_ROUND_TOWARD_ZERO -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_MM_SET_ROUNDING_MODE +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_MM_SET_ROUNDING_MODE FORCE_INLINE void _MM_SET_ROUNDING_MODE(int rounding) { union { @@ -2400,9 +2571,9 @@ FORCE_INLINE void _MM_SET_ROUNDING_MODE(int rounding) } r; #if defined(__aarch64__) - asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ #else - asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ #endif switch (rounding) { @@ -2424,19 +2595,18 @@ FORCE_INLINE void _MM_SET_ROUNDING_MODE(int rounding) } #if defined(__aarch64__) - asm volatile("msr FPCR, %0" ::"r"(r)); /* write */ + __asm__ __volatile__("msr FPCR, %0" ::"r"(r)); /* write */ #else - asm volatile("vmsr FPSCR, %0" ::"r"(r)); /* write */ + __asm__ __volatile__("vmsr FPSCR, %0" ::"r"(r)); /* write */ #endif } // Copy single-precision (32-bit) floating-point element a to the lower element // of dst, and zero the upper 3 elements. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_set_ss FORCE_INLINE __m128 _mm_set_ss(float a) { - float ALIGN_STRUCT(16) data[4] = {a, 0, 0, 0}; - return vreinterpretq_m128_f32(vld1q_f32(data)); + return vreinterpretq_m128_f32(vsetq_lane_f32(a, vdupq_n_f32(0), 0)); } // Sets the four single-precision, floating-point values to w. @@ -2449,11 +2619,18 @@ FORCE_INLINE __m128 _mm_set1_ps(float _w) return vreinterpretq_m128_f32(vdupq_n_f32(_w)); } +// FIXME: _mm_setcsr() implementation supports changing the rounding mode only. FORCE_INLINE void _mm_setcsr(unsigned int a) { _MM_SET_ROUNDING_MODE(a); } +// FIXME: _mm_getcsr() implementation supports reading the rounding mode only. +FORCE_INLINE unsigned int _mm_getcsr() +{ + return _MM_GET_ROUNDING_MODE(); +} + // Sets the four single-precision, floating-point values to the four inputs in // reverse order. // https://msdn.microsoft.com/en-us/library/vstudio/d2172ct3(v=vs.100).aspx @@ -2472,11 +2649,11 @@ FORCE_INLINE __m128 _mm_setzero_ps(void) // Shuffle 16-bit integers in a using the control in imm8, and store the results // in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pi16 -#if __has_builtin(__builtin_shufflevector) +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_pi16 +#ifdef _sse2neon_shuffle #define _mm_shuffle_pi16(a, imm) \ __extension__({ \ - vreinterpret_m64_s16(__builtin_shufflevector( \ + vreinterpret_m64_s16(vshuffle_s16( \ vreinterpret_s16_m64(a), vreinterpret_s16_m64(a), (imm & 0x3), \ ((imm >> 2) & 0x3), ((imm >> 4) & 0x3), ((imm >> 6) & 0x3))); \ }) @@ -2499,25 +2676,48 @@ FORCE_INLINE __m128 _mm_setzero_ps(void) }) #endif -// Guarantees that every preceding store is globally visible before any -// subsequent store. -// https://msdn.microsoft.com/en-us/library/5h2w73d1%28v=vs.90%29.aspx +// Perform a serializing operation on all store-to-memory instructions that were +// issued prior to this instruction. Guarantees that every store instruction +// that precedes, in program order, is globally visible before any store +// instruction which follows the fence in program order. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sfence FORCE_INLINE void _mm_sfence(void) { - __sync_synchronize(); + _sse2neon_smp_mb(); +} + +// Perform a serializing operation on all load-from-memory and store-to-memory +// instructions that were issued prior to this instruction. Guarantees that +// every memory access that precedes, in program order, the memory fence +// instruction is globally visible before any memory instruction which follows +// the fence in program order. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mfence +FORCE_INLINE void _mm_mfence(void) +{ + _sse2neon_smp_mb(); +} + +// Perform a serializing operation on all load-from-memory instructions that +// were issued prior to this instruction. Guarantees that every load instruction +// that precedes, in program order, is globally visible before any load +// instruction which follows the fence in program order. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_lfence +FORCE_INLINE void _mm_lfence(void) +{ + _sse2neon_smp_mb(); } // FORCE_INLINE __m128 _mm_shuffle_ps(__m128 a, __m128 b, __constrange(0,255) // int imm) -#if __has_builtin(__builtin_shufflevector) -#define _mm_shuffle_ps(a, b, imm) \ - __extension__({ \ - float32x4_t _input1 = vreinterpretq_f32_m128(a); \ - float32x4_t _input2 = vreinterpretq_f32_m128(b); \ - float32x4_t _shuf = __builtin_shufflevector( \ - _input1, _input2, (imm) & (0x3), ((imm) >> 2) & 0x3, \ - (((imm) >> 4) & 0x3) + 4, (((imm) >> 6) & 0x3) + 4); \ - vreinterpretq_m128_f32(_shuf); \ +#ifdef _sse2neon_shuffle +#define _mm_shuffle_ps(a, b, imm) \ + __extension__({ \ + float32x4_t _input1 = vreinterpretq_f32_m128(a); \ + float32x4_t _input2 = vreinterpretq_f32_m128(b); \ + float32x4_t _shuf = \ + vshuffleq_s32(_input1, _input2, (imm) & (0x3), ((imm) >> 2) & 0x3, \ + (((imm) >> 4) & 0x3) + 4, (((imm) >> 6) & 0x3) + 4); \ + vreinterpretq_m128_f32(_shuf); \ }) #else // generic #define _mm_shuffle_ps(a, b, imm) \ @@ -2652,7 +2852,7 @@ FORCE_INLINE void _mm_store_ps(float *p, __m128 a) // MEM[mem_addr+95:mem_addr+64] := a[31:0] // MEM[mem_addr+127:mem_addr+96] := a[31:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_ps1 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_store_ps1 FORCE_INLINE void _mm_store_ps1(float *p, __m128 a) { float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); @@ -2675,7 +2875,7 @@ FORCE_INLINE void _mm_store_ss(float *p, __m128 a) // MEM[mem_addr+95:mem_addr+64] := a[31:0] // MEM[mem_addr+127:mem_addr+96] := a[31:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store1_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_store1_ps #define _mm_store1_ps _mm_store_ps1 // Stores the upper two single-precision, floating-point values of a to the @@ -2711,7 +2911,7 @@ FORCE_INLINE void _mm_storel_pi(__m64 *p, __m128 a) // MEM[mem_addr+95:mem_addr+64] := a[63:32] // MEM[mem_addr+127:mem_addr+96] := a[31:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storer_ps FORCE_INLINE void _mm_storer_ps(float *p, __m128 a) { float32x4_t tmp = vrev64q_f32(vreinterpretq_f32_m128(a)); @@ -2727,14 +2927,14 @@ FORCE_INLINE void _mm_storeu_ps(float *p, __m128 a) } // Stores 16-bits of integer data a at the address p. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storeu_si16 FORCE_INLINE void _mm_storeu_si16(void *p, __m128i a) { vst1q_lane_s16((int16_t *) p, vreinterpretq_s16_m128i(a), 0); } // Stores 64-bits of integer data a at the address p. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storeu_si64 FORCE_INLINE void _mm_storeu_si64(void *p, __m128i a) { vst1q_lane_s64((int64_t *) p, vreinterpretq_s64_m128i(a), 0); @@ -2742,7 +2942,7 @@ FORCE_INLINE void _mm_storeu_si64(void *p, __m128i a) // Store 64-bits of integer data from a into memory using a non-temporal memory // hint. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_pi +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_stream_pi FORCE_INLINE void _mm_stream_pi(__m64 *p, __m64 a) { vst1_s64((int64_t *) p, vreinterpret_s64_m64(a)); @@ -2750,11 +2950,11 @@ FORCE_INLINE void _mm_stream_pi(__m64 *p, __m64 a) // Store 128-bits (composed of 4 packed single-precision (32-bit) floating- // point elements) from a into memory using a non-temporal memory hint. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_stream_ps FORCE_INLINE void _mm_stream_ps(float *p, __m128 a) { #if __has_builtin(__builtin_nontemporal_store) - __builtin_nontemporal_store(a, (float32x4_t *) p); + __builtin_nontemporal_store(reinterpret_cast<float32x4_t>(a), (float32x4_t *) p); #else vst1q_f32(p, vreinterpretq_f32_m128(a)); #endif @@ -2782,7 +2982,7 @@ FORCE_INLINE __m128 _mm_sub_ps(__m128 a, __m128 b) // dst[31:0] := a[31:0] - b[31:0] // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sub_ss FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_sub_ps(a, b)); @@ -2791,7 +2991,7 @@ FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b) // Macro: Transpose the 4x4 matrix formed by the 4 rows of single-precision // (32-bit) floating-point elements in row0, row1, row2, and row3, and store the // transposed matrix in these vectors (row0 now contains column 0, etc.). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=MM_TRANSPOSE4_PS +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=MM_TRANSPOSE4_PS #define _MM_TRANSPOSE4_PS(row0, row1, row2, row3) \ do { \ float32x4x2_t ROW01 = vtrnq_f32(row0, row1); \ @@ -2816,7 +3016,7 @@ FORCE_INLINE __m128 _mm_sub_ss(__m128 a, __m128 b) #define _mm_ucomineq_ss _mm_comineq_ss // Return vector of type __m128i with undefined elements. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_undefined_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=mm_undefined_si128 FORCE_INLINE __m128i _mm_undefined_si128(void) { #if defined(__GNUC__) || defined(__clang__) @@ -2831,7 +3031,7 @@ FORCE_INLINE __m128i _mm_undefined_si128(void) } // Return vector of type __m128 with undefined elements. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_undefined_ps FORCE_INLINE __m128 _mm_undefined_ps(void) { #if defined(__GNUC__) || defined(__clang__) @@ -2944,7 +3144,7 @@ FORCE_INLINE __m128i _mm_add_epi8(__m128i a, __m128i b) // Add packed double-precision (64-bit) floating-point elements in a and b, and // store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_add_pd FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -2967,7 +3167,7 @@ FORCE_INLINE __m128d _mm_add_pd(__m128d a, __m128d b) // dst[63:0] := a[63:0] + b[63:0] // dst[127:64] := a[127:64] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_add_sd FORCE_INLINE __m128d _mm_add_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -2986,7 +3186,7 @@ FORCE_INLINE __m128d _mm_add_sd(__m128d a, __m128d b) // // dst[63:0] := a[63:0] + b[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_add_si64 FORCE_INLINE __m64 _mm_add_si64(__m64 a, __m64 b) { return vreinterpret_m64_s64( @@ -3016,7 +3216,7 @@ FORCE_INLINE __m128i _mm_adds_epi16(__m128i a, __m128i b) // dst[i+7:i] := Saturate8( a[i+7:i] + b[i+7:i] ) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_adds_epi8 FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( @@ -3025,7 +3225,7 @@ FORCE_INLINE __m128i _mm_adds_epi8(__m128i a, __m128i b) // Add packed unsigned 16-bit integers in a and b using saturation, and store // the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_adds_epu16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_adds_epu16 FORCE_INLINE __m128i _mm_adds_epu16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( @@ -3049,7 +3249,7 @@ FORCE_INLINE __m128i _mm_adds_epu8(__m128i a, __m128i b) // dst[i+63:i] := a[i+63:i] AND b[i+63:i] // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_and_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_and_pd FORCE_INLINE __m128d _mm_and_pd(__m128d a, __m128d b) { return vreinterpretq_m128d_s64( @@ -3072,11 +3272,11 @@ FORCE_INLINE __m128i _mm_and_si128(__m128i a, __m128i b) // elements in a and then AND with b, and store the results in dst. // // FOR j := 0 to 1 -// i := j*64 -// dst[i+63:i] := ((NOT a[i+63:i]) AND b[i+63:i]) +// i := j*64 +// dst[i+63:i] := ((NOT a[i+63:i]) AND b[i+63:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_andnot_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_andnot_pd FORCE_INLINE __m128d _mm_andnot_pd(__m128d a, __m128d b) { // *NOTE* argument swap @@ -3129,17 +3329,17 @@ FORCE_INLINE __m128i _mm_avg_epu8(__m128i a, __m128i b) // Shift a left by imm8 bytes while shifting in zeros, and store the results in // dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bslli_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_bslli_si128 #define _mm_bslli_si128(a, imm) _mm_slli_si128(a, imm) // Shift a right by imm8 bytes while shifting in zeros, and store the results in // dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_bsrli_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_bsrli_si128 #define _mm_bsrli_si128(a, imm) _mm_srli_si128(a, imm) // Cast vector of type __m128d to type __m128. This intrinsic is only used for // compilation and does not generate any instructions, thus it has zero latency. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_castpd_ps FORCE_INLINE __m128 _mm_castpd_ps(__m128d a) { return vreinterpretq_m128_s64(vreinterpretq_s64_m128d(a)); @@ -3147,7 +3347,7 @@ FORCE_INLINE __m128 _mm_castpd_ps(__m128d a) // Cast vector of type __m128d to type __m128i. This intrinsic is only used for // compilation and does not generate any instructions, thus it has zero latency. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castpd_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_castpd_si128 FORCE_INLINE __m128i _mm_castpd_si128(__m128d a) { return vreinterpretq_m128i_s64(vreinterpretq_s64_m128d(a)); @@ -3155,7 +3355,7 @@ FORCE_INLINE __m128i _mm_castpd_si128(__m128d a) // Cast vector of type __m128 to type __m128d. This intrinsic is only used for // compilation and does not generate any instructions, thus it has zero latency. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castps_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_castps_pd FORCE_INLINE __m128d _mm_castps_pd(__m128 a) { return vreinterpretq_m128d_s32(vreinterpretq_s32_m128(a)); @@ -3171,7 +3371,7 @@ FORCE_INLINE __m128i _mm_castps_si128(__m128 a) // Cast vector of type __m128i to type __m128d. This intrinsic is only used for // compilation and does not generate any instructions, thus it has zero latency. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_castsi128_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_castsi128_pd FORCE_INLINE __m128d _mm_castsi128_pd(__m128i a) { #if defined(__aarch64__) @@ -3189,13 +3389,29 @@ FORCE_INLINE __m128 _mm_castsi128_ps(__m128i a) return vreinterpretq_m128_s32(vreinterpretq_s32_m128i(a)); } -// Cache line containing p is flushed and invalidated from all caches in the -// coherency domain. : -// https://msdn.microsoft.com/en-us/library/ba08y07y(v=vs.100).aspx +// Invalidate and flush the cache line that contains p from all levels of the +// cache hierarchy. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clflush +#if defined(__APPLE__) +#include <libkern/OSCacheControl.h> +#endif FORCE_INLINE void _mm_clflush(void const *p) { (void) p; - // no corollary for Neon? + + /* sys_icache_invalidate is supported since macOS 10.5. + * However, it does not work on non-jailbroken iOS devices, although the + * compilation is successful. + */ +#if defined(__APPLE__) + sys_icache_invalidate((void *) (uintptr_t) p, SSE2NEON_CACHELINE_SIZE); +#elif defined(__GNUC__) || defined(__clang__) + uintptr_t ptr = (uintptr_t) p; + __builtin___clear_cache((char *) ptr, + (char *) ptr + SSE2NEON_CACHELINE_SIZE); +#else + /* FIXME: MSVC support */ +#endif } // Compares the 8 signed or unsigned 16-bit integers in a and the 8 signed or @@ -3226,7 +3442,7 @@ FORCE_INLINE __m128i _mm_cmpeq_epi8(__m128i a, __m128i b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for equality, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpeq_pd FORCE_INLINE __m128d _mm_cmpeq_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3244,7 +3460,7 @@ FORCE_INLINE __m128d _mm_cmpeq_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for equality, store the result in the lower element of dst, and copy the // upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpeq_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpeq_sd FORCE_INLINE __m128d _mm_cmpeq_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_cmpeq_pd(a, b)); @@ -3252,7 +3468,7 @@ FORCE_INLINE __m128d _mm_cmpeq_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for greater-than-or-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpge_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpge_pd FORCE_INLINE __m128d _mm_cmpge_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3274,7 +3490,7 @@ FORCE_INLINE __m128d _mm_cmpge_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for greater-than-or-equal, store the result in the lower element of dst, // and copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpge_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpge_sd FORCE_INLINE __m128d _mm_cmpge_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3333,7 +3549,7 @@ FORCE_INLINE __m128i _mm_cmpgt_epi8(__m128i a, __m128i b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for greater-than, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpgt_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpgt_pd FORCE_INLINE __m128d _mm_cmpgt_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3355,7 +3571,7 @@ FORCE_INLINE __m128d _mm_cmpgt_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for greater-than, store the result in the lower element of dst, and copy // the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpgt_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpgt_sd FORCE_INLINE __m128d _mm_cmpgt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3375,7 +3591,7 @@ FORCE_INLINE __m128d _mm_cmpgt_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for less-than-or-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmple_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmple_pd FORCE_INLINE __m128d _mm_cmple_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3397,7 +3613,7 @@ FORCE_INLINE __m128d _mm_cmple_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for less-than-or-equal, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmple_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmple_sd FORCE_INLINE __m128d _mm_cmple_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3451,7 +3667,7 @@ FORCE_INLINE __m128i _mm_cmplt_epi8(__m128i a, __m128i b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for less-than, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmplt_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmplt_pd FORCE_INLINE __m128d _mm_cmplt_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3473,7 +3689,7 @@ FORCE_INLINE __m128d _mm_cmplt_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for less-than, store the result in the lower element of dst, and copy the // upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmplt_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmplt_sd FORCE_INLINE __m128d _mm_cmplt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3492,7 +3708,7 @@ FORCE_INLINE __m128d _mm_cmplt_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpneq_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpneq_pd FORCE_INLINE __m128d _mm_cmpneq_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3510,7 +3726,7 @@ FORCE_INLINE __m128d _mm_cmpneq_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-equal, store the result in the lower element of dst, and copy the // upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpneq_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpneq_sd FORCE_INLINE __m128d _mm_cmpneq_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_cmpneq_pd(a, b)); @@ -3518,7 +3734,7 @@ FORCE_INLINE __m128d _mm_cmpneq_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-greater-than-or-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnge_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpnge_pd FORCE_INLINE __m128d _mm_cmpnge_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3543,7 +3759,7 @@ FORCE_INLINE __m128d _mm_cmpnge_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-greater-than-or-equal, store the result in the lower element of // dst, and copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnge_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpnge_sd FORCE_INLINE __m128d _mm_cmpnge_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_cmpnge_pd(a, b)); @@ -3551,7 +3767,7 @@ FORCE_INLINE __m128d _mm_cmpnge_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-greater-than, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_cmpngt_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_cmpngt_pd FORCE_INLINE __m128d _mm_cmpngt_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3576,7 +3792,7 @@ FORCE_INLINE __m128d _mm_cmpngt_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-greater-than, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpngt_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpngt_sd FORCE_INLINE __m128d _mm_cmpngt_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_cmpngt_pd(a, b)); @@ -3584,7 +3800,7 @@ FORCE_INLINE __m128d _mm_cmpngt_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-less-than-or-equal, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnle_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpnle_pd FORCE_INLINE __m128d _mm_cmpnle_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3609,7 +3825,7 @@ FORCE_INLINE __m128d _mm_cmpnle_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-less-than-or-equal, store the result in the lower element of dst, // and copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnle_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpnle_sd FORCE_INLINE __m128d _mm_cmpnle_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_cmpnle_pd(a, b)); @@ -3617,7 +3833,7 @@ FORCE_INLINE __m128d _mm_cmpnle_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // for not-less-than, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnlt_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpnlt_pd FORCE_INLINE __m128d _mm_cmpnlt_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3642,7 +3858,7 @@ FORCE_INLINE __m128d _mm_cmpnlt_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b for not-less-than, store the result in the lower element of dst, and copy // the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpnlt_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpnlt_sd FORCE_INLINE __m128d _mm_cmpnlt_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_cmpnlt_pd(a, b)); @@ -3650,7 +3866,7 @@ FORCE_INLINE __m128d _mm_cmpnlt_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // to see if neither is NaN, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpord_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpord_pd FORCE_INLINE __m128d _mm_cmpord_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3682,7 +3898,7 @@ FORCE_INLINE __m128d _mm_cmpord_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b to see if neither is NaN, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpord_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpord_sd FORCE_INLINE __m128d _mm_cmpord_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3704,7 +3920,7 @@ FORCE_INLINE __m128d _mm_cmpord_sd(__m128d a, __m128d b) // Compare packed double-precision (64-bit) floating-point elements in a and b // to see if either is NaN, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpunord_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpunord_pd FORCE_INLINE __m128d _mm_cmpunord_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3737,7 +3953,7 @@ FORCE_INLINE __m128d _mm_cmpunord_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b to see if either is NaN, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpunord_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpunord_sd FORCE_INLINE __m128d _mm_cmpunord_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3759,7 +3975,7 @@ FORCE_INLINE __m128d _mm_cmpunord_sd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point element in a and b // for greater-than-or-equal, and return the boolean result (0 or 1). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comige_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_comige_sd FORCE_INLINE int _mm_comige_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3774,7 +3990,7 @@ FORCE_INLINE int _mm_comige_sd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point element in a and b // for greater-than, and return the boolean result (0 or 1). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comigt_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_comigt_sd FORCE_INLINE int _mm_comigt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3789,7 +4005,7 @@ FORCE_INLINE int _mm_comigt_sd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point element in a and b // for less-than-or-equal, and return the boolean result (0 or 1). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comile_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_comile_sd FORCE_INLINE int _mm_comile_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3804,7 +4020,7 @@ FORCE_INLINE int _mm_comile_sd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point element in a and b // for less-than, and return the boolean result (0 or 1). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comilt_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_comilt_sd FORCE_INLINE int _mm_comilt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3819,7 +4035,7 @@ FORCE_INLINE int _mm_comilt_sd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point element in a and b // for equality, and return the boolean result (0 or 1). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comieq_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_comieq_sd FORCE_INLINE int _mm_comieq_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -3840,7 +4056,7 @@ FORCE_INLINE int _mm_comieq_sd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point element in a and b // for not-equal, and return the boolean result (0 or 1). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comineq_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_comineq_sd FORCE_INLINE int _mm_comineq_sd(__m128d a, __m128d b) { return !_mm_comieq_sd(a, b); @@ -3855,7 +4071,7 @@ FORCE_INLINE int _mm_comineq_sd(__m128d a, __m128d b) // dst[m+63:m] := Convert_Int32_To_FP64(a[i+31:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtepi32_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtepi32_pd FORCE_INLINE __m128d _mm_cvtepi32_pd(__m128i a) { #if defined(__aarch64__) @@ -3885,13 +4101,21 @@ FORCE_INLINE __m128 _mm_cvtepi32_ps(__m128i a) // dst[i+31:i] := Convert_FP64_To_Int32(a[k+63:k]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpd_epi32 FORCE_INLINE __m128i _mm_cvtpd_epi32(__m128d a) { +// vrnd32xq_f64 not supported on clang +#if defined(__ARM_FEATURE_FRINT) && !defined(__clang__) + float64x2_t rounded = vrnd32xq_f64(vreinterpretq_f64_m128d(a)); + int64x2_t integers = vcvtq_s64_f64(rounded); + return vreinterpretq_m128i_s32( + vcombine_s32(vmovn_s64(integers), vdup_n_s32(0))); +#else __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); double d0 = ((double *) &rnd)[0]; double d1 = ((double *) &rnd)[1]; return _mm_set_epi32(0, 0, (int32_t) d1, (int32_t) d0); +#endif } // Convert packed double-precision (64-bit) floating-point elements in a to @@ -3903,7 +4127,7 @@ FORCE_INLINE __m128i _mm_cvtpd_epi32(__m128d a) // dst[i+31:i] := Convert_FP64_To_Int32(a[k+63:k]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_pi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpd_pi32 FORCE_INLINE __m64 _mm_cvtpd_pi32(__m128d a) { __m128d rnd = _mm_round_pd(a, _MM_FROUND_CUR_DIRECTION); @@ -3924,7 +4148,7 @@ FORCE_INLINE __m64 _mm_cvtpd_pi32(__m128d a) // ENDFOR // dst[127:64] := 0 // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpd_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpd_ps FORCE_INLINE __m128 _mm_cvtpd_ps(__m128d a) { #if defined(__aarch64__) @@ -3946,7 +4170,7 @@ FORCE_INLINE __m128 _mm_cvtpd_ps(__m128d a) // dst[m+63:m] := Convert_Int32_To_FP64(a[i+31:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtpi32_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtpi32_pd FORCE_INLINE __m128d _mm_cvtpi32_pd(__m64 a) { #if defined(__aarch64__) @@ -3972,7 +4196,9 @@ FORCE_INLINE __m128d _mm_cvtpi32_pd(__m64 a) // does not support! It is supported on ARMv8-A however. FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a) { -#if defined(__aarch64__) +#if defined(__ARM_FEATURE_FRINT) + return vreinterpretq_m128i_s32(vcvtq_s32_f32(vrnd32xq_f32(a))); +#elif defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) switch (_MM_GET_ROUNDING_MODE()) { case _MM_ROUND_NEAREST: return vreinterpretq_m128i_s32(vcvtnq_s32_f32(a)); @@ -4029,7 +4255,7 @@ FORCE_INLINE __m128i _mm_cvtps_epi32(__m128 a) // dst[i+63:i] := Convert_FP32_To_FP64(a[k+31:k]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtps_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_pd FORCE_INLINE __m128d _mm_cvtps_pd(__m128 a) { #if defined(__aarch64__) @@ -4046,7 +4272,7 @@ FORCE_INLINE __m128d _mm_cvtps_pd(__m128 a) // // dst[63:0] := a[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_f64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsd_f64 FORCE_INLINE double _mm_cvtsd_f64(__m128d a) { #if defined(__aarch64__) @@ -4061,7 +4287,7 @@ FORCE_INLINE double _mm_cvtsd_f64(__m128d a) // // dst[31:0] := Convert_FP64_To_Int32(a[63:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsd_si32 FORCE_INLINE int32_t _mm_cvtsd_si32(__m128d a) { #if defined(__aarch64__) @@ -4078,7 +4304,7 @@ FORCE_INLINE int32_t _mm_cvtsd_si32(__m128d a) // // dst[63:0] := Convert_FP64_To_Int64(a[63:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsd_si64 FORCE_INLINE int64_t _mm_cvtsd_si64(__m128d a) { #if defined(__aarch64__) @@ -4095,14 +4321,14 @@ FORCE_INLINE int64_t _mm_cvtsd_si64(__m128d a) // // dst[63:0] := Convert_FP64_To_Int64(a[63:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_si64x +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsd_si64x #define _mm_cvtsd_si64x _mm_cvtsd_si64 // Convert the lower double-precision (64-bit) floating-point element in b to a // single-precision (32-bit) floating-point element, store the result in the // lower element of dst, and copy the upper 3 packed elements from a to the // upper elements of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsd_ss FORCE_INLINE __m128 _mm_cvtsd_ss(__m128 a, __m128d b) { #if defined(__aarch64__) @@ -4119,7 +4345,7 @@ FORCE_INLINE __m128 _mm_cvtsd_ss(__m128 a, __m128d b) // // dst[31:0] := a[31:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi128_si32 FORCE_INLINE int _mm_cvtsi128_si32(__m128i a) { return vgetq_lane_s32(vreinterpretq_s32_m128i(a), 0); @@ -4129,20 +4355,20 @@ FORCE_INLINE int _mm_cvtsi128_si32(__m128i a) // // dst[63:0] := a[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi128_si64 FORCE_INLINE int64_t _mm_cvtsi128_si64(__m128i a) { return vgetq_lane_s64(vreinterpretq_s64_m128i(a), 0); } // Copy the lower 64-bit integer in a to dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi128_si64x #define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a) // Convert the signed 32-bit integer b to a double-precision (64-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi32_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi32_sd FORCE_INLINE __m128d _mm_cvtsi32_sd(__m128d a, int32_t b) { #if defined(__aarch64__) @@ -4159,7 +4385,7 @@ FORCE_INLINE __m128d _mm_cvtsi32_sd(__m128d a, int32_t b) // // dst[63:0] := a[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi128_si64x +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi128_si64x #define _mm_cvtsi128_si64x(a) _mm_cvtsi128_si64(a) // Moves 32-bit integer a to the least significant 32 bits of an __m128 object, @@ -4179,7 +4405,7 @@ FORCE_INLINE __m128i _mm_cvtsi32_si128(int a) // Convert the signed 64-bit integer b to a double-precision (64-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi64_sd FORCE_INLINE __m128d _mm_cvtsi64_sd(__m128d a, int64_t b) { #if defined(__aarch64__) @@ -4204,13 +4430,13 @@ FORCE_INLINE __m128i _mm_cvtsi64_si128(int64_t a) // Copy 64-bit integer a to the lower element of dst, and zero the upper // element. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64x_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi64x_si128 #define _mm_cvtsi64x_si128(a) _mm_cvtsi64_si128(a) // Convert the signed 64-bit integer b to a double-precision (64-bit) // floating-point element, store the result in the lower element of dst, and // copy the upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsi64x_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtsi64x_sd #define _mm_cvtsi64x_sd(a, b) _mm_cvtsi64_sd(a, b) // Convert the lower single-precision (32-bit) floating-point element in b to a @@ -4221,7 +4447,7 @@ FORCE_INLINE __m128i _mm_cvtsi64_si128(int64_t a) // dst[63:0] := Convert_FP32_To_FP64(b[31:0]) // dst[127:64] := a[127:64] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtss_sd FORCE_INLINE __m128d _mm_cvtss_sd(__m128d a, __m128 b) { double d = (double) vgetq_lane_f32(vreinterpretq_f32_m128(b), 0); @@ -4236,7 +4462,7 @@ FORCE_INLINE __m128d _mm_cvtss_sd(__m128d a, __m128 b) // Convert packed double-precision (64-bit) floating-point elements in a to // packed 32-bit integers with truncation, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttpd_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttpd_epi32 FORCE_INLINE __m128i _mm_cvttpd_epi32(__m128d a) { double a0 = ((double *) &a)[0]; @@ -4246,7 +4472,7 @@ FORCE_INLINE __m128i _mm_cvttpd_epi32(__m128d a) // Convert packed double-precision (64-bit) floating-point elements in a to // packed 32-bit integers with truncation, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttpd_pi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttpd_pi32 FORCE_INLINE __m64 _mm_cvttpd_pi32(__m128d a) { double a0 = ((double *) &a)[0]; @@ -4268,7 +4494,7 @@ FORCE_INLINE __m128i _mm_cvttps_epi32(__m128 a) // // dst[63:0] := Convert_FP64_To_Int32_Truncate(a[63:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttsd_si32 FORCE_INLINE int32_t _mm_cvttsd_si32(__m128d a) { double ret = *((double *) &a); @@ -4280,7 +4506,7 @@ FORCE_INLINE int32_t _mm_cvttsd_si32(__m128d a) // // dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttsd_si64 FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a) { #if defined(__aarch64__) @@ -4296,7 +4522,7 @@ FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a) // // dst[63:0] := Convert_FP64_To_Int64_Truncate(a[63:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_si64x +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttsd_si64x #define _mm_cvttsd_si64x(a) _mm_cvttsd_si64(a) // Divide packed double-precision (64-bit) floating-point elements in a by @@ -4307,7 +4533,7 @@ FORCE_INLINE int64_t _mm_cvttsd_si64(__m128d a) // dst[i+63:i] := a[i+63:i] / b[i+63:i] // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_div_pd FORCE_INLINE __m128d _mm_div_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -4327,7 +4553,7 @@ FORCE_INLINE __m128d _mm_div_pd(__m128d a, __m128d b) // lower double-precision (64-bit) floating-point element in b, store the result // in the lower element of dst, and copy the upper element from a to the upper // element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_div_sd FORCE_INLINE __m128d _mm_div_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -4363,7 +4589,7 @@ FORCE_INLINE __m128d _mm_div_sd(__m128d a, __m128d b) // // dst[127:0] := MEM[mem_addr+127:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_load_pd FORCE_INLINE __m128d _mm_load_pd(const double *p) { #if defined(__aarch64__) @@ -4381,7 +4607,7 @@ FORCE_INLINE __m128d _mm_load_pd(const double *p) // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := MEM[mem_addr+63:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_pd1 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_load_pd1 #define _mm_load_pd1 _mm_load1_pd // Load a double-precision (64-bit) floating-point element from memory into the @@ -4391,7 +4617,7 @@ FORCE_INLINE __m128d _mm_load_pd(const double *p) // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := 0 // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_load_sd FORCE_INLINE __m128d _mm_load_sd(const double *p) { #if defined(__aarch64__) @@ -4416,7 +4642,7 @@ FORCE_INLINE __m128i _mm_load_si128(const __m128i *p) // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := MEM[mem_addr+63:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_load1_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_load1_pd FORCE_INLINE __m128d _mm_load1_pd(const double *p) { #if defined(__aarch64__) @@ -4433,7 +4659,7 @@ FORCE_INLINE __m128d _mm_load1_pd(const double *p) // dst[63:0] := a[63:0] // dst[127:64] := MEM[mem_addr+63:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadh_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadh_pd FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double *p) { #if defined(__aarch64__) @@ -4446,7 +4672,7 @@ FORCE_INLINE __m128d _mm_loadh_pd(__m128d a, const double *p) } // Load 64-bit integer from memory into the first element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_epi64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadl_epi64 FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p) { /* Load the lower 64 bits of the value pointed to by p into the @@ -4463,7 +4689,7 @@ FORCE_INLINE __m128i _mm_loadl_epi64(__m128i const *p) // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := a[127:64] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadl_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadl_pd FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double *p) { #if defined(__aarch64__) @@ -4483,7 +4709,7 @@ FORCE_INLINE __m128d _mm_loadl_pd(__m128d a, const double *p) // dst[63:0] := MEM[mem_addr+127:mem_addr+64] // dst[127:64] := MEM[mem_addr+63:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadr_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadr_pd FORCE_INLINE __m128d _mm_loadr_pd(const double *p) { #if defined(__aarch64__) @@ -4496,7 +4722,7 @@ FORCE_INLINE __m128d _mm_loadr_pd(const double *p) } // Loads two double-precision from unaligned memory, floating-point values. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadu_pd FORCE_INLINE __m128d _mm_loadu_pd(const double *p) { return _mm_load_pd(p); @@ -4514,7 +4740,7 @@ FORCE_INLINE __m128i _mm_loadu_si128(const __m128i *p) // dst[31:0] := MEM[mem_addr+31:mem_addr] // dst[MAX:32] := 0 // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loadu_si32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loadu_si32 FORCE_INLINE __m128i _mm_loadu_si32(const void *p) { return vreinterpretq_m128i_s32( @@ -4533,6 +4759,12 @@ FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) { int32x4_t low = vmull_s16(vget_low_s16(vreinterpretq_s16_m128i(a)), vget_low_s16(vreinterpretq_s16_m128i(b))); +#if defined(__aarch64__) + int32x4_t high = + vmull_high_s16(vreinterpretq_s16_m128i(a), vreinterpretq_s16_m128i(b)); + + return vreinterpretq_m128i_s32(vpaddq_s32(low, high)); +#else int32x4_t high = vmull_s16(vget_high_s16(vreinterpretq_s16_m128i(a)), vget_high_s16(vreinterpretq_s16_m128i(b))); @@ -4540,13 +4772,14 @@ FORCE_INLINE __m128i _mm_madd_epi16(__m128i a, __m128i b) int32x2_t high_sum = vpadd_s32(vget_low_s32(high), vget_high_s32(high)); return vreinterpretq_m128i_s32(vcombine_s32(low_sum, high_sum)); +#endif } // Conditionally store 8-bit integer elements from a into memory using mask // (elements are not stored when the highest bit is not set in the corresponding // element) and a non-temporal memory hint. mem_addr does not need to be aligned // on any particular boundary. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskmoveu_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maskmoveu_si128 FORCE_INLINE void _mm_maskmoveu_si128(__m128i a, __m128i mask, char *mem_addr) { int8x16_t shr_mask = vshrq_n_s8(vreinterpretq_s8_m128i(mask), 7); @@ -4577,12 +4810,18 @@ FORCE_INLINE __m128i _mm_max_epu8(__m128i a, __m128i b) // Compare packed double-precision (64-bit) floating-point elements in a and b, // and store packed maximum values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_pd FORCE_INLINE __m128d _mm_max_pd(__m128d a, __m128d b) { #if defined(__aarch64__) +#if SSE2NEON_PRECISE_MINMAX + float64x2_t _a = vreinterpretq_f64_m128d(a); + float64x2_t _b = vreinterpretq_f64_m128d(b); + return vreinterpretq_m128d_f64(vbslq_f64(vcgtq_f64(_a, _b), _a, _b)); +#else return vreinterpretq_m128d_f64( vmaxq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#endif #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); @@ -4599,7 +4838,7 @@ FORCE_INLINE __m128d _mm_max_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b, store the maximum value in the lower element of dst, and copy the upper // element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_sd FORCE_INLINE __m128d _mm_max_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -4607,8 +4846,8 @@ FORCE_INLINE __m128d _mm_max_sd(__m128d a, __m128d b) #else double *da = (double *) &a; double *db = (double *) &b; - double c[2] = {fmax(da[0], db[0]), da[1]}; - return vld1q_f32((float32_t *) c); + double c[2] = {da[0] > db[0] ? da[0] : db[0], da[1]}; + return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) c)); #endif } @@ -4632,12 +4871,18 @@ FORCE_INLINE __m128i _mm_min_epu8(__m128i a, __m128i b) // Compare packed double-precision (64-bit) floating-point elements in a and b, // and store packed minimum values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_min_pd FORCE_INLINE __m128d _mm_min_pd(__m128d a, __m128d b) { #if defined(__aarch64__) +#if SSE2NEON_PRECISE_MINMAX + float64x2_t _a = vreinterpretq_f64_m128d(a); + float64x2_t _b = vreinterpretq_f64_m128d(b); + return vreinterpretq_m128d_f64(vbslq_f64(vcltq_f64(_a, _b), _a, _b)); +#else return vreinterpretq_m128d_f64( vminq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b))); +#endif #else uint64_t a0 = (uint64_t) vget_low_u64(vreinterpretq_u64_m128d(a)); uint64_t a1 = (uint64_t) vget_high_u64(vreinterpretq_u64_m128d(a)); @@ -4653,7 +4898,7 @@ FORCE_INLINE __m128d _mm_min_pd(__m128d a, __m128d b) // Compare the lower double-precision (64-bit) floating-point elements in a and // b, store the minimum value in the lower element of dst, and copy the upper // element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_min_sd FORCE_INLINE __m128d _mm_min_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -4661,8 +4906,8 @@ FORCE_INLINE __m128d _mm_min_sd(__m128d a, __m128d b) #else double *da = (double *) &a; double *db = (double *) &b; - double c[2] = {fmin(da[0], db[0]), da[1]}; - return vld1q_f32((float32_t *) c); + double c[2] = {da[0] < db[0] ? da[0] : db[0], da[1]}; + return vreinterpretq_m128d_f32(vld1q_f32((float32_t *) c)); #endif } @@ -4672,7 +4917,7 @@ FORCE_INLINE __m128d _mm_min_sd(__m128d a, __m128d b) // dst[63:0] := a[63:0] // dst[127:64] := 0 // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_epi64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_move_epi64 FORCE_INLINE __m128i _mm_move_epi64(__m128i a) { return vreinterpretq_m128i_s64( @@ -4686,7 +4931,7 @@ FORCE_INLINE __m128i _mm_move_epi64(__m128i a) // dst[63:0] := b[63:0] // dst[127:64] := a[127:64] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_move_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_move_sd FORCE_INLINE __m128d _mm_move_sd(__m128d a, __m128d b) { return vreinterpretq_m128d_f32( @@ -4780,7 +5025,7 @@ FORCE_INLINE int _mm_movemask_epi8(__m128i a) // Set each bit of mask dst based on the most significant bit of the // corresponding packed double-precision (64-bit) floating-point element in a. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movemask_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_movemask_pd FORCE_INLINE int _mm_movemask_pd(__m128d a) { uint64x2_t input = vreinterpretq_u64_m128d(a); @@ -4792,7 +5037,7 @@ FORCE_INLINE int _mm_movemask_pd(__m128d a) // // dst[63:0] := a[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movepi64_pi64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_movepi64_pi64 FORCE_INLINE __m64 _mm_movepi64_pi64(__m128i a) { return vreinterpret_m64_s64(vget_low_s64(vreinterpretq_s64_m128i(a))); @@ -4804,7 +5049,7 @@ FORCE_INLINE __m64 _mm_movepi64_pi64(__m128i a) // dst[63:0] := a[63:0] // dst[127:64] := 0 // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movpi64_epi64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_movpi64_epi64 FORCE_INLINE __m128i _mm_movpi64_epi64(__m64 a) { return vreinterpretq_m128i_s64( @@ -4826,7 +5071,7 @@ FORCE_INLINE __m128i _mm_mul_epu32(__m128i a, __m128i b) // Multiply packed double-precision (64-bit) floating-point elements in a and b, // and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mul_pd FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -4845,7 +5090,7 @@ FORCE_INLINE __m128d _mm_mul_pd(__m128d a, __m128d b) // Multiply the lower double-precision (64-bit) floating-point element in a and // b, store the result in the lower element of dst, and copy the upper element // from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_mul_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=mm_mul_sd FORCE_INLINE __m128d _mm_mul_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_mul_pd(a, b)); @@ -4856,7 +5101,7 @@ FORCE_INLINE __m128d _mm_mul_sd(__m128d a, __m128d b) // // dst[63:0] := a[31:0] * b[31:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_su32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mul_su32 FORCE_INLINE __m64 _mm_mul_su32(__m64 a, __m64 b) { return vreinterpret_m64_u64(vget_low_u64( @@ -4892,7 +5137,7 @@ FORCE_INLINE __m128i _mm_mulhi_epi16(__m128i a, __m128i b) // Multiply the packed unsigned 16-bit integers in a and b, producing // intermediate 32-bit integers, and store the high 16 bits of the intermediate // integers in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhi_epu16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhi_epu16 FORCE_INLINE __m128i _mm_mulhi_epu16(__m128i a, __m128i b) { uint16x4_t a3210 = vget_low_u16(vreinterpretq_u16_m128i(a)); @@ -4931,7 +5176,7 @@ FORCE_INLINE __m128i _mm_mullo_epi16(__m128i a, __m128i b) // Compute the bitwise OR of packed double-precision (64-bit) floating-point // elements in a and b, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_or_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=mm_or_pd FORCE_INLINE __m128d _mm_or_pd(__m128d a, __m128d b) { return vreinterpretq_m128d_s64( @@ -5001,7 +5246,7 @@ FORCE_INLINE __m128i _mm_packus_epi16(const __m128i a, const __m128i b) // Pause the processor. This is typically used in spin-wait loops and depending // on the x86 processor typical values are in the 40-100 cycle range. The -// 'yield' instruction isn't a good fit beacuse it's effectively a nop on most +// 'yield' instruction isn't a good fit because it's effectively a nop on most // Arm cores. Experience with several databases has shown has shown an 'isb' is // a reasonable approximation. FORCE_INLINE void _mm_pause() @@ -5013,7 +5258,7 @@ FORCE_INLINE void _mm_pause() // b, then horizontally sum each consecutive 8 differences to produce two // unsigned 16-bit integers, and pack these unsigned 16-bit integers in the low // 16 bits of 64-bit elements in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sad_epu8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sad_epu8 FORCE_INLINE __m128i _mm_sad_epu8(__m128i a, __m128i b) { uint16x8_t t = vpaddlq_u8(vabdq_u8((uint8x16_t) a, (uint8x16_t) b)); @@ -5089,7 +5334,7 @@ FORCE_INLINE __m128i _mm_set_epi8(signed char b15, // Set packed double-precision (64-bit) floating-point elements in dst with the // supplied values. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_set_pd FORCE_INLINE __m128d _mm_set_pd(double e1, double e0) { double ALIGN_STRUCT(16) data[2] = {e0, e1}; @@ -5102,15 +5347,19 @@ FORCE_INLINE __m128d _mm_set_pd(double e1, double e0) // Broadcast double-precision (64-bit) floating-point value a to all elements of // dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_pd1 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_set_pd1 #define _mm_set_pd1 _mm_set1_pd // Copy double-precision (64-bit) floating-point element a to the lower element // of dst, and zero the upper element. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_set_sd FORCE_INLINE __m128d _mm_set_sd(double a) { +#if defined(__aarch64__) + return vreinterpretq_m128d_f64(vsetq_lane_f64(a, vdupq_n_f64(0), 0)); +#else return _mm_set_pd(0, a); +#endif } // Sets the 8 signed 16-bit integer values to w. @@ -5147,7 +5396,7 @@ FORCE_INLINE __m128i _mm_set1_epi64(__m64 _i) } // Sets the 2 signed 64-bit integer values to i. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_epi64x +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_set1_epi64x FORCE_INLINE __m128i _mm_set1_epi64x(int64_t _i) { return vreinterpretq_m128i_s64(vdupq_n_s64(_i)); @@ -5168,7 +5417,7 @@ FORCE_INLINE __m128i _mm_set1_epi8(signed char w) // Broadcast double-precision (64-bit) floating-point value a to all elements of // dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_set1_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_set1_pd FORCE_INLINE __m128d _mm_set1_pd(double d) { #if defined(__aarch64__) @@ -5207,7 +5456,7 @@ FORCE_INLINE __m128i _mm_setr_epi32(int i3, int i2, int i1, int i0) } // Set packed 64-bit integers in dst with the supplied values in reverse order. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_epi64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_setr_epi64 FORCE_INLINE __m128i _mm_setr_epi64(__m64 e1, __m64 e0) { return vreinterpretq_m128i_s64(vcombine_s64(e1, e0)); @@ -5242,14 +5491,14 @@ FORCE_INLINE __m128i _mm_setr_epi8(signed char b0, // Set packed double-precision (64-bit) floating-point elements in dst with the // supplied values in reverse order. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setr_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_setr_pd FORCE_INLINE __m128d _mm_setr_pd(double e1, double e0) { return _mm_set_pd(e0, e1); } // Return vector of type __m128d with all elements set to zero. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_setzero_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_setzero_pd FORCE_INLINE __m128d _mm_setzero_pd(void) { #if defined(__aarch64__) @@ -5270,14 +5519,14 @@ FORCE_INLINE __m128i _mm_setzero_si128(void) // https://msdn.microsoft.com/en-us/library/56f67xbk%28v=vs.90%29.aspx // FORCE_INLINE __m128i _mm_shuffle_epi32(__m128i a, // __constrange(0,255) int imm) -#if __has_builtin(__builtin_shufflevector) -#define _mm_shuffle_epi32(a, imm) \ - __extension__({ \ - int32x4_t _input = vreinterpretq_s32_m128i(a); \ - int32x4_t _shuf = __builtin_shufflevector( \ - _input, _input, (imm) & (0x3), ((imm) >> 2) & 0x3, \ - ((imm) >> 4) & 0x3, ((imm) >> 6) & 0x3); \ - vreinterpretq_m128i_s32(_shuf); \ +#ifdef _sse2neon_shuffle +#define _mm_shuffle_epi32(a, imm) \ + __extension__({ \ + int32x4_t _input = vreinterpretq_s32_m128i(a); \ + int32x4_t _shuf = \ + vshuffleq_s32(_input, _input, (imm) & (0x3), ((imm) >> 2) & 0x3, \ + ((imm) >> 4) & 0x3, ((imm) >> 6) & 0x3); \ + vreinterpretq_m128i_s32(_shuf); \ }) #else // generic #define _mm_shuffle_epi32(a, imm) \ @@ -5340,12 +5589,12 @@ FORCE_INLINE __m128i _mm_setzero_si128(void) // dst[63:0] := (imm8[0] == 0) ? a[63:0] : a[127:64] // dst[127:64] := (imm8[1] == 0) ? b[63:0] : b[127:64] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pd -#if __has_builtin(__builtin_shufflevector) -#define _mm_shuffle_pd(a, b, imm8) \ - vreinterpretq_m128d_s64(__builtin_shufflevector( \ - vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b), imm8 & 0x1, \ - ((imm8 & 0x2) >> 1) + 2)) +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_pd +#ifdef _sse2neon_shuffle +#define _mm_shuffle_pd(a, b, imm8) \ + vreinterpretq_m128d_s64( \ + vshuffleq_s64(vreinterpretq_s64_m128d(a), vreinterpretq_s64_m128d(b), \ + imm8 & 0x1, ((imm8 & 0x2) >> 1) + 2)) #else #define _mm_shuffle_pd(a, b, imm8) \ _mm_castsi128_pd(_mm_set_epi64x( \ @@ -5355,15 +5604,15 @@ FORCE_INLINE __m128i _mm_setzero_si128(void) // FORCE_INLINE __m128i _mm_shufflehi_epi16(__m128i a, // __constrange(0,255) int imm) -#if __has_builtin(__builtin_shufflevector) -#define _mm_shufflehi_epi16(a, imm) \ - __extension__({ \ - int16x8_t _input = vreinterpretq_s16_m128i(a); \ - int16x8_t _shuf = __builtin_shufflevector( \ - _input, _input, 0, 1, 2, 3, ((imm) & (0x3)) + 4, \ - (((imm) >> 2) & 0x3) + 4, (((imm) >> 4) & 0x3) + 4, \ - (((imm) >> 6) & 0x3) + 4); \ - vreinterpretq_m128i_s16(_shuf); \ +#ifdef _sse2neon_shuffle +#define _mm_shufflehi_epi16(a, imm) \ + __extension__({ \ + int16x8_t _input = vreinterpretq_s16_m128i(a); \ + int16x8_t _shuf = \ + vshuffleq_s16(_input, _input, 0, 1, 2, 3, ((imm) & (0x3)) + 4, \ + (((imm) >> 2) & 0x3) + 4, (((imm) >> 4) & 0x3) + 4, \ + (((imm) >> 6) & 0x3) + 4); \ + vreinterpretq_m128i_s16(_shuf); \ }) #else // generic #define _mm_shufflehi_epi16(a, imm) _mm_shufflehi_epi16_function((a), (imm)) @@ -5371,11 +5620,11 @@ FORCE_INLINE __m128i _mm_setzero_si128(void) // FORCE_INLINE __m128i _mm_shufflelo_epi16(__m128i a, // __constrange(0,255) int imm) -#if __has_builtin(__builtin_shufflevector) +#ifdef _sse2neon_shuffle #define _mm_shufflelo_epi16(a, imm) \ __extension__({ \ int16x8_t _input = vreinterpretq_s16_m128i(a); \ - int16x8_t _shuf = __builtin_shufflevector( \ + int16x8_t _shuf = vshuffleq_s16( \ _input, _input, ((imm) & (0x3)), (((imm) >> 2) & 0x3), \ (((imm) >> 4) & 0x3), (((imm) >> 6) & 0x3), 4, 5, 6, 7); \ vreinterpretq_m128i_s16(_shuf); \ @@ -5396,7 +5645,7 @@ FORCE_INLINE __m128i _mm_setzero_si128(void) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sll_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sll_epi16 FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); @@ -5419,7 +5668,7 @@ FORCE_INLINE __m128i _mm_sll_epi16(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sll_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sll_epi32 FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); @@ -5442,7 +5691,7 @@ FORCE_INLINE __m128i _mm_sll_epi32(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sll_epi64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sll_epi64 FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); @@ -5465,7 +5714,7 @@ FORCE_INLINE __m128i _mm_sll_epi64(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_slli_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_slli_epi16 FORCE_INLINE __m128i _mm_slli_epi16(__m128i a, int imm) { if (_sse2neon_unlikely(imm & ~15)) @@ -5486,7 +5735,7 @@ FORCE_INLINE __m128i _mm_slli_epi16(__m128i a, int imm) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_slli_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_slli_epi32 FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int imm) { if (_sse2neon_unlikely(imm & ~31)) @@ -5507,7 +5756,7 @@ FORCE_INLINE __m128i _mm_slli_epi32(__m128i a, int imm) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_slli_epi64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_slli_epi64 FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int imm) { if (_sse2neon_unlikely(imm & ~63)) @@ -5525,19 +5774,23 @@ FORCE_INLINE __m128i _mm_slli_epi64(__m128i a, int imm) // FI // dst[127:0] := a[127:0] << (tmp*8) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_slli_si128 -FORCE_INLINE __m128i _mm_slli_si128(__m128i a, int imm) -{ - if (_sse2neon_unlikely(imm & ~15)) - return _mm_setzero_si128(); - uint8x16_t tmp[2] = {vdupq_n_u8(0), vreinterpretq_u8_m128i(a)}; - return vreinterpretq_m128i_u8( - vld1q_u8(((uint8_t const *) tmp) + (16 - imm))); -} +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_slli_si128 +#define _mm_slli_si128(a, imm) \ + __extension__({ \ + int8x16_t ret; \ + if (_sse2neon_unlikely(imm == 0)) \ + ret = vreinterpretq_s8_m128i(a); \ + else if (_sse2neon_unlikely((imm) & ~15)) \ + ret = vdupq_n_s8(0); \ + else \ + ret = vextq_s8(vdupq_n_s8(0), vreinterpretq_s8_m128i(a), \ + ((imm <= 0 || imm > 15) ? 0 : (16 - imm))); \ + vreinterpretq_m128i_s8(ret); \ + }) // Compute the square root of packed double-precision (64-bit) floating-point // elements in a, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sqrt_pd FORCE_INLINE __m128d _mm_sqrt_pd(__m128d a) { #if defined(__aarch64__) @@ -5552,7 +5805,7 @@ FORCE_INLINE __m128d _mm_sqrt_pd(__m128d a) // Compute the square root of the lower double-precision (64-bit) floating-point // element in b, store the result in the lower element of dst, and copy the // upper element from a to the upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sqrt_sd FORCE_INLINE __m128d _mm_sqrt_sd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -5574,7 +5827,7 @@ FORCE_INLINE __m128d _mm_sqrt_sd(__m128d a, __m128d b) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sra_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sra_epi16 FORCE_INLINE __m128i _mm_sra_epi16(__m128i a, __m128i count) { int64_t c = (int64_t) vget_low_s64((int64x2_t) count); @@ -5595,7 +5848,7 @@ FORCE_INLINE __m128i _mm_sra_epi16(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sra_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sra_epi32 FORCE_INLINE __m128i _mm_sra_epi32(__m128i a, __m128i count) { int64_t c = (int64_t) vget_low_s64((int64x2_t) count); @@ -5616,7 +5869,7 @@ FORCE_INLINE __m128i _mm_sra_epi32(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srai_epi16 FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm) { const int count = (imm & ~15) ? 15 : imm; @@ -5635,21 +5888,21 @@ FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srai_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srai_epi32 // FORCE_INLINE __m128i _mm_srai_epi32(__m128i a, __constrange(0,255) int imm) -#define _mm_srai_epi32(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (_sse2neon_unlikely((imm) == 0)) { \ - ret = a; \ - } else if (_sse2neon_likely(0 < (imm) && (imm) < 32)) { \ - ret = vreinterpretq_m128i_s32( \ - vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(-imm))); \ - } else { \ - ret = vreinterpretq_m128i_s32( \ - vshrq_n_s32(vreinterpretq_s32_m128i(a), 31)); \ - } \ - ret; \ +#define _mm_srai_epi32(a, imm) \ + __extension__({ \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) == 0)) { \ + ret = a; \ + } else if (_sse2neon_likely(0 < (imm) && (imm) < 32)) { \ + ret = vreinterpretq_m128i_s32( \ + vshlq_s32(vreinterpretq_s32_m128i(a), vdupq_n_s32(-(imm)))); \ + } else { \ + ret = vreinterpretq_m128i_s32( \ + vshrq_n_s32(vreinterpretq_s32_m128i(a), 31)); \ + } \ + ret; \ }) // Shift packed 16-bit integers in a right by count while shifting in zeros, and @@ -5664,7 +5917,7 @@ FORCE_INLINE __m128i _mm_srai_epi16(__m128i a, int imm) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srl_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srl_epi16 FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); @@ -5687,7 +5940,7 @@ FORCE_INLINE __m128i _mm_srl_epi16(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srl_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srl_epi32 FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); @@ -5710,7 +5963,7 @@ FORCE_INLINE __m128i _mm_srl_epi32(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srl_epi64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srl_epi64 FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) { uint64_t c = vreinterpretq_nth_u64_m128i(count, 0); @@ -5733,17 +5986,17 @@ FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi16 -#define _mm_srli_epi16(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (_sse2neon_unlikely(imm & ~15)) { \ - ret = _mm_setzero_si128(); \ - } else { \ - ret = vreinterpretq_m128i_u16( \ - vshlq_u16(vreinterpretq_u16_m128i(a), vdupq_n_s16(-imm))); \ - } \ - ret; \ +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srli_epi16 +#define _mm_srli_epi16(a, imm) \ + __extension__({ \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) & ~15)) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_u16( \ + vshlq_u16(vreinterpretq_u16_m128i(a), vdupq_n_s16(-(imm)))); \ + } \ + ret; \ }) // Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and @@ -5758,18 +6011,18 @@ FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srli_epi32 // FORCE_INLINE __m128i _mm_srli_epi32(__m128i a, __constrange(0,255) int imm) -#define _mm_srli_epi32(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (_sse2neon_unlikely(imm & ~31)) { \ - ret = _mm_setzero_si128(); \ - } else { \ - ret = vreinterpretq_m128i_u32( \ - vshlq_u32(vreinterpretq_u32_m128i(a), vdupq_n_s32(-imm))); \ - } \ - ret; \ +#define _mm_srli_epi32(a, imm) \ + __extension__({ \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) & ~31)) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_u32( \ + vshlq_u32(vreinterpretq_u32_m128i(a), vdupq_n_s32(-(imm)))); \ + } \ + ret; \ }) // Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and @@ -5784,17 +6037,17 @@ FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_epi64 -#define _mm_srli_epi64(a, imm) \ - __extension__({ \ - __m128i ret; \ - if (_sse2neon_unlikely(imm & ~63)) { \ - ret = _mm_setzero_si128(); \ - } else { \ - ret = vreinterpretq_m128i_u64( \ - vshlq_u64(vreinterpretq_u64_m128i(a), vdupq_n_s64(-imm))); \ - } \ - ret; \ +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srli_epi64 +#define _mm_srli_epi64(a, imm) \ + __extension__({ \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) & ~63)) { \ + ret = _mm_setzero_si128(); \ + } else { \ + ret = vreinterpretq_m128i_u64( \ + vshlq_u64(vreinterpretq_u64_m128i(a), vdupq_n_s64(-(imm)))); \ + } \ + ret; \ }) // Shift a right by imm8 bytes while shifting in zeros, and store the results in @@ -5806,19 +6059,22 @@ FORCE_INLINE __m128i _mm_srl_epi64(__m128i a, __m128i count) // FI // dst[127:0] := a[127:0] >> (tmp*8) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_srli_si128 -FORCE_INLINE __m128i _mm_srli_si128(__m128i a, int imm) -{ - if (_sse2neon_unlikely(imm & ~15)) - return _mm_setzero_si128(); - uint8x16_t tmp[2] = {vreinterpretq_u8_m128i(a), vdupq_n_u8(0)}; - return vreinterpretq_m128i_u8(vld1q_u8(((uint8_t const *) tmp) + imm)); -} +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_srli_si128 +#define _mm_srli_si128(a, imm) \ + __extension__({ \ + int8x16_t ret; \ + if (_sse2neon_unlikely((imm) & ~15)) \ + ret = vdupq_n_s8(0); \ + else \ + ret = vextq_s8(vreinterpretq_s8_m128i(a), vdupq_n_s8(0), \ + (imm > 15 ? 0 : imm)); \ + vreinterpretq_m128i_s8(ret); \ + }) // Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point // elements) from a into memory. mem_addr must be aligned on a 16-byte boundary // or a general-protection exception may be generated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_store_pd FORCE_INLINE void _mm_store_pd(double *mem_addr, __m128d a) { #if defined(__aarch64__) @@ -5831,7 +6087,7 @@ FORCE_INLINE void _mm_store_pd(double *mem_addr, __m128d a) // Store the lower double-precision (64-bit) floating-point element from a into // 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte // boundary or a general-protection exception may be generated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_store_pd1 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_store_pd1 FORCE_INLINE void _mm_store_pd1(double *mem_addr, __m128d a) { #if defined(__aarch64__) @@ -5847,7 +6103,7 @@ FORCE_INLINE void _mm_store_pd1(double *mem_addr, __m128d a) // Store the lower double-precision (64-bit) floating-point element from a into // memory. mem_addr does not need to be aligned on any particular boundary. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_store_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=mm_store_sd FORCE_INLINE void _mm_store_sd(double *mem_addr, __m128d a) { #if defined(__aarch64__) @@ -5867,7 +6123,7 @@ FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a) // Store the lower double-precision (64-bit) floating-point element from a into // 2 contiguous elements in memory. mem_addr must be aligned on a 16-byte // boundary or a general-protection exception may be generated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=9,526,5601&text=_mm_store1_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#expand=9,526,5601&text=_mm_store1_pd #define _mm_store1_pd _mm_store_pd1 // Store the upper double-precision (64-bit) floating-point element from a into @@ -5875,7 +6131,7 @@ FORCE_INLINE void _mm_store_si128(__m128i *p, __m128i a) // // MEM[mem_addr+63:mem_addr] := a[127:64] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeh_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storeh_pd FORCE_INLINE void _mm_storeh_pd(double *mem_addr, __m128d a) { #if defined(__aarch64__) @@ -5889,9 +6145,7 @@ FORCE_INLINE void _mm_storeh_pd(double *mem_addr, __m128d a) // https://msdn.microsoft.com/en-us/library/hhwf428f%28v=vs.90%29.aspx FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b) { - uint64x1_t hi = vget_high_u64(vreinterpretq_u64_m128i(*a)); - uint64x1_t lo = vget_low_u64(vreinterpretq_u64_m128i(b)); - *a = vreinterpretq_m128i_u64(vcombine_u64(lo, hi)); + vst1_u64((uint64_t *) a, vget_low_u64(vreinterpretq_u64_m128i(b))); } // Store the lower double-precision (64-bit) floating-point element from a into @@ -5899,7 +6153,7 @@ FORCE_INLINE void _mm_storel_epi64(__m128i *a, __m128i b) // // MEM[mem_addr+63:mem_addr] := a[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storel_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storel_pd FORCE_INLINE void _mm_storel_pd(double *mem_addr, __m128d a) { #if defined(__aarch64__) @@ -5916,7 +6170,7 @@ FORCE_INLINE void _mm_storel_pd(double *mem_addr, __m128d a) // MEM[mem_addr+63:mem_addr] := a[127:64] // MEM[mem_addr+127:mem_addr+64] := a[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storer_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storer_pd FORCE_INLINE void _mm_storer_pd(double *mem_addr, __m128d a) { float32x4_t f = vreinterpretq_f32_m128d(a); @@ -5926,21 +6180,21 @@ FORCE_INLINE void _mm_storer_pd(double *mem_addr, __m128d a) // Store 128-bits (composed of 2 packed double-precision (64-bit) floating-point // elements) from a into memory. mem_addr does not need to be aligned on any // particular boundary. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storeu_pd FORCE_INLINE void _mm_storeu_pd(double *mem_addr, __m128d a) { _mm_store_pd(mem_addr, a); } // Stores 128-bits of integer data a at the address p. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storeu_si128 FORCE_INLINE void _mm_storeu_si128(__m128i *p, __m128i a) { vst1q_s32((int32_t *) p, vreinterpretq_s32_m128i(a)); } // Stores 32-bits of integer data a at the address p. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_storeu_si32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_storeu_si32 FORCE_INLINE void _mm_storeu_si32(void *p, __m128i a) { vst1q_lane_s32((int32_t *) p, vreinterpretq_s32_m128i(a), 0); @@ -5950,11 +6204,11 @@ FORCE_INLINE void _mm_storeu_si32(void *p, __m128i a) // elements) from a into memory using a non-temporal memory hint. mem_addr must // be aligned on a 16-byte boundary or a general-protection exception may be // generated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_stream_pd FORCE_INLINE void _mm_stream_pd(double *p, __m128d a) { #if __has_builtin(__builtin_nontemporal_store) - __builtin_nontemporal_store(a, (float32x4_t *) p); + __builtin_nontemporal_store(reinterpret_cast<float32x4_t>(a), (float32x4_t *) p); #elif defined(__aarch64__) vst1q_f64(p, vreinterpretq_f64_m128d(a)); #else @@ -5978,15 +6232,24 @@ FORCE_INLINE void _mm_stream_si128(__m128i *p, __m128i a) // Store 32-bit integer a into memory using a non-temporal hint to minimize // cache pollution. If the cache line containing address mem_addr is already in // the cache, the cache will be updated. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_si32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_stream_si32 FORCE_INLINE void _mm_stream_si32(int *p, int a) { vst1q_lane_s32((int32_t *) p, vdupq_n_s32(a), 0); } +// Store 64-bit integer a into memory using a non-temporal hint to minimize +// cache pollution. If the cache line containing address mem_addr is already in +// the cache, the cache will be updated. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_stream_si64 +FORCE_INLINE void _mm_stream_si64(__int64 *p, __int64 a) +{ + vst1_s64((int64_t *) p, vdup_n_s64((int64_t) a)); +} + // Subtract packed 16-bit integers in b from packed 16-bit integers in a, and // store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sub_epi16 FORCE_INLINE __m128i _mm_sub_epi16(__m128i a, __m128i b) { return vreinterpretq_m128i_s16( @@ -6020,7 +6283,7 @@ FORCE_INLINE __m128i _mm_sub_epi64(__m128i a, __m128i b) // Subtract packed 8-bit integers in b from packed 8-bit integers in a, and // store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_epi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sub_epi8 FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( @@ -6036,7 +6299,7 @@ FORCE_INLINE __m128i _mm_sub_epi8(__m128i a, __m128i b) // dst[i+63:i] := a[i+63:i] - b[i+63:i] // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_sub_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=mm_sub_pd FORCE_INLINE __m128d _mm_sub_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -6056,7 +6319,7 @@ FORCE_INLINE __m128d _mm_sub_pd(__m128d a, __m128d b) // the lower double-precision (64-bit) floating-point element in a, store the // result in the lower element of dst, and copy the upper element from a to the // upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sub_sd FORCE_INLINE __m128d _mm_sub_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_sub_pd(a, b)); @@ -6066,7 +6329,7 @@ FORCE_INLINE __m128d _mm_sub_sd(__m128d a, __m128d b) // // dst[63:0] := a[63:0] - b[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_si64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sub_si64 FORCE_INLINE __m64 _mm_sub_si64(__m64 a, __m64 b) { return vreinterpret_m64_s64( @@ -6135,7 +6398,7 @@ FORCE_INLINE __m128i _mm_subs_epu8(__m128i a, __m128i b) #define _mm_ucomineq_sd _mm_comineq_sd // Return vector of type __m128d with undefined elements. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_undefined_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_undefined_pd FORCE_INLINE __m128d _mm_undefined_pd(void) { #if defined(__GNUC__) || defined(__clang__) @@ -6240,7 +6503,7 @@ FORCE_INLINE __m128i _mm_unpackhi_epi8(__m128i a, __m128i b) // } // dst[127:0] := INTERLEAVE_HIGH_QWORDS(a[127:0], b[127:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpackhi_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_unpackhi_pd FORCE_INLINE __m128d _mm_unpackhi_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -6343,7 +6606,7 @@ FORCE_INLINE __m128i _mm_unpacklo_epi8(__m128i a, __m128i b) // } // dst[127:0] := INTERLEAVE_QWORDS(a[127:0], b[127:0]) // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_unpacklo_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_unpacklo_pd FORCE_INLINE __m128d _mm_unpacklo_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -6364,7 +6627,7 @@ FORCE_INLINE __m128d _mm_unpacklo_pd(__m128d a, __m128d b) // dst[i+63:i] := a[i+63:i] XOR b[i+63:i] // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_xor_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_xor_pd FORCE_INLINE __m128d _mm_xor_pd(__m128d a, __m128d b) { return vreinterpretq_m128d_s64( @@ -6394,10 +6657,10 @@ FORCE_INLINE __m128i _mm_xor_si128(__m128i a, __m128i b) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_addsub_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_addsub_pd FORCE_INLINE __m128d _mm_addsub_pd(__m128d a, __m128d b) { - __m128d mask = _mm_set_pd(1.0f, -1.0f); + _sse2neon_const __m128d mask = _mm_set_pd(1.0f, -1.0f); #if defined(__aarch64__) return vreinterpretq_m128d_f64(vfmaq_f64(vreinterpretq_f64_m128d(a), vreinterpretq_f64_m128d(b), @@ -6410,10 +6673,10 @@ FORCE_INLINE __m128d _mm_addsub_pd(__m128d a, __m128d b) // Alternatively add and subtract packed single-precision (32-bit) // floating-point elements in a to/from packed elements in b, and store the // results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=addsub_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=addsub_ps FORCE_INLINE __m128 _mm_addsub_ps(__m128 a, __m128 b) { - __m128 mask = {-1.0f, 1.0f, -1.0f, 1.0f}; + _sse2neon_const __m128 mask = _mm_setr_ps(-1.0f, 1.0f, -1.0f, 1.0f); #if defined(__aarch64__) || defined(__ARM_FEATURE_FMA) /* VFPv4+ */ return vreinterpretq_m128_f32(vfmaq_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(mask), @@ -6425,7 +6688,7 @@ FORCE_INLINE __m128 _mm_addsub_ps(__m128 a, __m128 b) // Horizontally add adjacent pairs of double-precision (64-bit) floating-point // elements in a and b, and pack the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hadd_pd FORCE_INLINE __m128d _mm_hadd_pd(__m128d a, __m128d b) { #if defined(__aarch64__) @@ -6459,13 +6722,14 @@ FORCE_INLINE __m128 _mm_hadd_ps(__m128 a, __m128 b) // Horizontally subtract adjacent pairs of double-precision (64-bit) // floating-point elements in a and b, and pack the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hsub_pd FORCE_INLINE __m128d _mm_hsub_pd(__m128d _a, __m128d _b) { #if defined(__aarch64__) - return vreinterpretq_m128d_f64(vsubq_f64( - vuzp1q_f64(vreinterpretq_f64_m128d(_a), vreinterpretq_f64_m128d(_b)), - vuzp2q_f64(vreinterpretq_f64_m128d(_a), vreinterpretq_f64_m128d(_b)))); + float64x2_t a = vreinterpretq_f64_m128d(_a); + float64x2_t b = vreinterpretq_f64_m128d(_b); + return vreinterpretq_m128d_f64( + vsubq_f64(vuzp1q_f64(a, b), vuzp2q_f64(a, b))); #else double *da = (double *) &_a; double *db = (double *) &_b; @@ -6474,18 +6738,18 @@ FORCE_INLINE __m128d _mm_hsub_pd(__m128d _a, __m128d _b) #endif } -// Horizontally substract adjacent pairs of single-precision (32-bit) +// Horizontally subtract adjacent pairs of single-precision (32-bit) // floating-point elements in a and b, and pack the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hsub_ps FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b) { + float32x4_t a = vreinterpretq_f32_m128(_a); + float32x4_t b = vreinterpretq_f32_m128(_b); #if defined(__aarch64__) - return vreinterpretq_m128_f32(vsubq_f32( - vuzp1q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)), - vuzp2q_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)))); + return vreinterpretq_m128_f32( + vsubq_f32(vuzp1q_f32(a, b), vuzp2q_f32(a, b))); #else - float32x4x2_t c = - vuzpq_f32(vreinterpretq_f32_m128(_a), vreinterpretq_f32_m128(_b)); + float32x4x2_t c = vuzpq_f32(a, b); return vreinterpretq_m128_f32(vsubq_f32(c.val[0], c.val[1])); #endif } @@ -6496,7 +6760,7 @@ FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b) // // dst[127:0] := MEM[mem_addr+127:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_lddqu_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_lddqu_si128 #define _mm_lddqu_si128 _mm_loadu_si128 // Load a double-precision (64-bit) floating-point element from memory into both @@ -6505,15 +6769,15 @@ FORCE_INLINE __m128 _mm_hsub_ps(__m128 _a, __m128 _b) // dst[63:0] := MEM[mem_addr+63:mem_addr] // dst[127:64] := MEM[mem_addr+63:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_loaddup_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_loaddup_pd #define _mm_loaddup_pd _mm_load1_pd // Duplicate the low double-precision (64-bit) floating-point element from a, // and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movedup_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_movedup_pd FORCE_INLINE __m128d _mm_movedup_pd(__m128d a) { -#if (__aarch64__) +#if defined(__aarch64__) return vreinterpretq_m128d_f64( vdupq_laneq_f64(vreinterpretq_f64_m128d(a), 0)); #else @@ -6524,11 +6788,14 @@ FORCE_INLINE __m128d _mm_movedup_pd(__m128d a) // Duplicate odd-indexed single-precision (32-bit) floating-point elements // from a, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_movehdup_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_movehdup_ps FORCE_INLINE __m128 _mm_movehdup_ps(__m128 a) { -#if __has_builtin(__builtin_shufflevector) - return vreinterpretq_m128_f32(__builtin_shufflevector( +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vtrn2q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a))); +#elif defined(_sse2neon_shuffle) + return vreinterpretq_m128_f32(vshuffleq_s32( vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 1, 1, 3, 3)); #else float32_t a1 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 1); @@ -6540,11 +6807,14 @@ FORCE_INLINE __m128 _mm_movehdup_ps(__m128 a) // Duplicate even-indexed single-precision (32-bit) floating-point elements // from a, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_moveldup_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_moveldup_ps FORCE_INLINE __m128 _mm_moveldup_ps(__m128 a) { -#if __has_builtin(__builtin_shufflevector) - return vreinterpretq_m128_f32(__builtin_shufflevector( +#if defined(__aarch64__) + return vreinterpretq_m128_f32( + vtrn1q_f32(vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a))); +#elif defined(_sse2neon_shuffle) + return vreinterpretq_m128_f32(vshuffleq_s32( vreinterpretq_f32_m128(a), vreinterpretq_f32_m128(a), 0, 0, 2, 2)); #else float32_t a0 = vgetq_lane_f32(vreinterpretq_f32_m128(a), 0); @@ -6564,7 +6834,7 @@ FORCE_INLINE __m128 _mm_moveldup_ps(__m128 a) // dst[i+15:i] := ABS(a[i+15:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_abs_epi16 FORCE_INLINE __m128i _mm_abs_epi16(__m128i a) { return vreinterpretq_m128i_s16(vabsq_s16(vreinterpretq_s16_m128i(a))); @@ -6578,7 +6848,7 @@ FORCE_INLINE __m128i _mm_abs_epi16(__m128i a) // dst[i+31:i] := ABS(a[i+31:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_abs_epi32 FORCE_INLINE __m128i _mm_abs_epi32(__m128i a) { return vreinterpretq_m128i_s32(vabsq_s32(vreinterpretq_s32_m128i(a))); @@ -6592,7 +6862,7 @@ FORCE_INLINE __m128i _mm_abs_epi32(__m128i a) // dst[i+7:i] := ABS(a[i+7:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_epi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_abs_epi8 FORCE_INLINE __m128i _mm_abs_epi8(__m128i a) { return vreinterpretq_m128i_s8(vabsq_s8(vreinterpretq_s8_m128i(a))); @@ -6606,7 +6876,7 @@ FORCE_INLINE __m128i _mm_abs_epi8(__m128i a) // dst[i+15:i] := ABS(a[i+15:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_abs_pi16 FORCE_INLINE __m64 _mm_abs_pi16(__m64 a) { return vreinterpret_m64_s16(vabs_s16(vreinterpret_s16_m64(a))); @@ -6620,7 +6890,7 @@ FORCE_INLINE __m64 _mm_abs_pi16(__m64 a) // dst[i+31:i] := ABS(a[i+31:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_abs_pi32 FORCE_INLINE __m64 _mm_abs_pi32(__m64 a) { return vreinterpret_m64_s32(vabs_s32(vreinterpret_s32_m64(a))); @@ -6634,7 +6904,7 @@ FORCE_INLINE __m64 _mm_abs_pi32(__m64 a) // dst[i+7:i] := ABS(a[i+7:i]) // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_abs_pi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_abs_pi8 FORCE_INLINE __m64 _mm_abs_pi8(__m64 a) { return vreinterpret_m64_s8(vabs_s8(vreinterpret_s8_m64(a))); @@ -6646,24 +6916,21 @@ FORCE_INLINE __m64 _mm_abs_pi8(__m64 a) // tmp[255:0] := ((a[127:0] << 128)[255:0] OR b[127:0]) >> (imm8*8) // dst[127:0] := tmp[127:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_epi8 -FORCE_INLINE __m128i _mm_alignr_epi8(__m128i a, __m128i b, int imm) -{ - if (_sse2neon_unlikely(imm & ~31)) - return _mm_setzero_si128(); - int idx; - uint8x16_t tmp[2]; - if (imm >= 16) { - idx = imm - 16; - tmp[0] = vreinterpretq_u8_m128i(a); - tmp[1] = vdupq_n_u8(0); - } else { - idx = imm; - tmp[0] = vreinterpretq_u8_m128i(b); - tmp[1] = vreinterpretq_u8_m128i(a); - } - return vreinterpretq_m128i_u8(vld1q_u8(((uint8_t const *) tmp) + idx)); -} +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_alignr_epi8 +#define _mm_alignr_epi8(a, b, imm) \ + __extension__({ \ + uint8x16_t _a = vreinterpretq_u8_m128i(a); \ + uint8x16_t _b = vreinterpretq_u8_m128i(b); \ + __m128i ret; \ + if (_sse2neon_unlikely((imm) & ~31)) \ + ret = vreinterpretq_m128i_u8(vdupq_n_u8(0)); \ + else if (imm >= 16) \ + ret = _mm_srli_si128(a, imm >= 16 ? imm - 16 : 0); \ + else \ + ret = \ + vreinterpretq_m128i_u8(vextq_u8(_b, _a, imm < 16 ? imm : 0)); \ + ret; \ + }) // Concatenate 8-byte blocks in a and b into a 16-byte temporary result, shift // the result right by imm8 bytes, and store the low 8 bytes in dst. @@ -6671,7 +6938,7 @@ FORCE_INLINE __m128i _mm_alignr_epi8(__m128i a, __m128i b, int imm) // tmp[127:0] := ((a[63:0] << 64)[127:0] OR b[63:0]) >> (imm8*8) // dst[63:0] := tmp[63:0] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_alignr_pi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_alignr_pi8 #define _mm_alignr_pi8(a, b, imm) \ __extension__({ \ __m64 ret; \ @@ -6679,13 +6946,13 @@ FORCE_INLINE __m128i _mm_alignr_epi8(__m128i a, __m128i b, int imm) ret = vreinterpret_m64_s8(vdup_n_s8(0)); \ } else { \ uint8x8_t tmp_low, tmp_high; \ - if (imm >= 8) { \ - const int idx = imm - 8; \ + if ((imm) >= 8) { \ + const int idx = (imm) -8; \ tmp_low = vreinterpret_u8_m64(a); \ tmp_high = vdup_n_u8(0); \ ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \ } else { \ - const int idx = imm; \ + const int idx = (imm); \ tmp_low = vreinterpret_u8_m64(b); \ tmp_high = vreinterpret_u8_m64(a); \ ret = vreinterpret_m64_u8(vext_u8(tmp_low, tmp_high, idx)); \ @@ -6715,14 +6982,18 @@ FORCE_INLINE __m128i _mm_hadd_epi32(__m128i _a, __m128i _b) { int32x4_t a = vreinterpretq_s32_m128i(_a); int32x4_t b = vreinterpretq_s32_m128i(_b); +#if defined(__aarch64__) + return vreinterpretq_m128i_s32(vpaddq_s32(a, b)); +#else return vreinterpretq_m128i_s32( vcombine_s32(vpadd_s32(vget_low_s32(a), vget_high_s32(a)), vpadd_s32(vget_low_s32(b), vget_high_s32(b)))); +#endif } // Horizontally add adjacent pairs of 16-bit integers in a and b, and pack the // signed 16-bit results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hadd_pi16 FORCE_INLINE __m64 _mm_hadd_pi16(__m64 a, __m64 b) { return vreinterpret_m64_s16( @@ -6731,7 +7002,7 @@ FORCE_INLINE __m64 _mm_hadd_pi16(__m64 a, __m64 b) // Horizontally add adjacent pairs of 32-bit integers in a and b, and pack the // signed 32-bit results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadd_pi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hadd_pi32 FORCE_INLINE __m64 _mm_hadd_pi32(__m64 a, __m64 b) { return vreinterpret_m64_s32( @@ -6762,7 +7033,7 @@ FORCE_INLINE __m128i _mm_hadds_epi16(__m128i _a, __m128i _b) // Horizontally add adjacent pairs of signed 16-bit integers in a and b using // saturation, and pack the signed 16-bit results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hadds_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hadds_pi16 FORCE_INLINE __m64 _mm_hadds_pi16(__m64 _a, __m64 _b) { int16x4_t a = vreinterpret_s16_m64(_a); @@ -6775,101 +7046,96 @@ FORCE_INLINE __m64 _mm_hadds_pi16(__m64 _a, __m64 _b) #endif } -// Computes pairwise difference of each argument as a 16-bit signed or unsigned -// integer values a and b. +// Horizontally subtract adjacent pairs of 16-bit integers in a and b, and pack +// the signed 16-bit results in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hsub_epi16 FORCE_INLINE __m128i _mm_hsub_epi16(__m128i _a, __m128i _b) { - int32x4_t a = vreinterpretq_s32_m128i(_a); - int32x4_t b = vreinterpretq_s32_m128i(_b); - // Interleave using vshrn/vmovn - // [a0|a2|a4|a6|b0|b2|b4|b6] - // [a1|a3|a5|a7|b1|b3|b5|b7] - int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); - int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); - // Subtract - return vreinterpretq_m128i_s16(vsubq_s16(ab0246, ab1357)); + int16x8_t a = vreinterpretq_s16_m128i(_a); + int16x8_t b = vreinterpretq_s16_m128i(_b); +#if defined(__aarch64__) + return vreinterpretq_m128i_s16( + vsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); +#else + int16x8x2_t c = vuzpq_s16(a, b); + return vreinterpretq_m128i_s16(vsubq_s16(c.val[0], c.val[1])); +#endif } -// Computes pairwise difference of each argument as a 32-bit signed or unsigned -// integer values a and b. +// Horizontally subtract adjacent pairs of 32-bit integers in a and b, and pack +// the signed 32-bit results in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hsub_epi32 FORCE_INLINE __m128i _mm_hsub_epi32(__m128i _a, __m128i _b) { - int64x2_t a = vreinterpretq_s64_m128i(_a); - int64x2_t b = vreinterpretq_s64_m128i(_b); - // Interleave using vshrn/vmovn - // [a0|a2|b0|b2] - // [a1|a2|b1|b3] - int32x4_t ab02 = vcombine_s32(vmovn_s64(a), vmovn_s64(b)); - int32x4_t ab13 = vcombine_s32(vshrn_n_s64(a, 32), vshrn_n_s64(b, 32)); - // Subtract - return vreinterpretq_m128i_s32(vsubq_s32(ab02, ab13)); + int32x4_t a = vreinterpretq_s32_m128i(_a); + int32x4_t b = vreinterpretq_s32_m128i(_b); +#if defined(__aarch64__) + return vreinterpretq_m128i_s32( + vsubq_s32(vuzp1q_s32(a, b), vuzp2q_s32(a, b))); +#else + int32x4x2_t c = vuzpq_s32(a, b); + return vreinterpretq_m128i_s32(vsubq_s32(c.val[0], c.val[1])); +#endif } // Horizontally subtract adjacent pairs of 16-bit integers in a and b, and pack // the signed 16-bit results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsub_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hsub_pi16 FORCE_INLINE __m64 _mm_hsub_pi16(__m64 _a, __m64 _b) { - int32x4_t ab = - vcombine_s32(vreinterpret_s32_m64(_a), vreinterpret_s32_m64(_b)); - - int16x4_t ab_low_bits = vmovn_s32(ab); - int16x4_t ab_high_bits = vshrn_n_s32(ab, 16); - - return vreinterpret_m64_s16(vsub_s16(ab_low_bits, ab_high_bits)); + int16x4_t a = vreinterpret_s16_m64(_a); + int16x4_t b = vreinterpret_s16_m64(_b); +#if defined(__aarch64__) + return vreinterpret_m64_s16(vsub_s16(vuzp1_s16(a, b), vuzp2_s16(a, b))); +#else + int16x4x2_t c = vuzp_s16(a, b); + return vreinterpret_m64_s16(vsub_s16(c.val[0], c.val[1])); +#endif } // Horizontally subtract adjacent pairs of 32-bit integers in a and b, and pack // the signed 32-bit results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_hsub_pi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=mm_hsub_pi32 FORCE_INLINE __m64 _mm_hsub_pi32(__m64 _a, __m64 _b) { -#if defined(__aarch64__) int32x2_t a = vreinterpret_s32_m64(_a); int32x2_t b = vreinterpret_s32_m64(_b); - return vreinterpret_m64_s32(vsub_s32(vtrn1_s32(a, b), vtrn2_s32(a, b))); +#if defined(__aarch64__) + return vreinterpret_m64_s32(vsub_s32(vuzp1_s32(a, b), vuzp2_s32(a, b))); #else - int32x2x2_t trn_ab = - vtrn_s32(vreinterpret_s32_m64(_a), vreinterpret_s32_m64(_b)); - return vreinterpret_m64_s32(vsub_s32(trn_ab.val[0], trn_ab.val[1])); + int32x2x2_t c = vuzp_s32(a, b); + return vreinterpret_m64_s32(vsub_s32(c.val[0], c.val[1])); #endif } // Computes saturated pairwise difference of each argument as a 16-bit signed // integer values a and b. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hsubs_epi16 FORCE_INLINE __m128i _mm_hsubs_epi16(__m128i _a, __m128i _b) { -#if defined(__aarch64__) int16x8_t a = vreinterpretq_s16_m128i(_a); int16x8_t b = vreinterpretq_s16_m128i(_b); - return vreinterpretq_s64_s16( +#if defined(__aarch64__) + return vreinterpretq_m128i_s16( vqsubq_s16(vuzp1q_s16(a, b), vuzp2q_s16(a, b))); #else - int32x4_t a = vreinterpretq_s32_m128i(_a); - int32x4_t b = vreinterpretq_s32_m128i(_b); - // Interleave using vshrn/vmovn - // [a0|a2|a4|a6|b0|b2|b4|b6] - // [a1|a3|a5|a7|b1|b3|b5|b7] - int16x8_t ab0246 = vcombine_s16(vmovn_s32(a), vmovn_s32(b)); - int16x8_t ab1357 = vcombine_s16(vshrn_n_s32(a, 16), vshrn_n_s32(b, 16)); - // Saturated subtract - return vreinterpretq_m128i_s16(vqsubq_s16(ab0246, ab1357)); + int16x8x2_t c = vuzpq_s16(a, b); + return vreinterpretq_m128i_s16(vqsubq_s16(c.val[0], c.val[1])); #endif } // Horizontally subtract adjacent pairs of signed 16-bit integers in a and b // using saturation, and pack the signed 16-bit results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_hsubs_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_hsubs_pi16 FORCE_INLINE __m64 _mm_hsubs_pi16(__m64 _a, __m64 _b) { int16x4_t a = vreinterpret_s16_m64(_a); int16x4_t b = vreinterpret_s16_m64(_b); #if defined(__aarch64__) - return vreinterpret_s64_s16(vqsub_s16(vuzp1_s16(a, b), vuzp2_s16(a, b))); + return vreinterpret_m64_s16(vqsub_s16(vuzp1_s16(a, b), vuzp2_s16(a, b))); #else - int16x4x2_t res = vuzp_s16(a, b); - return vreinterpret_s64_s16(vqsub_s16(res.val[0], res.val[1])); + int16x4x2_t c = vuzp_s16(a, b); + return vreinterpret_m64_s16(vqsub_s16(c.val[0], c.val[1])); #endif } @@ -6921,7 +7187,7 @@ FORCE_INLINE __m128i _mm_maddubs_epi16(__m128i _a, __m128i _b) // signed 8-bit integer from b, producing intermediate signed 16-bit integers. // Horizontally add adjacent pairs of intermediate signed 16-bit integers, and // pack the saturated results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maddubs_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_maddubs_pi16 FORCE_INLINE __m64 _mm_maddubs_pi16(__m64 _a, __m64 _b) { uint16x4_t a = vreinterpret_u16_m64(_a); @@ -6975,7 +7241,7 @@ FORCE_INLINE __m128i _mm_mulhrs_epi16(__m128i a, __m128i b) // Multiply packed signed 16-bit integers in a and b, producing intermediate // signed 32-bit integers. Truncate each intermediate integer to the 18 most // significant bits, round by adding 1, and store bits [16:1] to dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mulhrs_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mulhrs_pi16 FORCE_INLINE __m64 _mm_mulhrs_pi16(__m64 a, __m64 b) { int32x4_t mul_extend = @@ -6987,7 +7253,7 @@ FORCE_INLINE __m64 _mm_mulhrs_pi16(__m64 a, __m64 b) // Shuffle packed 8-bit integers in a according to shuffle control mask in the // corresponding 8-bit element of b, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_epi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_epi8 FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b) { int8x16_t tbl = vreinterpretq_s8_m128i(a); // input a @@ -7028,11 +7294,11 @@ FORCE_INLINE __m128i _mm_shuffle_epi8(__m128i a, __m128i b) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_pi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_shuffle_pi8 FORCE_INLINE __m64 _mm_shuffle_pi8(__m64 a, __m64 b) { const int8x8_t controlMask = - vand_s8(vreinterpret_s8_m64(b), vdup_n_s8((int8_t)(0x1 << 7 | 0x07))); + vand_s8(vreinterpret_s8_m64(b), vdup_n_s8((int8_t) (0x1 << 7 | 0x07))); int8x8_t res = vtbl1_s8(vreinterpret_s8_m64(a), controlMask); return vreinterpret_m64_s8(res); } @@ -7142,7 +7408,7 @@ FORCE_INLINE __m128i _mm_sign_epi8(__m128i _a, __m128i _b) int8x16_t zeroMask = vreinterpretq_s8_u8(vceqq_s8(b, vdupq_n_s8(0))); #endif - // bitwise select either a or nagative 'a' (vnegq_s8(a) return nagative 'a') + // bitwise select either a or negative 'a' (vnegq_s8(a) return negative 'a') // based on ltMask int8x16_t masked = vbslq_s8(ltMask, vnegq_s8(a), a); // res = masked & (~zeroMask) @@ -7166,7 +7432,7 @@ FORCE_INLINE __m128i _mm_sign_epi8(__m128i _a, __m128i _b) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sign_pi16 FORCE_INLINE __m64 _mm_sign_pi16(__m64 _a, __m64 _b) { int16x4_t a = vreinterpret_s16_m64(_a); @@ -7183,7 +7449,7 @@ FORCE_INLINE __m64 _mm_sign_pi16(__m64 _a, __m64 _b) int16x4_t zeroMask = vreinterpret_s16_u16(vceq_s16(b, vdup_n_s16(0))); #endif - // bitwise select either a or nagative 'a' (vneg_s16(a) return nagative 'a') + // bitwise select either a or negative 'a' (vneg_s16(a) return negative 'a') // based on ltMask int16x4_t masked = vbsl_s16(ltMask, vneg_s16(a), a); // res = masked & (~zeroMask) @@ -7207,7 +7473,7 @@ FORCE_INLINE __m64 _mm_sign_pi16(__m64 _a, __m64 _b) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sign_pi32 FORCE_INLINE __m64 _mm_sign_pi32(__m64 _a, __m64 _b) { int32x2_t a = vreinterpret_s32_m64(_a); @@ -7224,7 +7490,7 @@ FORCE_INLINE __m64 _mm_sign_pi32(__m64 _a, __m64 _b) int32x2_t zeroMask = vreinterpret_s32_u32(vceq_s32(b, vdup_n_s32(0))); #endif - // bitwise select either a or nagative 'a' (vneg_s32(a) return nagative 'a') + // bitwise select either a or negative 'a' (vneg_s32(a) return negative 'a') // based on ltMask int32x2_t masked = vbsl_s32(ltMask, vneg_s32(a), a); // res = masked & (~zeroMask) @@ -7248,7 +7514,7 @@ FORCE_INLINE __m64 _mm_sign_pi32(__m64 _a, __m64 _b) // FI // ENDFOR // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sign_pi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sign_pi8 FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b) { int8x8_t a = vreinterpret_s8_m64(_a); @@ -7265,7 +7531,7 @@ FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b) int8x8_t zeroMask = vreinterpret_s8_u8(vceq_s8(b, vdup_n_s8(0))); #endif - // bitwise select either a or nagative 'a' (vneg_s8(a) return nagative 'a') + // bitwise select either a or negative 'a' (vneg_s8(a) return negative 'a') // based on ltMask int8x8_t masked = vbsl_s8(ltMask, vneg_s8(a), a); // res = masked & (~zeroMask) @@ -7309,7 +7575,7 @@ FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b) // Blend packed double-precision (64-bit) floating-point elements from a and b // using control mask imm8, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_blend_pd #define _mm_blend_pd(a, b, imm) \ __extension__({ \ const uint64_t _mask[2] = { \ @@ -7323,7 +7589,7 @@ FORCE_INLINE __m64 _mm_sign_pi8(__m64 _a, __m64 _b) // Blend packed single-precision (32-bit) floating-point elements from a and b // using mask, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blend_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_blend_ps FORCE_INLINE __m128 _mm_blend_ps(__m128 _a, __m128 _b, const char imm8) { const uint32_t ALIGN_STRUCT(16) @@ -7360,7 +7626,7 @@ FORCE_INLINE __m128i _mm_blendv_epi8(__m128i _a, __m128i _b, __m128i _mask) // Blend packed double-precision (64-bit) floating-point elements from a and b // using mask, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_blendv_pd FORCE_INLINE __m128d _mm_blendv_pd(__m128d _a, __m128d _b, __m128d _mask) { uint64x2_t mask = @@ -7378,7 +7644,7 @@ FORCE_INLINE __m128d _mm_blendv_pd(__m128d _a, __m128d _b, __m128d _mask) // Blend packed single-precision (32-bit) floating-point elements from a and b // using mask, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_blendv_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_blendv_ps FORCE_INLINE __m128 _mm_blendv_ps(__m128 _a, __m128 _b, __m128 _mask) { // Use a signed shift right to create a mask with the sign bit @@ -7392,7 +7658,7 @@ FORCE_INLINE __m128 _mm_blendv_ps(__m128 _a, __m128 _b, __m128 _mask) // Round the packed double-precision (64-bit) floating-point elements in a up // to an integer value, and store the results as packed double-precision // floating-point elements in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_ceil_pd FORCE_INLINE __m128d _mm_ceil_pd(__m128d a) { #if defined(__aarch64__) @@ -7406,10 +7672,10 @@ FORCE_INLINE __m128d _mm_ceil_pd(__m128d a) // Round the packed single-precision (32-bit) floating-point elements in a up to // an integer value, and store the results as packed single-precision // floating-point elements in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_ceil_ps FORCE_INLINE __m128 _mm_ceil_ps(__m128 a) { -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) return vreinterpretq_m128_f32(vrndpq_f32(vreinterpretq_f32_m128(a))); #else float *f = (float *) &a; @@ -7421,7 +7687,7 @@ FORCE_INLINE __m128 _mm_ceil_ps(__m128 a) // an integer value, store the result as a double-precision floating-point // element in the lower element of dst, and copy the upper element from a to the // upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_ceil_sd FORCE_INLINE __m128d _mm_ceil_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_ceil_pd(b)); @@ -7435,7 +7701,7 @@ FORCE_INLINE __m128d _mm_ceil_sd(__m128d a, __m128d b) // dst[31:0] := CEIL(b[31:0]) // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_ceil_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_ceil_ss FORCE_INLINE __m128 _mm_ceil_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_ceil_ps(b)); @@ -7542,7 +7808,7 @@ FORCE_INLINE __m128i _mm_cvtepu32_epi64(__m128i a) // Zero extend packed unsigned 8-bit integers in a to packed 16-bit integers, // and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtepu8_epi16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtepu8_epi16 FORCE_INLINE __m128i _mm_cvtepu8_epi16(__m128i a) { uint8x16_t u8x16 = vreinterpretq_u8_m128i(a); /* xxxx xxxx HGFE DCBA */ @@ -7575,7 +7841,7 @@ FORCE_INLINE __m128i _mm_cvtepu8_epi64(__m128i a) // Conditionally multiply the packed double-precision (64-bit) floating-point // elements in a and b using the high 4 bits in imm8, sum the four products, and // conditionally store the sum in dst using the low 4 bits of imm8. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_dp_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_dp_pd FORCE_INLINE __m128d _mm_dp_pd(__m128d a, __m128d b, const int imm) { // Generate mask value from constant immediate bit value @@ -7621,7 +7887,7 @@ FORCE_INLINE __m128d _mm_dp_pd(__m128d a, __m128d b, const int imm) // Conditionally multiply the packed single-precision (32-bit) floating-point // elements in a and b using the high 4 bits in imm8, sum the four products, // and conditionally store the sum in dst using the low 4 bits of imm. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_dp_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_dp_ps FORCE_INLINE __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm) { #if defined(__aarch64__) @@ -7677,7 +7943,7 @@ FORCE_INLINE __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm) // Extracts the selected signed or unsigned 8-bit integer from a and zero // extends. // FORCE_INLINE int _mm_extract_epi8(__m128i a, __constrange(0,16) int imm) -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_extract_epi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_extract_epi8 #define _mm_extract_epi8(a, imm) vgetq_lane_u8(vreinterpretq_u8_m128i(a), (imm)) // Extracts the selected single-precision (32-bit) floating-point from a. @@ -7687,7 +7953,7 @@ FORCE_INLINE __m128 _mm_dp_ps(__m128 a, __m128 b, const int imm) // Round the packed double-precision (64-bit) floating-point elements in a down // to an integer value, and store the results as packed double-precision // floating-point elements in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_floor_pd FORCE_INLINE __m128d _mm_floor_pd(__m128d a) { #if defined(__aarch64__) @@ -7701,10 +7967,10 @@ FORCE_INLINE __m128d _mm_floor_pd(__m128d a) // Round the packed single-precision (32-bit) floating-point elements in a down // to an integer value, and store the results as packed single-precision // floating-point elements in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_floor_ps FORCE_INLINE __m128 _mm_floor_ps(__m128 a) { -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) return vreinterpretq_m128_f32(vrndmq_f32(vreinterpretq_f32_m128(a))); #else float *f = (float *) &a; @@ -7716,7 +7982,7 @@ FORCE_INLINE __m128 _mm_floor_ps(__m128 a) // an integer value, store the result as a double-precision floating-point // element in the lower element of dst, and copy the upper element from a to the // upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_floor_sd FORCE_INLINE __m128d _mm_floor_sd(__m128d a, __m128d b) { return _mm_move_sd(a, _mm_floor_pd(b)); @@ -7730,7 +7996,7 @@ FORCE_INLINE __m128d _mm_floor_sd(__m128d a, __m128d b) // dst[31:0] := FLOOR(b[31:0]) // dst[127:32] := a[127:32] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_floor_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_floor_ss FORCE_INLINE __m128 _mm_floor_ss(__m128 a, __m128 b) { return _mm_move_ss(a, _mm_floor_ps(b)); @@ -7769,7 +8035,7 @@ FORCE_INLINE __m128 _mm_floor_ss(__m128 a, __m128 b) // Copy a to tmp, then insert a single-precision (32-bit) floating-point // element from b into tmp using the control in imm8. Store tmp to dst using // the mask in imm8 (elements are zeroed out when the corresponding bit is set). -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=insert_ps +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=insert_ps #define _mm_insert_ps(a, b, imm8) \ __extension__({ \ float32x4_t tmp1 = \ @@ -7808,7 +8074,7 @@ FORCE_INLINE __m128i _mm_max_epi32(__m128i a, __m128i b) // Compare packed signed 8-bit integers in a and b, and store packed maximum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_epi8 FORCE_INLINE __m128i _mm_max_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( @@ -7817,7 +8083,7 @@ FORCE_INLINE __m128i _mm_max_epi8(__m128i a, __m128i b) // Compare packed unsigned 16-bit integers in a and b, and store packed maximum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_epu16 FORCE_INLINE __m128i _mm_max_epu16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( @@ -7826,7 +8092,7 @@ FORCE_INLINE __m128i _mm_max_epu16(__m128i a, __m128i b) // Compare packed unsigned 32-bit integers in a and b, and store packed maximum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_epu32 FORCE_INLINE __m128i _mm_max_epu32(__m128i a, __m128i b) { return vreinterpretq_m128i_u32( @@ -7851,7 +8117,7 @@ FORCE_INLINE __m128i _mm_min_epi32(__m128i a, __m128i b) // Compare packed signed 8-bit integers in a and b, and store packed minimum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epi8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_min_epi8 FORCE_INLINE __m128i _mm_min_epi8(__m128i a, __m128i b) { return vreinterpretq_m128i_s8( @@ -7860,7 +8126,7 @@ FORCE_INLINE __m128i _mm_min_epi8(__m128i a, __m128i b) // Compare packed unsigned 16-bit integers in a and b, and store packed minimum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_epu16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_min_epu16 FORCE_INLINE __m128i _mm_min_epu16(__m128i a, __m128i b) { return vreinterpretq_m128i_u16( @@ -7869,7 +8135,7 @@ FORCE_INLINE __m128i _mm_min_epu16(__m128i a, __m128i b) // Compare packed unsigned 32-bit integers in a and b, and store packed minimum // values in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_epu32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_max_epu32 FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b) { return vreinterpretq_m128i_u32( @@ -7892,15 +8158,22 @@ FORCE_INLINE __m128i _mm_min_epu32(__m128i a, __m128i b) // dst[18:16] := index[2:0] // dst[127:19] := 0 // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_minpos_epu16 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_minpos_epu16 FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a) { __m128i dst; uint16_t min, idx = 0; - // Find the minimum value #if defined(__aarch64__) + // Find the minimum value min = vminvq_u16(vreinterpretq_u16_m128i(a)); + + // Get the index of the minimum value + static const uint16_t idxv[] = {0, 1, 2, 3, 4, 5, 6, 7}; + uint16x8_t minv = vdupq_n_u16(min); + uint16x8_t cmeq = vceqq_u16(minv, vreinterpretq_u16_m128i(a)); + idx = vminvq_u16(vornq_u16(vld1q_u16(idxv), cmeq)); #else + // Find the minimum value __m64 tmp; tmp = vreinterpret_m64_u16( vmin_u16(vget_low_u16(vreinterpretq_u16_m128i(a)), @@ -7910,7 +8183,6 @@ FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a) tmp = vreinterpret_m64_u16( vpmin_u16(vreinterpret_u16_m64(tmp), vreinterpret_u16_m64(tmp))); min = vget_lane_u16(vreinterpret_u16_m64(tmp), 0); -#endif // Get the index of the minimum value int i; for (i = 0; i < 8; i++) { @@ -7920,6 +8192,7 @@ FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a) } a = _mm_srli_si128(a, 2); } +#endif // Generate result dst = _mm_setzero_si128(); dst = vreinterpretq_m128i_u16( @@ -7935,7 +8208,7 @@ FORCE_INLINE __m128i _mm_minpos_epu16(__m128i a) // quadruplets from a. One quadruplet is selected from b starting at on the // offset specified in imm8. Eight quadruplets are formed from sequential 8-bit // integers selected from a starting at the offset specified in imm8. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mpsadbw_epu8 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mpsadbw_epu8 FORCE_INLINE __m128i _mm_mpsadbw_epu8(__m128i a, __m128i b, const int imm) { uint8x16_t _a, _b; @@ -7982,13 +8255,13 @@ FORCE_INLINE __m128i _mm_mpsadbw_epu8(__m128i a, __m128i b, const int imm) int16x8_t c04, c15, c26, c37; uint8x8_t low_b = vget_low_u8(_b); - c04 = vabsq_s16(vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(_a), low_b))); - _a = vextq_u8(_a, _a, 1); - c15 = vabsq_s16(vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(_a), low_b))); - _a = vextq_u8(_a, _a, 1); - c26 = vabsq_s16(vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(_a), low_b))); - _a = vextq_u8(_a, _a, 1); - c37 = vabsq_s16(vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(_a), low_b))); + c04 = vreinterpretq_s16_u16(vabdl_u8(vget_low_u8(_a), low_b)); + uint8x16_t _a_1 = vextq_u8(_a, _a, 1); + c15 = vreinterpretq_s16_u16(vabdl_u8(vget_low_u8(_a_1), low_b)); + uint8x16_t _a_2 = vextq_u8(_a, _a, 2); + c26 = vreinterpretq_s16_u16(vabdl_u8(vget_low_u8(_a_2), low_b)); + uint8x16_t _a_3 = vextq_u8(_a, _a, 3); + c37 = vreinterpretq_s16_u16(vabdl_u8(vget_low_u8(_a_3), low_b)); #if defined(__aarch64__) // |0|4|2|6| c04 = vpaddq_s16(c04, c26); @@ -8056,7 +8329,7 @@ FORCE_INLINE __m128i _mm_packus_epi32(__m128i a, __m128i b) // Round the packed double-precision (64-bit) floating-point elements in a using // the rounding parameter, and store the results as packed double-precision // floating-point elements in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_pd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_round_pd FORCE_INLINE __m128d _mm_round_pd(__m128d a, int rounding) { #if defined(__aarch64__) @@ -8128,7 +8401,7 @@ FORCE_INLINE __m128d _mm_round_pd(__m128d a, int rounding) // software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ps FORCE_INLINE __m128 _mm_round_ps(__m128 a, int rounding) { -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__ARM_FEATURE_DIRECTED_ROUNDING) switch (rounding) { case (_MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC): return vreinterpretq_m128_f32(vrndnq_f32(vreinterpretq_f32_m128(a))); @@ -8185,7 +8458,7 @@ FORCE_INLINE __m128 _mm_round_ps(__m128 a, int rounding) // the rounding parameter, store the result as a double-precision floating-point // element in the lower element of dst, and copy the upper element from a to the // upper element of dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_sd +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_round_sd FORCE_INLINE __m128d _mm_round_sd(__m128d a, __m128d b, int rounding) { return _mm_move_sd(a, _mm_round_pd(b, rounding)); @@ -8205,7 +8478,7 @@ FORCE_INLINE __m128d _mm_round_sd(__m128d a, __m128d b, int rounding) // (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress // exceptions _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see // _MM_SET_ROUNDING_MODE -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_round_ss +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_round_ss FORCE_INLINE __m128 _mm_round_ss(__m128 a, __m128 b, int rounding) { return _mm_move_ss(a, _mm_round_ps(b, rounding)); @@ -8217,7 +8490,7 @@ FORCE_INLINE __m128 _mm_round_ss(__m128 a, __m128 b, int rounding) // // dst[127:0] := MEM[mem_addr+127:mem_addr] // -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_stream_load_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_stream_load_si128 FORCE_INLINE __m128i _mm_stream_load_si128(__m128i *p) { #if __has_builtin(__builtin_nontemporal_store) @@ -8229,16 +8502,16 @@ FORCE_INLINE __m128i _mm_stream_load_si128(__m128i *p) // Compute the bitwise NOT of a and then AND with a 128-bit vector containing // all 1's, and return 1 if the result is zero, otherwise return 0. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_ones +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_test_all_ones FORCE_INLINE int _mm_test_all_ones(__m128i a) { - return (uint64_t)(vgetq_lane_s64(a, 0) & vgetq_lane_s64(a, 1)) == + return (uint64_t) (vgetq_lane_s64(a, 0) & vgetq_lane_s64(a, 1)) == ~(uint64_t) 0; } // Compute the bitwise AND of 128 bits (representing integer data) in a and // mask, and return 1 if the result is zero, otherwise return 0. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_test_all_zeros +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_test_all_zeros FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask) { int64x2_t a_and_mask = @@ -8251,7 +8524,7 @@ FORCE_INLINE int _mm_test_all_zeros(__m128i a, __m128i mask) // the bitwise NOT of a and then AND with mask, and set CF to 1 if the result is // zero, otherwise set CF to 0. Return 1 if both the ZF and CF values are zero, // otherwise return 0. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm_test_mix_ones_zero +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=mm_test_mix_ones_zero FORCE_INLINE int _mm_test_mix_ones_zeros(__m128i a, __m128i mask) { uint64x2_t zf = @@ -8266,12 +8539,11 @@ FORCE_INLINE int _mm_test_mix_ones_zeros(__m128i a, __m128i mask) // and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the // bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, // otherwise set CF to 0. Return the CF value. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testc_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_testc_si128 FORCE_INLINE int _mm_testc_si128(__m128i a, __m128i b) { int64x2_t s64 = - vandq_s64(vreinterpretq_s64_s32(vmvnq_s32(vreinterpretq_s32_m128i(a))), - vreinterpretq_s64_m128i(b)); + vbicq_s64(vreinterpretq_s64_m128i(b), vreinterpretq_s64_m128i(a)); return !(vgetq_lane_s64(s64, 0) | vgetq_lane_s64(s64, 1)); } @@ -8280,14 +8552,14 @@ FORCE_INLINE int _mm_testc_si128(__m128i a, __m128i b) // bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, // otherwise set CF to 0. Return 1 if both the ZF and CF values are zero, // otherwise return 0. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testnzc_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_testnzc_si128 #define _mm_testnzc_si128(a, b) _mm_test_mix_ones_zeros(a, b) // Compute the bitwise AND of 128 bits (representing integer data) in a and b, // and set ZF to 1 if the result is zero, otherwise set ZF to 0. Compute the // bitwise NOT of a and then AND with b, and set CF to 1 if the result is zero, // otherwise set CF to 0. Return the ZF value. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_testz_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_testz_si128 FORCE_INLINE int _mm_testz_si128(__m128i a, __m128i b) { int64x2_t s64 = @@ -8297,6 +8569,756 @@ FORCE_INLINE int _mm_testz_si128(__m128i a, __m128i b) /* SSE4.2 */ +const static uint16_t _sse2neon_cmpestr_mask16b[8] ALIGN_STRUCT(16) = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, +}; +const static uint8_t _sse2neon_cmpestr_mask8b[16] ALIGN_STRUCT(16) = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, +}; + +/* specify the source data format */ +#define _SIDD_UBYTE_OPS 0x00 /* unsigned 8-bit characters */ +#define _SIDD_UWORD_OPS 0x01 /* unsigned 16-bit characters */ +#define _SIDD_SBYTE_OPS 0x02 /* signed 8-bit characters */ +#define _SIDD_SWORD_OPS 0x03 /* signed 16-bit characters */ + +/* specify the comparison operation */ +#define _SIDD_CMP_EQUAL_ANY 0x00 /* compare equal any: strchr */ +#define _SIDD_CMP_RANGES 0x04 /* compare ranges */ +#define _SIDD_CMP_EQUAL_EACH 0x08 /* compare equal each: strcmp */ +#define _SIDD_CMP_EQUAL_ORDERED 0x0C /* compare equal ordered */ + +/* specify the polarity */ +#define _SIDD_POSITIVE_POLARITY 0x00 +#define _SIDD_MASKED_POSITIVE_POLARITY 0x20 +#define _SIDD_NEGATIVE_POLARITY 0x10 /* negate results */ +#define _SIDD_MASKED_NEGATIVE_POLARITY \ + 0x30 /* negate results only before end of string */ + +/* specify the output selection in _mm_cmpXstri */ +#define _SIDD_LEAST_SIGNIFICANT 0x00 +#define _SIDD_MOST_SIGNIFICANT 0x40 + +/* specify the output selection in _mm_cmpXstrm */ +#define _SIDD_BIT_MASK 0x00 +#define _SIDD_UNIT_MASK 0x40 + +/* Pattern Matching for C macros. + * https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms + */ + +/* catenate */ +#define SSE2NEON_PRIMITIVE_CAT(a, ...) a##__VA_ARGS__ +#define SSE2NEON_CAT(a, b) SSE2NEON_PRIMITIVE_CAT(a, b) + +#define SSE2NEON_IIF(c) SSE2NEON_PRIMITIVE_CAT(SSE2NEON_IIF_, c) +/* run the 2nd parameter */ +#define SSE2NEON_IIF_0(t, ...) __VA_ARGS__ +/* run the 1st parameter */ +#define SSE2NEON_IIF_1(t, ...) t + +#define SSE2NEON_COMPL(b) SSE2NEON_PRIMITIVE_CAT(SSE2NEON_COMPL_, b) +#define SSE2NEON_COMPL_0 1 +#define SSE2NEON_COMPL_1 0 + +#define SSE2NEON_DEC(x) SSE2NEON_PRIMITIVE_CAT(SSE2NEON_DEC_, x) +#define SSE2NEON_DEC_1 0 +#define SSE2NEON_DEC_2 1 +#define SSE2NEON_DEC_3 2 +#define SSE2NEON_DEC_4 3 +#define SSE2NEON_DEC_5 4 +#define SSE2NEON_DEC_6 5 +#define SSE2NEON_DEC_7 6 +#define SSE2NEON_DEC_8 7 +#define SSE2NEON_DEC_9 8 +#define SSE2NEON_DEC_10 9 +#define SSE2NEON_DEC_11 10 +#define SSE2NEON_DEC_12 11 +#define SSE2NEON_DEC_13 12 +#define SSE2NEON_DEC_14 13 +#define SSE2NEON_DEC_15 14 +#define SSE2NEON_DEC_16 15 + +/* detection */ +#define SSE2NEON_CHECK_N(x, n, ...) n +#define SSE2NEON_CHECK(...) SSE2NEON_CHECK_N(__VA_ARGS__, 0, ) +#define SSE2NEON_PROBE(x) x, 1, + +#define SSE2NEON_NOT(x) SSE2NEON_CHECK(SSE2NEON_PRIMITIVE_CAT(SSE2NEON_NOT_, x)) +#define SSE2NEON_NOT_0 SSE2NEON_PROBE(~) + +#define SSE2NEON_BOOL(x) SSE2NEON_COMPL(SSE2NEON_NOT(x)) +#define SSE2NEON_IF(c) SSE2NEON_IIF(SSE2NEON_BOOL(c)) + +#define SSE2NEON_EAT(...) +#define SSE2NEON_EXPAND(...) __VA_ARGS__ +#define SSE2NEON_WHEN(c) SSE2NEON_IF(c)(SSE2NEON_EXPAND, SSE2NEON_EAT) + +/* recursion */ +/* deferred expression */ +#define SSE2NEON_EMPTY() +#define SSE2NEON_DEFER(id) id SSE2NEON_EMPTY() +#define SSE2NEON_OBSTRUCT(...) __VA_ARGS__ SSE2NEON_DEFER(SSE2NEON_EMPTY)() +#define SSE2NEON_EXPAND(...) __VA_ARGS__ + +#define SSE2NEON_EVAL(...) \ + SSE2NEON_EVAL1(SSE2NEON_EVAL1(SSE2NEON_EVAL1(__VA_ARGS__))) +#define SSE2NEON_EVAL1(...) \ + SSE2NEON_EVAL2(SSE2NEON_EVAL2(SSE2NEON_EVAL2(__VA_ARGS__))) +#define SSE2NEON_EVAL2(...) \ + SSE2NEON_EVAL3(SSE2NEON_EVAL3(SSE2NEON_EVAL3(__VA_ARGS__))) +#define SSE2NEON_EVAL3(...) __VA_ARGS__ + +#define SSE2NEON_REPEAT(count, macro, ...) \ + SSE2NEON_WHEN(count) \ + (SSE2NEON_OBSTRUCT(SSE2NEON_REPEAT_INDIRECT)()( \ + SSE2NEON_DEC(count), macro, \ + __VA_ARGS__) SSE2NEON_OBSTRUCT(macro)(SSE2NEON_DEC(count), \ + __VA_ARGS__)) +#define SSE2NEON_REPEAT_INDIRECT() SSE2NEON_REPEAT + +#define SSE2NEON_SIZE_OF_byte 8 +#define SSE2NEON_NUMBER_OF_LANES_byte 16 +#define SSE2NEON_SIZE_OF_word 16 +#define SSE2NEON_NUMBER_OF_LANES_word 8 + +#define SSE2NEON_COMPARE_EQUAL_THEN_FILL_LANE(i, type) \ + mtx[i] = vreinterpretq_m128i_##type(vceqq_##type( \ + vdupq_n_##type(vgetq_lane_##type(vreinterpretq_##type##_m128i(b), i)), \ + vreinterpretq_##type##_m128i(a))); + +#define SSE2NEON_FILL_LANE(i, type) \ + vec_b[i] = \ + vdupq_n_##type(vgetq_lane_##type(vreinterpretq_##type##_m128i(b), i)); + +#define PCMPSTR_RANGES(a, b, mtx, data_type_prefix, type_prefix, size, \ + number_of_lanes, byte_or_word) \ + do { \ + SSE2NEON_CAT( \ + data_type_prefix, \ + SSE2NEON_CAT(size, \ + SSE2NEON_CAT(x, SSE2NEON_CAT(number_of_lanes, _t)))) \ + vec_b[number_of_lanes]; \ + __m128i mask = SSE2NEON_IIF(byte_or_word)( \ + vreinterpretq_m128i_u16(vdupq_n_u16(0xff)), \ + vreinterpretq_m128i_u32(vdupq_n_u32(0xffff))); \ + SSE2NEON_EVAL(SSE2NEON_REPEAT(number_of_lanes, SSE2NEON_FILL_LANE, \ + SSE2NEON_CAT(type_prefix, size))) \ + for (int i = 0; i < number_of_lanes; i++) { \ + mtx[i] = SSE2NEON_CAT(vreinterpretq_m128i_u, \ + size)(SSE2NEON_CAT(vbslq_u, size)( \ + SSE2NEON_CAT(vreinterpretq_u, \ + SSE2NEON_CAT(size, _m128i))(mask), \ + SSE2NEON_CAT(vcgeq_, SSE2NEON_CAT(type_prefix, size))( \ + vec_b[i], \ + SSE2NEON_CAT( \ + vreinterpretq_, \ + SSE2NEON_CAT(type_prefix, \ + SSE2NEON_CAT(size, _m128i(a))))), \ + SSE2NEON_CAT(vcleq_, SSE2NEON_CAT(type_prefix, size))( \ + vec_b[i], \ + SSE2NEON_CAT( \ + vreinterpretq_, \ + SSE2NEON_CAT(type_prefix, \ + SSE2NEON_CAT(size, _m128i(a))))))); \ + } \ + } while (0) + +#define PCMPSTR_EQ(a, b, mtx, size, number_of_lanes) \ + do { \ + SSE2NEON_EVAL(SSE2NEON_REPEAT(number_of_lanes, \ + SSE2NEON_COMPARE_EQUAL_THEN_FILL_LANE, \ + SSE2NEON_CAT(u, size))) \ + } while (0) + +#define SSE2NEON_CMP_EQUAL_ANY_IMPL(type) \ + static int _sse2neon_cmp_##type##_equal_any(__m128i a, int la, __m128i b, \ + int lb) \ + { \ + __m128i mtx[16]; \ + PCMPSTR_EQ(a, b, mtx, SSE2NEON_CAT(SSE2NEON_SIZE_OF_, type), \ + SSE2NEON_CAT(SSE2NEON_NUMBER_OF_LANES_, type)); \ + return SSE2NEON_CAT( \ + _sse2neon_aggregate_equal_any_, \ + SSE2NEON_CAT( \ + SSE2NEON_CAT(SSE2NEON_SIZE_OF_, type), \ + SSE2NEON_CAT(x, SSE2NEON_CAT(SSE2NEON_NUMBER_OF_LANES_, \ + type))))(la, lb, mtx); \ + } + +#define SSE2NEON_CMP_RANGES_IMPL(type, data_type, us, byte_or_word) \ + static int _sse2neon_cmp_##us##type##_ranges(__m128i a, int la, __m128i b, \ + int lb) \ + { \ + __m128i mtx[16]; \ + PCMPSTR_RANGES( \ + a, b, mtx, data_type, us, SSE2NEON_CAT(SSE2NEON_SIZE_OF_, type), \ + SSE2NEON_CAT(SSE2NEON_NUMBER_OF_LANES_, type), byte_or_word); \ + return SSE2NEON_CAT( \ + _sse2neon_aggregate_ranges_, \ + SSE2NEON_CAT( \ + SSE2NEON_CAT(SSE2NEON_SIZE_OF_, type), \ + SSE2NEON_CAT(x, SSE2NEON_CAT(SSE2NEON_NUMBER_OF_LANES_, \ + type))))(la, lb, mtx); \ + } + +#define SSE2NEON_CMP_EQUAL_ORDERED_IMPL(type) \ + static int _sse2neon_cmp_##type##_equal_ordered(__m128i a, int la, \ + __m128i b, int lb) \ + { \ + __m128i mtx[16]; \ + PCMPSTR_EQ(a, b, mtx, SSE2NEON_CAT(SSE2NEON_SIZE_OF_, type), \ + SSE2NEON_CAT(SSE2NEON_NUMBER_OF_LANES_, type)); \ + return SSE2NEON_CAT( \ + _sse2neon_aggregate_equal_ordered_, \ + SSE2NEON_CAT( \ + SSE2NEON_CAT(SSE2NEON_SIZE_OF_, type), \ + SSE2NEON_CAT(x, \ + SSE2NEON_CAT(SSE2NEON_NUMBER_OF_LANES_, type))))( \ + SSE2NEON_CAT(SSE2NEON_NUMBER_OF_LANES_, type), la, lb, mtx); \ + } + +static int _sse2neon_aggregate_equal_any_8x16(int la, int lb, __m128i mtx[16]) +{ + int res = 0; + int m = (1 << la) - 1; + uint8x8_t vec_mask = vld1_u8(_sse2neon_cmpestr_mask8b); + uint8x8_t t_lo = vtst_u8(vdup_n_u8(m & 0xff), vec_mask); + uint8x8_t t_hi = vtst_u8(vdup_n_u8(m >> 8), vec_mask); + uint8x16_t vec = vcombine_u8(t_lo, t_hi); + for (int j = 0; j < lb; j++) { + mtx[j] = vreinterpretq_m128i_u8( + vandq_u8(vec, vreinterpretq_u8_m128i(mtx[j]))); + mtx[j] = vreinterpretq_m128i_u8( + vshrq_n_u8(vreinterpretq_u8_m128i(mtx[j]), 7)); + int tmp = _sse2neon_vaddvq_u8(vreinterpretq_u8_m128i(mtx[j])) ? 1 : 0; + res |= (tmp << j); + } + return res; +} + +static int _sse2neon_aggregate_equal_any_16x8(int la, int lb, __m128i mtx[16]) +{ + int res = 0; + int m = (1 << la) - 1; + uint16x8_t vec = + vtstq_u16(vdupq_n_u16(m), vld1q_u16(_sse2neon_cmpestr_mask16b)); + for (int j = 0; j < lb; j++) { + mtx[j] = vreinterpretq_m128i_u16( + vandq_u16(vec, vreinterpretq_u16_m128i(mtx[j]))); + mtx[j] = vreinterpretq_m128i_u16( + vshrq_n_u16(vreinterpretq_u16_m128i(mtx[j]), 15)); + int tmp = _sse2neon_vaddvq_u16(vreinterpretq_u16_m128i(mtx[j])) ? 1 : 0; + res |= (tmp << j); + } + return res; +} + +/* clang-format off */ +#define SSE2NEON_GENERATE_CMP_EQUAL_ANY(prefix) \ + prefix##IMPL(byte) \ + prefix##IMPL(word) +/* clang-format on */ + +SSE2NEON_GENERATE_CMP_EQUAL_ANY(SSE2NEON_CMP_EQUAL_ANY_) + +static int _sse2neon_aggregate_ranges_16x8(int la, int lb, __m128i mtx[16]) +{ + int res = 0; + int m = (1 << la) - 1; + uint16x8_t vec = + vtstq_u16(vdupq_n_u16(m), vld1q_u16(_sse2neon_cmpestr_mask16b)); + for (int j = 0; j < lb; j++) { + mtx[j] = vreinterpretq_m128i_u16( + vandq_u16(vec, vreinterpretq_u16_m128i(mtx[j]))); + mtx[j] = vreinterpretq_m128i_u16( + vshrq_n_u16(vreinterpretq_u16_m128i(mtx[j]), 15)); + __m128i tmp = vreinterpretq_m128i_u32( + vshrq_n_u32(vreinterpretq_u32_m128i(mtx[j]), 16)); + uint32x4_t vec_res = vandq_u32(vreinterpretq_u32_m128i(mtx[j]), + vreinterpretq_u32_m128i(tmp)); +#if defined(__aarch64__) + int t = vaddvq_u32(vec_res) ? 1 : 0; +#else + uint64x2_t sumh = vpaddlq_u32(vec_res); + int t = vgetq_lane_u64(sumh, 0) + vgetq_lane_u64(sumh, 1); +#endif + res |= (t << j); + } + return res; +} + +static int _sse2neon_aggregate_ranges_8x16(int la, int lb, __m128i mtx[16]) +{ + int res = 0; + int m = (1 << la) - 1; + uint8x8_t vec_mask = vld1_u8(_sse2neon_cmpestr_mask8b); + uint8x8_t t_lo = vtst_u8(vdup_n_u8(m & 0xff), vec_mask); + uint8x8_t t_hi = vtst_u8(vdup_n_u8(m >> 8), vec_mask); + uint8x16_t vec = vcombine_u8(t_lo, t_hi); + for (int j = 0; j < lb; j++) { + mtx[j] = vreinterpretq_m128i_u8( + vandq_u8(vec, vreinterpretq_u8_m128i(mtx[j]))); + mtx[j] = vreinterpretq_m128i_u8( + vshrq_n_u8(vreinterpretq_u8_m128i(mtx[j]), 7)); + __m128i tmp = vreinterpretq_m128i_u16( + vshrq_n_u16(vreinterpretq_u16_m128i(mtx[j]), 8)); + uint16x8_t vec_res = vandq_u16(vreinterpretq_u16_m128i(mtx[j]), + vreinterpretq_u16_m128i(tmp)); + int t = _sse2neon_vaddvq_u16(vec_res) ? 1 : 0; + res |= (t << j); + } + return res; +} + +#define SSE2NEON_CMP_RANGES_IS_BYTE 1 +#define SSE2NEON_CMP_RANGES_IS_WORD 0 + +/* clang-format off */ +#define SSE2NEON_GENERATE_CMP_RANGES(prefix) \ + prefix##IMPL(byte, uint, u, prefix##IS_BYTE) \ + prefix##IMPL(byte, int, s, prefix##IS_BYTE) \ + prefix##IMPL(word, uint, u, prefix##IS_WORD) \ + prefix##IMPL(word, int, s, prefix##IS_WORD) +/* clang-format on */ + +SSE2NEON_GENERATE_CMP_RANGES(SSE2NEON_CMP_RANGES_) + +#undef SSE2NEON_CMP_RANGES_IS_BYTE +#undef SSE2NEON_CMP_RANGES_IS_WORD + +static int _sse2neon_cmp_byte_equal_each(__m128i a, int la, __m128i b, int lb) +{ + uint8x16_t mtx = + vceqq_u8(vreinterpretq_u8_m128i(a), vreinterpretq_u8_m128i(b)); + int m0 = (la < lb) ? 0 : ((1 << la) - (1 << lb)); + int m1 = 0x10000 - (1 << la); + int tb = 0x10000 - (1 << lb); + uint8x8_t vec_mask, vec0_lo, vec0_hi, vec1_lo, vec1_hi; + uint8x8_t tmp_lo, tmp_hi, res_lo, res_hi; + vec_mask = vld1_u8(_sse2neon_cmpestr_mask8b); + vec0_lo = vtst_u8(vdup_n_u8(m0), vec_mask); + vec0_hi = vtst_u8(vdup_n_u8(m0 >> 8), vec_mask); + vec1_lo = vtst_u8(vdup_n_u8(m1), vec_mask); + vec1_hi = vtst_u8(vdup_n_u8(m1 >> 8), vec_mask); + tmp_lo = vtst_u8(vdup_n_u8(tb), vec_mask); + tmp_hi = vtst_u8(vdup_n_u8(tb >> 8), vec_mask); + + res_lo = vbsl_u8(vec0_lo, vdup_n_u8(0), vget_low_u8(mtx)); + res_hi = vbsl_u8(vec0_hi, vdup_n_u8(0), vget_high_u8(mtx)); + res_lo = vbsl_u8(vec1_lo, tmp_lo, res_lo); + res_hi = vbsl_u8(vec1_hi, tmp_hi, res_hi); + res_lo = vand_u8(res_lo, vec_mask); + res_hi = vand_u8(res_hi, vec_mask); + + int res = _sse2neon_vaddv_u8(res_lo) + (_sse2neon_vaddv_u8(res_hi) << 8); + return res; +} + +static int _sse2neon_cmp_word_equal_each(__m128i a, int la, __m128i b, int lb) +{ + uint16x8_t mtx = + vceqq_u16(vreinterpretq_u16_m128i(a), vreinterpretq_u16_m128i(b)); + int m0 = (la < lb) ? 0 : ((1 << la) - (1 << lb)); + int m1 = 0x100 - (1 << la); + int tb = 0x100 - (1 << lb); + uint16x8_t vec_mask = vld1q_u16(_sse2neon_cmpestr_mask16b); + uint16x8_t vec0 = vtstq_u16(vdupq_n_u16(m0), vec_mask); + uint16x8_t vec1 = vtstq_u16(vdupq_n_u16(m1), vec_mask); + uint16x8_t tmp = vtstq_u16(vdupq_n_u16(tb), vec_mask); + mtx = vbslq_u16(vec0, vdupq_n_u16(0), mtx); + mtx = vbslq_u16(vec1, tmp, mtx); + mtx = vandq_u16(mtx, vec_mask); + return _sse2neon_vaddvq_u16(mtx); +} + +#define SSE2NEON_AGGREGATE_EQUAL_ORDER_IS_UBYTE 1 +#define SSE2NEON_AGGREGATE_EQUAL_ORDER_IS_UWORD 0 + +#define SSE2NEON_AGGREGATE_EQUAL_ORDER_IMPL(size, number_of_lanes, data_type) \ + static int _sse2neon_aggregate_equal_ordered_##size##x##number_of_lanes( \ + int bound, int la, int lb, __m128i mtx[16]) \ + { \ + int res = 0; \ + int m1 = SSE2NEON_IIF(data_type)(0x10000, 0x100) - (1 << la); \ + uint##size##x8_t vec_mask = SSE2NEON_IIF(data_type)( \ + vld1_u##size(_sse2neon_cmpestr_mask##size##b), \ + vld1q_u##size(_sse2neon_cmpestr_mask##size##b)); \ + uint##size##x##number_of_lanes##_t vec1 = SSE2NEON_IIF(data_type)( \ + vcombine_u##size(vtst_u##size(vdup_n_u##size(m1), vec_mask), \ + vtst_u##size(vdup_n_u##size(m1 >> 8), vec_mask)), \ + vtstq_u##size(vdupq_n_u##size(m1), vec_mask)); \ + uint##size##x##number_of_lanes##_t vec_minusone = vdupq_n_u##size(-1); \ + uint##size##x##number_of_lanes##_t vec_zero = vdupq_n_u##size(0); \ + for (int j = 0; j < lb; j++) { \ + mtx[j] = vreinterpretq_m128i_u##size(vbslq_u##size( \ + vec1, vec_minusone, vreinterpretq_u##size##_m128i(mtx[j]))); \ + } \ + for (int j = lb; j < bound; j++) { \ + mtx[j] = vreinterpretq_m128i_u##size( \ + vbslq_u##size(vec1, vec_minusone, vec_zero)); \ + } \ + unsigned SSE2NEON_IIF(data_type)(char, short) *ptr = \ + (unsigned SSE2NEON_IIF(data_type)(char, short) *) mtx; \ + for (int i = 0; i < bound; i++) { \ + int val = 1; \ + for (int j = 0, k = i; j < bound - i && k < bound; j++, k++) \ + val &= ptr[k * bound + j]; \ + res += val << i; \ + } \ + return res; \ + } + +/* clang-format off */ +#define SSE2NEON_GENERATE_AGGREGATE_EQUAL_ORDER(prefix) \ + prefix##IMPL(8, 16, prefix##IS_UBYTE) \ + prefix##IMPL(16, 8, prefix##IS_UWORD) +/* clang-format on */ + +SSE2NEON_GENERATE_AGGREGATE_EQUAL_ORDER(SSE2NEON_AGGREGATE_EQUAL_ORDER_) + +#undef SSE2NEON_AGGREGATE_EQUAL_ORDER_IS_UBYTE +#undef SSE2NEON_AGGREGATE_EQUAL_ORDER_IS_UWORD + +/* clang-format off */ +#define SSE2NEON_GENERATE_CMP_EQUAL_ORDERED(prefix) \ + prefix##IMPL(byte) \ + prefix##IMPL(word) +/* clang-format on */ + +SSE2NEON_GENERATE_CMP_EQUAL_ORDERED(SSE2NEON_CMP_EQUAL_ORDERED_) + +#define SSE2NEON_CMPESTR_LIST \ + _(CMP_UBYTE_EQUAL_ANY, cmp_byte_equal_any) \ + _(CMP_UWORD_EQUAL_ANY, cmp_word_equal_any) \ + _(CMP_SBYTE_EQUAL_ANY, cmp_byte_equal_any) \ + _(CMP_SWORD_EQUAL_ANY, cmp_word_equal_any) \ + _(CMP_UBYTE_RANGES, cmp_ubyte_ranges) \ + _(CMP_UWORD_RANGES, cmp_uword_ranges) \ + _(CMP_SBYTE_RANGES, cmp_sbyte_ranges) \ + _(CMP_SWORD_RANGES, cmp_sword_ranges) \ + _(CMP_UBYTE_EQUAL_EACH, cmp_byte_equal_each) \ + _(CMP_UWORD_EQUAL_EACH, cmp_word_equal_each) \ + _(CMP_SBYTE_EQUAL_EACH, cmp_byte_equal_each) \ + _(CMP_SWORD_EQUAL_EACH, cmp_word_equal_each) \ + _(CMP_UBYTE_EQUAL_ORDERED, cmp_byte_equal_ordered) \ + _(CMP_UWORD_EQUAL_ORDERED, cmp_word_equal_ordered) \ + _(CMP_SBYTE_EQUAL_ORDERED, cmp_byte_equal_ordered) \ + _(CMP_SWORD_EQUAL_ORDERED, cmp_word_equal_ordered) + +enum { +#define _(name, func_suffix) name, + SSE2NEON_CMPESTR_LIST +#undef _ +}; +typedef int (*cmpestr_func_t)(__m128i a, int la, __m128i b, int lb); +static cmpestr_func_t _sse2neon_cmpfunc_table[] = { +#define _(name, func_suffix) _sse2neon_##func_suffix, + SSE2NEON_CMPESTR_LIST +#undef _ +}; + +FORCE_INLINE int _sse2neon_sido_negative(int res, int lb, int imm8, int bound) +{ + switch (imm8 & 0x30) { + case _SIDD_NEGATIVE_POLARITY: + res ^= 0xffffffff; + break; + case _SIDD_MASKED_NEGATIVE_POLARITY: + res ^= (1 << lb) - 1; + break; + default: + break; + } + + return res & ((bound == 8) ? 0xFF : 0xFFFF); +} + +FORCE_INLINE int _sse2neon_clz(unsigned int x) +{ +#if _MSC_VER + DWORD cnt = 0; + if (_BitScanForward(&cnt, x)) + return cnt; + return 32; +#else + return x != 0 ? __builtin_clz(x) : 32; +#endif +} + +FORCE_INLINE int _sse2neon_ctz(unsigned int x) +{ +#if _MSC_VER + DWORD cnt = 0; + if (_BitScanReverse(&cnt, x)) + return 31 - cnt; + return 32; +#else + return x != 0 ? __builtin_ctz(x) : 32; +#endif +} + +FORCE_INLINE int _sse2neon_ctzll(unsigned long long x) +{ +#if _MSC_VER + unsigned long cnt; +#ifdef defined(SSE2NEON_HAS_BITSCAN64) + (defined(_M_AMD64) || defined(__x86_64__)) + if((_BitScanForward64(&cnt, x)) + return (int)(cnt); +#else + if (_BitScanForward(&cnt, (unsigned long) (x))) + return (int) cnt; + if (_BitScanForward(&cnt, (unsigned long) (x >> 32))) + return (int) (cnt + 32); +#endif + return 64; +#else + return x != 0 ? __builtin_ctzll(x) : 64; +#endif +} + +#define SSE2NEON_MIN(x, y) (x) < (y) ? (x) : (y) + +#define SSE2NEON_CMPSTR_SET_UPPER(var, imm) \ + const int var = (imm & 0x01) ? 8 : 16 + +#define SSE2NEON_CMPESTRX_LEN_PAIR(a, b, la, lb) \ + int tmp1 = la ^ (la >> 31); \ + la = tmp1 - (la >> 31); \ + int tmp2 = lb ^ (lb >> 31); \ + lb = tmp2 - (lb >> 31); \ + la = SSE2NEON_MIN(la, bound); \ + lb = SSE2NEON_MIN(lb, bound) + +// Compare all pairs of character in string a and b, +// then aggregate the result. +// As the only difference of PCMPESTR* and PCMPISTR* is the way to calculate the +// length of string, we use SSE2NEON_CMP{I,E}STRX_GET_LEN to get the length of +// string a and b. +#define SSE2NEON_COMP_AGG(a, b, la, lb, imm8, IE) \ + SSE2NEON_CMPSTR_SET_UPPER(bound, imm8); \ + SSE2NEON_##IE##_LEN_PAIR(a, b, la, lb); \ + int r2 = (_sse2neon_cmpfunc_table[imm8 & 0x0f])(a, la, b, lb); \ + r2 = _sse2neon_sido_negative(r2, lb, imm8, bound) + +#define SSE2NEON_CMPSTR_GENERATE_INDEX(r2, bound, imm8) \ + return (r2 == 0) ? bound \ + : ((imm8 & 0x40) ? (31 - _sse2neon_clz(r2)) \ + : _sse2neon_ctz(r2)) + +#define SSE2NEON_CMPSTR_GENERATE_MASK(dst) \ + __m128i dst = vreinterpretq_m128i_u8(vdupq_n_u8(0)); \ + if (imm8 & 0x40) { \ + if (bound == 8) { \ + uint16x8_t tmp = vtstq_u16(vdupq_n_u16(r2), \ + vld1q_u16(_sse2neon_cmpestr_mask16b)); \ + dst = vreinterpretq_m128i_u16(vbslq_u16( \ + tmp, vdupq_n_u16(-1), vreinterpretq_u16_m128i(dst))); \ + } else { \ + uint8x16_t vec_r2 = \ + vcombine_u8(vdup_n_u8(r2), vdup_n_u8(r2 >> 8)); \ + uint8x16_t tmp = \ + vtstq_u8(vec_r2, vld1q_u8(_sse2neon_cmpestr_mask8b)); \ + dst = vreinterpretq_m128i_u8( \ + vbslq_u8(tmp, vdupq_n_u8(-1), vreinterpretq_u8_m128i(dst))); \ + } \ + } else { \ + if (bound == 16) { \ + dst = vreinterpretq_m128i_u16( \ + vsetq_lane_u16(r2 & 0xffff, vreinterpretq_u16_m128i(dst), 0)); \ + } else { \ + dst = vreinterpretq_m128i_u8( \ + vsetq_lane_u8(r2 & 0xff, vreinterpretq_u8_m128i(dst), 0)); \ + } \ + } \ + return dst + +// Compare packed strings in a and b with lengths la and lb using the control +// in imm8, and returns 1 if b did not contain a null character and the +// resulting mask was zero, and 0 otherwise. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestra +FORCE_INLINE int _mm_cmpestra(__m128i a, + int la, + __m128i b, + int lb, + const int imm8) +{ + int lb_cpy = lb; + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPESTRX); + return !r2 & (lb_cpy > bound); +} + +// Compare packed strings in a and b with lengths la and lb using the control in +// imm8, and returns 1 if the resulting mask was non-zero, and 0 otherwise. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestrc +FORCE_INLINE int _mm_cmpestrc(__m128i a, + int la, + __m128i b, + int lb, + const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPESTRX); + return r2 != 0; +} + +// Compare packed strings in a and b with lengths la and lb using the control +// in imm8, and store the generated index in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestri +FORCE_INLINE int _mm_cmpestri(__m128i a, + int la, + __m128i b, + int lb, + const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPESTRX); + SSE2NEON_CMPSTR_GENERATE_INDEX(r2, bound, imm8); +} + +// Compare packed strings in a and b with lengths la and lb using the control +// in imm8, and store the generated mask in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestrm +FORCE_INLINE __m128i +_mm_cmpestrm(__m128i a, int la, __m128i b, int lb, const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPESTRX); + SSE2NEON_CMPSTR_GENERATE_MASK(dst); +} + +// Compare packed strings in a and b with lengths la and lb using the control in +// imm8, and returns bit 0 of the resulting bit mask. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestro +FORCE_INLINE int _mm_cmpestro(__m128i a, + int la, + __m128i b, + int lb, + const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPESTRX); + return r2 & 1; +} + +// Compare packed strings in a and b with lengths la and lb using the control in +// imm8, and returns 1 if any character in a was null, and 0 otherwise. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestrs +FORCE_INLINE int _mm_cmpestrs(__m128i a, + int la, + __m128i b, + int lb, + const int imm8) +{ + SSE2NEON_CMPSTR_SET_UPPER(bound, imm8); + return la <= (bound - 1); +} + +// Compare packed strings in a and b with lengths la and lb using the control in +// imm8, and returns 1 if any character in b was null, and 0 otherwise. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestrz +FORCE_INLINE int _mm_cmpestrz(__m128i a, + int la, + __m128i b, + int lb, + const int imm8) +{ + SSE2NEON_CMPSTR_SET_UPPER(bound, imm8); + return lb <= (bound - 1); +} + +#define SSE2NEON_CMPISTRX_LENGTH(str, len, imm8) \ + do { \ + if (imm8 & 0x01) { \ + uint16x8_t equal_mask_##str = \ + vceqq_u16(vreinterpretq_u16_m128i(str), vdupq_n_u16(0)); \ + uint8x8_t res_##str = vshrn_n_u16(equal_mask_##str, 4); \ + uint64_t matches_##str = \ + vget_lane_u64(vreinterpret_u64_u8(res_##str), 0); \ + len = _sse2neon_ctzll(matches_##str) >> 3; \ + } else { \ + uint16x8_t equal_mask_##str = vreinterpretq_u16_u8( \ + vceqq_u8(vreinterpretq_u8_m128i(str), vdupq_n_u8(0))); \ + uint8x8_t res_##str = vshrn_n_u16(equal_mask_##str, 4); \ + uint64_t matches_##str = \ + vget_lane_u64(vreinterpret_u64_u8(res_##str), 0); \ + len = _sse2neon_ctzll(matches_##str) >> 2; \ + } \ + } while (0) + +#define SSE2NEON_CMPISTRX_LEN_PAIR(a, b, la, lb) \ + int la, lb; \ + do { \ + SSE2NEON_CMPISTRX_LENGTH(a, la, imm8); \ + SSE2NEON_CMPISTRX_LENGTH(b, lb, imm8); \ + } while (0) + +// Compare packed strings with implicit lengths in a and b using the control in +// imm8, and returns 1 if b did not contain a null character and the resulting +// mask was zero, and 0 otherwise. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpistra +FORCE_INLINE int _mm_cmpistra(__m128i a, __m128i b, const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPISTRX); + return !r2 & (lb >= bound); +} + +// Compare packed strings with implicit lengths in a and b using the control in +// imm8, and returns 1 if the resulting mask was non-zero, and 0 otherwise. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpistrc +FORCE_INLINE int _mm_cmpistrc(__m128i a, __m128i b, const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPISTRX); + return r2 != 0; +} + +// Compare packed strings with implicit lengths in a and b using the control in +// imm8, and store the generated index in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpistri +FORCE_INLINE int _mm_cmpistri(__m128i a, __m128i b, const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPISTRX); + SSE2NEON_CMPSTR_GENERATE_INDEX(r2, bound, imm8); +} + +// Compare packed strings with implicit lengths in a and b using the control in +// imm8, and store the generated mask in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpistrm +FORCE_INLINE __m128i _mm_cmpistrm(__m128i a, __m128i b, const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPISTRX); + SSE2NEON_CMPSTR_GENERATE_MASK(dst); +} + +// Compare packed strings with implicit lengths in a and b using the control in +// imm8, and returns bit 0 of the resulting bit mask. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpistro +FORCE_INLINE int _mm_cmpistro(__m128i a, __m128i b, const int imm8) +{ + SSE2NEON_COMP_AGG(a, b, la, lb, imm8, CMPISTRX); + return r2 & 1; +} + +// Compare packed strings with implicit lengths in a and b using the control in +// imm8, and returns 1 if any character in a was null, and 0 otherwise. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpistrs +FORCE_INLINE int _mm_cmpistrs(__m128i a, __m128i b, const int imm8) +{ + SSE2NEON_CMPSTR_SET_UPPER(bound, imm8); + int la; + SSE2NEON_CMPISTRX_LENGTH(a, la, imm8); + return la <= (bound - 1); +} + +// Compare packed strings with implicit lengths in a and b using the control in +// imm8, and returns 1 if any character in b was null, and 0 otherwise. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpistrz +FORCE_INLINE int _mm_cmpistrz(__m128i a, __m128i b, const int imm8) +{ + SSE2NEON_CMPSTR_SET_UPPER(bound, imm8); + int lb; + SSE2NEON_CMPISTRX_LENGTH(b, lb, imm8); + return lb <= (bound - 1); +} + // Compares the 2 signed 64-bit integers in a and the 2 signed 64-bit integers // in b for greater than. FORCE_INLINE __m128i _mm_cmpgt_epi64(__m128i a, __m128i b) @@ -8320,6 +9342,8 @@ FORCE_INLINE uint32_t _mm_crc32_u16(uint32_t crc, uint16_t v) __asm__ __volatile__("crc32ch %w[c], %w[c], %w[v]\n\t" : [c] "+r"(crc) : [v] "r"(v)); +#elif (__ARM_ARCH == 8) && defined(__ARM_FEATURE_CRC32) + crc = __crc32ch(crc, v); #else crc = _mm_crc32_u8(crc, v & 0xff); crc = _mm_crc32_u8(crc, (v >> 8) & 0xff); @@ -8336,6 +9360,8 @@ FORCE_INLINE uint32_t _mm_crc32_u32(uint32_t crc, uint32_t v) __asm__ __volatile__("crc32cw %w[c], %w[c], %w[v]\n\t" : [c] "+r"(crc) : [v] "r"(v)); +#elif (__ARM_ARCH == 8) && defined(__ARM_FEATURE_CRC32) + crc = __crc32cw(crc, v); #else crc = _mm_crc32_u16(crc, v & 0xffff); crc = _mm_crc32_u16(crc, (v >> 16) & 0xffff); @@ -8353,8 +9379,8 @@ FORCE_INLINE uint64_t _mm_crc32_u64(uint64_t crc, uint64_t v) : [c] "+r"(crc) : [v] "r"(v)); #else - crc = _mm_crc32_u32((uint32_t)(crc), v & 0xffffffff); - crc = _mm_crc32_u32((uint32_t)(crc), (v >> 32) & 0xffffffff); + crc = _mm_crc32_u32((uint32_t) (crc), v & 0xffffffff); + crc = _mm_crc32_u32((uint32_t) (crc), (v >> 32) & 0xffffffff); #endif return crc; } @@ -8368,6 +9394,8 @@ FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v) __asm__ __volatile__("crc32cb %w[c], %w[c], %w[v]\n\t" : [c] "+r"(crc) : [v] "r"(v)); +#elif (__ARM_ARCH == 8) && defined(__ARM_FEATURE_CRC32) + crc = __crc32cb(crc, v); #else crc ^= v; for (int bit = 0; bit < 8; bit++) { @@ -8384,7 +9412,7 @@ FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v) #if !defined(__ARM_FEATURE_CRYPTO) /* clang-format off */ -#define SSE2NEON_AES_DATA(w) \ +#define SSE2NEON_AES_SBOX(w) \ { \ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), \ w(0xc5), w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), \ @@ -8424,53 +9452,115 @@ FORCE_INLINE uint32_t _mm_crc32_u8(uint32_t crc, uint8_t v) w(0xe6), w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), \ w(0xb0), w(0x54), w(0xbb), w(0x16) \ } +#define SSE2NEON_AES_RSBOX(w) \ + { \ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), \ + w(0x38), w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), \ + w(0xd7), w(0xfb), w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), \ + w(0x2f), w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), \ + w(0xc4), w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), \ + w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), \ + w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e), w(0x08), \ + w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2), \ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), \ + w(0x25), w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), \ + w(0x98), w(0x16), w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), \ + w(0x65), w(0xb6), w(0x92), w(0x6c), w(0x70), w(0x48), w(0x50), \ + w(0xfd), w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), \ + w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), \ + w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), \ + w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06), \ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), \ + w(0x02), w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), \ + w(0x8a), w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), \ + w(0x67), w(0xdc), w(0xea), w(0x97), w(0xf2), w(0xcf), w(0xce), \ + w(0xf0), w(0xb4), w(0xe6), w(0x73), w(0x96), w(0xac), w(0x74), \ + w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), \ + w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), \ + w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), \ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), \ + w(0x1b), w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), \ + w(0x79), w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), \ + w(0xcd), w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), \ + w(0x88), w(0x07), w(0xc7), w(0x31), w(0xb1), w(0x12), w(0x10), \ + w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f), w(0x60), w(0x51), \ + w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), \ + w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), \ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), \ + w(0xb0), w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), \ + w(0x99), w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), \ + w(0x77), w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), \ + w(0x55), w(0x21), w(0x0c), w(0x7d) \ + } /* clang-format on */ /* X Macro trick. See https://en.wikipedia.org/wiki/X_Macro */ #define SSE2NEON_AES_H0(x) (x) -static const uint8_t SSE2NEON_sbox[256] = SSE2NEON_AES_DATA(SSE2NEON_AES_H0); +static const uint8_t _sse2neon_sbox[256] = SSE2NEON_AES_SBOX(SSE2NEON_AES_H0); +static const uint8_t _sse2neon_rsbox[256] = SSE2NEON_AES_RSBOX(SSE2NEON_AES_H0); #undef SSE2NEON_AES_H0 +/* x_time function and matrix multiply function */ +#if !defined(__aarch64__) +#define SSE2NEON_XT(x) (((x) << 1) ^ ((((x) >> 7) & 1) * 0x1b)) +#define SSE2NEON_MULTIPLY(x, y) \ + (((y & 1) * x) ^ ((y >> 1 & 1) * SSE2NEON_XT(x)) ^ \ + ((y >> 2 & 1) * SSE2NEON_XT(SSE2NEON_XT(x))) ^ \ + ((y >> 3 & 1) * SSE2NEON_XT(SSE2NEON_XT(SSE2NEON_XT(x)))) ^ \ + ((y >> 4 & 1) * SSE2NEON_XT(SSE2NEON_XT(SSE2NEON_XT(SSE2NEON_XT(x)))))) +#endif + // In the absence of crypto extensions, implement aesenc using regular neon // intrinsics instead. See: // https://www.workofard.com/2017/01/accelerated-aes-for-the-arm64-linux-kernel/ // https://www.workofard.com/2017/07/ghash-for-low-end-cores/ and // https://github.com/ColinIanKing/linux-next-mirror/blob/b5f466091e130caaf0735976648f72bd5e09aa84/crypto/aegis128-neon-inner.c#L52 // for more information Reproduced with permission of the author. -FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey) +FORCE_INLINE __m128i _mm_aesenc_si128(__m128i a, __m128i RoundKey) { #if defined(__aarch64__) - static const uint8_t shift_rows[] = {0x0, 0x5, 0xa, 0xf, 0x4, 0x9, - 0xe, 0x3, 0x8, 0xd, 0x2, 0x7, - 0xc, 0x1, 0x6, 0xb}; - static const uint8_t ror32by8[] = {0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4, - 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc}; + static const uint8_t shift_rows[] = { + 0x0, 0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x3, + 0x8, 0xd, 0x2, 0x7, 0xc, 0x1, 0x6, 0xb, + }; + static const uint8_t ror32by8[] = { + 0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4, + 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc, + }; uint8x16_t v; - uint8x16_t w = vreinterpretq_u8_m128i(EncBlock); + uint8x16_t w = vreinterpretq_u8_m128i(a); - // shift rows + /* shift rows */ w = vqtbl1q_u8(w, vld1q_u8(shift_rows)); - // sub bytes - v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(SSE2NEON_sbox), w); - v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0x40), w - 0x40); - v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0x80), w - 0x80); - v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(SSE2NEON_sbox + 0xc0), w - 0xc0); - - // mix columns - w = (v << 1) ^ (uint8x16_t)(((int8x16_t) v >> 7) & 0x1b); + /* sub bytes */ + // Here, we separate the whole 256-bytes table into 4 64-bytes tables, and + // look up each of the table. After each lookup, we load the next table + // which locates at the next 64-bytes. In the meantime, the index in the + // table would be smaller than it was, so the index parameters of + // `vqtbx4q_u8()` need to be added the same constant as the loaded tables. + v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(_sse2neon_sbox), w); + // 'w-0x40' equals to 'vsubq_u8(w, vdupq_n_u8(0x40))' + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0x40), w - 0x40); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0x80), w - 0x80); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0xc0), w - 0xc0); + + /* mix columns */ + w = (v << 1) ^ (uint8x16_t) (((int8x16_t) v >> 7) & 0x1b); w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v); w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8)); - // add round key + /* add round key */ return vreinterpretq_m128i_u8(w) ^ RoundKey; -#else /* ARMv7-A NEON implementation */ -#define SSE2NEON_AES_B2W(b0, b1, b2, b3) \ - (((uint32_t)(b3) << 24) | ((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | \ - (b0)) +#else /* ARMv7-A implementation for a table-based AES */ +#define SSE2NEON_AES_B2W(b0, b1, b2, b3) \ + (((uint32_t) (b3) << 24) | ((uint32_t) (b2) << 16) | \ + ((uint32_t) (b1) << 8) | (uint32_t) (b0)) +// muliplying 'x' by 2 in GF(2^8) #define SSE2NEON_AES_F2(x) ((x << 1) ^ (((x >> 7) & 1) * 0x011b /* WPOLY */)) +// muliplying 'x' by 3 in GF(2^8) #define SSE2NEON_AES_F3(x) (SSE2NEON_AES_F2(x) ^ x) #define SSE2NEON_AES_U0(p) \ SSE2NEON_AES_B2W(SSE2NEON_AES_F2(p), p, p, SSE2NEON_AES_F3(p)) @@ -8480,11 +9570,14 @@ FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey) SSE2NEON_AES_B2W(p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p), p) #define SSE2NEON_AES_U3(p) \ SSE2NEON_AES_B2W(p, p, SSE2NEON_AES_F3(p), SSE2NEON_AES_F2(p)) + + // this generates a table containing every possible permutation of + // shift_rows() and sub_bytes() with mix_columns(). static const uint32_t ALIGN_STRUCT(16) aes_table[4][256] = { - SSE2NEON_AES_DATA(SSE2NEON_AES_U0), - SSE2NEON_AES_DATA(SSE2NEON_AES_U1), - SSE2NEON_AES_DATA(SSE2NEON_AES_U2), - SSE2NEON_AES_DATA(SSE2NEON_AES_U3), + SSE2NEON_AES_SBOX(SSE2NEON_AES_U0), + SSE2NEON_AES_SBOX(SSE2NEON_AES_U1), + SSE2NEON_AES_SBOX(SSE2NEON_AES_U2), + SSE2NEON_AES_SBOX(SSE2NEON_AES_U3), }; #undef SSE2NEON_AES_B2W #undef SSE2NEON_AES_F2 @@ -8494,11 +9587,15 @@ FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey) #undef SSE2NEON_AES_U2 #undef SSE2NEON_AES_U3 - uint32_t x0 = _mm_cvtsi128_si32(EncBlock); - uint32_t x1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0x55)); - uint32_t x2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xAA)); - uint32_t x3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(EncBlock, 0xFF)); + uint32_t x0 = _mm_cvtsi128_si32(a); // get a[31:0] + uint32_t x1 = + _mm_cvtsi128_si32(_mm_shuffle_epi32(a, 0x55)); // get a[63:32] + uint32_t x2 = + _mm_cvtsi128_si32(_mm_shuffle_epi32(a, 0xAA)); // get a[95:64] + uint32_t x3 = + _mm_cvtsi128_si32(_mm_shuffle_epi32(a, 0xFF)); // get a[127:96] + // finish the modulo addition step in mix_columns() __m128i out = _mm_set_epi32( (aes_table[0][x3 & 0xff] ^ aes_table[1][(x0 >> 8) & 0xff] ^ aes_table[2][(x1 >> 16) & 0xff] ^ aes_table[3][x2 >> 24]), @@ -8513,34 +9610,210 @@ FORCE_INLINE __m128i _mm_aesenc_si128(__m128i EncBlock, __m128i RoundKey) #endif } +// Perform one round of an AES decryption flow on data (state) in a using the +// round key in RoundKey, and store the result in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128 +FORCE_INLINE __m128i _mm_aesdec_si128(__m128i a, __m128i RoundKey) +{ +#if defined(__aarch64__) + static const uint8_t inv_shift_rows[] = { + 0x0, 0xd, 0xa, 0x7, 0x4, 0x1, 0xe, 0xb, + 0x8, 0x5, 0x2, 0xf, 0xc, 0x9, 0x6, 0x3, + }; + static const uint8_t ror32by8[] = { + 0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4, + 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc, + }; + + uint8x16_t v; + uint8x16_t w = vreinterpretq_u8_m128i(a); + + // inverse shift rows + w = vqtbl1q_u8(w, vld1q_u8(inv_shift_rows)); + + // inverse sub bytes + v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(_sse2neon_rsbox), w); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_rsbox + 0x40), w - 0x40); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_rsbox + 0x80), w - 0x80); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_rsbox + 0xc0), w - 0xc0); + + // inverse mix columns + // muliplying 'v' by 4 in GF(2^8) + w = (v << 1) ^ (uint8x16_t) (((int8x16_t) v >> 7) & 0x1b); + w = (w << 1) ^ (uint8x16_t) (((int8x16_t) w >> 7) & 0x1b); + v ^= w; + v ^= (uint8x16_t) vrev32q_u16((uint16x8_t) w); + + w = (v << 1) ^ (uint8x16_t) (((int8x16_t) v >> 7) & + 0x1b); // muliplying 'v' by 2 in GF(2^8) + w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v); + w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8)); + + // add round key + return vreinterpretq_m128i_u8(w) ^ RoundKey; + +#else /* ARMv7-A NEON implementation */ + /* FIXME: optimized for NEON */ + uint8_t i, e, f, g, h, v[4][4]; + uint8_t *_a = (uint8_t *) &a; + for (i = 0; i < 16; ++i) { + v[((i / 4) + (i % 4)) % 4][i % 4] = _sse2neon_rsbox[_a[i]]; + } + + // inverse mix columns + for (i = 0; i < 4; ++i) { + e = v[i][0]; + f = v[i][1]; + g = v[i][2]; + h = v[i][3]; + + v[i][0] = SSE2NEON_MULTIPLY(e, 0x0e) ^ SSE2NEON_MULTIPLY(f, 0x0b) ^ + SSE2NEON_MULTIPLY(g, 0x0d) ^ SSE2NEON_MULTIPLY(h, 0x09); + v[i][1] = SSE2NEON_MULTIPLY(e, 0x09) ^ SSE2NEON_MULTIPLY(f, 0x0e) ^ + SSE2NEON_MULTIPLY(g, 0x0b) ^ SSE2NEON_MULTIPLY(h, 0x0d); + v[i][2] = SSE2NEON_MULTIPLY(e, 0x0d) ^ SSE2NEON_MULTIPLY(f, 0x09) ^ + SSE2NEON_MULTIPLY(g, 0x0e) ^ SSE2NEON_MULTIPLY(h, 0x0b); + v[i][3] = SSE2NEON_MULTIPLY(e, 0x0b) ^ SSE2NEON_MULTIPLY(f, 0x0d) ^ + SSE2NEON_MULTIPLY(g, 0x09) ^ SSE2NEON_MULTIPLY(h, 0x0e); + } + + return vreinterpretq_m128i_u8(vld1q_u8((uint8_t *) v)) ^ RoundKey; +#endif +} + // Perform the last round of an AES encryption flow on data (state) in a using // the round key in RoundKey, and store the result in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128 FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) { +#if defined(__aarch64__) + static const uint8_t shift_rows[] = { + 0x0, 0x5, 0xa, 0xf, 0x4, 0x9, 0xe, 0x3, + 0x8, 0xd, 0x2, 0x7, 0xc, 0x1, 0x6, 0xb, + }; + + uint8x16_t v; + uint8x16_t w = vreinterpretq_u8_m128i(a); + + // shift rows + w = vqtbl1q_u8(w, vld1q_u8(shift_rows)); + + // sub bytes + v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(_sse2neon_sbox), w); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0x40), w - 0x40); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0x80), w - 0x80); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0xc0), w - 0xc0); + + // add round key + return vreinterpretq_m128i_u8(v) ^ RoundKey; + +#else /* ARMv7-A implementation */ + uint8_t v[16] = { + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 0)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 5)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 10)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 15)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 4)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 9)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 14)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 3)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 8)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 13)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 2)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 7)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 12)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 1)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 6)], + _sse2neon_sbox[vgetq_lane_u8(vreinterpretq_u8_m128i(a), 11)], + }; + + return vreinterpretq_m128i_u8(vld1q_u8(v)) ^ RoundKey; +#endif +} + +// Perform the last round of an AES decryption flow on data (state) in a using +// the round key in RoundKey, and store the result in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128 +FORCE_INLINE __m128i _mm_aesdeclast_si128(__m128i a, __m128i RoundKey) +{ +#if defined(__aarch64__) + static const uint8_t inv_shift_rows[] = { + 0x0, 0xd, 0xa, 0x7, 0x4, 0x1, 0xe, 0xb, + 0x8, 0x5, 0x2, 0xf, 0xc, 0x9, 0x6, 0x3, + }; + + uint8x16_t v; + uint8x16_t w = vreinterpretq_u8_m128i(a); + + // inverse shift rows + w = vqtbl1q_u8(w, vld1q_u8(inv_shift_rows)); + + // inverse sub bytes + v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(_sse2neon_rsbox), w); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_rsbox + 0x40), w - 0x40); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_rsbox + 0x80), w - 0x80); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_rsbox + 0xc0), w - 0xc0); + + // add round key + return vreinterpretq_m128i_u8(v) ^ RoundKey; + +#else /* ARMv7-A NEON implementation */ /* FIXME: optimized for NEON */ - uint8_t v[4][4] = { - {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]}, - {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]}, - {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]}, - {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]}, + uint8_t v[4][4]; + uint8_t *_a = (uint8_t *) &a; + for (int i = 0; i < 16; ++i) { + v[((i / 4) + (i % 4)) % 4][i % 4] = _sse2neon_rsbox[_a[i]]; + } + + return vreinterpretq_m128i_u8(vld1q_u8((uint8_t *) v)) ^ RoundKey; +#endif +} + +// Perform the InvMixColumns transformation on a and store the result in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesimc_si128 +FORCE_INLINE __m128i _mm_aesimc_si128(__m128i a) +{ +#if defined(__aarch64__) + static const uint8_t ror32by8[] = { + 0x1, 0x2, 0x3, 0x0, 0x5, 0x6, 0x7, 0x4, + 0x9, 0xa, 0xb, 0x8, 0xd, 0xe, 0xf, 0xc, }; - for (int i = 0; i < 16; i++) - vreinterpretq_nth_u8_m128i(a, i) = - v[i / 4][i % 4] ^ vreinterpretq_nth_u8_m128i(RoundKey, i); - return a; + uint8x16_t v = vreinterpretq_u8_m128i(a); + uint8x16_t w; + + // multiplying 'v' by 4 in GF(2^8) + w = (v << 1) ^ (uint8x16_t) (((int8x16_t) v >> 7) & 0x1b); + w = (w << 1) ^ (uint8x16_t) (((int8x16_t) w >> 7) & 0x1b); + v ^= w; + v ^= (uint8x16_t) vrev32q_u16((uint16x8_t) w); + + // multiplying 'v' by 2 in GF(2^8) + w = (v << 1) ^ (uint8x16_t) (((int8x16_t) v >> 7) & 0x1b); + w ^= (uint8x16_t) vrev32q_u16((uint16x8_t) v); + w ^= vqtbl1q_u8(v ^ w, vld1q_u8(ror32by8)); + return vreinterpretq_m128i_u8(w); + +#else /* ARMv7-A NEON implementation */ + uint8_t i, e, f, g, h, v[4][4]; + vst1q_u8((uint8_t *) v, vreinterpretq_u8_m128i(a)); + for (i = 0; i < 4; ++i) { + e = v[i][0]; + f = v[i][1]; + g = v[i][2]; + h = v[i][3]; + + v[i][0] = SSE2NEON_MULTIPLY(e, 0x0e) ^ SSE2NEON_MULTIPLY(f, 0x0b) ^ + SSE2NEON_MULTIPLY(g, 0x0d) ^ SSE2NEON_MULTIPLY(h, 0x09); + v[i][1] = SSE2NEON_MULTIPLY(e, 0x09) ^ SSE2NEON_MULTIPLY(f, 0x0e) ^ + SSE2NEON_MULTIPLY(g, 0x0b) ^ SSE2NEON_MULTIPLY(h, 0x0d); + v[i][2] = SSE2NEON_MULTIPLY(e, 0x0d) ^ SSE2NEON_MULTIPLY(f, 0x09) ^ + SSE2NEON_MULTIPLY(g, 0x0e) ^ SSE2NEON_MULTIPLY(h, 0x0b); + v[i][3] = SSE2NEON_MULTIPLY(e, 0x0b) ^ SSE2NEON_MULTIPLY(f, 0x0d) ^ + SSE2NEON_MULTIPLY(g, 0x09) ^ SSE2NEON_MULTIPLY(h, 0x0e); + } + + return vreinterpretq_m128i_u8(vld1q_u8((uint8_t *) v)); +#endif } // Emits the Advanced Encryption Standard (AES) instruction aeskeygenassist. @@ -8548,19 +9821,43 @@ FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) // https://kazakov.life/2017/11/01/cryptocurrency-mining-on-ios-devices/ // for details. // -// https://msdn.microsoft.com/en-us/library/cc714138(v=vs.120).aspx -FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i key, const int rcon) +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aeskeygenassist_si128 +FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon) { - uint32_t X1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0x55)); - uint32_t X3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0xFF)); +#if defined(__aarch64__) + uint8x16_t _a = vreinterpretq_u8_m128i(a); + uint8x16_t v = vqtbl4q_u8(_sse2neon_vld1q_u8_x4(_sse2neon_sbox), _a); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0x40), _a - 0x40); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0x80), _a - 0x80); + v = vqtbx4q_u8(v, _sse2neon_vld1q_u8_x4(_sse2neon_sbox + 0xc0), _a - 0xc0); + + uint32x4_t select_mask = {0xffffffff, 0x0, 0xffffffff, 0x0}; + uint64x2_t v_mask = vshrq_n_u64(vreinterpretq_u64_u8(v), 32); + uint32x4_t x = vbslq_u32(select_mask, vreinterpretq_u32_u64(v_mask), + vreinterpretq_u32_u8(v)); + uint32x4_t ror_x = vorrq_u32(vshrq_n_u32(x, 8), vshlq_n_u32(x, 24)); + uint32x4_t ror_xor_x = veorq_u32(ror_x, vdupq_n_u32(rcon)); + + return vreinterpretq_m128i_u32(vbslq_u32(select_mask, x, ror_xor_x)); + +#else /* ARMv7-A NEON implementation */ + uint32_t X1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, 0x55)); + uint32_t X3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(a, 0xFF)); for (int i = 0; i < 4; ++i) { - ((uint8_t *) &X1)[i] = SSE2NEON_sbox[((uint8_t *) &X1)[i]]; - ((uint8_t *) &X3)[i] = SSE2NEON_sbox[((uint8_t *) &X3)[i]]; + ((uint8_t *) &X1)[i] = _sse2neon_sbox[((uint8_t *) &X1)[i]]; + ((uint8_t *) &X3)[i] = _sse2neon_sbox[((uint8_t *) &X3)[i]]; } return _mm_set_epi32(((X3 >> 8) | (X3 << 24)) ^ rcon, X3, ((X1 >> 8) | (X1 << 24)) ^ rcon, X1); +#endif } -#undef SSE2NEON_AES_DATA +#undef SSE2NEON_AES_SBOX +#undef SSE2NEON_AES_RSBOX + +#if defined(__aarch64__) +#undef SSE2NEON_XT +#undef SSE2NEON_MULTIPLY +#endif #else /* __ARM_FEATURE_CRYPTO */ // Implements equivalent of 'aesenc' by combining AESE (with an empty key) and @@ -8576,7 +9873,19 @@ FORCE_INLINE __m128i _mm_aesenc_si128(__m128i a, __m128i b) vreinterpretq_u8_m128i(b)); } -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_aesenclast_si128 +// Perform one round of an AES decryption flow on data (state) in a using the +// round key in RoundKey, and store the result in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128 +FORCE_INLINE __m128i _mm_aesdec_si128(__m128i a, __m128i RoundKey) +{ + return vreinterpretq_m128i_u8(veorq_u8( + vaesimcq_u8(vaesdq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0))), + vreinterpretq_u8_m128i(RoundKey))); +} + +// Perform the last round of an AES encryption flow on data (state) in a using +// the round key in RoundKey, and store the result in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128 FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) { return _mm_xor_si128(vreinterpretq_m128i_u8(vaeseq_u8( @@ -8584,6 +9893,27 @@ FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) RoundKey); } +// Perform the last round of an AES decryption flow on data (state) in a using +// the round key in RoundKey, and store the result in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128 +FORCE_INLINE __m128i _mm_aesdeclast_si128(__m128i a, __m128i RoundKey) +{ + return vreinterpretq_m128i_u8( + vaesdq_u8(vreinterpretq_u8_m128i(a), vdupq_n_u8(0))) ^ + vreinterpretq_u8_m128i(RoundKey); +} + +// Perform the InvMixColumns transformation on a and store the result in dst. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesimc_si128 +FORCE_INLINE __m128i _mm_aesimc_si128(__m128i a) +{ + return vreinterpretq_m128i_u8(vaesimcq_u8(a)); +} + +// Assist in expanding the AES cipher key by computing steps towards generating +// a round key for encryption cipher using data from a and an 8-bit round +// constant specified in imm8, and store the result in dst." +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aeskeygenassist_si128 FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon) { // AESE does ShiftRows and SubBytes on A @@ -8605,7 +9935,7 @@ FORCE_INLINE __m128i _mm_aeskeygenassist_si128(__m128i a, const int rcon) // Perform a carry-less multiplication of two 64-bit integers, selected from a // and b according to imm8, and store the results in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_clmulepi64_si128 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clmulepi64_si128 FORCE_INLINE __m128i _mm_clmulepi64_si128(__m128i _a, __m128i _b, const int imm) { uint64x2_t a = vreinterpretq_u64_m128i(_a); @@ -8640,9 +9970,9 @@ FORCE_INLINE unsigned int _sse2neon_mm_get_denormals_zero_mode() } r; #if defined(__aarch64__) - asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ #else - asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ #endif return r.field.bit24 ? _MM_DENORMALS_ZERO_ON : _MM_DENORMALS_ZERO_OFF; @@ -8650,7 +9980,7 @@ FORCE_INLINE unsigned int _sse2neon_mm_get_denormals_zero_mode() // Count the number of bits set to 1 in unsigned 32-bit integer a, and // return that count in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u32 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_popcnt_u32 FORCE_INLINE int _mm_popcnt_u32(unsigned int a) { #if defined(__aarch64__) @@ -8677,7 +10007,7 @@ FORCE_INLINE int _mm_popcnt_u32(unsigned int a) // Count the number of bits set to 1 in unsigned 64-bit integer a, and // return that count in dst. -// https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_popcnt_u64 +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_popcnt_u64 FORCE_INLINE int64_t _mm_popcnt_u64(uint64_t a) { #if defined(__aarch64__) @@ -8717,17 +10047,55 @@ FORCE_INLINE void _sse2neon_mm_set_denormals_zero_mode(unsigned int flag) } r; #if defined(__aarch64__) - asm volatile("mrs %0, FPCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("mrs %0, FPCR" : "=r"(r.value)); /* read */ #else - asm volatile("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ + __asm__ __volatile__("vmrs %0, FPSCR" : "=r"(r.value)); /* read */ #endif r.field.bit24 = (flag & _MM_DENORMALS_ZERO_MASK) == _MM_DENORMALS_ZERO_ON; #if defined(__aarch64__) - asm volatile("msr FPCR, %0" ::"r"(r)); /* write */ + __asm__ __volatile__("msr FPCR, %0" ::"r"(r)); /* write */ #else - asm volatile("vmsr FPSCR, %0" ::"r"(r)); /* write */ + __asm__ __volatile__("vmsr FPSCR, %0" ::"r"(r)); /* write */ +#endif +} + +// Return the current 64-bit value of the processor's time-stamp counter. +// https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=rdtsc + +FORCE_INLINE uint64_t _rdtsc(void) +{ +#if defined(__aarch64__) + uint64_t val; + + /* According to ARM DDI 0487F.c, from Armv8.0 to Armv8.5 inclusive, the + * system counter is at least 56 bits wide; from Armv8.6, the counter + * must be 64 bits wide. So the system counter could be less than 64 + * bits wide and it is attributed with the flag 'cap_user_time_short' + * is true. + */ + __asm__ __volatile__("mrs %0, cntvct_el0" : "=r"(val)); + + return val; +#else + uint32_t pmccntr, pmuseren, pmcntenset; + // Read the user mode Performance Monitoring Unit (PMU) + // User Enable Register (PMUSERENR) access permissions. + __asm__ __volatile__("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren)); + if (pmuseren & 1) { // Allows reading PMUSERENR for user mode code. + __asm__ __volatile__("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset)); + if (pmcntenset & 0x80000000UL) { // Is it counting? + __asm__ __volatile__("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr)); + // The counter is set up to count every 64th cycle + return (uint64_t) (pmccntr) << 6; + } + } + + // Fallback to syscall as we can't enable PMUSERENR in user mode. + struct timeval tv; + gettimeofday(&tv, NULL); + return (uint64_t) (tv.tv_sec) * 1000000 + tv.tv_usec; #endif } @@ -8740,4 +10108,4 @@ FORCE_INLINE void _sse2neon_mm_set_denormals_zero_mode(unsigned int flag) #pragma GCC pop_options #endif -#endif
\ No newline at end of file +#endif diff --git a/thirdparty/embree/common/simd/avx.h b/thirdparty/embree/common/simd/avx.h index d3100306ee..7c63749f56 100644 --- a/thirdparty/embree/common/simd/avx.h +++ b/thirdparty/embree/common/simd/avx.h @@ -31,4 +31,3 @@ #if defined(__AVX512F__) #include "avx512.h" #endif - diff --git a/thirdparty/embree/common/simd/simd.h b/thirdparty/embree/common/simd/simd.h index 34e37b08b1..e777d2df01 100644 --- a/thirdparty/embree/common/simd/simd.h +++ b/thirdparty/embree/common/simd/simd.h @@ -3,7 +3,7 @@ #pragma once -#include "../math/math.h" +#include "../math/emath.h" /* include SSE wrapper classes */ #if defined(__SSE__) || defined(__ARM_NEON) diff --git a/thirdparty/embree/common/simd/varying.h b/thirdparty/embree/common/simd/varying.h index 9b98d326be..20fd3cac48 100644 --- a/thirdparty/embree/common/simd/varying.h +++ b/thirdparty/embree/common/simd/varying.h @@ -15,7 +15,7 @@ namespace embree __forceinline const float& operator [](size_t index) const { assert(index < N); return f[index]; } __forceinline float& operator [](size_t index) { assert(index < N); return f[index]; } }; - + template<int N> struct vdouble_impl { @@ -31,7 +31,7 @@ namespace embree __forceinline const int& operator [](size_t index) const { assert(index < N); return i[index]; } __forceinline int& operator [](size_t index) { assert(index < N); return i[index]; } }; - + template<int N> struct vuint_impl { diff --git a/thirdparty/embree/common/simd/vboolf4_sse2.h b/thirdparty/embree/common/simd/vboolf4_sse2.h index 9e0fdf5c6f..e96525c9a7 100644 --- a/thirdparty/embree/common/simd/vboolf4_sse2.h +++ b/thirdparty/embree/common/simd/vboolf4_sse2.h @@ -119,7 +119,7 @@ namespace embree #if defined(__aarch64__) template<int i0, int i1, int i2, int i3> __forceinline vboolf4 shuffle(const vboolf4& v) { - return vreinterpretq_f32_u8(vqtbl1q_u8( vreinterpretq_u8_s32(v), _MN_SHUFFLE(i0, i1, i2, i3))); + return vreinterpretq_f32_u8(vqtbl1q_u8( vreinterpretq_u8_s32((int32x4_t)v.v), _MN_SHUFFLE(i0, i1, i2, i3))); } template<int i0, int i1, int i2, int i3> diff --git a/thirdparty/embree/common/simd/vfloat16_avx512.h b/thirdparty/embree/common/simd/vfloat16_avx512.h index 75c471cc0c..b6160a438c 100644 --- a/thirdparty/embree/common/simd/vfloat16_avx512.h +++ b/thirdparty/embree/common/simd/vfloat16_avx512.h @@ -316,6 +316,17 @@ namespace embree return madd(t,b-a,a); } + __forceinline bool isvalid (const vfloat16& v) { + return all((v > vfloat16(-FLT_LARGE)) & (v < vfloat16(+FLT_LARGE))); + } + + __forceinline void xchg(vboolf16 m, vfloat16& a, vfloat16& b) + { + vfloat16 c = a; + a = select(m,b,a); + b = select(m,c,b); + } + //////////////////////////////////////////////////////////////////////////////// /// Rounding Functions //////////////////////////////////////////////////////////////////////////////// diff --git a/thirdparty/embree/common/simd/vfloat4_sse2.h b/thirdparty/embree/common/simd/vfloat4_sse2.h index 6d7e11fe72..fccf11fe0c 100644 --- a/thirdparty/embree/common/simd/vfloat4_sse2.h +++ b/thirdparty/embree/common/simd/vfloat4_sse2.h @@ -32,6 +32,8 @@ namespace embree __forceinline vfloat() {} __forceinline vfloat(const vfloat4& other) { v = other.v; } + //__forceinline vfloat(const vfloat4& other) = default; + __forceinline vfloat4& operator =(const vfloat4& other) { v = other.v; return *this; } __forceinline vfloat(__m128 a) : v(a) {} diff --git a/thirdparty/embree/common/simd/vint4_sse2.h b/thirdparty/embree/common/simd/vint4_sse2.h index eea03a771e..e9e4a5a2c2 100644 --- a/thirdparty/embree/common/simd/vint4_sse2.h +++ b/thirdparty/embree/common/simd/vint4_sse2.h @@ -3,7 +3,7 @@ #pragma once -#include "../math/math.h" +#include "../math/emath.h" #define vboolf vboolf_impl #define vboold vboold_impl diff --git a/thirdparty/embree/common/simd/vuint4_sse2.h b/thirdparty/embree/common/simd/vuint4_sse2.h index f7817da6be..c2e86c6633 100644 --- a/thirdparty/embree/common/simd/vuint4_sse2.h +++ b/thirdparty/embree/common/simd/vuint4_sse2.h @@ -3,7 +3,7 @@ #pragma once -#include "../math/math.h" +#include "../math/emath.h" #define vboolf vboolf_impl #define vboold vboold_impl diff --git a/thirdparty/embree/common/sys/alloc.cpp b/thirdparty/embree/common/sys/alloc.cpp index abdd269069..71616a3982 100644 --- a/thirdparty/embree/common/sys/alloc.cpp +++ b/thirdparty/embree/common/sys/alloc.cpp @@ -12,33 +12,177 @@ namespace embree { - void* alignedMalloc(size_t size, size_t align) + size_t total_allocations = 0; + +#if defined(EMBREE_SYCL_SUPPORT) + + __thread sycl::context* tls_context_tutorial = nullptr; + __thread sycl::device* tls_device_tutorial = nullptr; + + __thread sycl::context* tls_context_embree = nullptr; + __thread sycl::device* tls_device_embree = nullptr; + + void enableUSMAllocEmbree(sycl::context* context, sycl::device* device) + { + // -- GODOT start -- + // if (tls_context_embree != nullptr) throw std::runtime_error("USM allocation already enabled"); + // if (tls_device_embree != nullptr) throw std::runtime_error("USM allocation already enabled"); + if (tls_context_embree != nullptr) { + abort(); + } + if (tls_device_embree != nullptr) { + abort(); + } + // -- GODOT end -- + tls_context_embree = context; + tls_device_embree = device; + } + + void disableUSMAllocEmbree() + { + // -- GODOT start -- + // if (tls_context_embree == nullptr) throw std::runtime_error("USM allocation not enabled"); + // if (tls_device_embree == nullptr) throw std::runtime_error("USM allocation not enabled"); + if (tls_context_embree == nullptr) { + abort(); + } + if (tls_device_embree == nullptr) { + abort(); + } + // -- GODOT end -- + tls_context_embree = nullptr; + tls_device_embree = nullptr; + } + + void enableUSMAllocTutorial(sycl::context* context, sycl::device* device) + { + //if (tls_context_tutorial != nullptr) throw std::runtime_error("USM allocation already enabled"); + //if (tls_device_tutorial != nullptr) throw std::runtime_error("USM allocation already enabled"); + tls_context_tutorial = context; + tls_device_tutorial = device; + } + + void disableUSMAllocTutorial() + { + // -- GODOT start -- + // if (tls_context_tutorial == nullptr) throw std::runtime_error("USM allocation not enabled"); + // if (tls_device_tutorial == nullptr) throw std::runtime_error("USM allocation not enabled"); + if (tls_context_tutorial == nullptr) { + abort(); + } + if (tls_device_tutorial == nullptr) { + abort(); + } + // -- GODOT end -- + + tls_context_tutorial = nullptr; + tls_device_tutorial = nullptr; + } + +#endif + + void* alignedMalloc(size_t size, size_t align) { if (size == 0) return nullptr; - + assert((align & (align-1)) == 0); void* ptr = _mm_malloc(size,align); - - if (size != 0 && ptr == nullptr) - // -- GODOT start -- - // throw std::bad_alloc(); + // -- GODOT start -- + // if (size != 0 && ptr == nullptr) + // throw std::bad_alloc(); + if (size != 0 && ptr == nullptr) { abort(); - // -- GODOT end -- - + } + // -- GODOT end -- return ptr; } - + void alignedFree(void* ptr) { if (ptr) _mm_free(ptr); } +#if defined(EMBREE_SYCL_SUPPORT) + + void* alignedSYCLMalloc(sycl::context* context, sycl::device* device, size_t size, size_t align, EmbreeUSMMode mode) + { + assert(context); + assert(device); + + if (size == 0) + return nullptr; + + assert((align & (align-1)) == 0); + total_allocations++; + + void* ptr = nullptr; + if (mode == EMBREE_USM_SHARED_DEVICE_READ_ONLY) + ptr = sycl::aligned_alloc_shared(align,size,*device,*context,sycl::ext::oneapi::property::usm::device_read_only()); + else + ptr = sycl::aligned_alloc_shared(align,size,*device,*context); + + // -- GODOT start -- + // if (size != 0 && ptr == nullptr) + // throw std::bad_alloc(); + if (size != 0 && ptr == nullptr) { + abort(); + } + // -- GODOT end -- + + return ptr; + } + + static MutexSys g_alloc_mutex; + + void* alignedSYCLMalloc(size_t size, size_t align, EmbreeUSMMode mode) + { + if (tls_context_tutorial) return alignedSYCLMalloc(tls_context_tutorial, tls_device_tutorial, size, align, mode); + if (tls_context_embree ) return alignedSYCLMalloc(tls_context_embree, tls_device_embree, size, align, mode); + return nullptr; + } + + void alignedSYCLFree(sycl::context* context, void* ptr) + { + assert(context); + if (ptr) { + sycl::free(ptr,*context); + } + } + + void alignedSYCLFree(void* ptr) + { + if (tls_context_tutorial) return alignedSYCLFree(tls_context_tutorial, ptr); + if (tls_context_embree ) return alignedSYCLFree(tls_context_embree, ptr); + } + +#endif + + void* alignedUSMMalloc(size_t size, size_t align, EmbreeUSMMode mode) + { +#if defined(EMBREE_SYCL_SUPPORT) + if (tls_context_embree || tls_context_tutorial) + return alignedSYCLMalloc(size,align,mode); + else +#endif + return alignedMalloc(size,align); + } + + void alignedUSMFree(void* ptr) + { +#if defined(EMBREE_SYCL_SUPPORT) + if (tls_context_embree || tls_context_tutorial) + return alignedSYCLFree(ptr); + else +#endif + return alignedFree(ptr); + } + static bool huge_pages_enabled = false; static MutexSys os_init_mutex; - __forceinline bool isHugePageCandidate(const size_t bytes) + __forceinline bool isHugePageCandidate(const size_t bytes) { if (!huge_pages_enabled) return false; @@ -133,7 +277,9 @@ namespace embree char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE); // -- GODOT start -- // if (ptr == nullptr) throw std::bad_alloc(); - if (ptr == nullptr) abort(); + if (ptr == nullptr) { + abort(); + } // -- GODOT end -- hugepages = false; return ptr; @@ -150,11 +296,13 @@ namespace embree if (bytesNew >= bytesOld) return bytesOld; - if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT)) - // -- GODOT start -- - // throw std::bad_alloc(); + // -- GODOT start -- + // if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT)) + // throw std::bad_alloc(); + if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT)) { abort(); - // -- GODOT end -- + } + // -- GODOT end -- return bytesNew; } @@ -164,11 +312,13 @@ namespace embree if (bytes == 0) return; - if (!VirtualFree(ptr,0,MEM_RELEASE)) - // -- GODOT start -- - // throw std::bad_alloc(); + // -- GODOT start -- + // if (!VirtualFree(ptr,0,MEM_RELEASE)) + // throw std::bad_alloc(); + if (!VirtualFree(ptr,0,MEM_RELEASE)) { abort(); - // -- GODOT end -- + } + // -- GODOT end -- } void os_advise(void *ptr, size_t bytes) @@ -274,7 +424,9 @@ namespace embree void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); // -- GODOT start -- // if (ptr == MAP_FAILED) throw std::bad_alloc(); - if (ptr == MAP_FAILED) abort(); + if (ptr == MAP_FAILED) { + abort(); + } // -- GODOT end -- hugepages = false; @@ -291,11 +443,13 @@ namespace embree if (bytesNew >= bytesOld) return bytesOld; - if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1) - // -- GODOT start -- - // throw std::bad_alloc(); + // -- GODOT start -- + // if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1) + // throw std::bad_alloc(); + if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1) { abort(); - // -- GODOT end -- + } + // -- GODOT end -- return bytesNew; } @@ -308,11 +462,13 @@ namespace embree /* for hugepages we need to also align the size */ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K; bytes = (bytes+pageSize-1) & ~(pageSize-1); - if (munmap(ptr,bytes) == -1) - // -- GODOT start -- - // throw std::bad_alloc(); + // -- GODOT start -- + // if (munmap(ptr,bytes) == -1) + // throw std::bad_alloc(); + if (munmap(ptr,bytes) == -1) { abort(); - // -- GODOT end -- + } + // -- GODOT end -- } /* hint for transparent huge pages (THP) */ diff --git a/thirdparty/embree/common/sys/alloc.h b/thirdparty/embree/common/sys/alloc.h index 4fa474ec1d..28b17f988d 100644 --- a/thirdparty/embree/common/sys/alloc.h +++ b/thirdparty/embree/common/sys/alloc.h @@ -9,20 +9,72 @@ namespace embree { -#define ALIGNED_STRUCT_(align) \ - void* operator new(size_t size) { return alignedMalloc(size,align); } \ - void operator delete(void* ptr) { alignedFree(ptr); } \ +#if defined(EMBREE_SYCL_SUPPORT) + + /* enables SYCL USM allocation */ + void enableUSMAllocEmbree(sycl::context* context, sycl::device* device); + void enableUSMAllocTutorial(sycl::context* context, sycl::device* device); + + /* disables SYCL USM allocation */ + void disableUSMAllocEmbree(); + void disableUSMAllocTutorial(); + +#endif + +#define ALIGNED_STRUCT_(align) \ + void* operator new(size_t size) { return alignedMalloc(size,align); } \ + void operator delete(void* ptr) { alignedFree(ptr); } \ void* operator new[](size_t size) { return alignedMalloc(size,align); } \ void operator delete[](void* ptr) { alignedFree(ptr); } + +#define ALIGNED_STRUCT_USM_(align) \ + void* operator new(size_t size) { return alignedUSMMalloc(size,align); } \ + void operator delete(void* ptr) { alignedUSMFree(ptr); } \ + void* operator new[](size_t size) { return alignedUSMMalloc(size,align); } \ + void operator delete[](void* ptr) { alignedUSMFree(ptr); } + +#define ALIGNED_CLASS_(align) \ + public: \ + ALIGNED_STRUCT_(align) \ + private: -#define ALIGNED_CLASS_(align) \ +#define ALIGNED_CLASS_USM_(align) \ public: \ - ALIGNED_STRUCT_(align) \ + ALIGNED_STRUCT_USM_(align) \ private: + + enum EmbreeUSMMode { + EMBREE_USM_SHARED = 0, + EMBREE_USM_SHARED_DEVICE_READ_WRITE = 0, + EMBREE_USM_SHARED_DEVICE_READ_ONLY = 1 + }; /*! aligned allocation */ void* alignedMalloc(size_t size, size_t align); void alignedFree(void* ptr); + + /*! aligned allocation using SYCL USM */ + void* alignedUSMMalloc(size_t size, size_t align = 16, EmbreeUSMMode mode = EMBREE_USM_SHARED_DEVICE_READ_ONLY); + void alignedUSMFree(void* ptr); + +#if defined(EMBREE_SYCL_SUPPORT) + + /*! aligned allocation using SYCL USM */ + void* alignedSYCLMalloc(sycl::context* context, sycl::device* device, size_t size, size_t align, EmbreeUSMMode mode); + void alignedSYCLFree(sycl::context* context, void* ptr); + + // deleter functor to use as deleter in std unique or shared pointers that + // capture raw pointers created by sycl::malloc and it's variants + template<typename T> + struct sycl_deleter + { + void operator()(T const* ptr) + { + alignedUSMFree((void*)ptr); + } + }; + +#endif /*! allocator that performs aligned allocations */ template<typename T, size_t alignment> @@ -95,6 +147,37 @@ namespace embree bool hugepages; }; + /*! allocator that newer performs allocations */ + template<typename T> + struct no_allocator + { + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + __forceinline pointer allocate( size_type n ) { + // -- GODOT start -- + // throw std::runtime_error("no allocation supported"); + abort(); + // -- GODOT end -- + } + + __forceinline void deallocate( pointer p, size_type n ) { + } + + __forceinline void construct( pointer p, const_reference val ) { + new (p) T(val); + } + + __forceinline void destroy( pointer p ) { + p->~T(); + } + }; + /*! allocator for IDs */ template<typename T, size_t max_id> struct IDPool diff --git a/thirdparty/embree/common/sys/atomic.h b/thirdparty/embree/common/sys/atomic.h index 67af254f36..cf9909aad9 100644 --- a/thirdparty/embree/common/sys/atomic.h +++ b/thirdparty/embree/common/sys/atomic.h @@ -36,7 +36,7 @@ namespace embree }; template<typename T> - __forceinline void atomic_min(std::atomic<T>& aref, const T& bref) + __forceinline void _atomic_min(std::atomic<T>& aref, const T& bref) { const T b = bref.load(); while (true) { @@ -47,7 +47,7 @@ namespace embree } template<typename T> - __forceinline void atomic_max(std::atomic<T>& aref, const T& bref) + __forceinline void _atomic_max(std::atomic<T>& aref, const T& bref) { const T b = bref.load(); while (true) { diff --git a/thirdparty/embree/common/sys/barrier.h b/thirdparty/embree/common/sys/barrier.h index c56513a2ed..e1580f41a9 100644 --- a/thirdparty/embree/common/sys/barrier.h +++ b/thirdparty/embree/common/sys/barrier.h @@ -34,7 +34,7 @@ namespace embree void* opaque; }; - /*! fast active barrier using atomitc counter */ + /*! fast active barrier using atomic counter */ struct BarrierActive { public: diff --git a/thirdparty/embree/common/sys/string.cpp b/thirdparty/embree/common/sys/estring.cpp index f42fdc8536..c66c5c5b84 100644 --- a/thirdparty/embree/common/sys/string.cpp +++ b/thirdparty/embree/common/sys/estring.cpp @@ -1,7 +1,7 @@ // Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -#include "string.h" +#include "estring.h" #include <algorithm> #include <ctype.h> diff --git a/thirdparty/embree/common/sys/string.h b/thirdparty/embree/common/sys/estring.h index 820076b21c..63051ad3c3 100644 --- a/thirdparty/embree/common/sys/string.h +++ b/thirdparty/embree/common/sys/estring.h @@ -28,6 +28,42 @@ namespace embree std::streamsize precision; }; + struct IndentOStream : public std::streambuf + { + explicit IndentOStream(std::ostream &ostream, int indent = 2) + : streambuf(ostream.rdbuf()) + , start_of_line(true) + , ident_str(indent, ' ') + , stream(&ostream) + { + // set streambuf of ostream to this and save original streambuf + stream->rdbuf(this); + } + + virtual ~IndentOStream() + { + if (stream != NULL) { + // restore old streambuf + stream->rdbuf(streambuf); + } + } + + protected: + virtual int overflow(int ch) { + if (start_of_line && ch != '\n') { + streambuf->sputn(ident_str.data(), ident_str.size()); + } + start_of_line = ch == '\n'; + return streambuf->sputc(ch); + } + + private: + std::streambuf *streambuf; + bool start_of_line; + std::string ident_str; + std::ostream *stream; + }; + std::string toLowerCase(const std::string& s); std::string toUpperCase(const std::string& s); diff --git a/thirdparty/embree/common/sys/intrinsics.h b/thirdparty/embree/common/sys/intrinsics.h index 2c2f6eccda..f5074bb29d 100644 --- a/thirdparty/embree/common/sys/intrinsics.h +++ b/thirdparty/embree/common/sys/intrinsics.h @@ -64,7 +64,7 @@ namespace embree /// Windows Platform //////////////////////////////////////////////////////////////////////////////// -#if defined(__WIN32__) +#if defined(__WIN32__) && !defined(__INTEL_LLVM_COMPILER) __forceinline size_t read_tsc() { @@ -89,7 +89,7 @@ namespace embree #endif } -#if defined(__X86_64__) +#if defined(__X86_64__) || defined (__aarch64__) __forceinline size_t bsf(size_t v) { #if defined(__AVX2__) return _tzcnt_u64(v); @@ -113,7 +113,7 @@ namespace embree return i; } -#if defined(__X86_64__) +#if defined(__X86_64__) || defined (__aarch64__) __forceinline size_t bscf(size_t& v) { size_t i = bsf(v); @@ -138,7 +138,7 @@ namespace embree #endif } -#if defined(__X86_64__) +#if defined(__X86_64__) || defined (__aarch64__) __forceinline size_t bsr(size_t v) { #if defined(__AVX2__) return 63 -_lzcnt_u64(v); @@ -196,49 +196,6 @@ namespace embree #else -#if defined(__i386__) && defined(__PIC__) - - __forceinline void __cpuid(int out[4], int op) - { - asm volatile ("xchg{l}\t{%%}ebx, %1\n\t" - "cpuid\n\t" - "xchg{l}\t{%%}ebx, %1\n\t" - : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) - : "0"(op)); - } - - __forceinline void __cpuid_count(int out[4], int op1, int op2) - { - asm volatile ("xchg{l}\t{%%}ebx, %1\n\t" - "cpuid\n\t" - "xchg{l}\t{%%}ebx, %1\n\t" - : "=a" (out[0]), "=r" (out[1]), "=c" (out[2]), "=d" (out[3]) - : "0" (op1), "2" (op2)); - } - -#elif defined(__X86_ASM__) - - __forceinline void __cpuid(int out[4], int op) { -#if defined(__ARM_NEON) - if (op == 0) { // Get CPU name - out[0] = 0x41524d20; - out[1] = 0x41524d20; - out[2] = 0x41524d20; - out[3] = 0x41524d20; - } -#else - asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op)); -#endif - } - -#if !defined(__ARM_NEON) - __forceinline void __cpuid_count(int out[4], int op1, int op2) { - asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op1), "c"(op2)); - } -#endif - -#endif - __forceinline uint64_t read_tsc() { #if defined(__X86_ASM__) uint32_t high,low; @@ -263,6 +220,13 @@ namespace embree #endif #endif } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + __forceinline unsigned int bsf(unsigned v) { + return sycl::ctz(v); + } + +#else #if defined(__64BIT__) __forceinline unsigned bsf(unsigned v) @@ -280,6 +244,13 @@ namespace embree #endif } #endif +#endif + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + __forceinline size_t bsf(size_t v) { + return sycl::ctz(v); + } +#else __forceinline size_t bsf(size_t v) { #if defined(__AVX2__) && !defined(__aarch64__) @@ -294,6 +265,7 @@ namespace embree return __builtin_ctzl(v); #endif } +#endif __forceinline int bscf(int& v) { @@ -434,6 +406,41 @@ namespace embree #endif +#if !defined(__WIN32__) + +#if defined(__i386__) && defined(__PIC__) + + __forceinline void __cpuid(int out[4], int op) + { + asm volatile ("xchg{l}\t{%%}ebx, %1\n\t" + "cpuid\n\t" + "xchg{l}\t{%%}ebx, %1\n\t" + : "=a"(out[0]), "=r"(out[1]), "=c"(out[2]), "=d"(out[3]) + : "0"(op)); + } + + __forceinline void __cpuid_count(int out[4], int op1, int op2) + { + asm volatile ("xchg{l}\t{%%}ebx, %1\n\t" + "cpuid\n\t" + "xchg{l}\t{%%}ebx, %1\n\t" + : "=a" (out[0]), "=r" (out[1]), "=c" (out[2]), "=d" (out[3]) + : "0" (op1), "2" (op2)); + } + +#elif defined(__X86_ASM__) + + __forceinline void __cpuid(int out[4], int op) { + asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op)); + } + + __forceinline void __cpuid_count(int out[4], int op1, int op2) { + asm volatile ("cpuid" : "=a"(out[0]), "=b"(out[1]), "=c"(out[2]), "=d"(out[3]) : "a"(op1), "c"(op2)); + } + +#endif +#endif + //////////////////////////////////////////////////////////////////////////////// /// All Platforms //////////////////////////////////////////////////////////////////////////////// @@ -459,8 +466,16 @@ namespace embree #endif #endif -#if defined(__SSE4_2__) || defined(__ARM_NEON) +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + __forceinline unsigned int popcnt(unsigned int in) { + return sycl::popcount(in); + } + +#else + +#if defined(__SSE4_2__) || defined(__ARM_NEON) + __forceinline int popcnt(int in) { return _mm_popcnt_u32(in); } @@ -476,6 +491,8 @@ namespace embree #endif #endif + +#endif #if defined(__X86_ASM__) __forceinline uint64_t rdtsc() diff --git a/thirdparty/embree/common/sys/mutex.h b/thirdparty/embree/common/sys/mutex.h index 26af6c582c..0f7345cf45 100644 --- a/thirdparty/embree/common/sys/mutex.h +++ b/thirdparty/embree/common/sys/mutex.h @@ -86,8 +86,8 @@ namespace embree class PaddedSpinLock : public SpinLock { - private: - char padding[CPU_CACHELINE_SIZE - sizeof(SpinLock)]; + private: + MAYBE_UNUSED char padding[CPU_CACHELINE_SIZE - sizeof(SpinLock)]; }; /*! safe mutex lock and unlock helper */ template<typename Mutex> class Lock { diff --git a/thirdparty/embree/common/sys/platform.h b/thirdparty/embree/common/sys/platform.h index 728bf6ed7d..d4a9b9e119 100644 --- a/thirdparty/embree/common/sys/platform.h +++ b/thirdparty/embree/common/sys/platform.h @@ -3,7 +3,9 @@ #pragma once +#if !defined(_CRT_SECURE_NO_WARNINGS) #define _CRT_SECURE_NO_WARNINGS +#endif #include <cstddef> #include <cassert> @@ -18,6 +20,30 @@ #include <cstring> #include <stdint.h> #include <functional> +#include <mutex> + +#if defined(EMBREE_SYCL_SUPPORT) + +#define __SYCL_USE_NON_VARIADIC_SPIRV_OCL_PRINTF__ + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-W#pragma-messages" + +#include <sycl/sycl.hpp> + +#pragma clang diagnostic pop + +#include "sycl.h" + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) +#define CONSTANT __attribute__((opencl_constant)) +#else +#define CONSTANT +#endif + +#endif + //////////////////////////////////////////////////////////////////////////////// /// detect platform @@ -115,7 +141,7 @@ #else #define __restrict__ //__restrict // causes issues with MSVC #endif -#if !defined(__thread) +#if !defined(__thread) && !defined(__INTEL_LLVM_COMPILER) #define __thread __declspec(thread) #endif #if !defined(__aligned) @@ -148,6 +174,10 @@ #define MAYBE_UNUSED #endif +#if !defined(_unused) +#define _unused(x) ((void)(x)) +#endif + #if defined(_MSC_VER) && (_MSC_VER < 1900) // before VS2015 deleted functions are not supported properly #define DELETED #else @@ -155,7 +185,7 @@ #endif #if !defined(likely) -#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) +#if defined(_MSC_VER) && !defined(__INTEL_COMPILER) || defined(__SYCL_DEVICE_ONLY__) #define likely(expr) (expr) #define unlikely(expr) (expr) #else @@ -171,22 +201,27 @@ /* debug printing macros */ #define STRING(x) #x #define TOSTRING(x) STRING(x) -#define PING embree_cout << __FILE__ << " (" << __LINE__ << "): " << __FUNCTION__ << embree_endl +#define PING embree_cout_uniform << __FILE__ << " (" << __LINE__ << "): " << __FUNCTION__ << embree_endl #define PRINT(x) embree_cout << STRING(x) << " = " << (x) << embree_endl #define PRINT2(x,y) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << embree_endl #define PRINT3(x,y,z) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << embree_endl #define PRINT4(x,y,z,w) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << embree_endl +#define UPRINT(x) embree_cout_uniform << STRING(x) << " = " << (x) << embree_endl +#define UPRINT2(x,y) embree_cout_uniform << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << embree_endl +#define UPRINT3(x,y,z) embree_cout_uniform << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << embree_endl +#define UPRINT4(x,y,z,w) embree_cout_uniform << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << embree_endl + #if defined(DEBUG) // only report file and line in debug mode // -- GODOT start -- - // #define THROW_RUNTIME_ERROR(str) + // #define THROW_RUNTIME_ERROR(str) \ // throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)); #define THROW_RUNTIME_ERROR(str) \ printf("%s (%d): %s", __FILE__, __LINE__, std::string(str).c_str()), abort(); // -- GODOT end -- #else // -- GODOT start -- - // #define THROW_RUNTIME_ERROR(str) + // #define THROW_RUNTIME_ERROR(str) \ // throw std::runtime_error(str); #define THROW_RUNTIME_ERROR(str) \ abort(); @@ -323,13 +358,209 @@ __forceinline std::string toString(long long value) { #define DISABLE_DEPRECATED_WARNING __pragma(warning (disable: 4996)) // warning: function was declared deprecated #define ENABLE_DEPRECATED_WARNING __pragma(warning (enable : 4996)) // warning: function was declared deprecated #endif + +//////////////////////////////////////////////////////////////////////////////// +/// SYCL specific +//////////////////////////////////////////////////////////////////////////////// + + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + +#define sycl_printf0(format, ...) { \ + static const CONSTANT char fmt[] = format; \ + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) \ + sycl::ext::oneapi::experimental::printf(fmt, __VA_ARGS__ ); \ + } + +#define sycl_printf0_(format) { \ + static const CONSTANT char fmt[] = format; \ + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) \ + sycl::ext::oneapi::experimental::printf(fmt); \ + } + +#else + +#define sycl_printf0(format, ...) { \ + static const CONSTANT char fmt[] = format; \ + sycl::ext::oneapi::experimental::printf(fmt, __VA_ARGS__ ); \ + } + +#define sycl_printf0_(format) { \ + static const CONSTANT char fmt[] = format; \ + sycl::ext::oneapi::experimental::printf(fmt); \ + } + +#endif + +#define sycl_printf(format, ...) { \ + static const CONSTANT char fmt[] = format; \ + sycl::ext::oneapi::experimental::printf(fmt, __VA_ARGS__ ); \ + } + +#define sycl_printf_(format) { \ + static const CONSTANT char fmt[] = format; \ + sycl::ext::oneapi::experimental::printf(fmt); \ + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + +namespace embree +{ + struct sycl_ostream_ { + sycl_ostream_ (bool uniform) : uniform(uniform) {} + bool uniform = false; + }; + struct sycl_endl_ {}; + +#define embree_ostream embree::sycl_ostream_ +#define embree_cout embree::sycl_ostream_(false) +#define embree_cout_uniform embree::sycl_ostream_(true) +#define embree_endl embree::sycl_endl_() + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, int i) + { + if (cout.uniform) { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf("%i",i); + } + else + sycl_printf("%i ",i); + + return cout; + } + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, unsigned int i) + { + if (cout.uniform) { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf("%u",i); + } else + sycl_printf("%u ",i); + + return cout; + } + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, float f) + { + if (cout.uniform) { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf("%f",f); + } else + sycl_printf("%f ",f); + + return cout; + } + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, double d) + { + if (cout.uniform) { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf("%f",d); + } else + sycl_printf("%f ",d); + + return cout; + } + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, uint64_t l) + { + if (cout.uniform) { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf("%lu",l); + } else + sycl_printf("%lu ",l); + + return cout; + } + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, long l) + { + if (cout.uniform) { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf("%l",l); + } else + sycl_printf("%l ",l); + + return cout; + } + + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, void* p) + { + if (cout.uniform) { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf("%p",p); + } else + sycl_printf("%p ",p); + + return cout; + } + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, const char* c) + { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf("%s",c); + return cout; + } + + inline sycl_ostream_ operator <<(sycl_ostream_ cout, sycl_endl_) + { + if (get_sub_group_local_id() == sycl::ctz(intel_sub_group_ballot(true))) + sycl_printf_("\n"); + return cout; + } +} + +#else -/* embree output stream */ #define embree_ostream std::ostream& #define embree_cout std::cout #define embree_cout_uniform std::cout #define embree_endl std::endl - + +#endif + +#if defined(EMBREE_SYCL_SUPPORT) + + /* printing out sycle vector types */ + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::float4& v) { + return out << "(" << v.x() << "," << v.y() << "," << v.z() << "," << v.w() << ")"; + } + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::float3& v) { + return out << "(" << v.x() << "," << v.y() << "," << v.z() << ")"; + } + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::float2& v) { + return out << "(" << v.x() << "," << v.y() << ")"; + } + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::int4& v) { + return out << "(" << v.x() << "," << v.y() << "," << v.z() << "," << v.w() << ")"; + } + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::int3& v) { + return out << "(" << v.x() << "," << v.y() << "," << v.z() << ")"; + } + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::int2& v) { + return out << "(" << v.x() << "," << v.y() << ")"; + } + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::uint4& v) { + return out << "(" << v.x() << "," << v.y() << "," << v.z() << "," << v.w() << ")"; + } + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::uint3& v) { + return out << "(" << v.x() << "," << v.y() << "," << v.z() << ")"; + } + __forceinline embree_ostream operator<<(embree_ostream out, const sycl::uint2& v) { + return out << "(" << v.x() << "," << v.y() << ")"; + } + +#endif + +inline void tab(std::ostream& cout, int n) { + for (int i=0; i<n; i++) cout << " "; +} + +inline std::string tab(int depth) { + return std::string(2*depth,' '); +} + //////////////////////////////////////////////////////////////////////////////// /// Some macros for static profiling //////////////////////////////////////////////////////////////////////////////// diff --git a/thirdparty/embree/common/sys/sycl.h b/thirdparty/embree/common/sys/sycl.h new file mode 100644 index 0000000000..2558eb052f --- /dev/null +++ b/thirdparty/embree/common/sys/sycl.h @@ -0,0 +1,307 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "platform.h" + +using sycl::float16; +using sycl::float8; +using sycl::float4; +using sycl::float3; +using sycl::float2; +using sycl::int16; +using sycl::int8; +using sycl::int4; +using sycl::int3; +using sycl::int2; +using sycl::uint16; +using sycl::uint8; +using sycl::uint4; +using sycl::uint3; +using sycl::uint2; +using sycl::uchar16; +using sycl::uchar8; +using sycl::uchar4; +using sycl::uchar3; +using sycl::uchar2; +using sycl::ushort16; +using sycl::ushort8; +using sycl::ushort4; +using sycl::ushort3; +using sycl::ushort2; + +#ifdef __SYCL_DEVICE_ONLY__ +#define GLOBAL __attribute__((opencl_global)) +#define LOCAL __attribute__((opencl_local)) + +SYCL_EXTERNAL extern int work_group_reduce_add(int x); +SYCL_EXTERNAL extern float work_group_reduce_min(float x); +SYCL_EXTERNAL extern float work_group_reduce_max(float x); + +SYCL_EXTERNAL extern float atomic_min(volatile GLOBAL float *p, float val); +SYCL_EXTERNAL extern float atomic_min(volatile LOCAL float *p, float val); +SYCL_EXTERNAL extern float atomic_max(volatile GLOBAL float *p, float val); +SYCL_EXTERNAL extern float atomic_max(volatile LOCAL float *p, float val); + +SYCL_EXTERNAL extern "C" unsigned int intel_sub_group_ballot(bool valid); + +SYCL_EXTERNAL extern "C" void __builtin_IB_assume_uniform(void *p); + +// Load message caching control + + enum LSC_LDCC { + LSC_LDCC_DEFAULT, + LSC_LDCC_L1UC_L3UC, // Override to L1 uncached and L3 uncached + LSC_LDCC_L1UC_L3C, // Override to L1 uncached and L3 cached + LSC_LDCC_L1C_L3UC, // Override to L1 cached and L3 uncached + LSC_LDCC_L1C_L3C, // Override to L1 cached and L3 cached + LSC_LDCC_L1S_L3UC, // Override to L1 streaming load and L3 uncached + LSC_LDCC_L1S_L3C, // Override to L1 streaming load and L3 cached + LSC_LDCC_L1IAR_L3C, // Override to L1 invalidate-after-read, and L3 cached + }; + + + +// Store message caching control (also used for atomics) + + enum LSC_STCC { + LSC_STCC_DEFAULT, + LSC_STCC_L1UC_L3UC, // Override to L1 uncached and L3 uncached + LSC_STCC_L1UC_L3WB, // Override to L1 uncached and L3 written back + LSC_STCC_L1WT_L3UC, // Override to L1 written through and L3 uncached + LSC_STCC_L1WT_L3WB, // Override to L1 written through and L3 written back + LSC_STCC_L1S_L3UC, // Override to L1 streaming and L3 uncached + LSC_STCC_L1S_L3WB, // Override to L1 streaming and L3 written back + LSC_STCC_L1WB_L3WB, // Override to L1 written through and L3 written back + }; + + + +/////////////////////////////////////////////////////////////////////// + +// LSC Loads + +/////////////////////////////////////////////////////////////////////// + +SYCL_EXTERNAL /* extern "C" */ uint32_t __builtin_IB_lsc_load_global_uchar_to_uint (const GLOBAL uint8_t *base, int elemOff, enum LSC_LDCC cacheOpt); //D8U32 +SYCL_EXTERNAL /* extern "C" */ uint32_t __builtin_IB_lsc_load_global_ushort_to_uint(const GLOBAL uint16_t *base, int elemOff, enum LSC_LDCC cacheOpt); //D16U32 +SYCL_EXTERNAL /* extern "C" */ uint32_t __builtin_IB_lsc_load_global_uint (const GLOBAL uint32_t *base, int elemOff, enum LSC_LDCC cacheOpt); //D32V1 +SYCL_EXTERNAL /* extern "C" */ sycl::uint2 __builtin_IB_lsc_load_global_uint2 (const GLOBAL sycl::uint2 *base, int elemOff, enum LSC_LDCC cacheOpt); //D32V2 +SYCL_EXTERNAL /* extern "C" */ sycl::uint3 __builtin_IB_lsc_load_global_uint3 (const GLOBAL sycl::uint3 *base, int elemOff, enum LSC_LDCC cacheOpt); //D32V3 +SYCL_EXTERNAL /* extern "C" */ sycl::uint4 __builtin_IB_lsc_load_global_uint4 (const GLOBAL sycl::uint4 *base, int elemOff, enum LSC_LDCC cacheOpt); //D32V4 +SYCL_EXTERNAL /* extern "C" */ sycl::uint8 __builtin_IB_lsc_load_global_uint8 (const GLOBAL sycl::uint8 *base, int elemOff, enum LSC_LDCC cacheOpt); //D32V8 +SYCL_EXTERNAL /* extern "C" */ uint64_t __builtin_IB_lsc_load_global_ulong (const GLOBAL uint64_t *base, int elemOff, enum LSC_LDCC cacheOpt); //D64V1 +SYCL_EXTERNAL /* extern "C" */ sycl::ulong2 __builtin_IB_lsc_load_global_ulong2 (const GLOBAL sycl::ulong2 *base, int elemOff, enum LSC_LDCC cacheOpt); //D64V2 +SYCL_EXTERNAL /* extern "C" */ sycl::ulong3 __builtin_IB_lsc_load_global_ulong3 (const GLOBAL sycl::ulong3 *base, int elemOff, enum LSC_LDCC cacheOpt); //D64V3 +SYCL_EXTERNAL /* extern "C" */ sycl::ulong4 __builtin_IB_lsc_load_global_ulong4 (const GLOBAL sycl::ulong4 *base, int elemOff, enum LSC_LDCC cacheOpt); //D64V4 +SYCL_EXTERNAL /* extern "C" */ sycl::ulong8 __builtin_IB_lsc_load_global_ulong8 (const GLOBAL sycl::ulong8 *base, int elemOff, enum LSC_LDCC cacheOpt); //D64V8 + +// global address space +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_uchar_from_uint (GLOBAL uint8_t *base, int immElemOff, uint32_t val, enum LSC_STCC cacheOpt); //D8U32 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_ushort_from_uint(GLOBAL uint16_t *base, int immElemOff, uint32_t val, enum LSC_STCC cacheOpt); //D16U32 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_uint (GLOBAL uint32_t *base, int immElemOff, uint32_t val, enum LSC_STCC cacheOpt); //D32V1 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_uint2 (GLOBAL sycl::uint2 *base, int immElemOff, sycl::uint2 val, enum LSC_STCC cacheOpt); //D32V2 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_uint3 (GLOBAL sycl::uint3 *base, int immElemOff, sycl::uint3 val, enum LSC_STCC cacheOpt); //D32V3 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_uint4 (GLOBAL sycl::uint4 *base, int immElemOff, sycl::uint4 val, enum LSC_STCC cacheOpt); //D32V4 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_uint8 (GLOBAL sycl::uint8 *base, int immElemOff, sycl::uint8 val, enum LSC_STCC cacheOpt); //D32V8 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_ulong (GLOBAL uint64_t *base, int immElemOff, uint64_t val, enum LSC_STCC cacheOpt); //D64V1 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_ulong2 (GLOBAL sycl::ulong2 *base, int immElemOff, sycl::ulong2 val, enum LSC_STCC cacheOpt); //D64V2 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_ulong3 (GLOBAL sycl::ulong3 *base, int immElemOff, sycl::ulong3 val, enum LSC_STCC cacheOpt); //D64V3 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_ulong4 (GLOBAL sycl::ulong4 *base, int immElemOff, sycl::ulong4 val, enum LSC_STCC cacheOpt); //D64V4 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_store_global_ulong8 (GLOBAL sycl::ulong8 *base, int immElemOff, sycl::ulong8 val, enum LSC_STCC cacheOpt); //D64V8 + +/////////////////////////////////////////////////////////////////////// +// prefetching +/////////////////////////////////////////////////////////////////////// +// +// LSC Pre-Fetch Load functions with CacheControls +// global address space +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_uchar (const GLOBAL uint8_t *base, int immElemOff, enum LSC_LDCC cacheOpt); //D8U32 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_ushort(const GLOBAL uint16_t *base, int immElemOff, enum LSC_LDCC cacheOpt); //D16U32 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_uint (const GLOBAL uint32_t *base, int immElemOff, enum LSC_LDCC cacheOpt); //D32V1 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_uint2 (const GLOBAL sycl::uint2 *base, int immElemOff, enum LSC_LDCC cacheOpt); //D32V2 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_uint3 (const GLOBAL sycl::uint3 *base, int immElemOff, enum LSC_LDCC cacheOpt); //D32V3 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_uint4 (const GLOBAL sycl::uint4 *base, int immElemOff, enum LSC_LDCC cacheOpt); //D32V4 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_uint8 (const GLOBAL sycl::uint8 *base, int immElemOff, enum LSC_LDCC cacheOpt); //D32V8 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_ulong (const GLOBAL uint64_t *base, int immElemOff, enum LSC_LDCC cacheOpt); //D64V1 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_ulong2(const GLOBAL sycl::ulong2 *base, int immElemOff, enum LSC_LDCC cacheOpt); //D64V2 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_ulong3(const GLOBAL sycl::ulong3 *base, int immElemOff, enum LSC_LDCC cacheOpt); //D64V3 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_ulong4(const GLOBAL sycl::ulong4 *base, int immElemOff, enum LSC_LDCC cacheOpt); //D64V4 +SYCL_EXTERNAL extern "C" void __builtin_IB_lsc_prefetch_global_ulong8(const GLOBAL sycl::ulong8 *base, int immElemOff, enum LSC_LDCC cacheOpt); //D64V8 + +#else + +#define GLOBAL +#define LOCAL + +/* dummy functions for host */ +inline int work_group_reduce_add(int x) { return x; } +inline float work_group_reduce_min(float x) { return x; } +inline float work_group_reduce_max(float x) { return x; } + +inline float atomic_min(volatile float *p, float val) { return val; }; +inline float atomic_max(volatile float *p, float val) { return val; }; + +inline uint32_t intel_sub_group_ballot(bool valid) { return 0; } + +#endif + +/* creates a temporary that is enforced to be uniform */ +#define SYCL_UNIFORM_VAR(Ty,tmp,k) \ + Ty tmp##_data; \ + Ty* p##tmp##_data = (Ty*) sub_group_broadcast((uint64_t)&tmp##_data,k); \ + Ty& tmp = *p##tmp##_data; + +#if !defined(__forceinline) +#define __forceinline inline __attribute__((always_inline)) +#endif + +#if __SYCL_COMPILER_VERSION < 20210801 +#define all_of_group all_of +#define any_of_group any_of +#define none_of_group none_of +#define group_broadcast broadcast +#define reduce_over_group reduce +#define exclusive_scan_over_group exclusive_scan +#define inclusive_scan_over_group inclusive_scan +#endif + +namespace embree +{ + template<typename T> + __forceinline T cselect(const bool mask, const T &a, const T &b) + { + return sycl::select(b,a,(int)mask); + } + + template<typename T, typename M> + __forceinline T cselect(const M &mask, const T &a, const T &b) + { + return sycl::select(b,a,mask); + } + + __forceinline const sycl::sub_group this_sub_group() { + return sycl::ext::oneapi::experimental::this_sub_group(); + } + + __forceinline const uint32_t get_sub_group_local_id() { + return this_sub_group().get_local_id()[0]; + } + + __forceinline const uint32_t get_sub_group_size() { + return this_sub_group().get_max_local_range().size(); + } + + __forceinline const uint32_t get_sub_group_id() { + return this_sub_group().get_group_id()[0]; + } + + __forceinline const uint32_t get_num_sub_groups() { + return this_sub_group().get_group_range().size(); + } + + __forceinline uint32_t sub_group_ballot(bool pred) { + return intel_sub_group_ballot(pred); + } + + __forceinline bool sub_group_all_of(bool pred) { + return sycl::all_of_group(this_sub_group(),pred); + } + + __forceinline bool sub_group_any_of(bool pred) { + return sycl::any_of_group(this_sub_group(),pred); + } + + __forceinline bool sub_group_none_of(bool pred) { + return sycl::none_of_group(this_sub_group(),pred); + } + + template <typename T> __forceinline T sub_group_broadcast(T x, sycl::id<1> local_id) { + return sycl::group_broadcast<sycl::sub_group>(this_sub_group(),x,local_id); + } + + template <typename T> __forceinline T sub_group_make_uniform(T x) { + return sub_group_broadcast(x,sycl::ctz(intel_sub_group_ballot(true))); + } + + __forceinline void assume_uniform_array(void* ptr) { +#ifdef __SYCL_DEVICE_ONLY__ + __builtin_IB_assume_uniform(ptr); +#endif + } + + template <typename T, class BinaryOperation> __forceinline T sub_group_reduce(T x, BinaryOperation binary_op) { + return sycl::reduce_over_group<sycl::sub_group>(this_sub_group(),x,binary_op); + } + + template <typename T, class BinaryOperation> __forceinline T sub_group_reduce(T x, T init, BinaryOperation binary_op) { + return sycl::reduce_over_group<sycl::sub_group>(this_sub_group(),x,init,binary_op); + } + + template <typename T> __forceinline T sub_group_reduce_min(T x, T init) { + return sub_group_reduce(x, init, sycl::ext::oneapi::minimum<T>()); + } + + template <typename T> __forceinline T sub_group_reduce_min(T x) { + return sub_group_reduce(x, sycl::ext::oneapi::minimum<T>()); + } + + template <typename T> __forceinline T sub_group_reduce_max(T x) { + return sub_group_reduce(x, sycl::ext::oneapi::maximum<T>()); + } + + template <typename T> __forceinline T sub_group_reduce_add(T x) { + return sub_group_reduce(x, sycl::ext::oneapi::plus<T>()); + } + + template <typename T, class BinaryOperation> __forceinline T sub_group_exclusive_scan(T x, BinaryOperation binary_op) { + return sycl::exclusive_scan_over_group(this_sub_group(),x,binary_op); + } + + template <typename T, class BinaryOperation> __forceinline T sub_group_exclusive_scan_min(T x) { + return sub_group_exclusive_scan(x,sycl::ext::oneapi::minimum<T>()); + } + + template <typename T, class BinaryOperation> __forceinline T sub_group_exclusive_scan(T x, T init, BinaryOperation binary_op) { + return sycl::exclusive_scan_over_group(this_sub_group(),x,init,binary_op); + } + + template <typename T, class BinaryOperation> __forceinline T sub_group_inclusive_scan(T x, BinaryOperation binary_op) { + return sycl::inclusive_scan_over_group(this_sub_group(),x,binary_op); + } + + template <typename T, class BinaryOperation> __forceinline T sub_group_inclusive_scan(T x, BinaryOperation binary_op, T init) { + return sycl::inclusive_scan_over_group(this_sub_group(),x,binary_op,init); + } + + template <typename T> __forceinline T sub_group_shuffle(T x, sycl::id<1> local_id) { + return this_sub_group().shuffle(x, local_id); + } + + template <typename T> __forceinline T sub_group_shuffle_down(T x, uint32_t delta) { + return this_sub_group().shuffle_down(x, delta); + } + + template <typename T> __forceinline T sub_group_shuffle_up(T x, uint32_t delta) { + return this_sub_group().shuffle_up(x, delta); + } + + template <typename T> __forceinline T sub_group_load(const void* src) { + return this_sub_group().load(sycl::multi_ptr<T,sycl::access::address_space::global_space>((T*)src)); + } + + template <typename T> __forceinline void sub_group_store(void* dst, const T& x) { + this_sub_group().store(sycl::multi_ptr<T,sycl::access::address_space::global_space>((T*)dst),x); + } +} + +#if __SYCL_COMPILER_VERSION < 20210801 +#undef all_of_group +#undef any_of_group +#undef none_of_group +#undef group_broadcast +#undef reduce_over_group +#undef exclusive_scan_over_group +#undef inclusive_scan_over_group +#endif diff --git a/thirdparty/embree/common/sys/sysinfo.cpp b/thirdparty/embree/common/sys/sysinfo.cpp index 7f7a009a1e..d01eab3c9d 100644 --- a/thirdparty/embree/common/sys/sysinfo.cpp +++ b/thirdparty/embree/common/sys/sysinfo.cpp @@ -1,9 +1,15 @@ // Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 +#if defined(__INTEL_LLVM_COMPILER) +// prevents "'__thiscall' calling convention is not supported for this target" warning from TBB +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wignored-attributes" +#endif + #include "sysinfo.h" #include "intrinsics.h" -#include "string.h" +#include "estring.h" #include "ref.h" #if defined(__FREEBSD__) #include <sys/cpuset.h> @@ -690,3 +696,6 @@ namespace embree } #endif +#if defined(__INTEL_LLVM_COMPILER) +#pragma clang diagnostic pop +#endif diff --git a/thirdparty/embree/common/sys/thread.cpp b/thirdparty/embree/common/sys/thread.cpp index 530c3c7810..8b072067e6 100644 --- a/thirdparty/embree/common/sys/thread.cpp +++ b/thirdparty/embree/common/sys/thread.cpp @@ -3,7 +3,7 @@ #include "thread.h" #include "sysinfo.h" -#include "string.h" +#include "estring.h" #include <iostream> #if defined(__ARM_NEON) diff --git a/thirdparty/embree/common/sys/vector.h b/thirdparty/embree/common/sys/vector.h index d05e1deb18..226cd34c21 100644 --- a/thirdparty/embree/common/sys/vector.h +++ b/thirdparty/embree/common/sys/vector.h @@ -8,6 +8,8 @@ namespace embree { + class Device; + template<typename T, typename allocator> class vector_t { @@ -25,6 +27,12 @@ namespace embree template<typename M> __forceinline explicit vector_t (M alloc, size_t sz) : alloc(alloc), size_active(0), size_alloced(0), items(nullptr) { internal_resize_init(sz); } + + __forceinline vector_t (Device* alloc) + : vector_t(alloc,0) {} + + __forceinline vector_t(void* data, size_t bytes) + : size_active(0), size_alloced(bytes/sizeof(T)), items((T*)data) {} __forceinline ~vector_t() { clear(); @@ -65,6 +73,10 @@ namespace embree return *this; } + __forceinline allocator& getAlloc() { + return alloc; + } + /********************** Iterators ****************************/ __forceinline iterator begin() { return items; }; @@ -215,6 +227,10 @@ namespace embree if (new_alloced <= size_alloced) return size_alloced; + /* if current size is 0 allocate exact requested size */ + if (size_alloced == 0) + return new_alloced; + /* resize to next power of 2 otherwise */ size_t new_size_alloced = size_alloced; while (new_size_alloced < new_alloced) { @@ -237,8 +253,12 @@ namespace embree /*! vector class that performs aligned allocations */ template<typename T> using avector = vector_t<T,aligned_allocator<T,std::alignment_of<T>::value> >; - + /*! vector class that performs OS allocations */ template<typename T> using ovector = vector_t<T,os_allocator<T> >; + + /*! vector class with externally managed data buffer */ + template<typename T> + using evector = vector_t<T,no_allocator<T>>; } diff --git a/thirdparty/embree/common/tasking/taskscheduler.h b/thirdparty/embree/common/tasking/taskscheduler.h index 8f3dd87689..edfffe0e57 100644 --- a/thirdparty/embree/common/tasking/taskscheduler.h +++ b/thirdparty/embree/common/tasking/taskscheduler.h @@ -3,7 +3,7 @@ #pragma once -#if defined(TASKING_INTERNAL) +#if defined(TASKING_INTERNAL) && !defined(TASKING_TBB) # include "taskschedulerinternal.h" #elif defined(TASKING_TBB) # include "taskschedulertbb.h" diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.cpp b/thirdparty/embree/common/tasking/taskschedulerinternal.cpp index ad438588a3..88b88a30ec 100644 --- a/thirdparty/embree/common/tasking/taskschedulerinternal.cpp +++ b/thirdparty/embree/common/tasking/taskschedulerinternal.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include "taskschedulerinternal.h" -#include "../math/math.h" +#include "../math/emath.h" #include "../sys/sysinfo.h" #include <algorithm> @@ -50,11 +50,11 @@ namespace embree thread.task = this; // -- GODOT start -- // try { - // if (thread.scheduler->cancellingException == nullptr) + // if (context->cancellingException == nullptr) closure->execute(); // } catch (...) { - // if (thread.scheduler->cancellingException == nullptr) - // thread.scheduler->cancellingException = std::current_exception(); + // if (context->cancellingException == nullptr) + // context->cancellingException = std::current_exception(); // } // -- GODOT end -- thread.task = prevTask; @@ -152,7 +152,8 @@ namespace embree { Lock<MutexSys> lock(g_mutex); assert(newNumThreads); - newNumThreads = min(newNumThreads, (size_t) getNumberOfLogicalThreads()); + if (newNumThreads == std::numeric_limits<size_t>::max()) + newNumThreads = (size_t) getNumberOfLogicalThreads(); numThreads = newNumThreads; if (!startThreads && !running) return; @@ -232,7 +233,8 @@ namespace embree TaskScheduler::TaskScheduler() : threadCounter(0), anyTasksRunning(0), hasRootTask(false) { - threadLocal.resize(2*getNumberOfLogicalThreads()); // FIXME: this has to be 2x as in the compatibility join mode with rtcCommitScene the worker threads also join. When disallowing rtcCommitScene to join a build we can remove the 2x. + assert(threadPool); + threadLocal.resize(2 * TaskScheduler::threadCount()); // FIXME: this has to be 2x as in the compatibility join mode with rtcCommitScene the worker threads also join. When disallowing rtcCommitScene to join a build we can remove the 2x. for (size_t i=0; i<threadLocal.size(); i++) threadLocal[i].store(nullptr); } @@ -293,11 +295,7 @@ namespace embree size_t threadIndex = allocThreadIndex(); condition.wait(mutex, [&] () { return hasRootTask.load(); }); mutex.unlock(); - // -- GODOT start -- - // std::exception_ptr except = thread_loop(threadIndex); - // if (except != nullptr) std::rethrow_exception(except); thread_loop(threadIndex); - // -- GODOT end -- } void TaskScheduler::reset() { @@ -321,18 +319,15 @@ namespace embree return old; } - dll_export bool TaskScheduler::wait() + dll_export void TaskScheduler::wait() { Thread* thread = TaskScheduler::thread(); - if (thread == nullptr) return true; + if (thread == nullptr) + return; while (thread->tasks.execute_local_internal(*thread,thread->task)) {}; - return thread->scheduler->cancellingException == nullptr; } -// -- GODOT start -- -// std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex) void TaskScheduler::thread_loop(size_t threadIndex) -// -- GODOT end -- { /* allocate thread structure */ std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation @@ -354,11 +349,6 @@ namespace embree threadLocal[threadIndex].store(nullptr); swapThread(oldThread); - /* remember exception to throw */ - // -- GODOT start -- - // std::exception_ptr except = nullptr; - // if (cancellingException != nullptr) except = cancellingException; - // -- GODOT end -- /* wait for all threads to terminate */ threadCounter--; #if defined(__WIN32__) @@ -376,10 +366,6 @@ namespace embree yield(); #endif } - // -- GODOT start -- - // return except; - return; - // -- GODOT end -- } bool TaskScheduler::steal_from_other_threads(Thread& thread) diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.h b/thirdparty/embree/common/tasking/taskschedulerinternal.h index 6cc2495195..e72d3b72ba 100644 --- a/thirdparty/embree/common/tasking/taskschedulerinternal.h +++ b/thirdparty/embree/common/tasking/taskschedulerinternal.h @@ -12,7 +12,7 @@ #include "../sys/ref.h" #include "../sys/atomic.h" #include "../math/range.h" -#include "../../include/embree3/rtcore.h" +#include "../../include/embree4/rtcore.h" #include <list> @@ -38,6 +38,13 @@ namespace embree virtual void execute() = 0; }; + + struct TaskGroupContext { + TaskGroupContext() : cancellingException(nullptr) {} + + std::exception_ptr cancellingException; + }; + /*! builds a task interface from a closure */ template<typename Closure> struct ClosureTaskFunction : public TaskFunction @@ -76,16 +83,16 @@ namespace embree : state(DONE) {} /*! construction of new task */ - __forceinline Task (TaskFunction* closure, Task* parent, size_t stackPtr, size_t N) - : dependencies(1), stealable(true), closure(closure), parent(parent), stackPtr(stackPtr), N(N) + __forceinline Task (TaskFunction* closure, Task* parent, TaskGroupContext* context, size_t stackPtr, size_t N) + : dependencies(1), stealable(true), closure(closure), parent(parent), context(context), stackPtr(stackPtr), N(N) { if (parent) parent->add_dependencies(+1); switch_state(DONE,INITIALIZED); } /*! construction of stolen task, stealing thread will decrement initial dependency */ - __forceinline Task (TaskFunction* closure, Task* parent) - : dependencies(1), stealable(false), closure(closure), parent(parent), stackPtr(-1), N(1) + __forceinline Task (TaskFunction* closure, Task* parent, TaskGroupContext* context) + : dependencies(1), stealable(false), closure(closure), parent(parent), context(context), stackPtr(-1), N(1) { switch_state(DONE,INITIALIZED); } @@ -95,7 +102,7 @@ namespace embree { if (!stealable) return false; if (!try_switch_state(INITIALIZED,DONE)) return false; - new (&child) Task(closure, this); + new (&child) Task(closure, this, context); return true; } @@ -110,6 +117,7 @@ namespace embree std::atomic<bool> stealable; //!< true if task can be stolen TaskFunction* closure; //!< the closure to execute Task* parent; //!< parent task to signal when we are finished + TaskGroupContext* context; size_t stackPtr; //!< stack location where closure is stored size_t N; //!< approximative size of task }; @@ -122,28 +130,32 @@ namespace embree __forceinline void* alloc(size_t bytes, size_t align = 64) { size_t ofs = bytes + ((align - stackPtr) & (align-1)); - if (stackPtr + ofs > CLOSURE_STACK_SIZE) - // -- GODOT start -- - // throw std::runtime_error("closure stack overflow"); + // -- GODOT start -- + // if (stackPtr + ofs > CLOSURE_STACK_SIZE) + // throw std::runtime_error("closure stack overflow"); + if (stackPtr + ofs > CLOSURE_STACK_SIZE) { abort(); - // -- GODOT end -- + } + // -- GODOT end -- stackPtr += ofs; return &stack[stackPtr-bytes]; } template<typename Closure> - __forceinline void push_right(Thread& thread, const size_t size, const Closure& closure) + __forceinline void push_right(Thread& thread, const size_t size, const Closure& closure, TaskGroupContext* context) { - if (right >= TASK_STACK_SIZE) - // -- GODOT start -- - // throw std::runtime_error("task stack overflow"); - abort(); - // -- GODOT end -- + // -- GODOT start -- + // if (right >= TASK_STACK_SIZE) + // throw std::runtime_error("task stack overflow"); + if (right >= TASK_STACK_SIZE) { + abort(); + } + // -- GODOT end -- /* allocate new task on right side of stack */ size_t oldStackPtr = stackPtr; TaskFunction* func = new (alloc(sizeof(ClosureTaskFunction<Closure>))) ClosureTaskFunction<Closure>(closure); - new (&(tasks[right.load()])) Task(func,thread.task,oldStackPtr,size); + new (&tasks[right.load()]) Task(func,thread.task,context,oldStackPtr,size); right++; /* also move left pointer */ @@ -178,7 +190,7 @@ namespace embree : threadIndex(threadIndex), task(nullptr), scheduler(scheduler) {} __forceinline size_t threadCount() { - return scheduler->threadCounter; + return scheduler->threadCounter; } size_t threadIndex; //!< ID of this thread @@ -244,10 +256,7 @@ namespace embree void wait_for_threads(size_t threadCount); /*! thread loop for all worker threads */ - // -- GODOT start -- - // std::exception_ptr thread_loop(size_t threadIndex); void thread_loop(size_t threadIndex); - // -- GODOT end -- /*! steals a task from a different thread */ bool steal_from_other_threads(Thread& thread); @@ -257,7 +266,7 @@ namespace embree /* spawn a new task at the top of the threads task stack */ template<typename Closure> - void spawn_root(const Closure& closure, size_t size = 1, bool useThreadPool = true) + void spawn_root(const Closure& closure, TaskGroupContext* context, size_t size = 1, bool useThreadPool = true) { if (useThreadPool) startThreads(); @@ -267,7 +276,7 @@ namespace embree assert(threadLocal[threadIndex].load() == nullptr); threadLocal[threadIndex] = &thread; Thread* oldThread = swapThread(&thread); - thread.tasks.push_right(thread,size,closure); + thread.tasks.push_right(thread,size,closure,context); { Lock<MutexSys> lock(mutex); anyTasksRunning++; @@ -286,51 +295,52 @@ namespace embree /* remember exception to throw */ std::exception_ptr except = nullptr; - if (cancellingException != nullptr) except = cancellingException; + if (context->cancellingException != nullptr) except = context->cancellingException; /* wait for all threads to terminate */ threadCounter--; while (threadCounter > 0) yield(); - cancellingException = nullptr; + context->cancellingException = nullptr; /* re-throw proper exception */ - if (except != nullptr) + if (except != nullptr) { std::rethrow_exception(except); + } } /* spawn a new task at the top of the threads task stack */ template<typename Closure> - static __forceinline void spawn(size_t size, const Closure& closure) + static __forceinline void spawn(size_t size, const Closure& closure, TaskGroupContext* context) { Thread* thread = TaskScheduler::thread(); - if (likely(thread != nullptr)) thread->tasks.push_right(*thread,size,closure); - else instance()->spawn_root(closure,size); + if (likely(thread != nullptr)) thread->tasks.push_right(*thread,size,closure,context); + else instance()->spawn_root(closure,context,size); } /* spawn a new task at the top of the threads task stack */ template<typename Closure> - static __forceinline void spawn(const Closure& closure) { - spawn(1,closure); + static __forceinline void spawn(const Closure& closure, TaskGroupContext* taskGroupContext) { + spawn(1,closure,taskGroupContext); } /* spawn a new task set */ template<typename Index, typename Closure> - static void spawn(const Index begin, const Index end, const Index blockSize, const Closure& closure) + static void spawn(const Index begin, const Index end, const Index blockSize, const Closure& closure, TaskGroupContext* context) { spawn(end-begin, [=]() - { - if (end-begin <= blockSize) { - return closure(range<Index>(begin,end)); - } - const Index center = (begin+end)/2; - spawn(begin,center,blockSize,closure); - spawn(center,end ,blockSize,closure); - wait(); - }); + { + if (end-begin <= blockSize) { + return closure(range<Index>(begin,end)); + } + const Index center = (begin+end)/2; + spawn(begin,center,blockSize,closure,context); + spawn(center,end ,blockSize,closure,context); + wait(); + },context); } /* work on spawned subtasks and wait until all have finished */ - dll_export static bool wait(); + dll_export static void wait(); /* returns the ID of the current thread */ dll_export static size_t threadID(); @@ -366,7 +376,6 @@ namespace embree std::atomic<size_t> threadCounter; std::atomic<size_t> anyTasksRunning; std::atomic<bool> hasRootTask; - std::exception_ptr cancellingException; MutexSys mutex; ConditionSys condition; diff --git a/thirdparty/embree/common/tasking/taskschedulertbb.h b/thirdparty/embree/common/tasking/taskschedulertbb.h index 042ba7bc4c..e1f647eb06 100644 --- a/thirdparty/embree/common/tasking/taskschedulertbb.h +++ b/thirdparty/embree/common/tasking/taskschedulertbb.h @@ -15,6 +15,12 @@ # define NOMINMAX #endif +#if defined(__INTEL_LLVM_COMPILER) +// prevents "'__thiscall' calling convention is not supported for this target" warning from TBB +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wignored-attributes" +#endif + // We need to define these to avoid implicit linkage against // tbb_debug.lib under Windows. When removing these lines debug build // under Windows fails. @@ -25,6 +31,18 @@ #include "tbb/tbb.h" #include "tbb/parallel_sort.h" +#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR >= 8) +# define USE_TASK_ARENA 1 +#else +# define USE_TASK_ARENA 0 +#endif + +#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION >= 11009) // TBB 2019 Update 9 +# define TASKING_TBB_USE_TASK_ISOLATION 1 +#else +# define TASKING_TBB_USE_TASK_ISOLATION 0 +#endif + namespace embree { struct TaskScheduler @@ -65,3 +83,7 @@ namespace embree }; }; + +#if defined(__INTEL_LLVM_COMPILER) +#pragma clang diagnostic pop +#endif
\ No newline at end of file diff --git a/thirdparty/embree/include/embree3/rtcore_scene.h b/thirdparty/embree/include/embree3/rtcore_scene.h deleted file mode 100644 index 34d87a2ce4..0000000000 --- a/thirdparty/embree/include/embree3/rtcore_scene.h +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "rtcore_device.h" - -RTC_NAMESPACE_BEGIN - -/* Forward declarations for ray structures */ -struct RTCRayHit; -struct RTCRayHit4; -struct RTCRayHit8; -struct RTCRayHit16; -struct RTCRayHitNp; - -/* Scene flags */ -enum RTCSceneFlags -{ - RTC_SCENE_FLAG_NONE = 0, - RTC_SCENE_FLAG_DYNAMIC = (1 << 0), - RTC_SCENE_FLAG_COMPACT = (1 << 1), - RTC_SCENE_FLAG_ROBUST = (1 << 2), - RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION = (1 << 3) -}; - -/* Creates a new scene. */ -RTC_API RTCScene rtcNewScene(RTCDevice device); - -/* Returns the device the scene got created in. The reference count of - * the device is incremented by this function. */ -RTC_API RTCDevice rtcGetSceneDevice(RTCScene hscene); - -/* Retains the scene (increments the reference count). */ -RTC_API void rtcRetainScene(RTCScene scene); - -/* Releases the scene (decrements the reference count). */ -RTC_API void rtcReleaseScene(RTCScene scene); - - -/* Attaches the geometry to a scene. */ -RTC_API unsigned int rtcAttachGeometry(RTCScene scene, RTCGeometry geometry); - -/* Attaches the geometry to a scene using the specified geometry ID. */ -RTC_API void rtcAttachGeometryByID(RTCScene scene, RTCGeometry geometry, unsigned int geomID); - -/* Detaches the geometry from the scene. */ -RTC_API void rtcDetachGeometry(RTCScene scene, unsigned int geomID); - -/* Gets a geometry handle from the scene. This function is not thread safe and should get used during rendering. */ -RTC_API RTCGeometry rtcGetGeometry(RTCScene scene, unsigned int geomID); - -/* Gets a geometry handle from the scene. This function is thread safe and should NOT get used during rendering. */ -RTC_API RTCGeometry rtcGetGeometryThreadSafe(RTCScene scene, unsigned int geomID); - - -/* Commits the scene. */ -RTC_API void rtcCommitScene(RTCScene scene); - -/* Commits the scene from multiple threads. */ -RTC_API void rtcJoinCommitScene(RTCScene scene); - - -/* Progress monitor callback function */ -typedef bool (*RTCProgressMonitorFunction)(void* ptr, double n); - -/* Sets the progress monitor callback function of the scene. */ -RTC_API void rtcSetSceneProgressMonitorFunction(RTCScene scene, RTCProgressMonitorFunction progress, void* ptr); - -/* Sets the build quality of the scene. */ -RTC_API void rtcSetSceneBuildQuality(RTCScene scene, enum RTCBuildQuality quality); - -/* Sets the scene flags. */ -RTC_API void rtcSetSceneFlags(RTCScene scene, enum RTCSceneFlags flags); - -/* Returns the scene flags. */ -RTC_API enum RTCSceneFlags rtcGetSceneFlags(RTCScene scene); - -/* Returns the axis-aligned bounds of the scene. */ -RTC_API void rtcGetSceneBounds(RTCScene scene, struct RTCBounds* bounds_o); - -/* Returns the linear axis-aligned bounds of the scene. */ -RTC_API void rtcGetSceneLinearBounds(RTCScene scene, struct RTCLinearBounds* bounds_o); - - -/* Perform a closest point query of the scene. */ -RTC_API bool rtcPointQuery(RTCScene scene, struct RTCPointQuery* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void* userPtr); - -/* Perform a closest point query with a packet of 4 points with the scene. */ -RTC_API bool rtcPointQuery4(const int* valid, RTCScene scene, struct RTCPointQuery4* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr); - -/* Perform a closest point query with a packet of 4 points with the scene. */ -RTC_API bool rtcPointQuery8(const int* valid, RTCScene scene, struct RTCPointQuery8* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr); - -/* Perform a closest point query with a packet of 4 points with the scene. */ -RTC_API bool rtcPointQuery16(const int* valid, RTCScene scene, struct RTCPointQuery16* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr); - -/* Intersects a single ray with the scene. */ -RTC_API void rtcIntersect1(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit* rayhit); - -/* Intersects a packet of 4 rays with the scene. */ -RTC_API void rtcIntersect4(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit4* rayhit); - -/* Intersects a packet of 8 rays with the scene. */ -RTC_API void rtcIntersect8(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit8* rayhit); - -/* Intersects a packet of 16 rays with the scene. */ -RTC_API void rtcIntersect16(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit16* rayhit); - -/* Intersects a stream of M rays with the scene. */ -RTC_API void rtcIntersect1M(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit* rayhit, unsigned int M, size_t byteStride); - -/* Intersects a stream of pointers to M rays with the scene. */ -RTC_API void rtcIntersect1Mp(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHit** rayhit, unsigned int M); - -/* Intersects a stream of M ray packets of size N in SOA format with the scene. */ -RTC_API void rtcIntersectNM(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayHitN* rayhit, unsigned int N, unsigned int M, size_t byteStride); - -/* Intersects a stream of M ray packets of size N in SOA format with the scene. */ -RTC_API void rtcIntersectNp(RTCScene scene, struct RTCIntersectContext* context, const struct RTCRayHitNp* rayhit, unsigned int N); - -/* Tests a single ray for occlusion with the scene. */ -RTC_API void rtcOccluded1(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay* ray); - -/* Tests a packet of 4 rays for occlusion occluded with the scene. */ -RTC_API void rtcOccluded4(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay4* ray); - -/* Tests a packet of 8 rays for occlusion with the scene. */ -RTC_API void rtcOccluded8(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay8* ray); - -/* Tests a packet of 16 rays for occlusion with the scene. */ -RTC_API void rtcOccluded16(const int* valid, RTCScene scene, struct RTCIntersectContext* context, struct RTCRay16* ray); - -/* Tests a stream of M rays for occlusion with the scene. */ -RTC_API void rtcOccluded1M(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay* ray, unsigned int M, size_t byteStride); - -/* Tests a stream of pointers to M rays for occlusion with the scene. */ -RTC_API void rtcOccluded1Mp(RTCScene scene, struct RTCIntersectContext* context, struct RTCRay** ray, unsigned int M); - -/* Tests a stream of M ray packets of size N in SOA format for occlusion with the scene. */ -RTC_API void rtcOccludedNM(RTCScene scene, struct RTCIntersectContext* context, struct RTCRayN* ray, unsigned int N, unsigned int M, size_t byteStride); - -/* Tests a stream of M ray packets of size N in SOA format for occlusion with the scene. */ -RTC_API void rtcOccludedNp(RTCScene scene, struct RTCIntersectContext* context, const struct RTCRayNp* ray, unsigned int N); - -/*! collision callback */ -struct RTCCollision { unsigned int geomID0; unsigned int primID0; unsigned int geomID1; unsigned int primID1; }; -typedef void (*RTCCollideFunc) (void* userPtr, struct RTCCollision* collisions, unsigned int num_collisions); - -/*! Performs collision detection of two scenes */ -RTC_API void rtcCollide (RTCScene scene0, RTCScene scene1, RTCCollideFunc callback, void* userPtr); - -#if defined(__cplusplus) - -/* Helper for easily combining scene flags */ -inline RTCSceneFlags operator|(RTCSceneFlags a, RTCSceneFlags b) { - return (RTCSceneFlags)((size_t)a | (size_t)b); -} - -#endif - -RTC_NAMESPACE_END - diff --git a/thirdparty/embree/include/embree3/rtcore.h b/thirdparty/embree/include/embree4/rtcore.h index 450ab4c535..450ab4c535 100644 --- a/thirdparty/embree/include/embree3/rtcore.h +++ b/thirdparty/embree/include/embree4/rtcore.h diff --git a/thirdparty/embree/include/embree3/rtcore_buffer.h b/thirdparty/embree/include/embree4/rtcore_buffer.h index 6b8eba9769..8721ce4a44 100644 --- a/thirdparty/embree/include/embree3/rtcore_buffer.h +++ b/thirdparty/embree/include/embree4/rtcore_buffer.h @@ -27,6 +27,8 @@ enum RTCBufferType RTC_BUFFER_TYPE_VERTEX_CREASE_WEIGHT = 21, RTC_BUFFER_TYPE_HOLE = 22, + RTC_BUFFER_TYPE_TRANSFORM = 23, + RTC_BUFFER_TYPE_FLAGS = 32 }; diff --git a/thirdparty/embree/include/embree3/rtcore_builder.h b/thirdparty/embree/include/embree4/rtcore_builder.h index 4bff999fed..4bff999fed 100644 --- a/thirdparty/embree/include/embree3/rtcore_builder.h +++ b/thirdparty/embree/include/embree4/rtcore_builder.h diff --git a/thirdparty/embree/include/embree3/rtcore_common.h b/thirdparty/embree/include/embree4/rtcore_common.h index 894628e47c..57448ddaea 100644 --- a/thirdparty/embree/include/embree3/rtcore_common.h +++ b/thirdparty/embree/include/embree4/rtcore_common.h @@ -12,7 +12,7 @@ RTC_NAMESPACE_BEGIN #if defined(_WIN32) -#if defined(_M_X64) +#if defined(_M_X64) || defined(_M_ARM64) typedef long long ssize_t; #else typedef int ssize_t; @@ -41,6 +41,12 @@ typedef int ssize_t; # define RTC_FORCEINLINE inline __attribute__((always_inline)) #endif +#if defined(__cplusplus) +# define RTC_OPTIONAL_ARGUMENT = nullptr +#else +# define RTC_OPTIONAL_ARGUMENT +#endif + /* Invalid geometry ID */ #define RTC_INVALID_GEOMETRY_ID ((unsigned int)-1) @@ -141,7 +147,9 @@ enum RTCFormat RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR = 0x9244, /* special 12-byte format for grids */ - RTC_FORMAT_GRID = 0xA001 + RTC_FORMAT_GRID = 0xA001, + + RTC_FORMAT_QUATERNION_DECOMPOSITION = 0xB001, }; /* Build quality levels */ @@ -167,12 +175,138 @@ struct RTC_ALIGN(16) RTCLinearBounds struct RTCBounds bounds1; }; -/* Intersection context flags */ -enum RTCIntersectContextFlags +/* Feature flags for SYCL specialization constants */ +enum RTCFeatureFlags { - RTC_INTERSECT_CONTEXT_FLAG_NONE = 0, - RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT = (0 << 0), // optimize for incoherent rays - RTC_INTERSECT_CONTEXT_FLAG_COHERENT = (1 << 0) // optimize for coherent rays + RTC_FEATURE_FLAG_NONE = 0, + + RTC_FEATURE_FLAG_MOTION_BLUR = 1 << 0, + + RTC_FEATURE_FLAG_TRIANGLE = 1 << 1, + RTC_FEATURE_FLAG_QUAD = 1 << 2, + RTC_FEATURE_FLAG_GRID = 1 << 3, + + RTC_FEATURE_FLAG_SUBDIVISION = 1 << 4, + + RTC_FEATURE_FLAG_CONE_LINEAR_CURVE = 1 << 5, + RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE = 1 << 6, + RTC_FEATURE_FLAG_FLAT_LINEAR_CURVE = 1 << 7, + + RTC_FEATURE_FLAG_ROUND_BEZIER_CURVE = 1 << 8, + RTC_FEATURE_FLAG_FLAT_BEZIER_CURVE = 1 << 9, + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BEZIER_CURVE = 1 << 10, + + RTC_FEATURE_FLAG_ROUND_BSPLINE_CURVE = 1 << 11, + RTC_FEATURE_FLAG_FLAT_BSPLINE_CURVE = 1 << 12, + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BSPLINE_CURVE = 1 << 13, + + RTC_FEATURE_FLAG_ROUND_HERMITE_CURVE = 1 << 14, + RTC_FEATURE_FLAG_FLAT_HERMITE_CURVE = 1 << 15, + RTC_FEATURE_FLAG_NORMAL_ORIENTED_HERMITE_CURVE = 1 << 16, + + RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE = 1 << 17, + RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE = 1 << 18, + RTC_FEATURE_FLAG_NORMAL_ORIENTED_CATMULL_ROM_CURVE = 1 << 19, + + RTC_FEATURE_FLAG_SPHERE_POINT = 1 << 20, + RTC_FEATURE_FLAG_DISC_POINT = 1 << 21, + RTC_FEATURE_FLAG_ORIENTED_DISC_POINT = 1 << 22, + + RTC_FEATURE_FLAG_POINT = + RTC_FEATURE_FLAG_SPHERE_POINT | + RTC_FEATURE_FLAG_DISC_POINT | + RTC_FEATURE_FLAG_ORIENTED_DISC_POINT, + + RTC_FEATURE_FLAG_ROUND_CURVES = + RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE | + RTC_FEATURE_FLAG_ROUND_BEZIER_CURVE | + RTC_FEATURE_FLAG_ROUND_BSPLINE_CURVE | + RTC_FEATURE_FLAG_ROUND_HERMITE_CURVE | + RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE, + + RTC_FEATURE_FLAG_FLAT_CURVES = + RTC_FEATURE_FLAG_FLAT_LINEAR_CURVE | + RTC_FEATURE_FLAG_FLAT_BEZIER_CURVE | + RTC_FEATURE_FLAG_FLAT_BSPLINE_CURVE | + RTC_FEATURE_FLAG_FLAT_HERMITE_CURVE | + RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE, + + RTC_FEATURE_FLAG_NORMAL_ORIENTED_CURVES = + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BEZIER_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BSPLINE_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_HERMITE_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_CATMULL_ROM_CURVE, + + RTC_FEATURE_FLAG_LINEAR_CURVES = + RTC_FEATURE_FLAG_CONE_LINEAR_CURVE | + RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE | + RTC_FEATURE_FLAG_FLAT_LINEAR_CURVE, + + RTC_FEATURE_FLAG_BEZIER_CURVES = + RTC_FEATURE_FLAG_ROUND_BEZIER_CURVE | + RTC_FEATURE_FLAG_FLAT_BEZIER_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BEZIER_CURVE, + + RTC_FEATURE_FLAG_BSPLINE_CURVES = + RTC_FEATURE_FLAG_ROUND_BSPLINE_CURVE | + RTC_FEATURE_FLAG_FLAT_BSPLINE_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BSPLINE_CURVE, + + RTC_FEATURE_FLAG_HERMITE_CURVES = + RTC_FEATURE_FLAG_ROUND_HERMITE_CURVE | + RTC_FEATURE_FLAG_FLAT_HERMITE_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_HERMITE_CURVE, + + RTC_FEATURE_FLAG_CURVES = + RTC_FEATURE_FLAG_CONE_LINEAR_CURVE | + RTC_FEATURE_FLAG_ROUND_LINEAR_CURVE | + RTC_FEATURE_FLAG_FLAT_LINEAR_CURVE | + RTC_FEATURE_FLAG_ROUND_BEZIER_CURVE | + RTC_FEATURE_FLAG_FLAT_BEZIER_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BEZIER_CURVE | + RTC_FEATURE_FLAG_ROUND_BSPLINE_CURVE | + RTC_FEATURE_FLAG_FLAT_BSPLINE_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_BSPLINE_CURVE | + RTC_FEATURE_FLAG_ROUND_HERMITE_CURVE | + RTC_FEATURE_FLAG_FLAT_HERMITE_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_HERMITE_CURVE | + RTC_FEATURE_FLAG_ROUND_CATMULL_ROM_CURVE | + RTC_FEATURE_FLAG_FLAT_CATMULL_ROM_CURVE | + RTC_FEATURE_FLAG_NORMAL_ORIENTED_CATMULL_ROM_CURVE, + + RTC_FEATURE_FLAG_INSTANCE = 1 << 23, + + RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS = 1 << 24, + RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_GEOMETRY = 1 << 25, + + RTC_FEATURE_FLAG_FILTER_FUNCTION = + RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS | + RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_GEOMETRY, + + RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_ARGUMENTS = 1 << 26, + RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_GEOMETRY = 1 << 27, + + RTC_FEATURE_FLAG_USER_GEOMETRY = + RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_ARGUMENTS | + RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_GEOMETRY, + + RTC_FEATURE_FLAG_32_BIT_RAY_MASK = 1 << 28, + + RTC_FEATURE_FLAG_INSTANCE_ARRAY = 1 << 29, + + RTC_FEATURE_FLAG_ALL = 0xffffffff, +}; + +/* Ray query flags */ +enum RTCRayQueryFlags +{ + /* matching intel_ray_flags_t layout */ + RTC_RAY_QUERY_FLAG_NONE = 0, + RTC_RAY_QUERY_FLAG_INVOKE_ARGUMENT_FILTER = (1 << 1), // enable argument filter for each geometry + + /* embree specific flags */ + RTC_RAY_QUERY_FLAG_INCOHERENT = (0 << 16), // optimize for incoherent rays + RTC_RAY_QUERY_FLAG_COHERENT = (1 << 16), // optimize for coherent rays }; /* Arguments for RTCFilterFunctionN */ @@ -180,7 +314,7 @@ struct RTCFilterFunctionNArguments { int* valid; void* geometryUserPtr; - struct RTCIntersectContext* context; + struct RTCRayQueryContext* context; struct RTCRayN* ray; struct RTCHitN* hit; unsigned int N; @@ -189,38 +323,41 @@ struct RTCFilterFunctionNArguments /* Filter callback function */ typedef void (*RTCFilterFunctionN)(const struct RTCFilterFunctionNArguments* args); -/* Intersection context passed to intersect/occluded calls */ -struct RTCIntersectContext +/* Intersection callback function */ +struct RTCIntersectFunctionNArguments; +typedef void (*RTCIntersectFunctionN)(const struct RTCIntersectFunctionNArguments* args); + +/* Occlusion callback function */ +struct RTCOccludedFunctionNArguments; +typedef void (*RTCOccludedFunctionN)(const struct RTCOccludedFunctionNArguments* args); + +/* Ray query context passed to intersect/occluded calls */ +struct RTCRayQueryContext { - enum RTCIntersectContextFlags flags; // intersection flags - RTCFilterFunctionN filter; // filter function to execute - #if RTC_MAX_INSTANCE_LEVEL_COUNT > 1 unsigned int instStackSize; // Number of instances currently on the stack. #endif unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // The current stack of instance ids. - -#if RTC_MIN_WIDTH - float minWidthDistanceFactor; // curve radius is set to this factor times distance to ray origin +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // The current stack of instance primitive ids. #endif }; -/* Initializes an intersection context. */ -RTC_FORCEINLINE void rtcInitIntersectContext(struct RTCIntersectContext* context) +/* Initializes an ray query context. */ +RTC_FORCEINLINE void rtcInitRayQueryContext(struct RTCRayQueryContext* context) { unsigned l = 0; - context->flags = RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT; - context->filter = NULL; - + #if RTC_MAX_INSTANCE_LEVEL_COUNT > 1 context->instStackSize = 0; #endif - for (; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + + for (; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) { context->instID[l] = RTC_INVALID_GEOMETRY_ID; - -#if RTC_MIN_WIDTH - context->minWidthDistanceFactor = 0.0f; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + context->instPrimID[l] = RTC_INVALID_GEOMETRY_ID; #endif + } } /* Point query structure for closest point query */ @@ -278,15 +415,28 @@ struct RTC_ALIGN(16) RTCPointQueryContext // instance ids. unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + // instance prim ids. + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; +#endif + // number of instances currently on the stack. unsigned int instStackSize; }; -/* Initializes an intersection context. */ +/* Initializes an ray query context. */ RTC_FORCEINLINE void rtcInitPointQueryContext(struct RTCPointQueryContext* context) { + unsigned l = 0; + context->instStackSize = 0; - context->instID[0] = RTC_INVALID_GEOMETRY_ID; + + for (; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) { + context->instID[l] = RTC_INVALID_GEOMETRY_ID; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + context->instPrimID[l] = RTC_INVALID_GEOMETRY_ID; +#endif + } } struct RTC_ALIGN(16) RTCPointQueryFunctionArguments @@ -308,7 +458,7 @@ struct RTC_ALIGN(16) RTCPointQueryFunctionArguments struct RTCPointQueryContext* context; // If the current instance transform M (= context->world2inst[context->instStackSize]) - // is a similarity matrix, i.e there is a constant factor similarityScale such that, + // is a similarity matrix, i.e there is a constant factor similarityScale such that // for all x,y: dist(Mx, My) = similarityScale * dist(x, y), // The similarity scale is 0, if the current instance transform is not a // similarity transform and vice versa. The similarity scale allows to compute @@ -322,5 +472,31 @@ struct RTC_ALIGN(16) RTCPointQueryFunctionArguments }; typedef bool (*RTCPointQueryFunction)(struct RTCPointQueryFunctionArguments* args); - + +#if defined(EMBREE_SYCL_SUPPORT) && defined(SYCL_LANGUAGE_VERSION) + +/* returns function pointer to be usable in SYCL kernel */ +template<auto F> +inline decltype(F) rtcGetSYCLDeviceFunctionPointer(sycl::queue& queue) +{ + sycl::buffer<cl_ulong> fptr_buf(1); + { + auto fptr_acc = fptr_buf.get_host_access(); + fptr_acc[0] = 0; + } + + queue.submit([&](sycl::handler& cgh) { + auto fptr_acc = fptr_buf.get_access<sycl::access::mode::discard_write>(cgh); + cgh.single_task([=]() { + fptr_acc[0] = reinterpret_cast<cl_ulong>(F); + }); + }); + queue.wait_and_throw(); + + auto fptr_acc = fptr_buf.get_host_access(); + return (decltype(F)) fptr_acc[0]; +} + +#endif + RTC_NAMESPACE_END diff --git a/thirdparty/embree/include/embree3/rtcore_config.h b/thirdparty/embree/include/embree4/rtcore_config.h index 0b399ef040..cb3a8678a7 100644 --- a/thirdparty/embree/include/embree3/rtcore_config.h +++ b/thirdparty/embree/include/embree4/rtcore_config.h @@ -3,21 +3,32 @@ #pragma once -#define RTC_VERSION_MAJOR 3 -#define RTC_VERSION_MINOR 13 -#define RTC_VERSION_PATCH 5 -#define RTC_VERSION 31305 -#define RTC_VERSION_STRING "3.13.5" +#if !defined(EMBREE_SYCL_SUPPORT) +// #cmakedefine EMBREE_SYCL_SUPPORT +#endif + +#define RTC_VERSION_MAJOR 4 +#define RTC_VERSION_MINOR 3 +#define RTC_VERSION_PATCH 1 +#define RTC_VERSION 40301 +#define RTC_VERSION_STRING "4.3.1" #define RTC_MAX_INSTANCE_LEVEL_COUNT 1 +// #cmakedefine EMBREE_GEOMETRY_INSTANCE_ARRAY +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + #define RTC_GEOMETRY_INSTANCE_ARRAY +#endif + +// #cmakedefine01 EMBREE_SYCL_GEOMETRY_CALLBACK + #define EMBREE_MIN_WIDTH 0 #define RTC_MIN_WIDTH EMBREE_MIN_WIDTH #if !defined(EMBREE_STATIC_LIB) -# define EMBREE_STATIC_LIB +#define EMBREE_STATIC_LIB #endif -/* #undef EMBREE_API_NAMESPACE*/ +// #cmakedefine EMBREE_API_NAMESPACE #if defined(EMBREE_API_NAMESPACE) # define RTC_NAMESPACE @@ -56,3 +67,14 @@ #else # define RTC_API RTC_API_IMPORT #endif + +#if defined(ISPC) +# define RTC_SYCL_INDIRECTLY_CALLABLE +#elif defined(__SYCL_DEVICE_ONLY__) +# define RTC_SYCL_INDIRECTLY_CALLABLE [[intel::device_indirectly_callable]] SYCL_EXTERNAL +# define RTC_SYCL_API SYCL_EXTERNAL +#else +# define RTC_SYCL_INDIRECTLY_CALLABLE +# define RTC_SYCL_API RTC_API +#endif + diff --git a/thirdparty/embree/include/embree3/rtcore_device.h b/thirdparty/embree/include/embree4/rtcore_device.h index 2dd3047603..5ca99bca0a 100644 --- a/thirdparty/embree/include/embree3/rtcore_device.h +++ b/thirdparty/embree/include/embree4/rtcore_device.h @@ -13,6 +13,24 @@ typedef struct RTCDeviceTy* RTCDevice; /* Creates a new Embree device. */ RTC_API RTCDevice rtcNewDevice(const char* config); +#if defined(EMBREE_SYCL_SUPPORT) && defined(SYCL_LANGUAGE_VERSION) + + +/* Creates a new Embree SYCL device. */ +RTC_API_EXTERN_C RTCDevice rtcNewSYCLDevice(sycl::context context, const char* config); + +/* Checks if SYCL device is supported by Embree. */ +RTC_API bool rtcIsSYCLDeviceSupported(const sycl::device sycl_device); + +/* SYCL selector for Embree supported devices */ +RTC_API int rtcSYCLDeviceSelector(const sycl::device sycl_device); + +/* Set the SYCL device to be used to allocate data */ +RTC_API void rtcSetDeviceSYCLDevice(RTCDevice device, const sycl::device sycl_device); + +#endif + + /* Retains the Embree device (increments the reference count). */ RTC_API void rtcRetainDevice(RTCDevice device); @@ -30,8 +48,8 @@ enum RTCDeviceProperty RTC_DEVICE_PROPERTY_NATIVE_RAY4_SUPPORTED = 32, RTC_DEVICE_PROPERTY_NATIVE_RAY8_SUPPORTED = 33, RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED = 34, - RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED = 35, + RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED = 62, RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED = 63, RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED = 64, RTC_DEVICE_PROPERTY_BACKFACE_CULLING_ENABLED = 65, @@ -66,7 +84,7 @@ enum RTCError RTC_ERROR_INVALID_OPERATION = 3, RTC_ERROR_OUT_OF_MEMORY = 4, RTC_ERROR_UNSUPPORTED_CPU = 5, - RTC_ERROR_CANCELLED = 6 + RTC_ERROR_CANCELLED = 6, }; /* Returns the error code. */ diff --git a/thirdparty/embree/include/embree3/rtcore_geometry.h b/thirdparty/embree/include/embree4/rtcore_geometry.h index d1de17491c..140d6721d5 100644 --- a/thirdparty/embree/include/embree3/rtcore_geometry.h +++ b/thirdparty/embree/include/embree4/rtcore_geometry.h @@ -48,7 +48,8 @@ enum RTCGeometryType RTC_GEOMETRY_TYPE_NORMAL_ORIENTED_CATMULL_ROM_CURVE = 60, // flat normal-oriented Catmull-Rom curves RTC_GEOMETRY_TYPE_USER = 120, // user-defined geometry - RTC_GEOMETRY_TYPE_INSTANCE = 121 // scene instance + RTC_GEOMETRY_TYPE_INSTANCE = 121, // scene instance + RTC_GEOMETRY_TYPE_INSTANCE_ARRAY = 122, // scene instance array }; /* Interpolation modes for subdivision surfaces */ @@ -86,30 +87,24 @@ struct RTCIntersectFunctionNArguments int* valid; void* geometryUserPtr; unsigned int primID; - struct RTCIntersectContext* context; + struct RTCRayQueryContext* context; struct RTCRayHitN* rayhit; unsigned int N; unsigned int geomID; }; -/* Intersection callback function */ -typedef void (*RTCIntersectFunctionN)(const struct RTCIntersectFunctionNArguments* args); - /* Arguments for RTCOccludedFunctionN */ struct RTCOccludedFunctionNArguments { int* valid; void* geometryUserPtr; unsigned int primID; - struct RTCIntersectContext* context; + struct RTCRayQueryContext* context; struct RTCRayN* ray; unsigned int N; unsigned int geomID; }; -/* Occlusion callback function */ -typedef void (*RTCOccludedFunctionN)(const struct RTCOccludedFunctionNArguments* args); - /* Arguments for RTCDisplacementFunctionN */ struct RTCDisplacementFunctionNArguments { @@ -192,6 +187,9 @@ RTC_API void rtcSetGeometryIntersectFilterFunction(RTCGeometry geometry, RTCFilt /* Sets the occlusion filter callback function of the geometry. */ RTC_API void rtcSetGeometryOccludedFilterFunction(RTCGeometry geometry, RTCFilterFunctionN filter); +/* Enables argument version of intersection or occlusion filter function. */ +RTC_API void rtcSetGeometryEnableFilterFunctionFromArguments(RTCGeometry geometry, bool enable); + /* Sets the user-defined data pointer of the geometry. */ RTC_API void rtcSetGeometryUserData(RTCGeometry geometry, void* ptr); @@ -214,15 +212,17 @@ RTC_API void rtcSetGeometryIntersectFunction(RTCGeometry geometry, RTCIntersectF RTC_API void rtcSetGeometryOccludedFunction(RTCGeometry geometry, RTCOccludedFunctionN occluded); /* Invokes the intersection filter from the intersection callback function. */ -RTC_API void rtcFilterIntersection(const struct RTCIntersectFunctionNArguments* args, const struct RTCFilterFunctionNArguments* filterArgs); +RTC_SYCL_API void rtcInvokeIntersectFilterFromGeometry(const struct RTCIntersectFunctionNArguments* args, const struct RTCFilterFunctionNArguments* filterArgs); /* Invokes the occlusion filter from the occlusion callback function. */ -RTC_API void rtcFilterOcclusion(const struct RTCOccludedFunctionNArguments* args, const struct RTCFilterFunctionNArguments* filterArgs); - +RTC_SYCL_API void rtcInvokeOccludedFilterFromGeometry(const struct RTCOccludedFunctionNArguments* args, const struct RTCFilterFunctionNArguments* filterArgs); /* Sets the instanced scene of an instance geometry. */ RTC_API void rtcSetGeometryInstancedScene(RTCGeometry geometry, RTCScene scene); +/* Sets the instanced scenes of an instance array geometry. */ +RTC_API void rtcSetGeometryInstancedScenes(RTCGeometry geometry, RTCScene* scenes, size_t numScenes); + /* Sets the transformation of an instance for the specified time step. */ RTC_API void rtcSetGeometryTransform(RTCGeometry geometry, unsigned int timeStep, enum RTCFormat format, const void* xfm); @@ -232,6 +232,12 @@ RTC_API void rtcSetGeometryTransformQuaternion(RTCGeometry geometry, unsigned in /* Returns the interpolated transformation of an instance for the specified time. */ RTC_API void rtcGetGeometryTransform(RTCGeometry geometry, float time, enum RTCFormat format, void* xfm); +/* + * Returns the interpolated transformation of the instPrimID'th instance of an + * instance array for the specified time. If geometry is an regular instance, + * instPrimID must be 0. + */ +RTC_API void rtcGetGeometryTransformEx(RTCGeometry geometry, unsigned int instPrimID, float time, enum RTCFormat format, void* xfm); /* Sets the uniform tessellation rate of the geometry. */ RTC_API void rtcSetGeometryTessellationRate(RTCGeometry geometry, float tessellationRate); diff --git a/thirdparty/embree/include/embree3/rtcore_quaternion.h b/thirdparty/embree/include/embree4/rtcore_quaternion.h index bd5fe1d89a..bd5fe1d89a 100644 --- a/thirdparty/embree/include/embree3/rtcore_quaternion.h +++ b/thirdparty/embree/include/embree4/rtcore_quaternion.h diff --git a/thirdparty/embree/include/embree3/rtcore_ray.h b/thirdparty/embree/include/embree4/rtcore_ray.h index a2ee6dabbb..7fc3f00cf9 100644 --- a/thirdparty/embree/include/embree3/rtcore_ray.h +++ b/thirdparty/embree/include/embree4/rtcore_ray.h @@ -39,6 +39,9 @@ struct RTC_ALIGN(16) RTCHit unsigned int primID; // primitive ID unsigned int geomID; // geometry ID unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance primitive ID +#endif }; /* Combined ray/hit structure for a single ray */ @@ -80,6 +83,9 @@ struct RTC_ALIGN(16) RTCHit4 unsigned int primID[4]; unsigned int geomID[4]; unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][4]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT][4]; +#endif }; /* Combined ray/hit structure for a packet of 4 rays */ @@ -121,6 +127,9 @@ struct RTC_ALIGN(32) RTCHit8 unsigned int primID[8]; unsigned int geomID[8]; unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][8]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT][8]; +#endif }; /* Combined ray/hit structure for a packet of 8 rays */ @@ -162,6 +171,9 @@ struct RTC_ALIGN(64) RTCHit16 unsigned int primID[16]; unsigned int geomID[16]; unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][16]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT][16]; +#endif }; /* Combined ray/hit structure for a packet of 16 rays */ @@ -171,47 +183,6 @@ struct RTCRayHit16 struct RTCHit16 hit; }; -/* Ray structure for a packet/stream of N rays in pointer SOA layout */ -struct RTCRayNp -{ - float* org_x; - float* org_y; - float* org_z; - float* tnear; - - float* dir_x; - float* dir_y; - float* dir_z; - float* time; - - float* tfar; - unsigned int* mask; - unsigned int* id; - unsigned int* flags; -}; - -/* Hit structure for a packet/stream of N rays in pointer SOA layout */ -struct RTCHitNp -{ - float* Ng_x; - float* Ng_y; - float* Ng_z; - - float* u; - float* v; - - unsigned int* primID; - unsigned int* geomID; - unsigned int* instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; -}; - -/* Combined ray/hit structure for a packet/stream of N rays in pointer SOA layout */ -struct RTCRayHitNp -{ - struct RTCRayNp ray; - struct RTCHitNp hit; -}; - struct RTCRayN; struct RTCHitN; struct RTCRayHitN; @@ -242,9 +213,12 @@ RTC_FORCEINLINE float& RTCHitN_Ng_z(RTCHitN* hit, unsigned int N, unsigned int i RTC_FORCEINLINE float& RTCHitN_u(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[3*N+i]; } RTC_FORCEINLINE float& RTCHitN_v(RTCHitN* hit, unsigned int N, unsigned int i) { return ((float*)hit)[4*N+i]; } -RTC_FORCEINLINE unsigned int& RTCHitN_primID(RTCHitN* hit, unsigned int N, unsigned int i) { return ((unsigned*)hit)[5*N+i]; } -RTC_FORCEINLINE unsigned int& RTCHitN_geomID(RTCHitN* hit, unsigned int N, unsigned int i) { return ((unsigned*)hit)[6*N+i]; } -RTC_FORCEINLINE unsigned int& RTCHitN_instID(RTCHitN* hit, unsigned int N, unsigned int i, unsigned int l) { return ((unsigned*)hit)[7*N+i+N*l]; } +RTC_FORCEINLINE unsigned int& RTCHitN_primID (RTCHitN* hit, unsigned int N, unsigned int i) { return ((unsigned*)hit)[5*N+i]; } +RTC_FORCEINLINE unsigned int& RTCHitN_geomID (RTCHitN* hit, unsigned int N, unsigned int i) { return ((unsigned*)hit)[6*N+i]; } +RTC_FORCEINLINE unsigned int& RTCHitN_instID (RTCHitN* hit, unsigned int N, unsigned int i, unsigned int l) { return ((unsigned*)hit)[7*N + N*l + i]; } +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) +RTC_FORCEINLINE unsigned int& RTCHitN_instPrimID(RTCHitN* hit, unsigned int N, unsigned int i, unsigned int l) { return ((unsigned*)hit)[7*N + N*RTC_MAX_INSTANCE_LEVEL_COUNT + N*l + i]; } +#endif /* Helper functions to extract RTCRayN and RTCHitN from RTCRayHitN */ RTC_FORCEINLINE RTCRayN* RTCRayHitN_RayN(RTCRayHitN* rayhit, unsigned int N) { return (RTCRayN*)&((float*)rayhit)[0*N]; } @@ -284,6 +258,9 @@ struct RTCHitNt unsigned int primID[N]; unsigned int geomID[N]; unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT][N]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT][N]; +#endif }; /* Helper structure for a combined ray/hit packet of compile-time size N */ @@ -322,8 +299,12 @@ RTC_FORCEINLINE RTCHit rtcGetHitFromHitN(RTCHitN* hitN, unsigned int N, unsigned hit.v = RTCHitN_v(hitN,N,i); hit.primID = RTCHitN_primID(hitN,N,i); hit.geomID = RTCHitN_geomID(hitN,N,i); - for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++) + for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++) { hit.instID[l] = RTCHitN_instID(hitN,N,i,l); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + hit.instPrimID[l] = RTCHitN_instPrimID(hitN,N,i,l); +#endif + } return hit; } @@ -336,8 +317,12 @@ RTC_FORCEINLINE void rtcCopyHitToHitN(RTCHitN* hitN, const RTCHit* hit, unsigned RTCHitN_v(hitN,N,i) = hit->v; RTCHitN_primID(hitN,N,i) = hit->primID; RTCHitN_geomID(hitN,N,i) = hit->geomID; - for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++) + for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++) { RTCHitN_instID(hitN,N,i,l) = hit->instID[l]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + RTCHitN_instPrimID(hitN,N,i,l) = hit->instPrimID[l]; +#endif + } } RTC_FORCEINLINE RTCRayHit rtcGetRayHitFromRayHitN(RTCRayHitN* rayhitN, unsigned int N, unsigned int i) @@ -366,8 +351,12 @@ RTC_FORCEINLINE RTCRayHit rtcGetRayHitFromRayHitN(RTCRayHitN* rayhitN, unsigned rh.hit.v = RTCHitN_v(hit,N,i); rh.hit.primID = RTCHitN_primID(hit,N,i); rh.hit.geomID = RTCHitN_geomID(hit,N,i); - for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++) + for (unsigned int l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; l++) { rh.hit.instID[l] = RTCHitN_instID(hit,N,i,l); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + rh.hit.instPrimID[l] = RTCHitN_instPrimID(hit,N,i,l); +#endif + } return rh; } diff --git a/thirdparty/embree/include/embree4/rtcore_scene.h b/thirdparty/embree/include/embree4/rtcore_scene.h new file mode 100644 index 0000000000..e37af4f962 --- /dev/null +++ b/thirdparty/embree/include/embree4/rtcore_scene.h @@ -0,0 +1,252 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "rtcore_device.h" + +RTC_NAMESPACE_BEGIN + +/* Forward declarations for ray structures */ +struct RTCRayHit; +struct RTCRayHit4; +struct RTCRayHit8; +struct RTCRayHit16; + +/* Scene flags */ +enum RTCSceneFlags +{ + RTC_SCENE_FLAG_NONE = 0, + RTC_SCENE_FLAG_DYNAMIC = (1 << 0), + RTC_SCENE_FLAG_COMPACT = (1 << 1), + RTC_SCENE_FLAG_ROBUST = (1 << 2), + RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS = (1 << 3) +}; + +/* Additional arguments for rtcIntersect1/4/8/16 calls */ +struct RTCIntersectArguments +{ + enum RTCRayQueryFlags flags; // intersection flags + enum RTCFeatureFlags feature_mask; // selectively enable features for traversal + struct RTCRayQueryContext* context; // optional pointer to ray query context + RTCFilterFunctionN filter; // filter function to execute + RTCIntersectFunctionN intersect; // user geometry intersection callback to execute +#if RTC_MIN_WIDTH + float minWidthDistanceFactor; // curve radius is set to this factor times distance to ray origin +#endif +}; + +/* Initializes intersection arguments. */ +RTC_FORCEINLINE void rtcInitIntersectArguments(struct RTCIntersectArguments* args) +{ + args->flags = RTC_RAY_QUERY_FLAG_INCOHERENT; + args->feature_mask = RTC_FEATURE_FLAG_ALL; + args->context = NULL; + args->filter = NULL; + args->intersect = NULL; + +#if RTC_MIN_WIDTH + args->minWidthDistanceFactor = 0.0f; +#endif +} + +/* Additional arguments for rtcOccluded1/4/8/16 calls */ +struct RTCOccludedArguments +{ + enum RTCRayQueryFlags flags; // intersection flags + enum RTCFeatureFlags feature_mask; // selectively enable features for traversal + struct RTCRayQueryContext* context; // optional pointer to ray query context + RTCFilterFunctionN filter; // filter function to execute + RTCOccludedFunctionN occluded; // user geometry occlusion callback to execute + +#if RTC_MIN_WIDTH + float minWidthDistanceFactor; // curve radius is set to this factor times distance to ray origin +#endif +}; + +/* Initializes an intersection arguments. */ +RTC_FORCEINLINE void rtcInitOccludedArguments(struct RTCOccludedArguments* args) +{ + args->flags = RTC_RAY_QUERY_FLAG_INCOHERENT; + args->feature_mask = RTC_FEATURE_FLAG_ALL; + args->context = NULL; + args->filter = NULL; + args->occluded = NULL; + +#if RTC_MIN_WIDTH + args->minWidthDistanceFactor = 0.0f; +#endif +} + +/* Creates a new scene. */ +RTC_API RTCScene rtcNewScene(RTCDevice device); + +/* Returns the device the scene got created in. The reference count of + * the device is incremented by this function. */ +RTC_API RTCDevice rtcGetSceneDevice(RTCScene hscene); + +/* Retains the scene (increments the reference count). */ +RTC_API void rtcRetainScene(RTCScene scene); + +/* Releases the scene (decrements the reference count). */ +RTC_API void rtcReleaseScene(RTCScene scene); + + +/* Attaches the geometry to a scene. */ +RTC_API unsigned int rtcAttachGeometry(RTCScene scene, RTCGeometry geometry); + +/* Attaches the geometry to a scene using the specified geometry ID. */ +RTC_API void rtcAttachGeometryByID(RTCScene scene, RTCGeometry geometry, unsigned int geomID); + +/* Detaches the geometry from the scene. */ +RTC_API void rtcDetachGeometry(RTCScene scene, unsigned int geomID); + +/* Gets a geometry handle from the scene. This function is not thread safe and should get used during rendering. */ +RTC_API RTCGeometry rtcGetGeometry(RTCScene scene, unsigned int geomID); + +/* Gets a geometry handle from the scene. This function is thread safe and should NOT get used during rendering. */ +RTC_API RTCGeometry rtcGetGeometryThreadSafe(RTCScene scene, unsigned int geomID); + +/* Gets the user-defined data pointer of the geometry. This function is not thread safe and should get used during rendering. */ +RTC_SYCL_API void* rtcGetGeometryUserDataFromScene(RTCScene scene, unsigned int geomID); + +/* Returns the interpolated transformation of an instance for the specified time. */ +RTC_SYCL_API void rtcGetGeometryTransformFromScene(RTCScene scene, unsigned int geomID, float time, enum RTCFormat format, void* xfm); + + +/* Commits the scene. */ +RTC_API void rtcCommitScene(RTCScene scene); + +/* Commits the scene from multiple threads. */ +RTC_API void rtcJoinCommitScene(RTCScene scene); + + +/* Progress monitor callback function */ +typedef bool (*RTCProgressMonitorFunction)(void* ptr, double n); + +/* Sets the progress monitor callback function of the scene. */ +RTC_API void rtcSetSceneProgressMonitorFunction(RTCScene scene, RTCProgressMonitorFunction progress, void* ptr); + +/* Sets the build quality of the scene. */ +RTC_API void rtcSetSceneBuildQuality(RTCScene scene, enum RTCBuildQuality quality); + +/* Sets the scene flags. */ +RTC_API void rtcSetSceneFlags(RTCScene scene, enum RTCSceneFlags flags); + +/* Returns the scene flags. */ +RTC_API enum RTCSceneFlags rtcGetSceneFlags(RTCScene scene); + +/* Returns the axis-aligned bounds of the scene. */ +RTC_API void rtcGetSceneBounds(RTCScene scene, struct RTCBounds* bounds_o); + +/* Returns the linear axis-aligned bounds of the scene. */ +RTC_API void rtcGetSceneLinearBounds(RTCScene scene, struct RTCLinearBounds* bounds_o); + + +/* Perform a closest point query of the scene. */ +RTC_API bool rtcPointQuery(RTCScene scene, struct RTCPointQuery* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void* userPtr); + +/* Perform a closest point query with a packet of 4 points with the scene. */ +RTC_API bool rtcPointQuery4(const int* valid, RTCScene scene, struct RTCPointQuery4* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr); + +/* Perform a closest point query with a packet of 4 points with the scene. */ +RTC_API bool rtcPointQuery8(const int* valid, RTCScene scene, struct RTCPointQuery8* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr); + +/* Perform a closest point query with a packet of 4 points with the scene. */ +RTC_API bool rtcPointQuery16(const int* valid, RTCScene scene, struct RTCPointQuery16* query, struct RTCPointQueryContext* context, RTCPointQueryFunction queryFunc, void** userPtr); + + +/* Intersects a single ray with the scene. */ +RTC_SYCL_API void rtcIntersect1(RTCScene scene, struct RTCRayHit* rayhit, struct RTCIntersectArguments* args RTC_OPTIONAL_ARGUMENT); + +/* Intersects a packet of 4 rays with the scene. */ +RTC_API void rtcIntersect4(const int* valid, RTCScene scene, struct RTCRayHit4* rayhit, struct RTCIntersectArguments* args RTC_OPTIONAL_ARGUMENT); + +/* Intersects a packet of 8 rays with the scene. */ +RTC_API void rtcIntersect8(const int* valid, RTCScene scene, struct RTCRayHit8* rayhit, struct RTCIntersectArguments* args RTC_OPTIONAL_ARGUMENT); + +/* Intersects a packet of 16 rays with the scene. */ +RTC_API void rtcIntersect16(const int* valid, RTCScene scene, struct RTCRayHit16* rayhit, struct RTCIntersectArguments* args RTC_OPTIONAL_ARGUMENT); + + +/* Forwards ray inside user geometry callback. */ +RTC_SYCL_API void rtcForwardIntersect1(const struct RTCIntersectFunctionNArguments* args, RTCScene scene, struct RTCRay* ray, unsigned int instID); + +/* Forwards ray inside user geometry callback. Extended to handle instance arrays using instPrimID parameter. */ +RTC_SYCL_API void rtcForwardIntersect1Ex(const struct RTCIntersectFunctionNArguments* args, RTCScene scene, struct RTCRay* ray, unsigned int instID, unsigned int instPrimID); + +/* Forwards ray packet of size 4 inside user geometry callback. */ +RTC_API void rtcForwardIntersect4(const int* valid, const struct RTCIntersectFunctionNArguments* args, RTCScene scene, struct RTCRay4* ray, unsigned int instID); + +/* Forwards ray packet of size 4 inside user geometry callback. Extended to handle instance arrays using instPrimID parameter. */ +RTC_API void rtcForwardIntersect4Ex(const int* valid, const struct RTCIntersectFunctionNArguments* args, RTCScene scene, struct RTCRay4* ray, unsigned int instID, unsigned int primInstID); + +/* Forwards ray packet of size 8 inside user geometry callback. */ +RTC_API void rtcForwardIntersect8(const int* valid, const struct RTCIntersectFunctionNArguments* args, RTCScene scene, struct RTCRay8* ray, unsigned int instID); + +/* Forwards ray packet of size 4 inside user geometry callback. Extended to handle instance arrays using instPrimID parameter. */ +RTC_API void rtcForwardIntersect8Ex(const int* valid, const struct RTCIntersectFunctionNArguments* args, RTCScene scene, struct RTCRay8* ray, unsigned int instID, unsigned int primInstID); + +/* Forwards ray packet of size 16 inside user geometry callback. */ +RTC_API void rtcForwardIntersect16(const int* valid, const struct RTCIntersectFunctionNArguments* args, RTCScene scene, struct RTCRay16* ray, unsigned int instID); + +/* Forwards ray packet of size 4 inside user geometry callback. Extended to handle instance arrays using instPrimID parameter. */ +RTC_API void rtcForwardIntersect16Ex(const int* valid, const struct RTCIntersectFunctionNArguments* args, RTCScene scene, struct RTCRay16* ray, unsigned int instID, unsigned int primInstID); + + +/* Tests a single ray for occlusion with the scene. */ +RTC_SYCL_API void rtcOccluded1(RTCScene scene, struct RTCRay* ray, struct RTCOccludedArguments* args RTC_OPTIONAL_ARGUMENT); + +/* Tests a packet of 4 rays for occlusion occluded with the scene. */ +RTC_API void rtcOccluded4(const int* valid, RTCScene scene, struct RTCRay4* ray, struct RTCOccludedArguments* args RTC_OPTIONAL_ARGUMENT); + +/* Tests a packet of 8 rays for occlusion with the scene. */ +RTC_API void rtcOccluded8(const int* valid, RTCScene scene, struct RTCRay8* ray, struct RTCOccludedArguments* args RTC_OPTIONAL_ARGUMENT); + +/* Tests a packet of 16 rays for occlusion with the scene. */ +RTC_API void rtcOccluded16(const int* valid, RTCScene scene, struct RTCRay16* ray, struct RTCOccludedArguments* args RTC_OPTIONAL_ARGUMENT); + + +/* Forwards single occlusion ray inside user geometry callback. */ +RTC_SYCL_API void rtcForwardOccluded1(const struct RTCOccludedFunctionNArguments* args, RTCScene scene, struct RTCRay* ray, unsigned int instID); + +/* Forwards single occlusion ray inside user geometry callback. Extended to handle instance arrays using instPrimID parameter. */ +RTC_SYCL_API void rtcForwardOccluded1Ex(const struct RTCOccludedFunctionNArguments* args, RTCScene scene, struct RTCRay* ray, unsigned int instID, unsigned int instPrimID); + +/* Forwards occlusion ray packet of size 4 inside user geometry callback. */ +RTC_API void rtcForwardOccluded4(const int* valid, const struct RTCOccludedFunctionNArguments* args, RTCScene scene, struct RTCRay4* ray, unsigned int instID); + +/* Forwards occlusion ray packet of size 4 inside user geometry callback. Extended to handle instance arrays using instPrimID parameter. */ +RTC_API void rtcForwardOccluded4Ex(const int* valid, const struct RTCOccludedFunctionNArguments* args, RTCScene scene, struct RTCRay4* ray, unsigned int instID, unsigned int instPrimID); + +/* Forwards occlusion ray packet of size 8 inside user geometry callback. */ +RTC_API void rtcForwardOccluded8(const int* valid, const struct RTCOccludedFunctionNArguments* args, RTCScene scene, struct RTCRay8* ray, unsigned int instID); + +/* Forwards occlusion ray packet of size 8 inside user geometry callback. Extended to handle instance arrays using instPrimID parameter. */ +RTC_API void rtcForwardOccluded8Ex(const int* valid, const struct RTCOccludedFunctionNArguments* args, RTCScene scene, struct RTCRay8* ray, unsigned int instID, unsigned int instPrimID); + +/* Forwards occlusion ray packet of size 16 inside user geometry callback. */ +RTC_API void rtcForwardOccluded16(const int* valid, const struct RTCOccludedFunctionNArguments* args, RTCScene scene, struct RTCRay16* ray, unsigned int instID); + +/* Forwards occlusion ray packet of size 16 inside user geometry callback. Extended to handle instance arrays using instPrimID parameter. */ +RTC_API void rtcForwardOccluded16Ex(const int* valid, const struct RTCOccludedFunctionNArguments* args, RTCScene scene, struct RTCRay16* ray, unsigned int instID, unsigned int instPrimID); + + +/*! collision callback */ +struct RTCCollision { unsigned int geomID0; unsigned int primID0; unsigned int geomID1; unsigned int primID1; }; +typedef void (*RTCCollideFunc) (void* userPtr, struct RTCCollision* collisions, unsigned int num_collisions); + +/*! Performs collision detection of two scenes */ +RTC_API void rtcCollide (RTCScene scene0, RTCScene scene1, RTCCollideFunc callback, void* userPtr); + +#if defined(__cplusplus) + +/* Helper for easily combining scene flags */ +inline RTCSceneFlags operator|(RTCSceneFlags a, RTCSceneFlags b) { + return (RTCSceneFlags)((size_t)a | (size_t)b); +} + +#endif + +RTC_NAMESPACE_END + diff --git a/thirdparty/embree/kernels/builders/bvh_builder_morton.h b/thirdparty/embree/kernels/builders/bvh_builder_morton.h index cba32ca73c..87d4786810 100644 --- a/thirdparty/embree/kernels/builders/bvh_builder_morton.h +++ b/thirdparty/embree/kernels/builders/bvh_builder_morton.h @@ -5,6 +5,7 @@ #include "../common/builder.h" #include "../../common/algorithms/parallel_reduce.h" +#include "../../common/algorithms/parallel_sort.h" namespace embree { @@ -101,7 +102,7 @@ namespace embree } }; -#if defined (__AVX2__) +#if defined (__AVX2__) || defined(__SYCL_DEVICE_ONLY__) /*! for AVX2 there is a fast scalar bitInterleave */ struct MortonCodeGenerator diff --git a/thirdparty/embree/kernels/builders/bvh_builder_msmblur.h b/thirdparty/embree/kernels/builders/bvh_builder_msmblur.h index 6e73c0d250..d4e3388db5 100644 --- a/thirdparty/embree/kernels/builders/bvh_builder_msmblur.h +++ b/thirdparty/embree/kernels/builders/bvh_builder_msmblur.h @@ -7,7 +7,7 @@ #define MBLUR_NUM_OBJECT_BINS 32 #include "../bvh/bvh.h" -#include "../common/primref_mb.h" +#include "../builders/primref_mb.h" #include "heuristic_binning_array_aligned.h" #include "heuristic_timesplit_array.h" @@ -141,16 +141,17 @@ namespace embree struct VirtualRecalculatePrimRef { Scene* scene; + const SubGridBuildData * const sgrids; - __forceinline VirtualRecalculatePrimRef (Scene* scene) - : scene(scene) {} + __forceinline VirtualRecalculatePrimRef (Scene* scene, const SubGridBuildData * const sgrids = nullptr) + : scene(scene), sgrids(sgrids) {} __forceinline PrimRefMB operator() (const PrimRefMB& prim, const BBox1f time_range) const { const unsigned geomID = prim.geomID(); const unsigned primID = prim.primID(); const Geometry* mesh = scene->get(geomID); - const LBBox3fa lbounds = mesh->vlinearBounds(primID, time_range); + const LBBox3fa lbounds = mesh->vlinearBounds(primID, time_range, sgrids); const range<int> tbounds = mesh->timeSegmentRange(time_range); return PrimRefMB (lbounds, tbounds.size(), mesh->time_range, mesh->numTimeSegments(), geomID, primID); } @@ -166,7 +167,7 @@ namespace embree } __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range) const { - return scene->get(prim.geomID())->vlinearBounds(prim.primID(), time_range); + return scene->get(prim.geomID())->vlinearBounds(prim.primID(), time_range, sgrids); } __forceinline LBBox3fa linearBounds(const PrimRefMB& prim, const BBox1f time_range, const LinearSpace3fa& space) const { diff --git a/thirdparty/embree/kernels/builders/bvh_builder_sah.h b/thirdparty/embree/kernels/builders/bvh_builder_sah.h index 24c5faf8be..7a0c0bdb8e 100644 --- a/thirdparty/embree/kernels/builders/bvh_builder_sah.h +++ b/thirdparty/embree/kernels/builders/bvh_builder_sah.h @@ -7,13 +7,8 @@ #include "heuristic_spatial_array.h" #include "heuristic_openmerge_array.h" -#if defined(__AVX512F__) && !defined(__AVX512VL__) // KNL -# define NUM_OBJECT_BINS 16 -# define NUM_SPATIAL_BINS 16 -#else -# define NUM_OBJECT_BINS 32 -# define NUM_SPATIAL_BINS 16 -#endif +#define NUM_OBJECT_BINS 32 +#define NUM_SPATIAL_BINS 16 namespace embree { diff --git a/thirdparty/embree/kernels/builders/heuristic_binning.h b/thirdparty/embree/kernels/builders/heuristic_binning.h index 41be6183b8..d66726d09b 100644 --- a/thirdparty/embree/kernels/builders/heuristic_binning.h +++ b/thirdparty/embree/kernels/builders/heuristic_binning.h @@ -4,6 +4,7 @@ #pragma once #include "priminfo.h" +#include "priminfo_mb.h" #include "../../common/algorithms/parallel_reduce.h" #include "../../common/algorithms/parallel_partition.h" @@ -390,6 +391,63 @@ namespace embree } return Split(bestSAH,bestDim,bestPos,mapping); } + + /*! finds the best split by scanning binning information */ + __forceinline Split best_block_size(const BinMapping<BINS>& mapping, const size_t blockSize) const + { + /* sweep from right to left and compute parallel prefix of merged bounds */ + vfloat4 rAreas[BINS]; + vuint4 rCounts[BINS]; + vuint4 count = 0; BBox bx = empty; BBox by = empty; BBox bz = empty; + for (size_t i=mapping.size()-1; i>0; i--) + { + count += counts(i); + rCounts[i] = count; + bx.extend(bounds(i,0)); rAreas[i][0] = expectedApproxHalfArea(bx); + by.extend(bounds(i,1)); rAreas[i][1] = expectedApproxHalfArea(by); + bz.extend(bounds(i,2)); rAreas[i][2] = expectedApproxHalfArea(bz); + rAreas[i][3] = 0.0f; + } + /* sweep from left to right and compute SAH */ + vuint4 blocks_add = blockSize-1; + vfloat4 blocks_factor = 1.0f/float(blockSize); + vuint4 ii = 1; vfloat4 vbestSAH = pos_inf; vuint4 vbestPos = 0; + count = 0; bx = empty; by = empty; bz = empty; + for (size_t i=1; i<mapping.size(); i++, ii+=1) + { + count += counts(i-1); + bx.extend(bounds(i-1,0)); float Ax = expectedApproxHalfArea(bx); + by.extend(bounds(i-1,1)); float Ay = expectedApproxHalfArea(by); + bz.extend(bounds(i-1,2)); float Az = expectedApproxHalfArea(bz); + const vfloat4 lArea = vfloat4(Ax,Ay,Az,Az); + const vfloat4 rArea = rAreas[i]; + const vfloat4 lCount = floor(vfloat4(count +blocks_add)*blocks_factor); + const vfloat4 rCount = floor(vfloat4(rCounts[i]+blocks_add)*blocks_factor); + const vfloat4 sah = madd(lArea,lCount,rArea*rCount); + + vbestPos = select(sah < vbestSAH,ii ,vbestPos); + vbestSAH = select(sah < vbestSAH,sah,vbestSAH); + } + + /* find best dimension */ + float bestSAH = inf; + int bestDim = -1; + int bestPos = 0; + for (int dim=0; dim<3; dim++) + { + /* ignore zero sized dimensions */ + if (unlikely(mapping.invalid(dim))) + continue; + + /* test if this is a better dimension */ + if (vbestSAH[dim] < bestSAH && vbestPos[dim] != 0) { + bestDim = dim; + bestPos = vbestPos[dim]; + bestSAH = vbestSAH[dim]; + } + } + return Split(bestSAH,bestDim,bestPos,mapping); + } /*! calculates extended split information */ __forceinline void getSplitInfo(const BinMapping<BINS>& mapping, const Split& split, SplitInfoT<BBox>& info) const diff --git a/thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.h b/thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.h index ab3b97efb9..51dda9b49d 100644 --- a/thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.h +++ b/thirdparty/embree/kernels/builders/heuristic_binning_array_aligned.h @@ -22,6 +22,9 @@ namespace embree __forceinline PrimInfoRange (size_t begin, size_t end, const CentGeomBBox3fa& centGeomBounds) : CentGeomBBox3fa(centGeomBounds), range<size_t>(begin,end) {} + + __forceinline PrimInfoRange (range<size_t> r, const CentGeomBBox3fa& centGeomBounds) + : CentGeomBBox3fa(centGeomBounds), range<size_t>(r) {} __forceinline float leafSAH() const { return expectedApproxHalfArea(geomBounds)*float(size()); @@ -30,7 +33,45 @@ namespace embree __forceinline float leafSAH(size_t block_shift) const { return expectedApproxHalfArea(geomBounds)*float((size()+(size_t(1)<<block_shift)-1) >> block_shift); } + + __forceinline range<size_t> get_range() const { + return range<size_t>(begin(),end()); + } + + template<typename PrimRef> + __forceinline void add_primref(const PrimRef& prim) + { + CentGeomBBox3fa::extend_primref(prim); + _end++; + } }; + + inline void performFallbackSplit(PrimRef* const prims, const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo) + { + const size_t begin = pinfo.begin(); + const size_t end = pinfo.end(); + const size_t center = (begin + end)/2; + + CentGeomBBox3fa left(empty); + for (size_t i=begin; i<center; i++) + left.extend_center2(prims[i]); + new (&linfo) PrimInfoRange(begin,center,left); + + CentGeomBBox3fa right(empty); + for (size_t i=center; i<end; i++) + right.extend_center2(prims[i]); + new (&rinfo) PrimInfoRange(center,end,right); + } + + template<typename Type, typename getTypeFunc> + inline void performTypeSplit(const getTypeFunc& getType, Type type, PrimRef* const prims, range<size_t> range, PrimInfoRange& linfo, PrimInfoRange& rinfo) + { + CentGeomBBox3fa local_left(empty), local_right(empty); + auto isLeft = [&] (const PrimRef& ref) { return type == getType(ref.geomID()); }; + const size_t center = serial_partitioning(prims,range.begin(),range.end(),local_left,local_right,isLeft,CentGeomBBox3fa::extend_ref); + linfo = PrimInfoRange(make_range(range.begin(),center ),local_left); + rinfo = PrimInfoRange(make_range(center ,range.end()),local_right); + } /*! Performs standard object binning */ template<typename PrimRef, size_t BINS> @@ -69,6 +110,24 @@ namespace embree return binner.best(mapping,logBlockSize); } + /*! finds the best split */ + __noinline const Split find_block_size(const PrimInfoRange& pinfo, const size_t blockSize) + { + if (likely(pinfo.size() < PARALLEL_THRESHOLD)) + return find_block_size_template<false>(pinfo,blockSize); + else + return find_block_size_template<true>(pinfo,blockSize); + } + + template<bool parallel> + __forceinline const Split find_block_size_template(const PrimInfoRange& pinfo, const size_t blockSize) + { + Binner binner(empty); + const BinMapping<BINS> mapping(pinfo); + bin_serial_or_parallel<parallel>(binner,prims,pinfo.begin(),pinfo.end(),PARALLEL_FIND_BLOCK_SIZE,mapping); + return binner.best_block_size(mapping,blockSize); + } + /*! array partitioning */ __forceinline void split(const Split& split, const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo) { @@ -121,21 +180,8 @@ namespace embree std::sort(&prims[pinfo.begin()],&prims[pinfo.end()]); } - void splitFallback(const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo) - { - const size_t begin = pinfo.begin(); - const size_t end = pinfo.end(); - const size_t center = (begin + end)/2; - - CentGeomBBox3fa left(empty); - for (size_t i=begin; i<center; i++) - left.extend_center2(prims[i]); - new (&linfo) PrimInfoRange(begin,center,left); - - CentGeomBBox3fa right(empty); - for (size_t i=center; i<end; i++) - right.extend_center2(prims[i]); - new (&rinfo) PrimInfoRange(center,end,right); + void splitFallback(const PrimInfoRange& pinfo, PrimInfoRange& linfo, PrimInfoRange& rinfo) { + performFallbackSplit(prims,pinfo,linfo,rinfo); } void splitByGeometry(const range<size_t>& range, PrimInfoRange& linfo, PrimInfoRange& rinfo) @@ -156,6 +202,8 @@ namespace embree PrimRef* const prims; }; +#if !defined(RTHWIF_STANDALONE) + /*! Performs standard object binning */ template<typename PrimRefMB, size_t BINS> struct HeuristicArrayBinningMB @@ -196,5 +244,6 @@ namespace embree new (&rset) SetMB(right,set.prims,range<size_t>(center,end ),set.time_range); } }; +#endif } } diff --git a/thirdparty/embree/kernels/builders/heuristic_spatial.h b/thirdparty/embree/kernels/builders/heuristic_spatial.h index 8b3499ac8d..25abf025ae 100644 --- a/thirdparty/embree/kernels/builders/heuristic_spatial.h +++ b/thirdparty/embree/kernels/builders/heuristic_spatial.h @@ -3,7 +3,6 @@ #pragma once -#include "../common/scene.h" #include "priminfo.h" namespace embree diff --git a/thirdparty/embree/kernels/builders/heuristic_timesplit_array.h b/thirdparty/embree/kernels/builders/heuristic_timesplit_array.h index b968e01c90..fe97862eb6 100644 --- a/thirdparty/embree/kernels/builders/heuristic_timesplit_array.h +++ b/thirdparty/embree/kernels/builders/heuristic_timesplit_array.h @@ -3,7 +3,7 @@ #pragma once -#include "../common/primref_mb.h" +#include "../builders/primref_mb.h" #include "../../common/algorithms/parallel_filter.h" #define MBLUR_TIME_SPLIT_THRESHOLD 1.25f diff --git a/thirdparty/embree/kernels/builders/priminfo.h b/thirdparty/embree/kernels/builders/priminfo.h index fee515247a..52f035e869 100644 --- a/thirdparty/embree/kernels/builders/priminfo.h +++ b/thirdparty/embree/kernels/builders/priminfo.h @@ -3,9 +3,7 @@ #pragma once -#include "../common/default.h" -#include "../common/primref.h" -#include "../common/primref_mb.h" +#include "primref.h" namespace embree { @@ -41,6 +39,10 @@ namespace embree centBounds.extend(center); } + static void extend_ref (CentGeom& pinfo, const PrimRef& ref) { + pinfo.extend_primref(ref); + }; + template<typename PrimRef> __forceinline void extend_center2(const PrimRef& prim) { @@ -84,6 +86,9 @@ namespace embree __forceinline PrimInfoT (EmptyTy) : CentGeom<BBox>(empty), begin(0), end(0) {} + __forceinline PrimInfoT (size_t N) + : CentGeom<BBox>(empty), begin(0), end(N) {} + __forceinline PrimInfoT (size_t begin, size_t end, const CentGeomBBox3fa& centGeomBounds) : CentGeom<BBox>(centGeomBounds), begin(begin), end(end) {} @@ -158,205 +163,5 @@ namespace embree typedef PrimInfoT<BBox3fa> PrimInfo; //typedef PrimInfoT<LBBox3fa> PrimInfoMB; - - /*! stores bounding information for a set of primitives */ - template<typename BBox> - class PrimInfoMBT : public CentGeom<BBox> - { - public: - using CentGeom<BBox>::geomBounds; - using CentGeom<BBox>::centBounds; - - __forceinline PrimInfoMBT () { - } - - __forceinline PrimInfoMBT (EmptyTy) - : CentGeom<BBox>(empty), object_range(0,0), num_time_segments(0), max_num_time_segments(0), max_time_range(0.0f,1.0f), time_range(1.0f,0.0f) {} - - __forceinline PrimInfoMBT (size_t begin, size_t end) - : CentGeom<BBox>(empty), object_range(begin,end), num_time_segments(0), max_num_time_segments(0), max_time_range(0.0f,1.0f), time_range(1.0f,0.0f) {} - - template<typename PrimRef> - __forceinline void add_primref(const PrimRef& prim) - { - CentGeom<BBox>::extend_primref(prim); - time_range.extend(prim.time_range); - object_range._end++; - num_time_segments += prim.size(); - if (max_num_time_segments < prim.totalTimeSegments()) { - max_num_time_segments = prim.totalTimeSegments(); - max_time_range = prim.time_range; - } - } - - __forceinline void merge(const PrimInfoMBT& other) - { - CentGeom<BBox>::merge(other); - time_range.extend(other.time_range); - object_range._begin += other.object_range.begin(); - object_range._end += other.object_range.end(); - num_time_segments += other.num_time_segments; - if (max_num_time_segments < other.max_num_time_segments) { - max_num_time_segments = other.max_num_time_segments; - max_time_range = other.max_time_range; - } - } - - static __forceinline const PrimInfoMBT merge2(const PrimInfoMBT& a, const PrimInfoMBT& b) { - PrimInfoMBT r = a; r.merge(b); return r; - } - - __forceinline size_t begin() const { - return object_range.begin(); - } - - __forceinline size_t end() const { - return object_range.end(); - } - - /*! returns the number of primitives */ - __forceinline size_t size() const { - return object_range.size(); - } - - __forceinline float halfArea() const { - return time_range.size()*expectedApproxHalfArea(geomBounds); - } - - __forceinline float leafSAH() const { - return time_range.size()*expectedApproxHalfArea(geomBounds)*float(num_time_segments); - } - - __forceinline float leafSAH(size_t block_shift) const { - return time_range.size()*expectedApproxHalfArea(geomBounds)*float((num_time_segments+(size_t(1)<<block_shift)-1) >> block_shift); - } - - __forceinline float align_time(float ct) const - { - //return roundf(ct * float(numTimeSegments)) / float(numTimeSegments); - float t0 = (ct-max_time_range.lower)/max_time_range.size(); - float t1 = roundf(t0 * float(max_num_time_segments)) / float(max_num_time_segments); - return t1*max_time_range.size()+max_time_range.lower; - } - - /*! stream output */ - friend embree_ostream operator<<(embree_ostream cout, const PrimInfoMBT& pinfo) - { - return cout << "PrimInfo { " << - "object_range = " << pinfo.object_range << - ", time_range = " << pinfo.time_range << - ", time_segments = " << pinfo.num_time_segments << - ", geomBounds = " << pinfo.geomBounds << - ", centBounds = " << pinfo.centBounds << - "}"; - } - - public: - range<size_t> object_range; //!< primitive range - size_t num_time_segments; //!< total number of time segments of all added primrefs - size_t max_num_time_segments; //!< maximum number of time segments of a primitive - BBox1f max_time_range; //!< time range of primitive with max_num_time_segments - BBox1f time_range; //!< merged time range of primitives when merging prims, or additionally clipped with build time range when used in SetMB - }; - - typedef PrimInfoMBT<typename PrimRefMB::BBox> PrimInfoMB; - - struct SetMB : public PrimInfoMB - { - static const size_t PARALLEL_THRESHOLD = 3 * 1024; - static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024; - static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128; - - typedef mvector<PrimRefMB>* PrimRefVector; - - __forceinline SetMB() {} - - __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims) - : PrimInfoMB(pinfo_i), prims(prims) {} - - __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims, range<size_t> object_range_in, BBox1f time_range_in) - : PrimInfoMB(pinfo_i), prims(prims) - { - object_range = object_range_in; - time_range = intersect(time_range,time_range_in); - } - - __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims, BBox1f time_range_in) - : PrimInfoMB(pinfo_i), prims(prims) - { - time_range = intersect(time_range,time_range_in); - } - - void deterministic_order() const - { - /* required as parallel partition destroys original primitive order */ - PrimRefMB* prim = prims->data(); - std::sort(&prim[object_range.begin()],&prim[object_range.end()]); - } - - template<typename RecalculatePrimRef> - __forceinline LBBox3fa linearBounds(const RecalculatePrimRef& recalculatePrimRef) const - { - auto reduce = [&](const range<size_t>& r) -> LBBox3fa - { - LBBox3fa cbounds(empty); - for (size_t j = r.begin(); j < r.end(); j++) - { - PrimRefMB& ref = (*prims)[j]; - const LBBox3fa bn = recalculatePrimRef.linearBounds(ref, time_range); - cbounds.extend(bn); - }; - return cbounds; - }; - - return parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, LBBox3fa(empty), - reduce, - [&](const LBBox3fa& b0, const LBBox3fa& b1) -> LBBox3fa { return embree::merge(b0, b1); }); - } - - template<typename RecalculatePrimRef> - __forceinline LBBox3fa linearBounds(const RecalculatePrimRef& recalculatePrimRef, const LinearSpace3fa& space) const - { - auto reduce = [&](const range<size_t>& r) -> LBBox3fa - { - LBBox3fa cbounds(empty); - for (size_t j = r.begin(); j < r.end(); j++) - { - PrimRefMB& ref = (*prims)[j]; - const LBBox3fa bn = recalculatePrimRef.linearBounds(ref, time_range, space); - cbounds.extend(bn); - }; - return cbounds; - }; - - return parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, LBBox3fa(empty), - reduce, - [&](const LBBox3fa& b0, const LBBox3fa& b1) -> LBBox3fa { return embree::merge(b0, b1); }); - } - - template<typename RecalculatePrimRef> - const SetMB primInfo(const RecalculatePrimRef& recalculatePrimRef, const LinearSpace3fa& space) const - { - auto computePrimInfo = [&](const range<size_t>& r) -> PrimInfoMB - { - PrimInfoMB pinfo(empty); - for (size_t j=r.begin(); j<r.end(); j++) - { - PrimRefMB& ref = (*prims)[j]; - PrimRefMB ref1 = recalculatePrimRef(ref,time_range,space); - pinfo.add_primref(ref1); - }; - return pinfo; - }; - - const PrimInfoMB pinfo = parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, - PrimInfoMB(empty), computePrimInfo, PrimInfoMB::merge2); - - return SetMB(pinfo,prims,object_range,time_range); - } - - public: - PrimRefVector prims; - }; //} } diff --git a/thirdparty/embree/kernels/builders/priminfo_mb.h b/thirdparty/embree/kernels/builders/priminfo_mb.h new file mode 100644 index 0000000000..4005f04da9 --- /dev/null +++ b/thirdparty/embree/kernels/builders/priminfo_mb.h @@ -0,0 +1,210 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "primref_mb.h" + +namespace embree +{ + /*! stores bounding information for a set of primitives */ + template<typename BBox> + class PrimInfoMBT : public CentGeom<BBox> + { + public: + using CentGeom<BBox>::geomBounds; + using CentGeom<BBox>::centBounds; + + __forceinline PrimInfoMBT () { + } + + __forceinline PrimInfoMBT (EmptyTy) + : CentGeom<BBox>(empty), object_range(0,0), num_time_segments(0), max_num_time_segments(0), max_time_range(0.0f,1.0f), time_range(1.0f,0.0f) {} + + __forceinline PrimInfoMBT (size_t begin, size_t end) + : CentGeom<BBox>(empty), object_range(begin,end), num_time_segments(0), max_num_time_segments(0), max_time_range(0.0f,1.0f), time_range(1.0f,0.0f) {} + + template<typename PrimRef> + __forceinline void add_primref(const PrimRef& prim) + { + CentGeom<BBox>::extend_primref(prim); + time_range.extend(prim.time_range); + object_range._end++; + num_time_segments += prim.size(); + if (max_num_time_segments < prim.totalTimeSegments()) { + max_num_time_segments = prim.totalTimeSegments(); + max_time_range = prim.time_range; + } + } + + __forceinline void merge(const PrimInfoMBT& other) + { + CentGeom<BBox>::merge(other); + time_range.extend(other.time_range); + object_range._begin += other.object_range.begin(); + object_range._end += other.object_range.end(); + num_time_segments += other.num_time_segments; + if (max_num_time_segments < other.max_num_time_segments) { + max_num_time_segments = other.max_num_time_segments; + max_time_range = other.max_time_range; + } + } + + static __forceinline const PrimInfoMBT merge2(const PrimInfoMBT& a, const PrimInfoMBT& b) { + PrimInfoMBT r = a; r.merge(b); return r; + } + + __forceinline size_t begin() const { + return object_range.begin(); + } + + __forceinline size_t end() const { + return object_range.end(); + } + + /*! returns the number of primitives */ + __forceinline size_t size() const { + return object_range.size(); + } + + __forceinline float halfArea() const { + return time_range.size()*expectedApproxHalfArea(geomBounds); + } + + __forceinline float leafSAH() const { + return time_range.size()*expectedApproxHalfArea(geomBounds)*float(num_time_segments); + } + + __forceinline float leafSAH(size_t block_shift) const { + return time_range.size()*expectedApproxHalfArea(geomBounds)*float((num_time_segments+(size_t(1)<<block_shift)-1) >> block_shift); + } + + __forceinline float align_time(float ct) const + { + //return roundf(ct * float(numTimeSegments)) / float(numTimeSegments); + float t0 = (ct-max_time_range.lower)/max_time_range.size(); + float t1 = roundf(t0 * float(max_num_time_segments)) / float(max_num_time_segments); + return t1*max_time_range.size()+max_time_range.lower; + } + + /*! stream output */ + friend embree_ostream operator<<(embree_ostream cout, const PrimInfoMBT& pinfo) + { + return cout << "PrimInfo { " << + "object_range = " << pinfo.object_range << + ", time_range = " << pinfo.time_range << + ", time_segments = " << pinfo.num_time_segments << + ", geomBounds = " << pinfo.geomBounds << + ", centBounds = " << pinfo.centBounds << + "}"; + } + + public: + range<size_t> object_range; //!< primitive range + size_t num_time_segments; //!< total number of time segments of all added primrefs + size_t max_num_time_segments; //!< maximum number of time segments of a primitive + BBox1f max_time_range; //!< time range of primitive with max_num_time_segments + BBox1f time_range; //!< merged time range of primitives when merging prims, or additionally clipped with build time range when used in SetMB + }; + + typedef PrimInfoMBT<typename PrimRefMB::BBox> PrimInfoMB; + + struct SetMB : public PrimInfoMB + { + static const size_t PARALLEL_THRESHOLD = 3 * 1024; + static const size_t PARALLEL_FIND_BLOCK_SIZE = 1024; + static const size_t PARALLEL_PARTITION_BLOCK_SIZE = 128; + + typedef mvector<PrimRefMB>* PrimRefVector; + + __forceinline SetMB() {} + + __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims) + : PrimInfoMB(pinfo_i), prims(prims) {} + + __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims, range<size_t> object_range_in, BBox1f time_range_in) + : PrimInfoMB(pinfo_i), prims(prims) + { + object_range = object_range_in; + time_range = intersect(time_range,time_range_in); + } + + __forceinline SetMB(const PrimInfoMB& pinfo_i, PrimRefVector prims, BBox1f time_range_in) + : PrimInfoMB(pinfo_i), prims(prims) + { + time_range = intersect(time_range,time_range_in); + } + + void deterministic_order() const + { + /* required as parallel partition destroys original primitive order */ + PrimRefMB* prim = prims->data(); + std::sort(&prim[object_range.begin()],&prim[object_range.end()]); + } + + template<typename RecalculatePrimRef> + __forceinline LBBox3fa linearBounds(const RecalculatePrimRef& recalculatePrimRef) const + { + auto reduce = [&](const range<size_t>& r) -> LBBox3fa + { + LBBox3fa cbounds(empty); + for (size_t j = r.begin(); j < r.end(); j++) + { + PrimRefMB& ref = (*prims)[j]; + const LBBox3fa bn = recalculatePrimRef.linearBounds(ref, time_range); + cbounds.extend(bn); + }; + return cbounds; + }; + + return parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, LBBox3fa(empty), + reduce, + [&](const LBBox3fa& b0, const LBBox3fa& b1) -> LBBox3fa { return embree::merge(b0, b1); }); + } + + template<typename RecalculatePrimRef> + __forceinline LBBox3fa linearBounds(const RecalculatePrimRef& recalculatePrimRef, const LinearSpace3fa& space) const + { + auto reduce = [&](const range<size_t>& r) -> LBBox3fa + { + LBBox3fa cbounds(empty); + for (size_t j = r.begin(); j < r.end(); j++) + { + PrimRefMB& ref = (*prims)[j]; + const LBBox3fa bn = recalculatePrimRef.linearBounds(ref, time_range, space); + cbounds.extend(bn); + }; + return cbounds; + }; + + return parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, LBBox3fa(empty), + reduce, + [&](const LBBox3fa& b0, const LBBox3fa& b1) -> LBBox3fa { return embree::merge(b0, b1); }); + } + + template<typename RecalculatePrimRef> + const SetMB primInfo(const RecalculatePrimRef& recalculatePrimRef, const LinearSpace3fa& space) const + { + auto computePrimInfo = [&](const range<size_t>& r) -> PrimInfoMB + { + PrimInfoMB pinfo(empty); + for (size_t j=r.begin(); j<r.end(); j++) + { + PrimRefMB& ref = (*prims)[j]; + PrimRefMB ref1 = recalculatePrimRef(ref,time_range,space); + pinfo.add_primref(ref1); + }; + return pinfo; + }; + + const PrimInfoMB pinfo = parallel_reduce(object_range.begin(), object_range.end(), PARALLEL_FIND_BLOCK_SIZE, PARALLEL_THRESHOLD, + PrimInfoMB(empty), computePrimInfo, PrimInfoMB::merge2); + + return SetMB(pinfo,prims,object_range,time_range); + } + + public: + PrimRefVector prims; + }; +//} +} diff --git a/thirdparty/embree/kernels/common/primref.h b/thirdparty/embree/kernels/builders/primref.h index d61763487b..cf349c4a0c 100644 --- a/thirdparty/embree/kernels/common/primref.h +++ b/thirdparty/embree/kernels/builders/primref.h @@ -3,7 +3,7 @@ #pragma once -#include "default.h" +#include "../common/default.h" namespace embree { @@ -118,7 +118,8 @@ namespace embree std::swap(a,b); #endif } - + + /************************************************************************************/ /************************************************************************************/ /************************************************************************************/ diff --git a/thirdparty/embree/kernels/common/primref_mb.h b/thirdparty/embree/kernels/builders/primref_mb.h index fb08a05003..2c4bef8b8b 100644 --- a/thirdparty/embree/kernels/common/primref_mb.h +++ b/thirdparty/embree/kernels/builders/primref_mb.h @@ -3,7 +3,7 @@ #pragma once -#include "default.h" +#include "../common/default.h" #define MBLUR_BIN_LBBOX 1 diff --git a/thirdparty/embree/kernels/builders/primrefgen.cpp b/thirdparty/embree/kernels/builders/primrefgen.cpp index e2d7c27bd8..33f67697cb 100644 --- a/thirdparty/embree/kernels/builders/primrefgen.cpp +++ b/thirdparty/embree/kernels/builders/primrefgen.cpp @@ -55,6 +55,29 @@ namespace embree return pinfo; } + PrimInfo createPrimRefArray(Scene* scene, Geometry::GTypeMask types, bool mblur, const size_t numPrimRefs, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids, BuildProgressMonitor& progressMonitor) + { + ParallelForForPrefixSumState<PrimInfo> pstate; + Scene::Iterator2 iter(scene,types,mblur); + + /* first try */ + progressMonitor(0); + pstate.init(iter,size_t(1024)); + PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo { + return mesh->createPrimRefArray(prims,sgrids,r,k,(unsigned)geomID); + }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); + + /* if we need to filter out geometry, run again */ + if (pinfo.size() != numPrimRefs) + { + progressMonitor(0); + pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo { + return mesh->createPrimRefArray(prims,sgrids,r,base.size(),(unsigned)geomID); + }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); + } + return pinfo; + } + PrimInfo createPrimRefArrayMBlur(Scene* scene, Geometry::GTypeMask types, const size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime) { ParallelForForPrefixSumState<PrimInfo> pstate; @@ -104,6 +127,32 @@ namespace embree return pinfo; } + PrimInfoMB createPrimRefArrayMSMBlur(Scene* scene, Geometry::GTypeMask types, const size_t numPrimRefs, mvector<PrimRefMB>& prims, mvector<SubGridBuildData>& sgrids, BuildProgressMonitor& progressMonitor, BBox1f t0t1) + { + ParallelForForPrefixSumState<PrimInfoMB> pstate; + Scene::Iterator2 iter(scene,types,true); + + /* first try */ + progressMonitor(0); + pstate.init(iter,size_t(1024)); + PrimInfoMB pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfoMB(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfoMB { + return mesh->createPrimRefMBArray(prims,sgrids,t0t1,r,k,(unsigned)geomID); + }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); }); + + /* if we need to filter out geometry, run again */ + if (pinfo.size() != numPrimRefs) + { + progressMonitor(0); + pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfoMB(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfoMB& base) -> PrimInfoMB { + return mesh->createPrimRefMBArray(prims,sgrids,t0t1,r,base.size(),(unsigned)geomID); + }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); }); + } + + /* the BVH starts with that time range, even though primitives might have smaller/larger time range */ + pinfo.time_range = t0t1; + return pinfo; + } + template<typename Mesh> size_t createMortonCodeArray(Mesh* mesh, mvector<BVHBuilderMorton::BuildPrim>& morton, BuildProgressMonitor& progressMonitor) { @@ -218,26 +267,8 @@ namespace embree /* second run to fill primrefs and SubGridBuildData arrays */ pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo { - k = base.size(); - size_t p_index = k; - PrimInfo pinfo(empty); - for (size_t j=r.begin(); j<r.end(); j++) - { - if (!mesh->valid(j)) continue; - const GridMesh::Grid &g = mesh->grid(j); - for (unsigned int y=0; y<g.resY-1u; y+=2) - for (unsigned int x=0; x<g.resX-1u; x+=2) - { - BBox3fa bounds = empty; - if (!mesh->buildBounds(g,x,y,bounds)) continue; // get bounds of subgrid - const PrimRef prim(bounds,(unsigned)geomID,(unsigned)p_index); - pinfo.add_center2(prim); - sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j)); - prims[p_index++] = prim; - } - } - return pinfo; - }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); + return mesh->createPrimRefArray(prims,sgrids,r,base.size(),geomID); + }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); assert(pinfo.size() == numPrimitives); return pinfo; } @@ -269,40 +300,60 @@ namespace embree prims.resize(numPrimitives); /* second run to fill primrefs and SubGridBuildData arrays */ - pinfo = parallel_prefix_sum( pstate, size_t(0), mesh->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo - { - - size_t p_index = base.size(); - PrimInfo pinfo(empty); - for (size_t j=r.begin(); j<r.end(); j++) - { - if (!mesh->valid(j)) continue; - const GridMesh::Grid &g = mesh->grid(j); - for (unsigned int y=0; y<g.resY-1u; y+=2) - for (unsigned int x=0; x<g.resX-1u; x+=2) - { - BBox3fa bounds = empty; - if (!mesh->buildBounds(g,x,y,bounds)) continue; // get bounds of subgrid - const PrimRef prim(bounds,geomID_,unsigned(p_index)); - pinfo.add_center2(prim); - sgrids[p_index] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j)); - prims[p_index++] = prim; - } - } - return pinfo; - }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); + pinfo = parallel_prefix_sum( pstate, size_t(0), mesh->size(), size_t(1024), PrimInfo(empty), [&](const range<size_t>& r, const PrimInfo& base) -> PrimInfo { + return mesh->createPrimRefArray(prims,sgrids,r,base.size(),geomID_); + }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); return pinfo; } + + PrimInfoMB createPrimRefArrayMSMBlurGrid(Scene* scene, mvector<PrimRefMB>& prims, mvector<SubGridBuildData>& sgrids, BuildProgressMonitor& progressMonitor, BBox1f t0t1) + { + /* first run to get #primitives */ + ParallelForForPrefixSumState<PrimInfoMB> pstate; + Scene::Iterator<GridMesh,true> iter(scene); + + pstate.init(iter,size_t(1024)); + /* iterate over all meshes in the scene */ + PrimInfoMB pinfoMB = parallel_for_for_prefix_sum0( pstate, iter, PrimInfoMB(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t /*geomID*/) -> PrimInfoMB { + + PrimInfoMB pinfoMB(empty); + for (size_t j=r.begin(); j<r.end(); j++) + { + if (!mesh->valid(j, mesh->timeSegmentRange(t0t1))) continue; + LBBox3fa bounds(empty); + PrimInfoMB gridMB(0,mesh->getNumSubGrids(j)); + pinfoMB.merge(gridMB); + } + return pinfoMB; + }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); }); + + size_t numPrimitives = pinfoMB.size(); + if (numPrimitives == 0) return pinfoMB; + + /* resize arrays */ + sgrids.resize(numPrimitives); + prims.resize(numPrimitives); + /* second run to fill primrefs and SubGridBuildData arrays */ + pinfoMB = parallel_for_for_prefix_sum1( pstate, iter, PrimInfoMB(empty), [&](GridMesh* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfoMB& base) -> PrimInfoMB { + return mesh->createPrimRefMBArray(prims,sgrids,t0t1,r,base.size(),(unsigned)geomID); + }, [](const PrimInfoMB& a, const PrimInfoMB& b) -> PrimInfoMB { return PrimInfoMB::merge2(a,b); }); + + assert(pinfoMB.size() == numPrimitives); + pinfoMB.time_range = t0t1; + return pinfoMB; + } + #endif // ==================================================================================================== // ==================================================================================================== // ==================================================================================================== - + IF_ENABLED_TRIS (template size_t createMortonCodeArray<TriangleMesh>(TriangleMesh* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor)); IF_ENABLED_QUADS(template size_t createMortonCodeArray<QuadMesh>(QuadMesh* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor)); IF_ENABLED_USER (template size_t createMortonCodeArray<UserGeometry>(UserGeometry* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor)); IF_ENABLED_INSTANCE (template size_t createMortonCodeArray<Instance>(Instance* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor)); + IF_ENABLED_INSTANCE_ARRAY (template size_t createMortonCodeArray<InstanceArray>(InstanceArray* mesh COMMA mvector<BVHBuilderMorton::BuildPrim>& morton COMMA BuildProgressMonitor& progressMonitor)); } } diff --git a/thirdparty/embree/kernels/builders/primrefgen.h b/thirdparty/embree/kernels/builders/primrefgen.h index c09a848ba3..0e2ab094fb 100644 --- a/thirdparty/embree/kernels/builders/primrefgen.h +++ b/thirdparty/embree/kernels/builders/primrefgen.h @@ -4,9 +4,8 @@ #pragma once #include "../common/scene.h" -#include "../common/primref.h" -#include "../common/primref_mb.h" #include "priminfo.h" +#include "priminfo_mb.h" #include "bvh_builder_morton.h" namespace embree @@ -16,19 +15,23 @@ namespace embree PrimInfo createPrimRefArray(Geometry* geometry, unsigned int geomID, size_t numPrimitives, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor); PrimInfo createPrimRefArray(Scene* scene, Geometry::GTypeMask types, bool mblur, size_t numPrimitives, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor); + + PrimInfo createPrimRefArray(Scene* scene, Geometry::GTypeMask types, bool mblur, size_t numPrimitives, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids, BuildProgressMonitor& progressMonitor); PrimInfo createPrimRefArrayMBlur(Scene* scene, Geometry::GTypeMask types, size_t numPrimitives, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor, size_t itime = 0); PrimInfoMB createPrimRefArrayMSMBlur(Scene* scene, Geometry::GTypeMask types, size_t numPrimitives, mvector<PrimRefMB>& prims, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f)); + PrimInfoMB createPrimRefArrayMSMBlur(Scene* scene, Geometry::GTypeMask types, size_t numPrimitives, mvector<PrimRefMB>& prims, mvector<SubGridBuildData>& sgrids, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f)); + template<typename Mesh> size_t createMortonCodeArray(Mesh* mesh, mvector<BVHBuilderMorton::BuildPrim>& morton, BuildProgressMonitor& progressMonitor); /* special variants for grids */ - PrimInfo createPrimRefArrayGrids(Scene* scene, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids); + PrimInfo createPrimRefArrayGrids(Scene* scene, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids); // FIXME: remove PrimInfo createPrimRefArrayGrids(GridMesh* mesh, mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids); - + + PrimInfoMB createPrimRefArrayMSMBlurGrid(Scene* scene, mvector<PrimRefMB>& prims, mvector<SubGridBuildData>& sgrids, BuildProgressMonitor& progressMonitor, BBox1f t0t1 = BBox1f(0.0f,1.0f)); } } - diff --git a/thirdparty/embree/kernels/builders/primrefgen_presplit.h b/thirdparty/embree/kernels/builders/primrefgen_presplit.h index aa2026a85e..db9010995d 100644 --- a/thirdparty/embree/kernels/builders/primrefgen_presplit.h +++ b/thirdparty/embree/kernels/builders/primrefgen_presplit.h @@ -3,10 +3,12 @@ #pragma once -#include "../builders/primrefgen.h" +#include "../../common/algorithms/parallel_reduce.h" +#include "../../common/algorithms/parallel_sort.h" #include "../builders/heuristic_spatial.h" #include "../builders/splitter.h" +#include "../../common/algorithms/parallel_partition.h" #include "../../common/algorithms/parallel_for_for.h" #include "../../common/algorithms/parallel_for_for_prefix_sum.h" @@ -14,15 +16,87 @@ #define CHECK_PRESPLIT(x) #define GRID_SIZE 1024 +//#define MAX_PRESPLITS_PER_PRIMITIVE_LOG 6 #define MAX_PRESPLITS_PER_PRIMITIVE_LOG 5 #define MAX_PRESPLITS_PER_PRIMITIVE (1<<MAX_PRESPLITS_PER_PRIMITIVE_LOG) -#define PRIORITY_CUTOFF_THRESHOLD 1.0f +//#define PRIORITY_CUTOFF_THRESHOLD 2.0f #define PRIORITY_SPLIT_POS_WEIGHT 1.5f namespace embree { namespace isa { + struct SplittingGrid + { + __forceinline SplittingGrid(const BBox3fa& bounds) + { + base = bounds.lower; + const Vec3fa diag = bounds.size(); + extend = max(diag.x,max(diag.y,diag.z)); + scale = extend == 0.0f ? 0.0f : GRID_SIZE / extend; + } + + __forceinline bool split_pos(const PrimRef& prim, unsigned int& dim_o, float& fsplit_o) const + { + /* compute morton code */ + const Vec3fa lower = prim.lower; + const Vec3fa upper = prim.upper; + const Vec3fa glower = (lower-base)*Vec3fa(scale)+Vec3fa(0.2f); + const Vec3fa gupper = (upper-base)*Vec3fa(scale)-Vec3fa(0.2f); + Vec3ia ilower(floor(glower)); + Vec3ia iupper(floor(gupper)); + + /* this ignores dimensions that are empty */ + iupper = (Vec3ia)select(vint4(glower) >= vint4(gupper),vint4(ilower),vint4(iupper)); + + /* compute a morton code for the lower and upper grid coordinates. */ + const unsigned int lower_code = bitInterleave(ilower.x,ilower.y,ilower.z); + const unsigned int upper_code = bitInterleave(iupper.x,iupper.y,iupper.z); + + /* if all bits are equal then we cannot split */ + if (unlikely(lower_code == upper_code)) + return false; + + /* compute octree level and dimension to perform the split in */ + const unsigned int diff = 31 - lzcnt(lower_code^upper_code); + const unsigned int level = diff / 3; + const unsigned int dim = diff % 3; + + /* now we compute the grid position of the split */ + const unsigned int isplit = iupper[dim] & ~((1<<level)-1); + + /* compute world space position of split */ + const float inv_grid_size = 1.0f / GRID_SIZE; + const float fsplit = base[dim] + isplit * inv_grid_size * extend; + assert(prim.lower[dim] <= fsplit && prim.upper[dim] >= fsplit); + + dim_o = dim; + fsplit_o = fsplit; + return true; + } + + __forceinline Vec2i computeMC(const PrimRef& ref) const + { + const Vec3fa lower = ref.lower; + const Vec3fa upper = ref.upper; + const Vec3fa glower = (lower-base)*Vec3fa(scale)+Vec3fa(0.2f); + const Vec3fa gupper = (upper-base)*Vec3fa(scale)-Vec3fa(0.2f); + Vec3ia ilower(floor(glower)); + Vec3ia iupper(floor(gupper)); + + /* this ignores dimensions that are empty */ + iupper = (Vec3ia)select(vint4(glower) >= vint4(gupper),vint4(ilower),vint4(iupper)); + + /* compute a morton code for the lower and upper grid coordinates. */ + const unsigned int lower_code = bitInterleave(ilower.x,ilower.y,ilower.z); + const unsigned int upper_code = bitInterleave(iupper.x,iupper.y,iupper.z); + return Vec2i(lower_code,upper_code); + } + + Vec3fa base; + float scale; + float extend; + }; struct PresplitItem { @@ -32,30 +106,30 @@ namespace embree }; unsigned int index; - __forceinline operator unsigned() const - { - return reinterpret_cast<const unsigned&>(priority); - } - __forceinline bool operator < (const PresplitItem& item) const - { - return (priority < item.priority); + __forceinline operator unsigned() const { + return data; } - template<typename Mesh> - __forceinline static float compute_priority(const PrimRef &ref, Scene *scene, const Vec2i &mc) + template<typename ProjectedPrimitiveAreaFunc> + __forceinline static float compute_priority(const ProjectedPrimitiveAreaFunc& primitiveArea, const PrimRef &ref, const Vec2i &mc) { - const unsigned int geomID = ref.geomID(); - const unsigned int primID = ref.primID(); const float area_aabb = area(ref.bounds()); - const float area_prim = ((Mesh*)scene->get(geomID))->projectedPrimitiveArea(primID); + const float area_prim = primitiveArea(ref); + if (area_prim == 0.0f) return 0.0f; const unsigned int diff = 31 - lzcnt(mc.x^mc.y); - assert(area_prim <= area_aabb); - //const float priority = powf((area_aabb - area_prim) * powf(PRIORITY_SPLIT_POS_WEIGHT,(float)diff),1.0f/4.0f); - const float priority = sqrtf(sqrtf( (area_aabb - area_prim) * powf(PRIORITY_SPLIT_POS_WEIGHT,(float)diff) )); + //assert(area_prim <= area_aabb); // may trigger due to numerical issues + const float area_diff = max(0.0f, area_aabb - area_prim); + //const float priority = powf(area_diff * powf(PRIORITY_SPLIT_POS_WEIGHT,(float)diff),1.0f/4.0f); + const float priority = sqrtf(sqrtf( area_diff * powf(PRIORITY_SPLIT_POS_WEIGHT,(float)diff) )); + //const float priority = sqrtf(sqrtf( area_diff ) ); + //const float priority = sqrtfarea_diff; + //const float priority = area_diff; // 104 fps !!!!!!!!!! + //const float priority = 0.2f*area_aabb + 0.8f*area_diff; // 104 fps + //const float priority = area_aabb * max(area_aabb/area_prim,32.0f); + //const float priority = area_prim; assert(priority >= 0.0f && priority < FLT_LARGE); return priority; } - }; @@ -63,77 +137,96 @@ namespace embree return cout << "index " << item.index << " priority " << item.priority; }; - template<typename SplitterFactory> - void splitPrimitive(SplitterFactory &Splitter, - const PrimRef &prim, - const unsigned int geomID, - const unsigned int primID, - const unsigned int split_level, - const Vec3fa &grid_base, - const float grid_scale, - const float grid_extend, +#if 1 + + template<typename Splitter> + void splitPrimitive(const Splitter& splitter, + const PrimRef& prim, + const unsigned int splitprims, + const SplittingGrid& grid, PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE], unsigned int& numSubPrims) { - assert(split_level <= MAX_PRESPLITS_PER_PRIMITIVE_LOG); - if (split_level == 0) + assert(splitprims > 0 && splitprims <= MAX_PRESPLITS_PER_PRIMITIVE); + + if (splitprims == 1) { assert(numSubPrims < MAX_PRESPLITS_PER_PRIMITIVE); subPrims[numSubPrims++] = prim; } else { - const Vec3fa lower = prim.lower; - const Vec3fa upper = prim.upper; - const Vec3fa glower = (lower-grid_base)*Vec3fa(grid_scale)+Vec3fa(0.2f); - const Vec3fa gupper = (upper-grid_base)*Vec3fa(grid_scale)-Vec3fa(0.2f); - Vec3ia ilower(floor(glower)); - Vec3ia iupper(floor(gupper)); - - /* this ignores dimensions that are empty */ - iupper = (Vec3ia)(select(vint4(glower) >= vint4(gupper),vint4(ilower),vint4(iupper))); - - /* compute a morton code for the lower and upper grid coordinates. */ - const unsigned int lower_code = bitInterleave(ilower.x,ilower.y,ilower.z); - const unsigned int upper_code = bitInterleave(iupper.x,iupper.y,iupper.z); - - /* if all bits are equal then we cannot split */ - if(unlikely(lower_code == upper_code)) + unsigned int dim; float fsplit; + if (!grid.split_pos(prim, dim, fsplit)) { assert(numSubPrims < MAX_PRESPLITS_PER_PRIMITIVE); subPrims[numSubPrims++] = prim; return; } - - /* compute octree level and dimension to perform the split in */ - const unsigned int diff = 31 - lzcnt(lower_code^upper_code); - const unsigned int level = diff / 3; - const unsigned int dim = diff % 3; + + /* split primitive */ + PrimRef left,right; + splitter(prim,dim,fsplit,left,right); + assert(!left.bounds().empty()); + assert(!right.bounds().empty()); + + const unsigned int splitprims_left = splitprims/2; + const unsigned int splitprims_right = splitprims - splitprims_left; + splitPrimitive(splitter,left,splitprims_left,grid,subPrims,numSubPrims); + splitPrimitive(splitter,right,splitprims_right,grid,subPrims,numSubPrims); + } + } + +#else + + template<typename Splitter> + void splitPrimitive(const Splitter& splitter, + const PrimRef& prim, + const unsigned int targetSubPrims, + const SplittingGrid& grid, + PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE], + unsigned int& numSubPrims) + { + assert(targetSubPrims > 0 && targetSubPrims <= MAX_PRESPLITS_PER_PRIMITIVE); - /* now we compute the grid position of the split */ - const unsigned int isplit = iupper[dim] & ~((1<<level)-1); - - /* compute world space position of split */ - const float inv_grid_size = 1.0f / GRID_SIZE; - const float fsplit = grid_base[dim] + isplit * inv_grid_size * grid_extend; + auto compare = [] ( const PrimRef& a, const PrimRef& b ) { + return area(a.bounds()) < area(b.bounds()); + }; + + subPrims[numSubPrims++] = prim; + + while (numSubPrims < targetSubPrims) + { + /* get top heap element */ + std::pop_heap(subPrims+0,subPrims+numSubPrims, compare); + PrimRef top = subPrims[--numSubPrims]; - assert(prim.lower[dim] <= fsplit && - prim.upper[dim] >= fsplit); - + unsigned int dim; float fsplit; + if (!grid.split_pos(top, dim, fsplit)) + { + assert(numSubPrims < MAX_PRESPLITS_PER_PRIMITIVE); + subPrims[numSubPrims++] = top; + return; + } + /* split primitive */ - const auto splitter = Splitter(prim); - BBox3fa left,right; - splitter(prim.bounds(),dim,fsplit,left,right); - assert(!left.empty()); - assert(!right.empty()); + PrimRef left,right; + splitter(top,dim,fsplit,left,right); + assert(!left.bounds().empty()); + assert(!right.bounds().empty()); - - splitPrimitive(Splitter,PrimRef(left ,geomID,primID),geomID,primID,split_level-1,grid_base,grid_scale,grid_extend,subPrims,numSubPrims); - splitPrimitive(Splitter,PrimRef(right,geomID,primID),geomID,primID,split_level-1,grid_base,grid_scale,grid_extend,subPrims,numSubPrims); + subPrims[numSubPrims++] = left; + std::push_heap(subPrims+0, subPrims+numSubPrims, compare); + + subPrims[numSubPrims++] = right; + std::push_heap(subPrims+0, subPrims+numSubPrims, compare); } } - +#endif + +#if !defined(RTHWIF_STANDALONE) + template<typename Mesh, typename SplitterFactory> PrimInfo createPrimRefArray_presplit(Geometry* geometry, unsigned int geomID, size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor) { @@ -155,87 +248,40 @@ namespace embree } return pinfo; } +#endif - __forceinline Vec2i computeMC(const Vec3fa &grid_base, const float grid_scale, const PrimRef &ref) + template<typename SplitPrimitiveFunc, typename ProjectedPrimitiveAreaFunc, typename PrimVector> + PrimInfo createPrimRefArray_presplit(size_t numPrimRefs, + PrimVector& prims, + const PrimInfo& pinfo, + const SplitPrimitiveFunc& splitPrimitive, + const ProjectedPrimitiveAreaFunc& primitiveArea) { - const Vec3fa lower = ref.lower; - const Vec3fa upper = ref.upper; - const Vec3fa glower = (lower-grid_base)*Vec3fa(grid_scale)+Vec3fa(0.2f); - const Vec3fa gupper = (upper-grid_base)*Vec3fa(grid_scale)-Vec3fa(0.2f); - Vec3ia ilower(floor(glower)); - Vec3ia iupper(floor(gupper)); - - /* this ignores dimensions that are empty */ - iupper = (Vec3ia)select(vint4(glower) >= vint4(gupper),vint4(ilower),vint4(iupper)); - - /* compute a morton code for the lower and upper grid coordinates. */ - const unsigned int lower_code = bitInterleave(ilower.x,ilower.y,ilower.z); - const unsigned int upper_code = bitInterleave(iupper.x,iupper.y,iupper.z); - return Vec2i(lower_code,upper_code); - } - - template<typename Mesh, typename SplitterFactory> - PrimInfo createPrimRefArray_presplit(Scene* scene, Geometry::GTypeMask types, bool mblur, size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor) - { static const size_t MIN_STEP_SIZE = 128; - ParallelForForPrefixSumState<PrimInfo> pstate; - Scene::Iterator2 iter(scene,types,mblur); - - /* first try */ - progressMonitor(0); - pstate.init(iter,size_t(1024)); - PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo { - return mesh->createPrimRefArray(prims,r,k,(unsigned)geomID); - }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); - - /* if we need to filter out geometry, run again */ - if (pinfo.size() != numPrimRefs) - { - progressMonitor(0); - pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo { - return mesh->createPrimRefArray(prims,r,base.size(),(unsigned)geomID); - }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); - } - /* use correct number of primitives */ size_t numPrimitives = pinfo.size(); - const size_t alloc_numPrimitives = prims.size(); - const size_t numSplitPrimitivesBudget = alloc_numPrimitives - numPrimitives; - - /* set up primitive splitter */ - SplitterFactory Splitter(scene); - - - DBG_PRESPLIT( - const size_t org_numPrimitives = pinfo.size(); - PRINT(numPrimitives); - PRINT(alloc_numPrimitives); - PRINT(numSplitPrimitivesBudget); - ); + const size_t numPrimitivesExt = prims.size(); + const size_t numSplitPrimitivesBudget = numPrimitivesExt - numPrimitives; /* allocate double buffer presplit items */ - const size_t presplit_allocation_size = sizeof(PresplitItem)*alloc_numPrimitives; - PresplitItem *presplitItem = (PresplitItem*)alignedMalloc(presplit_allocation_size,64); - PresplitItem *tmp_presplitItem = (PresplitItem*)alignedMalloc(presplit_allocation_size,64); + avector<PresplitItem> preSplitItem0(numPrimitivesExt); + avector<PresplitItem> preSplitItem1(numPrimitivesExt); /* compute grid */ - const Vec3fa grid_base = pinfo.geomBounds.lower; - const Vec3fa grid_diag = pinfo.geomBounds.size(); - const float grid_extend = max(grid_diag.x,max(grid_diag.y,grid_diag.z)); - const float grid_scale = grid_extend == 0.0f ? 0.0f : GRID_SIZE / grid_extend; - + SplittingGrid grid(pinfo.geomBounds); + /* init presplit items and get total sum */ const float psum = parallel_reduce( size_t(0), numPrimitives, size_t(MIN_STEP_SIZE), 0.0f, [&](const range<size_t>& r) -> float { float sum = 0.0f; for (size_t i=r.begin(); i<r.end(); i++) { - presplitItem[i].index = (unsigned int)i; - const Vec2i mc = computeMC(grid_base,grid_scale,prims[i]); + preSplitItem0[i].index = (unsigned int)i; + const Vec2i mc = grid.computeMC(prims[i]); /* if all bits are equal then we cannot split */ - presplitItem[i].priority = (mc.x != mc.y) ? PresplitItem::compute_priority<Mesh>(prims[i],scene,mc) : 0.0f; + preSplitItem0[i].priority = (mc.x != mc.y) ? PresplitItem::compute_priority(primitiveArea,prims[i],mc) : 0.0f; /* FIXME: sum undeterministic */ - sum += presplitItem[i].priority; + sum += preSplitItem0[i].priority; } return sum; },[](const float& a, const float& b) -> float { return a+b; }); @@ -245,132 +291,178 @@ namespace embree parallel_for( size_t(0), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& r) -> void { for (size_t i=r.begin(); i<r.end(); i++) { - if (presplitItem[i].priority > 0.0f) - { - const float rel_p = (float)numSplitPrimitivesBudget * presplitItem[i].priority * inv_psum; - if (rel_p >= PRIORITY_CUTOFF_THRESHOLD) // need at least a split budget that generates two sub-prims - { - presplitItem[i].priority = max(min(ceilf(logf(rel_p)/logf(2.0f)),(float)MAX_PRESPLITS_PER_PRIMITIVE_LOG),1.0f); - //presplitItem[i].priority = min(floorf(logf(rel_p)/logf(2.0f)),(float)MAX_PRESPLITS_PER_PRIMITIVE_LOG); - assert(presplitItem[i].priority >= 0.0f && presplitItem[i].priority <= (float)MAX_PRESPLITS_PER_PRIMITIVE_LOG); - } - else - presplitItem[i].priority = 0.0f; + if (preSplitItem0[i].priority <= 0.0f) { + preSplitItem0[i].data = 1; + continue; } + + const float rel_p = (float)numSplitPrimitivesBudget * preSplitItem0[i].priority * inv_psum; + if (rel_p < 1) { + preSplitItem0[i].data = 1; + continue; + } + + //preSplitItem0[i].data = max(min(ceilf(rel_p),(float)MAX_PRESPLITS_PER_PRIMITIVE),1.0f); + preSplitItem0[i].data = max(min(ceilf(logf(rel_p)/logf(2.0f)),(float)MAX_PRESPLITS_PER_PRIMITIVE_LOG),1.0f); + preSplitItem0[i].data = 1 << preSplitItem0[i].data; + assert(preSplitItem0[i].data <= MAX_PRESPLITS_PER_PRIMITIVE); } }); - auto isLeft = [&] (const PresplitItem &ref) { return ref.priority < PRIORITY_CUTOFF_THRESHOLD; }; - size_t center = parallel_partitioning(presplitItem,0,numPrimitives,isLeft,1024); + auto isLeft = [&] (const PresplitItem &ref) { return ref.data <= 1; }; + size_t center = parallel_partitioning(preSplitItem0.data(),0,numPrimitives,isLeft,1024); + assert(center <= numPrimitives); /* anything to split ? */ - if (center < numPrimitives) + if (center >= numPrimitives) + return pinfo; + + size_t numPrimitivesToSplit = numPrimitives - center; + assert(preSplitItem0[center].data >= 1.0f); + + /* sort presplit items in ascending order */ + radix_sort_u32(preSplitItem0.data() + center,preSplitItem1.data() + center,numPrimitivesToSplit,1024); + + CHECK_PRESPLIT( + parallel_for( size_t(center+1), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& r) -> void { + for (size_t i=r.begin(); i<r.end(); i++) + assert(preSplitItem0[i-1].data <= preSplitItem0[i].data); + }); + ); + + unsigned int* primOffset0 = (unsigned int*)preSplitItem1.data(); + unsigned int* primOffset1 = (unsigned int*)preSplitItem1.data() + numPrimitivesToSplit; + + /* compute actual number of sub-primitives generated within the [center;numPrimitives-1] range */ + const size_t totalNumSubPrims = parallel_reduce( size_t(center), numPrimitives, size_t(MIN_STEP_SIZE), size_t(0), [&](const range<size_t>& t) -> size_t { + size_t sum = 0; + for (size_t i=t.begin(); i<t.end(); i++) + { + const unsigned int primrefID = preSplitItem0[i].index; + const unsigned int splitprims = preSplitItem0[i].data; + assert(splitprims >= 1 && splitprims <= MAX_PRESPLITS_PER_PRIMITIVE); + + unsigned int numSubPrims = 0; + PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE]; + splitPrimitive(prims[primrefID],splitprims,grid,subPrims,numSubPrims); + assert(numSubPrims); + + numSubPrims--; // can reuse slot + sum+=numSubPrims; + preSplitItem0[i].data = (numSubPrims << 16) | splitprims; + + primOffset0[i-center] = numSubPrims; + } + return sum; + },[](const size_t& a, const size_t& b) -> size_t { return a+b; }); + + /* if we are over budget, need to shrink the range */ + if (totalNumSubPrims > numSplitPrimitivesBudget) { - size_t numPrimitivesToSplit = numPrimitives - center; - assert(presplitItem[center].priority >= 1.0f); - - /* sort presplit items in ascending order */ - radix_sort_u32(presplitItem + center,tmp_presplitItem + center,numPrimitivesToSplit,1024); - - CHECK_PRESPLIT( - parallel_for( size_t(center+1), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& r) -> void { - for (size_t i=r.begin(); i<r.end(); i++) - assert(presplitItem[i-1].priority <= presplitItem[i].priority); - }); - ); - - unsigned int* primOffset0 = (unsigned int*)tmp_presplitItem; - unsigned int* primOffset1 = (unsigned int*)tmp_presplitItem + numPrimitivesToSplit; - - /* compute actual number of sub-primitives generated within the [center;numPrimitives-1] range */ - const size_t totalNumSubPrims = parallel_reduce( size_t(center), numPrimitives, size_t(MIN_STEP_SIZE), size_t(0), [&](const range<size_t>& t) -> size_t { - size_t sum = 0; - for (size_t i=t.begin(); i<t.end(); i++) - { - PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE]; - assert(presplitItem[i].priority >= 1.0f); - const unsigned int primrefID = presplitItem[i].index; - const float prio = presplitItem[i].priority; - const unsigned int geomID = prims[primrefID].geomID(); - const unsigned int primID = prims[primrefID].primID(); - const unsigned int split_levels = (unsigned int)prio; - unsigned int numSubPrims = 0; - splitPrimitive(Splitter,prims[primrefID],geomID,primID,split_levels,grid_base,grid_scale,grid_extend,subPrims,numSubPrims); - assert(numSubPrims); - numSubPrims--; // can reuse slot - sum+=numSubPrims; - presplitItem[i].data = (numSubPrims << MAX_PRESPLITS_PER_PRIMITIVE_LOG) | split_levels; - primOffset0[i-center] = numSubPrims; - } - return sum; - },[](const size_t& a, const size_t& b) -> size_t { return a+b; }); + size_t new_center = numPrimitives-1; + size_t sum = 0; + for (;new_center>=center;new_center--) + { + const unsigned int numSubPrims = preSplitItem0[new_center].data >> 16; + if (unlikely(sum + numSubPrims >= numSplitPrimitivesBudget)) break; + sum += numSubPrims; + } + new_center++; - /* if we are over budget, need to shrink the range */ - if (totalNumSubPrims > numSplitPrimitivesBudget) + primOffset0 += new_center - center; + numPrimitivesToSplit -= new_center - center; + center = new_center; + assert(numPrimitivesToSplit == (numPrimitives - center)); + } + + /* parallel prefix sum to compute offsets for storing sub-primitives */ + const unsigned int offset = parallel_prefix_sum(primOffset0,primOffset1,numPrimitivesToSplit,(unsigned int)0,std::plus<unsigned int>()); + assert(numPrimitives+offset <= numPrimitivesExt); + + /* iterate over range, and split primitives into sub primitives and append them to prims array */ + parallel_for( size_t(center), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& rn) -> void { + for (size_t j=rn.begin(); j<rn.end(); j++) { - size_t new_center = numPrimitives-1; - size_t sum = 0; - for (;new_center>=center;new_center--) - { - const unsigned int numSubPrims = presplitItem[new_center].data >> MAX_PRESPLITS_PER_PRIMITIVE_LOG; - if (unlikely(sum + numSubPrims >= numSplitPrimitivesBudget)) break; - sum += numSubPrims; - } - new_center++; - - primOffset0 += new_center - center; - numPrimitivesToSplit -= new_center - center; - center = new_center; - assert(numPrimitivesToSplit == (numPrimitives - center)); + const unsigned int primrefID = preSplitItem0[j].index; + const unsigned int splitprims = preSplitItem0[j].data & 0xFFFF; + assert(splitprims >= 1 && splitprims <= MAX_PRESPLITS_PER_PRIMITIVE); + + unsigned int numSubPrims = 0; + PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE]; + splitPrimitive(prims[primrefID],splitprims,grid,subPrims,numSubPrims); + + const unsigned int numSubPrimsExpected MAYBE_UNUSED = preSplitItem0[j].data >> 16; + assert(numSubPrims-1 == numSubPrimsExpected); + + const size_t newID = numPrimitives + primOffset1[j-center]; + assert(newID+numSubPrims-1 <= numPrimitivesExt); + + prims[primrefID] = subPrims[0]; + for (size_t i=1;i<numSubPrims;i++) + prims[newID+i-1] = subPrims[i]; } + }); - /* parallel prefix sum to compute offsets for storing sub-primitives */ - const unsigned int offset = parallel_prefix_sum(primOffset0,primOffset1,numPrimitivesToSplit,(unsigned int)0,std::plus<unsigned int>()); - assert(numPrimitives+offset <= alloc_numPrimitives); - - /* iterate over range, and split primitives into sub primitives and append them to prims array */ - parallel_for( size_t(center), numPrimitives, size_t(MIN_STEP_SIZE), [&](const range<size_t>& rn) -> void { - for (size_t j=rn.begin(); j<rn.end(); j++) - { - PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE]; - const unsigned int primrefID = presplitItem[j].index; - const unsigned int geomID = prims[primrefID].geomID(); - const unsigned int primID = prims[primrefID].primID(); - const unsigned int split_levels = presplitItem[j].data & ((unsigned int)(1 << MAX_PRESPLITS_PER_PRIMITIVE_LOG)-1); - - assert(split_levels); - assert(split_levels <= MAX_PRESPLITS_PER_PRIMITIVE_LOG); - unsigned int numSubPrims = 0; - splitPrimitive(Splitter,prims[primrefID],geomID,primID,split_levels,grid_base,grid_scale,grid_extend,subPrims,numSubPrims); - const size_t newID = numPrimitives + primOffset1[j-center]; - assert(newID+numSubPrims-1 <= alloc_numPrimitives); - prims[primrefID] = subPrims[0]; - for (size_t i=1;i<numSubPrims;i++) - prims[newID+i-1] = subPrims[i]; - } - }); - - numPrimitives += offset; - DBG_PRESPLIT( - PRINT(pinfo.size()); - PRINT(numPrimitives); - PRINT((float)numPrimitives/org_numPrimitives)); - } + numPrimitives += offset; /* recompute centroid bounding boxes */ - pinfo = parallel_reduce(size_t(0),numPrimitives,size_t(MIN_STEP_SIZE),PrimInfo(empty),[&] (const range<size_t>& r) -> PrimInfo { + const PrimInfo pinfo1 = parallel_reduce(size_t(0),numPrimitives,size_t(MIN_STEP_SIZE),PrimInfo(empty),[&] (const range<size_t>& r) -> PrimInfo { PrimInfo p(empty); for (size_t j=r.begin(); j<r.end(); j++) p.add_center2(prims[j]); return p; }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); - assert(pinfo.size() == numPrimitives); + assert(pinfo1.size() == numPrimitives); - /* free double buffer presplit items */ - alignedFree(tmp_presplitItem); - alignedFree(presplitItem); - return pinfo; + return pinfo1; + } + +#if !defined(RTHWIF_STANDALONE) + + template<typename Mesh, typename SplitterFactory> + PrimInfo createPrimRefArray_presplit(Scene* scene, Geometry::GTypeMask types, bool mblur, size_t numPrimRefs, mvector<PrimRef>& prims, BuildProgressMonitor& progressMonitor) + { + ParallelForForPrefixSumState<PrimInfo> pstate; + Scene::Iterator2 iter(scene,types,mblur); + + /* first try */ + progressMonitor(0); + pstate.init(iter,size_t(1024)); + PrimInfo pinfo = parallel_for_for_prefix_sum0( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID) -> PrimInfo { + return mesh->createPrimRefArray(prims,r,k,(unsigned)geomID); + }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); + + /* if we need to filter out geometry, run again */ + if (pinfo.size() != numPrimRefs) + { + progressMonitor(0); + pinfo = parallel_for_for_prefix_sum1( pstate, iter, PrimInfo(empty), [&](Geometry* mesh, const range<size_t>& r, size_t k, size_t geomID, const PrimInfo& base) -> PrimInfo { + return mesh->createPrimRefArray(prims,r,base.size(),(unsigned)geomID); + }, [](const PrimInfo& a, const PrimInfo& b) -> PrimInfo { return PrimInfo::merge(a,b); }); + } + + + SplitterFactory Splitter(scene); + + auto split_primitive = [&] (const PrimRef &prim, + const unsigned int splitprims, + const SplittingGrid& grid, + PrimRef subPrims[MAX_PRESPLITS_PER_PRIMITIVE], + unsigned int& numSubPrims) + { + const auto splitter = Splitter(prim); + splitPrimitive(splitter,prim,splitprims,grid,subPrims,numSubPrims); + }; + + auto primitiveArea = [&] (const PrimRef &ref) { + const unsigned int geomID = ref.geomID(); + const unsigned int primID = ref.primID(); + return ((Mesh*)scene->get(geomID))->projectedPrimitiveArea(primID); + }; + + return createPrimRefArray_presplit(numPrimRefs,prims,pinfo,split_primitive,primitiveArea); } +#endif } } diff --git a/thirdparty/embree/kernels/builders/splitter.h b/thirdparty/embree/kernels/builders/splitter.h index da89d0b178..3daf55e801 100644 --- a/thirdparty/embree/kernels/builders/splitter.h +++ b/thirdparty/embree/kernels/builders/splitter.h @@ -3,8 +3,11 @@ #pragma once +#if !defined(RTHWIF_STANDALONE) #include "../common/scene.h" -#include "../common/primref.h" +#endif + +#include "../builders/primref.h" namespace embree { @@ -15,6 +18,41 @@ namespace embree const size_t dim, const float pos, const Vec3fa (&v)[N+1], + BBox3fa& left_o, + BBox3fa& right_o) + { + BBox3fa left = empty, right = empty; + /* clip triangle to left and right box by processing all edges */ + for (size_t i=0; i<N; i++) + { + const Vec3fa &v0 = v[i]; + const Vec3fa &v1 = v[i+1]; + const float v0d = v0[dim]; + const float v1d = v1[dim]; + + if (v0d <= pos) left. extend(v0); // this point is on left side + if (v0d >= pos) right.extend(v0); // this point is on right side + + if ((v0d < pos && pos < v1d) || (v1d < pos && pos < v0d)) // the edge crosses the splitting location + { + assert((v1d-v0d) != 0.0f); + const float inv_length = 1.0f/(v1d-v0d); + const Vec3fa c = madd(Vec3fa((pos-v0d)*inv_length),v1-v0,v0); + left.extend(c); + right.extend(c); + } + } + + /* clip against current bounds */ + left_o = intersect(left,bounds); + right_o = intersect(right,bounds); + } + + template<size_t N> + __forceinline void splitPolygon(const BBox3fa& bounds, + const size_t dim, + const float pos, + const Vec3fa (&v)[N+1], const Vec3fa (&inv_length)[N], BBox3fa& left_o, BBox3fa& right_o) @@ -78,7 +116,9 @@ namespace embree new (&left_o ) PrimRef(intersect(left ,prim.bounds()),prim.geomID(), prim.primID()); new (&right_o) PrimRef(intersect(right,prim.bounds()),prim.geomID(), prim.primID()); } - + +#if !defined(RTHWIF_STANDALONE) + struct TriangleSplitter { __forceinline TriangleSplitter(const Scene* scene, const PrimRef& prim) @@ -173,6 +213,13 @@ namespace embree __forceinline DummySplitter(const Scene* scene, const PrimRef& prim) { } + + __forceinline void operator() (const PrimRef& prim, const size_t dim, const float pos, PrimRef& left_o, PrimRef& right_o) const { + } + + __forceinline void operator() (const BBox3fa& prim, const size_t dim, const float pos, BBox3fa& left_o, BBox3fa& right_o) const { + } + }; struct DummySplitterFactory @@ -187,7 +234,7 @@ namespace embree private: const Scene* scene; }; - +#endif } } diff --git a/thirdparty/embree/kernels/bvh/bvh.h b/thirdparty/embree/kernels/bvh/bvh.h index 565eec5a58..e0ffb86af9 100644 --- a/thirdparty/embree/kernels/bvh/bvh.h +++ b/thirdparty/embree/kernels/bvh/bvh.h @@ -85,7 +85,7 @@ namespace embree typedef BVHNodeRecord<NodeRef> NodeRecord; typedef BVHNodeRecordMB<NodeRef> NodeRecordMB; typedef BVHNodeRecordMB4D<NodeRef> NodeRecordMB4D; - + public: /*! BVHN default constructor. */ diff --git a/thirdparty/embree/kernels/bvh/bvh4_factory.cpp b/thirdparty/embree/kernels/bvh/bvh4_factory.cpp index 890d5e7b7c..d03940deea 100644 --- a/thirdparty/embree/kernels/bvh/bvh4_factory.cpp +++ b/thirdparty/embree/kernels/bvh/bvh4_factory.cpp @@ -17,6 +17,7 @@ #include "../geometry/subdivpatch1.h" #include "../geometry/object.h" #include "../geometry/instance.h" +#include "../geometry/instance_array.h" #include "../geometry/subgrid.h" #include "../common/accelinstance.h" @@ -66,6 +67,9 @@ namespace embree DECLARE_SYMBOL2(Accel::Intersector1,BVH4InstanceIntersector1); DECLARE_SYMBOL2(Accel::Intersector1,BVH4InstanceMBIntersector1); + DECLARE_SYMBOL2(Accel::Intersector1,BVH4InstanceArrayIntersector1); + DECLARE_SYMBOL2(Accel::Intersector1,BVH4InstanceArrayMBIntersector1); + DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Moeller); DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridMBIntersector1Moeller); DECLARE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Pluecker); @@ -104,6 +108,9 @@ namespace embree DECLARE_SYMBOL2(Accel::Intersector4,BVH4InstanceIntersector4Chunk); DECLARE_SYMBOL2(Accel::Intersector4,BVH4InstanceMBIntersector4Chunk); + DECLARE_SYMBOL2(Accel::Intersector4,BVH4InstanceArrayIntersector4Chunk); + DECLARE_SYMBOL2(Accel::Intersector4,BVH4InstanceArrayMBIntersector4Chunk); + DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridMBIntersector4HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridPluecker); @@ -142,6 +149,9 @@ namespace embree DECLARE_SYMBOL2(Accel::Intersector8,BVH4InstanceIntersector8Chunk); DECLARE_SYMBOL2(Accel::Intersector8,BVH4InstanceMBIntersector8Chunk); + DECLARE_SYMBOL2(Accel::Intersector8,BVH4InstanceArrayIntersector8Chunk); + DECLARE_SYMBOL2(Accel::Intersector8,BVH4InstanceArrayMBIntersector8Chunk); + DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridMBIntersector8HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridPluecker); @@ -180,33 +190,20 @@ namespace embree DECLARE_SYMBOL2(Accel::Intersector16,BVH4InstanceIntersector16Chunk); DECLARE_SYMBOL2(Accel::Intersector16,BVH4InstanceMBIntersector16Chunk); + DECLARE_SYMBOL2(Accel::Intersector16,BVH4InstanceArrayIntersector16Chunk); + DECLARE_SYMBOL2(Accel::Intersector16,BVH4InstanceArrayMBIntersector16Chunk); + DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridMBIntersector16HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridPluecker); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4IntersectorStreamPacketFallback); - - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4IntersectorStreamMoeller); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4IntersectorStreamMoellerNoFilter); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4iIntersectorStreamMoeller); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4vIntersectorStreamPluecker); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Triangle4iIntersectorStreamPluecker); - - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamMoeller); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamMoellerNoFilter); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4iIntersectorStreamMoeller); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4vIntersectorStreamPluecker); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4Quad4iIntersectorStreamPluecker); - - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4VirtualIntersectorStream); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH4InstanceIntersectorStream); - DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4MeshSAH,void* COMMA Scene* COMMA bool); DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4vMeshSAH,void* COMMA Scene* COMMA bool); DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelTriangle4iMeshSAH,void* COMMA Scene* COMMA bool); DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool); DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool); DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool); + DECLARE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelInstanceArraySAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool); DECLARE_ISA_FUNCTION(Builder*,BVH4Curve4vBuilder_OBB_New,void* COMMA Scene* COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH4Curve4iBuilder_OBB_New,void* COMMA Scene* COMMA size_t); @@ -237,7 +234,10 @@ namespace embree DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); - + + DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceArraySceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceArrayMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DECLARE_ISA_FUNCTION(Builder*,BVH4GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH4GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t); @@ -266,6 +266,7 @@ namespace embree IF_ENABLED_QUADS (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelQuadMeshSAH)); IF_ENABLED_USER (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelVirtualSAH)); IF_ENABLED_INSTANCE (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelInstanceSAH)); + IF_ENABLED_INSTANCE_ARRAY (SELECT_SYMBOL_DEFAULT_AVX(features,BVH4BuilderTwoLevelInstanceArraySAH)); IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Curve4vBuilder_OBB_New)); IF_ENABLED_CURVES_OR_POINTS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4Curve4iBuilder_OBB_New)); @@ -296,7 +297,10 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4InstanceSceneBuilderSAH)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4InstanceMBSceneBuilderSAH)); - + + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4InstanceArraySceneBuilderSAH)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4InstanceArrayMBSceneBuilderSAH)); + IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4GridSceneBuilderSAH)); IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_AVX(features,BVH4GridMBSceneBuilderSAH)); @@ -349,6 +353,9 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceIntersector1)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceMBIntersector1)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceArrayIntersector1)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceArrayMBIntersector1)); + IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridIntersector1Moeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridMBIntersector1Moeller)) IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridIntersector1Pluecker)); @@ -389,7 +396,10 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceIntersector4Chunk)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceMBIntersector4Chunk)); - + + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceArrayIntersector4Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceArrayMBIntersector4Chunk)); + IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersector4HybridMoeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4GridIntersector4HybridMoeller)); @@ -424,13 +434,16 @@ namespace embree IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4SubdivPatch1Intersector8)); IF_ENABLED_SUBDIV(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4SubdivPatch1MBIntersector8)); - + IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4VirtualIntersector8Chunk)); IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4VirtualMBIntersector8Chunk)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4InstanceIntersector8Chunk)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4InstanceMBIntersector8Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4InstanceArrayIntersector8Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4InstanceArrayMBIntersector8Chunk)); + IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4GridIntersector8HybridMoeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4GridMBIntersector8HybridMoeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH4GridIntersector8HybridPluecker)); @@ -470,29 +483,13 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512(features,BVH4InstanceIntersector16Chunk)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512(features,BVH4InstanceMBIntersector16Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX512(features,BVH4InstanceArrayIntersector16Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX512(features,BVH4InstanceArrayMBIntersector16Chunk)); + IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH4GridIntersector16HybridMoeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH4GridMBIntersector16HybridMoeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH4GridIntersector16HybridPluecker)); - /* select stream intersectors */ - SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4IntersectorStreamPacketFallback); - - IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4IntersectorStreamMoeller)); - IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4IntersectorStreamMoellerNoFilter)); - IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iIntersectorStreamMoeller)); - IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4vIntersectorStreamPluecker)); - IF_ENABLED_TRIS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Triangle4iIntersectorStreamPluecker)); - - IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersectorStreamMoeller)); - IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersectorStreamMoellerNoFilter)); - IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iIntersectorStreamMoeller)); - IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4vIntersectorStreamPluecker)); - IF_ENABLED_QUADS(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4Quad4iIntersectorStreamPluecker)); - - IF_ENABLED_USER(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4VirtualIntersectorStream)); - - IF_ENABLED_INSTANCE(SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(features,BVH4InstanceIntersectorStream)); - #endif } @@ -509,7 +506,6 @@ namespace embree intersectors.intersector4 = BVH4OBBVirtualCurveIntersector4Hybrid(); intersectors.intersector8 = BVH4OBBVirtualCurveIntersector8Hybrid(); intersectors.intersector16 = BVH4OBBVirtualCurveIntersector16Hybrid(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -523,7 +519,6 @@ namespace embree intersectors.intersector4 = BVH4OBBVirtualCurveIntersectorRobust4Hybrid(); intersectors.intersector8 = BVH4OBBVirtualCurveIntersectorRobust8Hybrid(); intersectors.intersector16 = BVH4OBBVirtualCurveIntersectorRobust16Hybrid(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -545,7 +540,6 @@ namespace embree intersectors.intersector4 = BVH4OBBVirtualCurveIntersector4HybridMB(); intersectors.intersector8 = BVH4OBBVirtualCurveIntersector8HybridMB(); intersectors.intersector16 = BVH4OBBVirtualCurveIntersector16HybridMB(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -559,7 +553,6 @@ namespace embree intersectors.intersector4 = BVH4OBBVirtualCurveIntersectorRobust4HybridMB(); intersectors.intersector8 = BVH4OBBVirtualCurveIntersectorRobust8HybridMB(); intersectors.intersector16 = BVH4OBBVirtualCurveIntersectorRobust16HybridMB(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -581,8 +574,6 @@ namespace embree intersectors.intersector8_nofilter = BVH4Triangle4Intersector8HybridMoellerNoFilter(); intersectors.intersector16_filter = BVH4Triangle4Intersector16HybridMoeller(); intersectors.intersector16_nofilter = BVH4Triangle4Intersector16HybridMoellerNoFilter(); - intersectors.intersectorN_filter = BVH4Triangle4IntersectorStreamMoeller(); - intersectors.intersectorN_nofilter = BVH4Triangle4IntersectorStreamMoellerNoFilter(); #endif return intersectors; } @@ -597,7 +588,6 @@ namespace embree intersectors.intersector4 = BVH4Triangle4vIntersector4HybridPluecker(); intersectors.intersector8 = BVH4Triangle4vIntersector8HybridPluecker(); intersectors.intersector16 = BVH4Triangle4vIntersector16HybridPluecker(); - intersectors.intersectorN = BVH4Triangle4vIntersectorStreamPluecker(); #endif return intersectors; } @@ -614,7 +604,6 @@ namespace embree intersectors.intersector4 = BVH4Triangle4iIntersector4HybridMoeller(); intersectors.intersector8 = BVH4Triangle4iIntersector8HybridMoeller(); intersectors.intersector16 = BVH4Triangle4iIntersector16HybridMoeller(); - intersectors.intersectorN = BVH4Triangle4iIntersectorStreamMoeller(); #endif return intersectors; } @@ -627,7 +616,6 @@ namespace embree intersectors.intersector4 = BVH4Triangle4iIntersector4HybridPluecker(); intersectors.intersector8 = BVH4Triangle4iIntersector8HybridPluecker(); intersectors.intersector16 = BVH4Triangle4iIntersector16HybridPluecker(); - intersectors.intersectorN = BVH4Triangle4iIntersectorStreamPluecker(); #endif return intersectors; } @@ -647,7 +635,6 @@ namespace embree intersectors.intersector4 = BVH4Triangle4vMBIntersector4HybridMoeller(); intersectors.intersector8 = BVH4Triangle4vMBIntersector8HybridMoeller(); intersectors.intersector16 = BVH4Triangle4vMBIntersector16HybridMoeller(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -660,7 +647,6 @@ namespace embree intersectors.intersector4 = BVH4Triangle4vMBIntersector4HybridPluecker(); intersectors.intersector8 = BVH4Triangle4vMBIntersector8HybridPluecker(); intersectors.intersector16 = BVH4Triangle4vMBIntersector16HybridPluecker(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -680,7 +666,6 @@ namespace embree intersectors.intersector4 = BVH4Triangle4iMBIntersector4HybridMoeller(); intersectors.intersector8 = BVH4Triangle4iMBIntersector8HybridMoeller(); intersectors.intersector16 = BVH4Triangle4iMBIntersector16HybridMoeller(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -693,7 +678,6 @@ namespace embree intersectors.intersector4 = BVH4Triangle4iMBIntersector4HybridPluecker(); intersectors.intersector8 = BVH4Triangle4iMBIntersector8HybridPluecker(); intersectors.intersector16 = BVH4Triangle4iMBIntersector16HybridPluecker(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -716,8 +700,6 @@ namespace embree intersectors.intersector8_nofilter = BVH4Quad4vIntersector8HybridMoellerNoFilter(); intersectors.intersector16_filter = BVH4Quad4vIntersector16HybridMoeller(); intersectors.intersector16_nofilter = BVH4Quad4vIntersector16HybridMoellerNoFilter(); - intersectors.intersectorN_filter = BVH4Quad4vIntersectorStreamMoeller(); - intersectors.intersectorN_nofilter = BVH4Quad4vIntersectorStreamMoellerNoFilter(); #endif return intersectors; } @@ -730,7 +712,6 @@ namespace embree intersectors.intersector4 = BVH4Quad4vIntersector4HybridPluecker(); intersectors.intersector8 = BVH4Quad4vIntersector8HybridPluecker(); intersectors.intersector16 = BVH4Quad4vIntersector16HybridPluecker(); - intersectors.intersectorN = BVH4Quad4vIntersectorStreamPluecker(); #endif return intersectors; } @@ -750,7 +731,6 @@ namespace embree intersectors.intersector4 = BVH4Quad4iIntersector4HybridMoeller(); intersectors.intersector8 = BVH4Quad4iIntersector8HybridMoeller(); intersectors.intersector16= BVH4Quad4iIntersector16HybridMoeller(); - intersectors.intersectorN = BVH4Quad4iIntersectorStreamMoeller(); #endif return intersectors; } @@ -763,7 +743,6 @@ namespace embree intersectors.intersector4 = BVH4Quad4iIntersector4HybridPluecker(); intersectors.intersector8 = BVH4Quad4iIntersector8HybridPluecker(); intersectors.intersector16= BVH4Quad4iIntersector16HybridPluecker(); - intersectors.intersectorN = BVH4Quad4iIntersectorStreamPluecker(); #endif return intersectors; } @@ -783,7 +762,6 @@ namespace embree intersectors.intersector4 = BVH4Quad4iMBIntersector4HybridMoeller(); intersectors.intersector8 = BVH4Quad4iMBIntersector8HybridMoeller(); intersectors.intersector16= BVH4Quad4iMBIntersector16HybridMoeller(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -796,7 +774,6 @@ namespace embree intersectors.intersector4 = BVH4Quad4iMBIntersector4HybridPluecker(); intersectors.intersector8 = BVH4Quad4iMBIntersector8HybridPluecker(); intersectors.intersector16= BVH4Quad4iMBIntersector16HybridPluecker(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -829,7 +806,6 @@ namespace embree intersectors.intersector4 = BVH4VirtualIntersector4Chunk(); intersectors.intersector8 = BVH4VirtualIntersector8Chunk(); intersectors.intersector16 = BVH4VirtualIntersector16Chunk(); - intersectors.intersectorN = BVH4VirtualIntersectorStream(); #endif intersectors.collider = BVH4ColliderUserGeom(); return intersectors; @@ -844,7 +820,6 @@ namespace embree intersectors.intersector4 = BVH4VirtualMBIntersector4Chunk(); intersectors.intersector8 = BVH4VirtualMBIntersector8Chunk(); intersectors.intersector16 = BVH4VirtualMBIntersector16Chunk(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -858,7 +833,6 @@ namespace embree intersectors.intersector4 = BVH4InstanceIntersector4Chunk(); intersectors.intersector8 = BVH4InstanceIntersector8Chunk(); intersectors.intersector16 = BVH4InstanceIntersector16Chunk(); - intersectors.intersectorN = BVH4InstanceIntersectorStream(); #endif return intersectors; } @@ -872,7 +846,32 @@ namespace embree intersectors.intersector4 = BVH4InstanceMBIntersector4Chunk(); intersectors.intersector8 = BVH4InstanceMBIntersector8Chunk(); intersectors.intersector16 = BVH4InstanceMBIntersector16Chunk(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); +#endif + return intersectors; + } + + Accel::Intersectors BVH4Factory::BVH4InstanceArrayIntersectors(BVH4* bvh) + { + Accel::Intersectors intersectors; + intersectors.ptr = bvh; + intersectors.intersector1 = BVH4InstanceArrayIntersector1(); +#if defined (EMBREE_RAY_PACKETS) + intersectors.intersector4 = BVH4InstanceArrayIntersector4Chunk(); + intersectors.intersector8 = BVH4InstanceArrayIntersector8Chunk(); + intersectors.intersector16 = BVH4InstanceArrayIntersector16Chunk(); +#endif + return intersectors; + } + + Accel::Intersectors BVH4Factory::BVH4InstanceArrayMBIntersectors(BVH4* bvh) + { + Accel::Intersectors intersectors; + intersectors.ptr = bvh; + intersectors.intersector1 = BVH4InstanceArrayMBIntersector1(); +#if defined (EMBREE_RAY_PACKETS) + intersectors.intersector4 = BVH4InstanceArrayMBIntersector4Chunk(); + intersectors.intersector8 = BVH4InstanceArrayMBIntersector8Chunk(); + intersectors.intersector16 = BVH4InstanceArrayMBIntersector16Chunk(); #endif return intersectors; } @@ -886,7 +885,6 @@ namespace embree intersectors.intersector4 = BVH4SubdivPatch1Intersector4(); intersectors.intersector8 = BVH4SubdivPatch1Intersector8(); intersectors.intersector16 = BVH4SubdivPatch1Intersector16(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -900,7 +898,6 @@ namespace embree intersectors.intersector4 = BVH4SubdivPatch1MBIntersector4(); intersectors.intersector8 = BVH4SubdivPatch1MBIntersector8(); intersectors.intersector16 = BVH4SubdivPatch1MBIntersector16(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -1255,6 +1252,35 @@ namespace embree return new AccelInstance(accel,builder,intersectors); } + Accel* BVH4Factory::BVH4InstanceArray(Scene* scene, BuildVariant bvariant) + { + BVH4* accel = new BVH4(InstanceArrayPrimitive::type,scene); + Accel::Intersectors intersectors = BVH4InstanceArrayIntersectors(accel); + auto gtype = Geometry::MTY_INSTANCE_ARRAY; + + Builder* builder = nullptr; + if (scene->device->object_builder == "default") { + switch (bvariant) { + case BuildVariant::STATIC : builder = BVH4InstanceArraySceneBuilderSAH(accel,scene,gtype); break; + case BuildVariant::DYNAMIC : builder = BVH4BuilderTwoLevelInstanceArraySAH(accel,scene,gtype,false); break; + case BuildVariant::HIGH_QUALITY: assert(false); break; + } + } + else if (scene->device->object_builder == "sah") { builder = BVH4InstanceArraySceneBuilderSAH(accel,scene,gtype); } + else if (scene->device->object_builder == "dynamic") { builder = BVH4BuilderTwoLevelInstanceArraySAH(accel,scene,gtype,false); } + else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH4<Object>"); + + return new AccelInstance(accel,builder,intersectors); + } + + Accel* BVH4Factory::BVH4InstanceArrayMB(Scene* scene) + { + BVH4* accel = new BVH4(InstanceArrayPrimitive::type,scene); + Accel::Intersectors intersectors = BVH4InstanceArrayMBIntersectors(accel); + Builder* builder = BVH4InstanceArrayMBSceneBuilderSAH(accel,scene,Geometry::MTY_INSTANCE_ARRAY); + return new AccelInstance(accel,builder,intersectors); + } + Accel::Intersectors BVH4Factory::BVH4GridIntersectors(BVH4* bvh, IntersectVariant ivariant) { Accel::Intersectors intersectors; @@ -1266,7 +1292,6 @@ namespace embree intersectors.intersector4 = BVH4GridIntersector4HybridMoeller(); intersectors.intersector8 = BVH4GridIntersector8HybridMoeller(); intersectors.intersector16 = BVH4GridIntersector16HybridMoeller(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif } else /* if (ivariant == IntersectVariant::ROBUST) */ @@ -1276,7 +1301,6 @@ namespace embree intersectors.intersector4 = BVH4GridIntersector4HybridPluecker(); intersectors.intersector8 = BVH4GridIntersector8HybridPluecker(); intersectors.intersector16 = BVH4GridIntersector16HybridPluecker(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif } return intersectors; @@ -1291,7 +1315,6 @@ namespace embree intersectors.intersector4 = BVH4GridMBIntersector4HybridMoeller(); intersectors.intersector8 = BVH4GridMBIntersector8HybridMoeller(); intersectors.intersector16 = BVH4GridMBIntersector16HybridMoeller(); - intersectors.intersectorN = BVH4IntersectorStreamPacketFallback(); #endif return intersectors; } diff --git a/thirdparty/embree/kernels/bvh/bvh4_factory.h b/thirdparty/embree/kernels/bvh/bvh4_factory.h index 30973971a4..abf51dd108 100644 --- a/thirdparty/embree/kernels/bvh/bvh4_factory.h +++ b/thirdparty/embree/kernels/bvh/bvh4_factory.h @@ -48,6 +48,9 @@ namespace embree Accel* BVH4Instance(Scene* scene, bool isExpensive, BuildVariant bvariant = BuildVariant::STATIC); Accel* BVH4InstanceMB(Scene* scene, bool isExpensive); + Accel* BVH4InstanceArray(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC); + Accel* BVH4InstanceArrayMB(Scene* scene); + Accel* BVH4Grid(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST); Accel* BVH4GridMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST); @@ -77,7 +80,10 @@ namespace embree Accel::Intersectors BVH4InstanceIntersectors(BVH4* bvh); Accel::Intersectors BVH4InstanceMBIntersectors(BVH4* bvh); - + + Accel::Intersectors BVH4InstanceArrayIntersectors(BVH4* bvh); + Accel::Intersectors BVH4InstanceArrayMBIntersectors(BVH4* bvh); + Accel::Intersectors BVH4SubdivPatch1Intersectors(BVH4* bvh); Accel::Intersectors BVH4SubdivPatch1MBIntersectors(BVH4* bvh); @@ -122,7 +128,10 @@ namespace embree DEFINE_SYMBOL2(Accel::Intersector1,BVH4InstanceIntersector1); DEFINE_SYMBOL2(Accel::Intersector1,BVH4InstanceMBIntersector1); - + + DEFINE_SYMBOL2(Accel::Intersector1,BVH4InstanceArrayIntersector1); + DEFINE_SYMBOL2(Accel::Intersector1,BVH4InstanceArrayMBIntersector1); + DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Moeller); DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridMBIntersector1Moeller); DEFINE_SYMBOL2(Accel::Intersector1,BVH4GridIntersector1Pluecker); @@ -161,6 +170,9 @@ namespace embree DEFINE_SYMBOL2(Accel::Intersector4,BVH4InstanceIntersector4Chunk); DEFINE_SYMBOL2(Accel::Intersector4,BVH4InstanceMBIntersector4Chunk); + DEFINE_SYMBOL2(Accel::Intersector4,BVH4InstanceArrayIntersector4Chunk); + DEFINE_SYMBOL2(Accel::Intersector4,BVH4InstanceArrayMBIntersector4Chunk); + DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridMoeller); DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridMBIntersector4HybridMoeller); DEFINE_SYMBOL2(Accel::Intersector4,BVH4GridIntersector4HybridPluecker); @@ -201,6 +213,9 @@ namespace embree DEFINE_SYMBOL2(Accel::Intersector8,BVH4InstanceIntersector8Chunk); DEFINE_SYMBOL2(Accel::Intersector8,BVH4InstanceMBIntersector8Chunk); + DEFINE_SYMBOL2(Accel::Intersector8,BVH4InstanceArrayIntersector8Chunk); + DEFINE_SYMBOL2(Accel::Intersector8,BVH4InstanceArrayMBIntersector8Chunk); + DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridMoeller); DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridMBIntersector8HybridMoeller); DEFINE_SYMBOL2(Accel::Intersector8,BVH4GridIntersector8HybridPluecker); @@ -241,30 +256,13 @@ namespace embree DEFINE_SYMBOL2(Accel::Intersector16,BVH4InstanceIntersector16Chunk); DEFINE_SYMBOL2(Accel::Intersector16,BVH4InstanceMBIntersector16Chunk); + DEFINE_SYMBOL2(Accel::Intersector16,BVH4InstanceArrayIntersector16Chunk); + DEFINE_SYMBOL2(Accel::Intersector16,BVH4InstanceArrayMBIntersector16Chunk); + DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridMoeller); DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridMBIntersector16HybridMoeller); DEFINE_SYMBOL2(Accel::Intersector16,BVH4GridIntersector16HybridPluecker); - // ============== - - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4IntersectorStreamPacketFallback); - - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4IntersectorStreamMoeller); - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4IntersectorStreamMoellerNoFilter); - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4iIntersectorStreamMoeller); - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4vIntersectorStreamPluecker); - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Triangle4iIntersectorStreamPluecker); - - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamMoeller); - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamMoellerNoFilter); - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4iIntersectorStreamMoeller); - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4vIntersectorStreamPluecker); - DEFINE_SYMBOL2(Accel::IntersectorN, BVH4Quad4iIntersectorStreamPluecker); - - DEFINE_SYMBOL2(Accel::IntersectorN,BVH4VirtualIntersectorStream); - - DEFINE_SYMBOL2(Accel::IntersectorN,BVH4InstanceIntersectorStream); - // SAH scene builders private: DEFINE_ISA_FUNCTION(Builder*,BVH4Curve4vBuilder_OBB_New,void* COMMA Scene* COMMA size_t); @@ -294,6 +292,9 @@ namespace embree DEFINE_ISA_FUNCTION(Builder*,BVH4InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); DEFINE_ISA_FUNCTION(Builder*,BVH4InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DEFINE_ISA_FUNCTION(Builder*,BVH4InstanceArraySceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DEFINE_ISA_FUNCTION(Builder*,BVH4InstanceArrayMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DEFINE_ISA_FUNCTION(Builder*,BVH4GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t); DEFINE_ISA_FUNCTION(Builder*,BVH4GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t); @@ -312,5 +313,6 @@ namespace embree DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool); DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool); DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool); + DEFINE_ISA_FUNCTION(Builder*,BVH4BuilderTwoLevelInstanceArraySAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool); }; } diff --git a/thirdparty/embree/kernels/bvh/bvh8_factory.cpp b/thirdparty/embree/kernels/bvh/bvh8_factory.cpp index d4521af241..7c0f7565fa 100644 --- a/thirdparty/embree/kernels/bvh/bvh8_factory.cpp +++ b/thirdparty/embree/kernels/bvh/bvh8_factory.cpp @@ -21,6 +21,7 @@ #include "../geometry/subdivpatch1.h" #include "../geometry/object.h" #include "../geometry/instance.h" +#include "../geometry/instance_array.h" #include "../geometry/subgrid.h" #include "../common/accelinstance.h" @@ -66,6 +67,9 @@ namespace embree DECLARE_SYMBOL2(Accel::Intersector1,BVH8InstanceIntersector1); DECLARE_SYMBOL2(Accel::Intersector1,BVH8InstanceMBIntersector1); + DECLARE_SYMBOL2(Accel::Intersector1,BVH8InstanceArrayIntersector1); + DECLARE_SYMBOL2(Accel::Intersector1,BVH8InstanceArrayMBIntersector1); + DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Moeller); DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridMBIntersector1Moeller); DECLARE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Pluecker); @@ -101,6 +105,9 @@ namespace embree DECLARE_SYMBOL2(Accel::Intersector4,BVH8InstanceIntersector4Chunk); DECLARE_SYMBOL2(Accel::Intersector4,BVH8InstanceMBIntersector4Chunk); + DECLARE_SYMBOL2(Accel::Intersector4,BVH8InstanceArrayIntersector4Chunk); + DECLARE_SYMBOL2(Accel::Intersector4,BVH8InstanceArrayMBIntersector4Chunk); + DECLARE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridPluecker); @@ -135,6 +142,9 @@ namespace embree DECLARE_SYMBOL2(Accel::Intersector8,BVH8InstanceIntersector8Chunk); DECLARE_SYMBOL2(Accel::Intersector8,BVH8InstanceMBIntersector8Chunk); + DECLARE_SYMBOL2(Accel::Intersector8,BVH8InstanceArrayIntersector8Chunk); + DECLARE_SYMBOL2(Accel::Intersector8,BVH8InstanceArrayMBIntersector8Chunk); + DECLARE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridPluecker); @@ -169,27 +179,12 @@ namespace embree DECLARE_SYMBOL2(Accel::Intersector16,BVH8InstanceIntersector16Chunk); DECLARE_SYMBOL2(Accel::Intersector16,BVH8InstanceMBIntersector16Chunk); + DECLARE_SYMBOL2(Accel::Intersector16,BVH8InstanceArrayIntersector16Chunk); + DECLARE_SYMBOL2(Accel::Intersector16,BVH8InstanceArrayMBIntersector16Chunk); + DECLARE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridMoeller); DECLARE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridPluecker); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8IntersectorStreamPacketFallback); - - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoeller); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoellerNoFilter); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamMoeller); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4vIntersectorStreamPluecker); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamPluecker); - - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoeller); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoellerNoFilter); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamMoeller); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamPluecker); - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamPluecker); - - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8VirtualIntersectorStream); - - DECLARE_SYMBOL2(Accel::IntersectorN,BVH8InstanceIntersectorStream); - DECLARE_ISA_FUNCTION(Builder*,BVH8Curve8vBuilder_OBB_New,void* COMMA Scene* COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH8OBBCurve8iMBBuilder_OBB,void* COMMA Scene* COMMA size_t); @@ -212,6 +207,9 @@ namespace embree DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceArraySceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceArrayMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4SceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH8Quad4vSceneBuilderFastSpatialSAH,void* COMMA Scene* COMMA size_t); @@ -224,6 +222,7 @@ namespace embree DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool); DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool); DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool); + DECLARE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelInstanceArraySAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool); BVH8Factory::BVH8Factory(int bfeatures, int ifeatures) { @@ -256,6 +255,9 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX(features,BVH8InstanceSceneBuilderSAH)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX(features,BVH8InstanceMBSceneBuilderSAH)); + + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX(features,BVH8InstanceArraySceneBuilderSAH)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX(features,BVH8InstanceArrayMBSceneBuilderSAH)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX(features,BVH8GridSceneBuilderSAH)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX(features,BVH8GridMBSceneBuilderSAH)); @@ -270,6 +272,7 @@ namespace embree IF_ENABLED_QUADS (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelQuadMeshSAH)); IF_ENABLED_USER (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelVirtualSAH)); IF_ENABLED_INSTANCE (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelInstanceSAH)); + IF_ENABLED_INSTANCE_ARRAY (SELECT_SYMBOL_INIT_AVX(features,BVH8BuilderTwoLevelInstanceArraySAH)); } void BVH8Factory::selectIntersectors(int features) @@ -313,6 +316,9 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceIntersector1)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceMBIntersector1)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceArrayIntersector1)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceArrayMBIntersector1)); + IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector1Moeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridMBIntersector1Moeller)) IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector1Pluecker)); @@ -351,6 +357,9 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceIntersector4Chunk)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceMBIntersector4Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceArrayIntersector4Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceArrayMBIntersector4Chunk)); + IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector4HybridMoeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector4HybridPluecker)); @@ -386,6 +395,9 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceIntersector8Chunk)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceMBIntersector8Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceArrayIntersector8Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceArrayMBIntersector8Chunk)); + IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector8HybridMoeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8GridIntersector8HybridPluecker)); @@ -421,29 +433,12 @@ namespace embree IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512(features,BVH8InstanceIntersector16Chunk)); IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX512(features,BVH8InstanceMBIntersector16Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX512(features,BVH8InstanceArrayIntersector16Chunk)); + IF_ENABLED_INSTANCE_ARRAY(SELECT_SYMBOL_INIT_AVX512(features,BVH8InstanceArrayMBIntersector16Chunk)); + IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH8GridIntersector16HybridMoeller)); IF_ENABLED_GRIDS(SELECT_SYMBOL_INIT_AVX512(features,BVH8GridIntersector16HybridPluecker)); - /* select stream intersectors */ - - SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8IntersectorStreamPacketFallback); - - IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4IntersectorStreamMoeller)); - IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4IntersectorStreamMoellerNoFilter)); - IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersectorStreamMoeller)); - IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4vIntersectorStreamPluecker)); - IF_ENABLED_TRIS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Triangle4iIntersectorStreamPluecker)); - - IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersectorStreamMoeller)); - IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersectorStreamMoellerNoFilter)); - IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersectorStreamMoeller)); - IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4vIntersectorStreamPluecker)); - IF_ENABLED_QUADS(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8Quad4iIntersectorStreamPluecker)); - - IF_ENABLED_USER(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8VirtualIntersectorStream)); - - IF_ENABLED_INSTANCE(SELECT_SYMBOL_INIT_AVX_AVX2_AVX512(features,BVH8InstanceIntersectorStream)); - #endif } @@ -460,7 +455,6 @@ namespace embree intersectors.intersector4 = BVH8OBBVirtualCurveIntersector4Hybrid(); intersectors.intersector8 = BVH8OBBVirtualCurveIntersector8Hybrid(); intersectors.intersector16 = BVH8OBBVirtualCurveIntersector16Hybrid(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -474,7 +468,6 @@ namespace embree intersectors.intersector4 = BVH8OBBVirtualCurveIntersectorRobust4Hybrid(); intersectors.intersector8 = BVH8OBBVirtualCurveIntersectorRobust8Hybrid(); intersectors.intersector16 = BVH8OBBVirtualCurveIntersectorRobust16Hybrid(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -496,7 +489,6 @@ namespace embree intersectors.intersector4 = BVH8OBBVirtualCurveIntersector4HybridMB(); intersectors.intersector8 = BVH8OBBVirtualCurveIntersector8HybridMB(); intersectors.intersector16 = BVH8OBBVirtualCurveIntersector16HybridMB(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -510,7 +502,6 @@ namespace embree intersectors.intersector4 = BVH8OBBVirtualCurveIntersectorRobust4HybridMB(); intersectors.intersector8 = BVH8OBBVirtualCurveIntersectorRobust8HybridMB(); intersectors.intersector16 = BVH8OBBVirtualCurveIntersectorRobust16HybridMB(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -532,8 +523,6 @@ namespace embree intersectors.intersector8_nofilter = BVH8Triangle4Intersector8HybridMoellerNoFilter(); intersectors.intersector16_filter = BVH8Triangle4Intersector16HybridMoeller(); intersectors.intersector16_nofilter = BVH8Triangle4Intersector16HybridMoellerNoFilter(); - intersectors.intersectorN_filter = BVH8Triangle4IntersectorStreamMoeller(); - intersectors.intersectorN_nofilter = BVH8Triangle4IntersectorStreamMoellerNoFilter(); #endif return intersectors; } @@ -554,7 +543,6 @@ namespace embree intersectors.intersector4 = BVH8Triangle4vIntersector4HybridPluecker(); intersectors.intersector8 = BVH8Triangle4vIntersector8HybridPluecker(); intersectors.intersector16 = BVH8Triangle4vIntersector16HybridPluecker(); - intersectors.intersectorN = BVH8Triangle4vIntersectorStreamPluecker(); #endif return intersectors; } @@ -571,7 +559,6 @@ namespace embree intersectors.intersector4 = BVH8Triangle4iIntersector4HybridMoeller(); intersectors.intersector8 = BVH8Triangle4iIntersector8HybridMoeller(); intersectors.intersector16 = BVH8Triangle4iIntersector16HybridMoeller(); - intersectors.intersectorN = BVH8Triangle4iIntersectorStreamMoeller(); #endif return intersectors; } @@ -584,7 +571,6 @@ namespace embree intersectors.intersector4 = BVH8Triangle4iIntersector4HybridPluecker(); intersectors.intersector8 = BVH8Triangle4iIntersector8HybridPluecker(); intersectors.intersector16 = BVH8Triangle4iIntersector16HybridPluecker(); - intersectors.intersectorN = BVH8Triangle4iIntersectorStreamPluecker(); #endif return intersectors; } @@ -604,7 +590,6 @@ namespace embree intersectors.intersector4 = BVH8Triangle4vMBIntersector4HybridMoeller(); intersectors.intersector8 = BVH8Triangle4vMBIntersector8HybridMoeller(); intersectors.intersector16 = BVH8Triangle4vMBIntersector16HybridMoeller(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -617,7 +602,6 @@ namespace embree intersectors.intersector4 = BVH8Triangle4vMBIntersector4HybridPluecker(); intersectors.intersector8 = BVH8Triangle4vMBIntersector8HybridPluecker(); intersectors.intersector16 = BVH8Triangle4vMBIntersector16HybridPluecker(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -637,7 +621,6 @@ namespace embree intersectors.intersector4 = BVH8Triangle4iMBIntersector4HybridMoeller(); intersectors.intersector8 = BVH8Triangle4iMBIntersector8HybridMoeller(); intersectors.intersector16 = BVH8Triangle4iMBIntersector16HybridMoeller(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -650,7 +633,6 @@ namespace embree intersectors.intersector4 = BVH8Triangle4iMBIntersector4HybridPluecker(); intersectors.intersector8 = BVH8Triangle4iMBIntersector8HybridPluecker(); intersectors.intersector16 = BVH8Triangle4iMBIntersector16HybridPluecker(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -673,8 +655,6 @@ namespace embree intersectors.intersector8_nofilter = BVH8Quad4vIntersector8HybridMoellerNoFilter(); intersectors.intersector16_filter = BVH8Quad4vIntersector16HybridMoeller(); intersectors.intersector16_nofilter = BVH8Quad4vIntersector16HybridMoellerNoFilter(); - intersectors.intersectorN_filter = BVH8Quad4vIntersectorStreamMoeller(); - intersectors.intersectorN_nofilter = BVH8Quad4vIntersectorStreamMoellerNoFilter(); #endif return intersectors; } @@ -687,7 +667,6 @@ namespace embree intersectors.intersector4 = BVH8Quad4vIntersector4HybridPluecker(); intersectors.intersector8 = BVH8Quad4vIntersector8HybridPluecker(); intersectors.intersector16 = BVH8Quad4vIntersector16HybridPluecker(); - intersectors.intersectorN = BVH8Quad4vIntersectorStreamPluecker(); #endif return intersectors; } @@ -707,7 +686,6 @@ namespace embree intersectors.intersector4 = BVH8Quad4iIntersector4HybridMoeller(); intersectors.intersector8 = BVH8Quad4iIntersector8HybridMoeller(); intersectors.intersector16 = BVH8Quad4iIntersector16HybridMoeller(); - intersectors.intersectorN = BVH8Quad4iIntersectorStreamMoeller(); #endif return intersectors; } @@ -720,7 +698,6 @@ namespace embree intersectors.intersector4 = BVH8Quad4iIntersector4HybridPluecker(); intersectors.intersector8 = BVH8Quad4iIntersector8HybridPluecker(); intersectors.intersector16 = BVH8Quad4iIntersector16HybridPluecker(); - intersectors.intersectorN = BVH8Quad4iIntersectorStreamPluecker(); #endif return intersectors; } @@ -740,7 +717,6 @@ namespace embree intersectors.intersector4 = BVH8Quad4iMBIntersector4HybridMoeller(); intersectors.intersector8 = BVH8Quad4iMBIntersector8HybridMoeller(); intersectors.intersector16 = BVH8Quad4iMBIntersector16HybridMoeller(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -753,7 +729,6 @@ namespace embree intersectors.intersector4 = BVH8Quad4iMBIntersector4HybridPluecker(); intersectors.intersector8 = BVH8Quad4iMBIntersector8HybridPluecker(); intersectors.intersector16 = BVH8Quad4iMBIntersector16HybridPluecker(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -794,7 +769,6 @@ namespace embree intersectors.intersector4 = BVH8VirtualIntersector4Chunk(); intersectors.intersector8 = BVH8VirtualIntersector8Chunk(); intersectors.intersector16 = BVH8VirtualIntersector16Chunk(); - intersectors.intersectorN = BVH8VirtualIntersectorStream(); #endif intersectors.collider = BVH8ColliderUserGeom(); return intersectors; @@ -809,7 +783,6 @@ namespace embree intersectors.intersector4 = BVH8VirtualMBIntersector4Chunk(); intersectors.intersector8 = BVH8VirtualMBIntersector8Chunk(); intersectors.intersector16 = BVH8VirtualMBIntersector16Chunk(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif return intersectors; } @@ -823,7 +796,19 @@ namespace embree intersectors.intersector4 = BVH8InstanceIntersector4Chunk(); intersectors.intersector8 = BVH8InstanceIntersector8Chunk(); intersectors.intersector16 = BVH8InstanceIntersector16Chunk(); - intersectors.intersectorN = BVH8InstanceIntersectorStream(); +#endif + return intersectors; + } + + Accel::Intersectors BVH8Factory::BVH8InstanceArrayIntersectors(BVH8* bvh) + { + Accel::Intersectors intersectors; + intersectors.ptr = bvh; + intersectors.intersector1 = BVH8InstanceArrayIntersector1(); +#if defined (EMBREE_RAY_PACKETS) + intersectors.intersector4 = BVH8InstanceArrayIntersector4Chunk(); + intersectors.intersector8 = BVH8InstanceArrayIntersector8Chunk(); + intersectors.intersector16 = BVH8InstanceArrayIntersector16Chunk(); #endif return intersectors; } @@ -837,7 +822,19 @@ namespace embree intersectors.intersector4 = BVH8InstanceMBIntersector4Chunk(); intersectors.intersector8 = BVH8InstanceMBIntersector8Chunk(); intersectors.intersector16 = BVH8InstanceMBIntersector16Chunk(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); +#endif + return intersectors; + } + + Accel::Intersectors BVH8Factory::BVH8InstanceArrayMBIntersectors(BVH8* bvh) + { + Accel::Intersectors intersectors; + intersectors.ptr = bvh; + intersectors.intersector1 = BVH8InstanceArrayMBIntersector1(); +#if defined (EMBREE_RAY_PACKETS) + intersectors.intersector4 = BVH8InstanceArrayMBIntersector4Chunk(); + intersectors.intersector8 = BVH8InstanceArrayMBIntersector8Chunk(); + intersectors.intersector16 = BVH8InstanceArrayMBIntersector16Chunk(); #endif return intersectors; } @@ -1086,6 +1083,28 @@ namespace embree return new AccelInstance(accel,builder,intersectors); } + Accel* BVH8Factory::BVH8InstanceArray(Scene* scene, BuildVariant bvariant) + { + BVH8* accel = new BVH8(InstanceArrayPrimitive::type,scene); + Accel::Intersectors intersectors = BVH8InstanceArrayIntersectors(accel); + auto gtype = Geometry::MTY_INSTANCE_ARRAY; + // Builder* builder = BVH8InstanceSceneBuilderSAH(accel,scene,gtype); + + Builder* builder = nullptr; + if (scene->device->object_builder == "default") { + switch (bvariant) { + case BuildVariant::STATIC : builder = BVH8InstanceArraySceneBuilderSAH(accel,scene,gtype); break; + case BuildVariant::DYNAMIC : builder = BVH8BuilderTwoLevelInstanceArraySAH(accel,scene,gtype,false); break; + case BuildVariant::HIGH_QUALITY: assert(false); break; + } + } + else if (scene->device->object_builder == "sah") builder = BVH8InstanceArraySceneBuilderSAH(accel,scene,gtype); + else if (scene->device->object_builder == "dynamic") builder = BVH8BuilderTwoLevelInstanceArraySAH(accel,scene,gtype,false); + else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown builder "+scene->device->object_builder+" for BVH8<Object>"); + + return new AccelInstance(accel,builder,intersectors); + } + Accel* BVH8Factory::BVH8InstanceMB(Scene* scene, bool isExpensive) { BVH8* accel = new BVH8(InstancePrimitive::type,scene); @@ -1095,6 +1114,15 @@ namespace embree return new AccelInstance(accel,builder,intersectors); } + Accel* BVH8Factory::BVH8InstanceArrayMB(Scene* scene) + { + BVH8* accel = new BVH8(InstanceArrayPrimitive::type,scene); + Accel::Intersectors intersectors = BVH8InstanceArrayMBIntersectors(accel); + auto gtype = Geometry::MTY_INSTANCE_ARRAY; + Builder* builder = BVH8InstanceArrayMBSceneBuilderSAH(accel,scene,gtype); + return new AccelInstance(accel,builder,intersectors); + } + Accel::Intersectors BVH8Factory::BVH8GridIntersectors(BVH8* bvh, IntersectVariant ivariant) { Accel::Intersectors intersectors; @@ -1106,7 +1134,6 @@ namespace embree intersectors.intersector4 = BVH8GridIntersector4HybridMoeller(); intersectors.intersector8 = BVH8GridIntersector8HybridMoeller(); intersectors.intersector16 = BVH8GridIntersector16HybridMoeller(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif } else /* if (ivariant == IntersectVariant::ROBUST) */ @@ -1116,7 +1143,6 @@ namespace embree intersectors.intersector4 = BVH8GridIntersector4HybridPluecker(); intersectors.intersector8 = BVH8GridIntersector8HybridPluecker(); intersectors.intersector16 = BVH8GridIntersector16HybridPluecker(); - intersectors.intersectorN = BVH8IntersectorStreamPacketFallback(); #endif } return intersectors; @@ -1131,7 +1157,6 @@ namespace embree intersectors.intersector4 = nullptr; intersectors.intersector8 = nullptr; intersectors.intersector16 = nullptr; - intersectors.intersectorN = nullptr; #endif return intersectors; } diff --git a/thirdparty/embree/kernels/bvh/bvh8_factory.h b/thirdparty/embree/kernels/bvh/bvh8_factory.h index 198d6f1df0..e55310b703 100644 --- a/thirdparty/embree/kernels/bvh/bvh8_factory.h +++ b/thirdparty/embree/kernels/bvh/bvh8_factory.h @@ -39,6 +39,9 @@ namespace embree Accel* BVH8Instance(Scene* scene, bool isExpensive, BuildVariant bvariant = BuildVariant::STATIC); Accel* BVH8InstanceMB(Scene* scene, bool isExpensive); + Accel* BVH8InstanceArray(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC); + Accel* BVH8InstanceArrayMB(Scene* scene); + Accel* BVH8Grid(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST); Accel* BVH8GridMB(Scene* scene, BuildVariant bvariant = BuildVariant::STATIC, IntersectVariant ivariant = IntersectVariant::FAST); @@ -70,6 +73,9 @@ namespace embree Accel::Intersectors BVH8InstanceIntersectors(BVH8* bvh); Accel::Intersectors BVH8InstanceMBIntersectors(BVH8* bvh); + Accel::Intersectors BVH8InstanceArrayIntersectors(BVH8* bvh); + Accel::Intersectors BVH8InstanceArrayMBIntersectors(BVH8* bvh); + Accel::Intersectors BVH8GridIntersectors(BVH8* bvh, IntersectVariant ivariant); Accel::Intersectors BVH8GridMBIntersectors(BVH8* bvh, IntersectVariant ivariant); @@ -111,6 +117,9 @@ namespace embree DEFINE_SYMBOL2(Accel::Intersector1,BVH8InstanceIntersector1); DEFINE_SYMBOL2(Accel::Intersector1,BVH8InstanceMBIntersector1); + DEFINE_SYMBOL2(Accel::Intersector1,BVH8InstanceArrayIntersector1); + DEFINE_SYMBOL2(Accel::Intersector1,BVH8InstanceArrayMBIntersector1); + DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Moeller); DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridMBIntersector1Moeller); DEFINE_SYMBOL2(Accel::Intersector1,BVH8GridIntersector1Pluecker); @@ -145,7 +154,10 @@ namespace embree DEFINE_SYMBOL2(Accel::Intersector4,BVH8InstanceIntersector4Chunk); DEFINE_SYMBOL2(Accel::Intersector4,BVH8InstanceMBIntersector4Chunk); - + + DEFINE_SYMBOL2(Accel::Intersector4,BVH8InstanceArrayIntersector4Chunk); + DEFINE_SYMBOL2(Accel::Intersector4,BVH8InstanceArrayMBIntersector4Chunk); + DEFINE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridMoeller); DEFINE_SYMBOL2(Accel::Intersector4,BVH8GridIntersector4HybridPluecker); @@ -180,9 +192,12 @@ namespace embree DEFINE_SYMBOL2(Accel::Intersector8,BVH8InstanceIntersector8Chunk); DEFINE_SYMBOL2(Accel::Intersector8,BVH8InstanceMBIntersector8Chunk); + DEFINE_SYMBOL2(Accel::Intersector8,BVH8InstanceArrayIntersector8Chunk); + DEFINE_SYMBOL2(Accel::Intersector8,BVH8InstanceArrayMBIntersector8Chunk); + DEFINE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridMoeller); DEFINE_SYMBOL2(Accel::Intersector8,BVH8GridIntersector8HybridPluecker); - + DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16Hybrid); DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersector16HybridMB); DEFINE_SYMBOL2(Accel::Intersector16,BVH8OBBVirtualCurveIntersectorRobust16Hybrid); @@ -213,27 +228,12 @@ namespace embree DEFINE_SYMBOL2(Accel::Intersector16,BVH8InstanceIntersector16Chunk); DEFINE_SYMBOL2(Accel::Intersector16,BVH8InstanceMBIntersector16Chunk); - - DEFINE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridMoeller); - DEFINE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridPluecker); - - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8IntersectorStreamPacketFallback); - - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoeller); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4IntersectorStreamMoellerNoFilter); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamMoeller); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4vIntersectorStreamPluecker); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Triangle4iIntersectorStreamPluecker); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoeller); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamMoellerNoFilter); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamMoeller); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4vIntersectorStreamPluecker); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8Quad4iIntersectorStreamPluecker); + DEFINE_SYMBOL2(Accel::Intersector16,BVH8InstanceArrayIntersector16Chunk); + DEFINE_SYMBOL2(Accel::Intersector16,BVH8InstanceArrayMBIntersector16Chunk); - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8VirtualIntersectorStream); - - DEFINE_SYMBOL2(Accel::IntersectorN,BVH8InstanceIntersectorStream); + DEFINE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridMoeller); + DEFINE_SYMBOL2(Accel::Intersector16,BVH8GridIntersector16HybridPluecker); // SAH scene builders private: @@ -258,6 +258,9 @@ namespace embree DEFINE_ISA_FUNCTION(Builder*,BVH8InstanceSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); DEFINE_ISA_FUNCTION(Builder*,BVH8InstanceMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + + DEFINE_ISA_FUNCTION(Builder*,BVH8InstanceArraySceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); + DEFINE_ISA_FUNCTION(Builder*,BVH8InstanceArrayMBSceneBuilderSAH,void* COMMA Scene* COMMA Geometry::GTypeMask); DEFINE_ISA_FUNCTION(Builder*,BVH8GridSceneBuilderSAH,void* COMMA Scene* COMMA size_t); DEFINE_ISA_FUNCTION(Builder*,BVH8GridMBSceneBuilderSAH,void* COMMA Scene* COMMA size_t); @@ -276,5 +279,6 @@ namespace embree DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelQuadMeshSAH,void* COMMA Scene* COMMA bool); DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelVirtualSAH,void* COMMA Scene* COMMA bool); DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelInstanceSAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool); + DEFINE_ISA_FUNCTION(Builder*,BVH8BuilderTwoLevelInstanceArraySAH,void* COMMA Scene* COMMA Geometry::GTypeMask COMMA bool); }; } diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_morton.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_morton.cpp index 4a4d8d71df..7d6548cb2a 100644 --- a/thirdparty/embree/kernels/bvh/bvh_builder_morton.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_builder_morton.cpp @@ -17,6 +17,7 @@ #include "../geometry/quadi.h" #include "../geometry/object.h" #include "../geometry/instance.h" +#include "../geometry/instance_array.h" #if defined(__64BIT__) # define ROTATE_TREE 1 // specifies number of tree rotation rounds to perform @@ -399,6 +400,50 @@ namespace embree unsigned int geomID_ = std::numeric_limits<unsigned int>::max(); }; + template<int N> + struct CreateMortonLeaf<N,InstanceArrayPrimitive> + { + typedef BVHN<N> BVH; + typedef typename BVH::NodeRef NodeRef; + typedef typename BVH::NodeRecord NodeRecord; + + __forceinline CreateMortonLeaf (InstanceArray* mesh, unsigned int geomID, BVHBuilderMorton::BuildPrim* morton) + : mesh(mesh), morton(morton), geomID_(geomID) {} + + __noinline NodeRecord operator() (const range<unsigned>& current, const FastAllocator::CachedAllocator& alloc) + { + vfloat4 lower(pos_inf); + vfloat4 upper(neg_inf); + size_t items = current.size(); + size_t start = current.begin(); + assert(items <= 1); + + /* allocate leaf node */ + InstanceArrayPrimitive* accel = (InstanceArrayPrimitive*) alloc.malloc1(items*sizeof(InstanceArrayPrimitive),BVH::byteAlignment); + NodeRef ref = BVH::encodeLeaf((char*)accel,items); + const InstanceArray* instance = this->mesh; + + BBox3fa bounds = empty; + for (size_t i=0; i<items; i++) + { + const unsigned int primID = morton[start+i].index; + bounds.extend(instance->bounds(primID)); + new (&accel[i]) InstanceArrayPrimitive(geomID_, primID); + } + + BBox3fx box_o = (BBox3fx&)bounds; +#if ROTATE_TREE + if (N == 4) + box_o.lower.a = current.size(); +#endif + return NodeRecord(ref,box_o); + } + private: + InstanceArray* mesh; + BVHBuilderMorton::BuildPrim* morton; + unsigned int geomID_ = std::numeric_limits<unsigned int>::max(); + }; + template<typename Mesh> struct CalculateMeshBounds { @@ -523,7 +568,14 @@ namespace embree #if defined(EMBREE_GEOMETRY_INSTANCE) Builder* BVH4InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,Instance,InstancePrimitive>((BVH4*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); } #if defined(__AVX__) - Builder* BVH8InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,Instance,InstancePrimitive>((BVH8*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); } + Builder* BVH8InstanceMeshBuilderMortonGeneral (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,Instance,InstancePrimitive>((BVH8*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); } +#endif +#endif + +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + Builder* BVH4InstanceArrayMeshBuilderMortonGeneral (void* bvh, InstanceArray* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<4,InstanceArray,InstanceArrayPrimitive>((BVH4*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); } +#if defined(__AVX__) + Builder* BVH8InstanceArrayMeshBuilderMortonGeneral (void* bvh, InstanceArray* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new class BVHNMeshBuilderMorton<8,InstanceArray,InstanceArrayPrimitive>((BVH8*)bvh,mesh,gtype,geomID,1,BVH4::maxLeafBlocks); } #endif #endif diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_sah.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_sah.cpp index fad02fcc04..e20c088bba 100644 --- a/thirdparty/embree/kernels/bvh/bvh_builder_sah.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_builder_sah.cpp @@ -15,6 +15,7 @@ #include "../geometry/quadi.h" #include "../geometry/object.h" #include "../geometry/instance.h" +#include "../geometry/instance_array.h" #include "../geometry/subgrid.h" #include "../common/state.h" @@ -150,7 +151,7 @@ namespace embree const size_t leaf_bytes = size_t(1.2*Primitive::blocks(numPrimitives)*sizeof(Primitive)); bvh->alloc.init_estimate(node_bytes+leaf_bytes); settings.singleThreadThreshold = bvh->alloc.fixSingleThreadThreshold(N,DEFAULT_SINGLE_THREAD_THRESHOLD,numPrimitives,node_bytes+leaf_bytes); - prims.resize(numPrimitives); + prims.resize(numPrimitives); PrimInfo pinfo = mesh ? createPrimRefArray(mesh,geomID_,numPrimitives,prims,bvh->scene->progressInterface) : @@ -518,14 +519,35 @@ namespace embree #endif #if defined(EMBREE_GEOMETRY_INSTANCE) - Builder* BVH4InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); } + Builder* BVH4InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { + return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); + } Builder* BVH4InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNBuilderSAH<4,InstancePrimitive>((BVH4*)bvh,mesh,geomID,4,1.0f,1,inf,gtype); } #if defined(__AVX__) - Builder* BVH8InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); } + Builder* BVH8InstanceSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { + return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); + } Builder* BVH8InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { - return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,mesh,geomID,8,1.0f,1,inf,gtype); + return new BVHNBuilderSAH<8,InstancePrimitive>((BVH8*)bvh,mesh,geomID,8,1.0f,1,1,gtype); + } +#endif +#endif + +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + Builder* BVH4InstanceArraySceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { + return new BVHNBuilderSAH<4,InstanceArrayPrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); + } + Builder* BVH4InstanceArrayMeshBuilderSAH (void* bvh, InstanceArray* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { + return new BVHNBuilderSAH<4,InstanceArrayPrimitive>((BVH4*)bvh,mesh,geomID,4,1.0f,1,1,gtype); + } +#if defined(__AVX__) + Builder* BVH8InstanceArraySceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { + return new BVHNBuilderSAH<8,InstanceArrayPrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); + } + Builder* BVH8InstanceArrayMeshBuilderSAH (void* bvh, InstanceArray* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { + return new BVHNBuilderSAH<8,InstanceArrayPrimitive>((BVH8*)bvh,mesh,geomID,8,1.0f,1,1,gtype); } #endif #endif diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_sah_mb.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_sah_mb.cpp index d163a80ab1..0dcf98a5be 100644 --- a/thirdparty/embree/kernels/bvh/bvh_builder_sah_mb.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_builder_sah_mb.cpp @@ -17,6 +17,7 @@ #include "../geometry/quadi.h" #include "../geometry/object.h" #include "../geometry/instance.h" +#include "../geometry/instance_array.h" #include "../geometry/subgrid.h" #include "../common/state.h" @@ -695,6 +696,13 @@ namespace embree #endif #endif +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + Builder* BVH4InstanceArrayMBSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderMBlurSAH<4,InstanceArray,InstanceArrayPrimitive>((BVH4*)bvh,scene,4,1.0f,1,1,gtype); } +#if defined(__AVX__) + Builder* BVH8InstanceArrayMBSceneBuilderSAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype) { return new BVHNBuilderMBlurSAH<8,InstanceArray,InstanceArrayPrimitive>((BVH8*)bvh,scene,8,1.0f,1,1,gtype); } +#endif +#endif + #if defined(EMBREE_GEOMETRY_GRID) Builder* BVH4GridMBSceneBuilderSAH (void* bvh, Scene* scene, size_t mode) { return new BVHNBuilderMBlurSAHGrid<4>((BVH4*)bvh,scene,4,1.0f,4,4); } #if defined(__AVX__) diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp index 5d45ed3748..990b1d59ad 100644 --- a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.cpp @@ -1,6 +1,10 @@ // Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 +#if !defined(_CRT_SECURE_NO_WARNINGS) +#define _CRT_SECURE_NO_WARNINGS +#endif + #include "bvh_builder_twolevel.h" #include "bvh_statistics.h" #include "../builders/bvh_builder_sah.h" @@ -333,6 +337,12 @@ namespace embree } #endif +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + Builder* BVH4BuilderTwoLevelInstanceArraySAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) { + return new BVHNBuilderTwoLevel<4,InstanceArray,InstanceArrayPrimitive>((BVH4*)bvh,scene,gtype,useMortonBuilder); + } +#endif + #if defined(__AVX__) #if defined(EMBREE_GEOMETRY_TRIANGLE) Builder* BVH8BuilderTwoLevelTriangle4MeshSAH (void* bvh, Scene* scene, bool useMortonBuilder) { @@ -364,6 +374,12 @@ namespace embree } #endif +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + Builder* BVH8BuilderTwoLevelInstanceArraySAH (void* bvh, Scene* scene, Geometry::GTypeMask gtype, bool useMortonBuilder) { + return new BVHNBuilderTwoLevel<8,InstanceArray,InstanceArrayPrimitive>((BVH8*)bvh,scene,gtype,useMortonBuilder); + } +#endif + #endif } } diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h index dc7ec7d278..97ae41a87d 100644 --- a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h +++ b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel.h @@ -7,7 +7,6 @@ #include "bvh_builder_twolevel_internal.h" #include "bvh.h" -#include "../common/primref.h" #include "../builders/priminfo.h" #include "../builders/primrefgen.h" diff --git a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel_internal.h b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel_internal.h index 023b52b780..b28afffae9 100644 --- a/thirdparty/embree/kernels/bvh/bvh_builder_twolevel_internal.h +++ b/thirdparty/embree/kernels/bvh/bvh_builder_twolevel_internal.h @@ -11,6 +11,7 @@ #include "../geometry/quadi.h" #include "../geometry/object.h" #include "../geometry/instance.h" +#include "../geometry/instance_array.h" namespace embree { @@ -32,6 +33,9 @@ namespace embree DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshBuilderMortonGeneral,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshBuilderSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceMeshRefitSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t) + DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceArrayMeshBuilderMortonGeneral,void* COMMA InstanceArray* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t); + DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceArrayMeshBuilderSAH,void* COMMA InstanceArray* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t); + DECLARE_ISA_FUNCTION(Builder*,BVH4InstanceArrayMeshRefitSAH,void* COMMA InstanceArray* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t) DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshBuilderMortonGeneral,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshBuilderSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH8Triangle4MeshRefitSAH,void* COMMA TriangleMesh* COMMA unsigned int COMMA size_t); @@ -50,6 +54,9 @@ namespace embree DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshBuilderMortonGeneral,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshBuilderSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t); DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceMeshRefitSAH,void* COMMA Instance* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t) + DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceArrayMeshBuilderMortonGeneral,void* COMMA InstanceArray* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t); + DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceArrayMeshBuilderSAH,void* COMMA InstanceArray* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t); + DECLARE_ISA_FUNCTION(Builder*,BVH8InstanceArrayMeshRefitSAH,void* COMMA InstanceArray* COMMA Geometry::GTypeMask COMMA unsigned int COMMA size_t) namespace isa { @@ -89,6 +96,11 @@ namespace embree Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshBuilderMortonGeneral(bvh,mesh,gtype,geomID,0);} }; template<> + struct MortonBuilder<4,InstanceArray,InstanceArrayPrimitive> { + MortonBuilder () {} + Builder* operator () (void* bvh, InstanceArray* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceArrayMeshBuilderMortonGeneral(bvh,mesh,gtype,geomID,0);} + }; + template<> struct MortonBuilder<8,TriangleMesh,Triangle4> { MortonBuilder () {} Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshBuilderMortonGeneral(bvh,mesh,geomID,0);} @@ -118,6 +130,11 @@ namespace embree MortonBuilder () {} Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshBuilderMortonGeneral(bvh,mesh,gtype,geomID,0);} }; + template<> + struct MortonBuilder<8,InstanceArray,InstanceArrayPrimitive> { + MortonBuilder () {} + Builder* operator () (void* bvh, InstanceArray* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceArrayMeshBuilderMortonGeneral(bvh,mesh,gtype,geomID,0);} + }; template<int N, typename Mesh, typename Primitive> struct SAHBuilder {}; @@ -152,6 +169,11 @@ namespace embree Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshBuilderSAH(bvh,mesh,gtype,geomID,0);} }; template<> + struct SAHBuilder<4,InstanceArray,InstanceArrayPrimitive> { + SAHBuilder () {} + Builder* operator () (void* bvh, InstanceArray* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceArrayMeshBuilderSAH(bvh,mesh,gtype,geomID,0);} + }; + template<> struct SAHBuilder<8,TriangleMesh,Triangle4> { SAHBuilder () {} Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshBuilderSAH(bvh,mesh,geomID,0);} @@ -181,6 +203,11 @@ namespace embree SAHBuilder () {} Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshBuilderSAH(bvh,mesh,gtype,geomID,0);} }; + template<> + struct SAHBuilder<8,InstanceArray,InstanceArrayPrimitive> { + SAHBuilder () {} + Builder* operator () (void* bvh, InstanceArray* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceArrayMeshBuilderSAH(bvh,mesh,gtype,geomID,0);} + }; template<int N, typename Mesh, typename Primitive> struct RefitBuilder {}; @@ -215,6 +242,11 @@ namespace embree Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceMeshRefitSAH(bvh,mesh,gtype,geomID,0);} }; template<> + struct RefitBuilder<4,InstanceArray,InstanceArrayPrimitive> { + RefitBuilder () {} + Builder* operator () (void* bvh, InstanceArray* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH4InstanceArrayMeshRefitSAH(bvh,mesh,gtype,geomID,0);} + }; + template<> struct RefitBuilder<8,TriangleMesh,Triangle4> { RefitBuilder () {} Builder* operator () (void* bvh, TriangleMesh* mesh, size_t geomID, Geometry::GTypeMask /*gtype*/) { return BVH8Triangle4MeshRefitSAH(bvh,mesh,geomID,0);} @@ -244,7 +276,12 @@ namespace embree RefitBuilder () {} Builder* operator () (void* bvh, Instance* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceMeshRefitSAH(bvh,mesh,gtype,geomID,0);} }; - + template<> + struct RefitBuilder<8,InstanceArray,InstanceArrayPrimitive> { + RefitBuilder () {} + Builder* operator () (void* bvh, InstanceArray* mesh, size_t geomID, Geometry::GTypeMask gtype) { return BVH8InstanceArrayMeshRefitSAH(bvh,mesh,gtype,geomID,0);} + }; + template<int N, typename Mesh, typename Primitive> struct MeshBuilder { MeshBuilder () {} diff --git a/thirdparty/embree/kernels/bvh/bvh_collider.cpp b/thirdparty/embree/kernels/bvh/bvh_collider.cpp index 9428c0b88e..a22d701827 100644 --- a/thirdparty/embree/kernels/bvh/bvh_collider.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_collider.cpp @@ -2,7 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 #include "bvh_collider.h" + #include "../geometry/triangle_triangle_intersector.h" +#include "../../common/algorithms/parallel_for.h" namespace embree { diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector1.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector1.cpp index 9594f402c3..1d797df88f 100644 --- a/thirdparty/embree/kernels/bvh/bvh_intersector1.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_intersector1.cpp @@ -19,6 +19,7 @@ #include "../geometry/subdivpatch1_intersector.h" #include "../geometry/object_intersector.h" #include "../geometry/instance_intersector.h" +#include "../geometry/instance_array_intersector.h" #include "../geometry/subgrid_intersector.h" #include "../geometry/subgrid_mb_intersector.h" #include "../geometry/curve_intersector_virtual.h" @@ -30,7 +31,7 @@ namespace embree template<int N, int types, bool robust, typename PrimitiveIntersector1> void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::intersect(const Accel::Intersectors* __restrict__ This, RayHit& __restrict__ ray, - IntersectContext* __restrict__ context) + RayQueryContext* __restrict__ context) { const BVH* __restrict__ bvh = (const BVH*)This->ptr; @@ -115,7 +116,7 @@ namespace embree template<int N, int types, bool robust, typename PrimitiveIntersector1> void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::occluded(const Accel::Intersectors* __restrict__ This, Ray& __restrict__ ray, - IntersectContext* __restrict__ context) + RayQueryContext* __restrict__ context) { const BVH* __restrict__ bvh = (const BVH*)This->ptr; diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector1.h b/thirdparty/embree/kernels/bvh/bvh_intersector1.h index 2df3d6eddb..3cec4e113b 100644 --- a/thirdparty/embree/kernels/bvh/bvh_intersector1.h +++ b/thirdparty/embree/kernels/bvh/bvh_intersector1.h @@ -26,8 +26,8 @@ namespace embree static const size_t stackSize = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store public: - static void intersect (const Accel::Intersectors* This, RayHit& ray, IntersectContext* context); - static void occluded (const Accel::Intersectors* This, Ray& ray, IntersectContext* context); + static void intersect (const Accel::Intersectors* This, RayHit& ray, RayQueryContext* context); + static void occluded (const Accel::Intersectors* This, Ray& ray, RayQueryContext* context); static bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context); }; } diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector1_bvh4.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector1_bvh4.cpp index 831d613367..1baecc7bbc 100644 --- a/thirdparty/embree/kernels/bvh/bvh_intersector1_bvh4.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_intersector1_bvh4.cpp @@ -48,6 +48,9 @@ namespace embree IF_ENABLED_INSTANCE(DEFINE_INTERSECTOR1(BVH4InstanceIntersector1,BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<InstanceIntersector1> >)); IF_ENABLED_INSTANCE(DEFINE_INTERSECTOR1(BVH4InstanceMBIntersector1,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<InstanceIntersector1MB> >)); + IF_ENABLED_INSTANCE_ARRAY(DEFINE_INTERSECTOR1(BVH4InstanceArrayIntersector1,BVHNIntersector1<4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersector1<InstanceArrayIntersector1> >)); + IF_ENABLED_INSTANCE_ARRAY(DEFINE_INTERSECTOR1(BVH4InstanceArrayMBIntersector1,BVHNIntersector1<4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersector1<InstanceArrayIntersector1MB> >)); + IF_ENABLED_TRIS(DEFINE_INTERSECTOR1(QBVH4Triangle4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_QN1 COMMA false COMMA ArrayIntersector1<TriangleMiIntersector1Pluecker<4 COMMA true> > >)); IF_ENABLED_QUADS(DEFINE_INTERSECTOR1(QBVH4Quad4iIntersector1Pluecker,BVHNIntersector1<4 COMMA BVH_QN1 COMMA false COMMA ArrayIntersector1<QuadMiIntersector1Pluecker<4 COMMA true> > >)); diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.cpp index 1d393fd06b..e9e2262984 100644 --- a/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.cpp @@ -20,6 +20,7 @@ #include "../geometry/subdivpatch1_intersector.h" #include "../geometry/object_intersector.h" #include "../geometry/instance_intersector.h" +#include "../geometry/instance_array_intersector.h" #include "../geometry/subgrid_intersector.h" #include "../geometry/subgrid_mb_intersector.h" #include "../geometry/curve_intersector_virtual.h" @@ -41,7 +42,7 @@ namespace embree Precalculations& pre, RayHitK<K>& ray, const TravRayK<K, robust>& tray, - IntersectContext* context) + RayQueryContext* context) { /* stack state */ StackItemT<NodeRef> stack[stackSizeSingle]; // stack of nodes @@ -105,7 +106,7 @@ namespace embree void BVHNIntersectorKHybrid<N, K, types, robust, PrimitiveIntersectorK, single>::intersect(vint<K>* __restrict__ valid_i, Accel::Intersectors* __restrict__ This, RayHitK<K>& __restrict__ ray, - IntersectContext* __restrict__ context) + RayQueryContext* __restrict__ context) { BVH* __restrict__ bvh = (BVH*)This->ptr; @@ -373,7 +374,7 @@ namespace embree void BVHNIntersectorKHybrid<N, K, types, robust, PrimitiveIntersectorK, single>::intersectCoherent(vint<K>* __restrict__ valid_i, Accel::Intersectors* __restrict__ This, RayHitK<K>& __restrict__ ray, - IntersectContext* context) + RayQueryContext* context) { BVH* __restrict__ bvh = (BVH*)This->ptr; @@ -539,7 +540,7 @@ namespace embree Precalculations& pre, RayK<K>& ray, const TravRayK<K, robust>& tray, - IntersectContext* context) + RayQueryContext* context) { /* stack state */ NodeRef stack[stackSizeSingle]; // stack of nodes that still need to get traversed @@ -599,7 +600,7 @@ namespace embree void BVHNIntersectorKHybrid<N, K, types, robust, PrimitiveIntersectorK, single>::occluded(vint<K>* __restrict__ valid_i, Accel::Intersectors* __restrict__ This, RayK<K>& __restrict__ ray, - IntersectContext* context) + RayQueryContext* context) { BVH* __restrict__ bvh = (BVH*)This->ptr; @@ -784,7 +785,7 @@ namespace embree void BVHNIntersectorKHybrid<N, K, types, robust, PrimitiveIntersectorK, single>::occludedCoherent(vint<K>* __restrict__ valid_i, Accel::Intersectors* __restrict__ This, RayK<K>& __restrict__ ray, - IntersectContext* context) + RayQueryContext* context) { BVH* __restrict__ bvh = (BVH*)This->ptr; @@ -861,7 +862,7 @@ namespace embree #if defined(__AVX__) //STAT3(normal.trav_hit_boxes[popcnt(m_frustum_node)], 1, 1, 1); #endif - size_t num_child_hits = 0; + //size_t num_child_hits = 0; do { const size_t i = bscf(m_frustum_node); vfloat<K> lnearP; @@ -875,7 +876,7 @@ namespace embree assert(child != BVH::emptyNode); BVHN<N>::prefetch(child); if (likely(cur != BVH::emptyNode)) { - num_child_hits++; + //num_child_hits++; stackPtr->ptr = cur; stackPtr->mask = m_active; stackPtr++; diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.h b/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.h index 50ebf375c4..1240bd5ab5 100644 --- a/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.h +++ b/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid.h @@ -38,16 +38,16 @@ namespace embree private: static void intersect1(Accel::Intersectors* This, const BVH* bvh, NodeRef root, size_t k, Precalculations& pre, - RayHitK<K>& ray, const TravRayK<K, robust>& tray, IntersectContext* context); + RayHitK<K>& ray, const TravRayK<K, robust>& tray, RayQueryContext* context); static bool occluded1(Accel::Intersectors* This, const BVH* bvh, NodeRef root, size_t k, Precalculations& pre, - RayK<K>& ray, const TravRayK<K, robust>& tray, IntersectContext* context); + RayK<K>& ray, const TravRayK<K, robust>& tray, RayQueryContext* context); public: - static void intersect(vint<K>* valid, Accel::Intersectors* This, RayHitK<K>& ray, IntersectContext* context); - static void occluded (vint<K>* valid, Accel::Intersectors* This, RayK<K>& ray, IntersectContext* context); + static void intersect(vint<K>* valid, Accel::Intersectors* This, RayHitK<K>& ray, RayQueryContext* context); + static void occluded (vint<K>* valid, Accel::Intersectors* This, RayK<K>& ray, RayQueryContext* context); - static void intersectCoherent(vint<K>* valid, Accel::Intersectors* This, RayHitK<K>& ray, IntersectContext* context); - static void occludedCoherent (vint<K>* valid, Accel::Intersectors* This, RayK<K>& ray, IntersectContext* context); + static void intersectCoherent(vint<K>* valid, Accel::Intersectors* This, RayHitK<K>& ray, RayQueryContext* context); + static void occludedCoherent (vint<K>* valid, Accel::Intersectors* This, RayK<K>& ray, RayQueryContext* context); }; diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid4_bvh4.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid4_bvh4.cpp index 2137da6a25..72cefa9e8e 100644 --- a/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid4_bvh4.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_intersector_hybrid4_bvh4.cpp @@ -48,6 +48,9 @@ namespace embree IF_ENABLED_INSTANCE(DEFINE_INTERSECTOR4(BVH4InstanceIntersector4Chunk, BVHNIntersectorKChunk<4 COMMA 4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersectorK_1<4 COMMA InstanceIntersectorK<4>> >)); IF_ENABLED_INSTANCE(DEFINE_INTERSECTOR4(BVH4InstanceMBIntersector4Chunk, BVHNIntersectorKChunk<4 COMMA 4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersectorK_1<4 COMMA InstanceIntersectorKMB<4>> >)); + IF_ENABLED_INSTANCE_ARRAY(DEFINE_INTERSECTOR4(BVH4InstanceArrayIntersector4Chunk, BVHNIntersectorKChunk<4 COMMA 4 COMMA BVH_AN1 COMMA false COMMA ArrayIntersectorK_1<4 COMMA InstanceArrayIntersectorK<4>> >)); + IF_ENABLED_INSTANCE_ARRAY(DEFINE_INTERSECTOR4(BVH4InstanceArrayMBIntersector4Chunk, BVHNIntersectorKChunk<4 COMMA 4 COMMA BVH_AN2_AN4D COMMA false COMMA ArrayIntersectorK_1<4 COMMA InstanceArrayIntersectorKMB<4>> >)); + IF_ENABLED_GRIDS(DEFINE_INTERSECTOR4(BVH4GridIntersector4HybridMoeller, BVHNIntersectorKHybrid<4 COMMA 4 COMMA BVH_AN1 COMMA false COMMA SubGridIntersectorKMoeller <4 COMMA 4 COMMA true> >)); //IF_ENABLED_GRIDS(DEFINE_INTERSECTOR4(BVH4GridIntersector4HybridMoeller, BVHNIntersectorKChunk<4 COMMA 4 COMMA BVH_AN1 COMMA false COMMA SubGridIntersectorKMoeller <4 COMMA 4 COMMA true> >)); diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_stream.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector_stream.cpp deleted file mode 100644 index 4a74d8468d..0000000000 --- a/thirdparty/embree/kernels/bvh/bvh_intersector_stream.cpp +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#include "bvh_intersector_stream.h" - -#include "../geometry/intersector_iterators.h" -#include "../geometry/triangle_intersector.h" -#include "../geometry/trianglev_intersector.h" -#include "../geometry/trianglev_mb_intersector.h" -#include "../geometry/trianglei_intersector.h" -#include "../geometry/quadv_intersector.h" -#include "../geometry/quadi_intersector.h" -#include "../geometry/linei_intersector.h" -#include "../geometry/subdivpatch1_intersector.h" -#include "../geometry/object_intersector.h" -#include "../geometry/instance_intersector.h" - -#include "../common/scene.h" -#include <bitset> - -namespace embree -{ - namespace isa - { - __aligned(64) static const int shiftTable[32] = { - (int)1 << 0, (int)1 << 1, (int)1 << 2, (int)1 << 3, (int)1 << 4, (int)1 << 5, (int)1 << 6, (int)1 << 7, - (int)1 << 8, (int)1 << 9, (int)1 << 10, (int)1 << 11, (int)1 << 12, (int)1 << 13, (int)1 << 14, (int)1 << 15, - (int)1 << 16, (int)1 << 17, (int)1 << 18, (int)1 << 19, (int)1 << 20, (int)1 << 21, (int)1 << 22, (int)1 << 23, - (int)1 << 24, (int)1 << 25, (int)1 << 26, (int)1 << 27, (int)1 << 28, (int)1 << 29, (int)1 << 30, (int)1 << 31 - }; - - template<int N, int types, bool robust, typename PrimitiveIntersector> - __forceinline void BVHNIntersectorStream<N, types, robust, PrimitiveIntersector>::intersect(Accel::Intersectors* __restrict__ This, - RayHitN** inputPackets, - size_t numOctantRays, - IntersectContext* context) - { - /* we may traverse an empty BVH in case all geometry was invalid */ - BVH* __restrict__ bvh = (BVH*) This->ptr; - if (bvh->root == BVH::emptyNode) - return; - - // Only the coherent code path is implemented - assert(context->isCoherent()); - intersectCoherent(This, (RayHitK<VSIZEL>**)inputPackets, numOctantRays, context); - } - - template<int N, int types, bool robust, typename PrimitiveIntersector> - template<int K> - __forceinline void BVHNIntersectorStream<N, types, robust, PrimitiveIntersector>::intersectCoherent(Accel::Intersectors* __restrict__ This, - RayHitK<K>** inputPackets, - size_t numOctantRays, - IntersectContext* context) - { - assert(context->isCoherent()); - - BVH* __restrict__ bvh = (BVH*) This->ptr; - __aligned(64) StackItemMaskCoherent stack[stackSizeSingle]; // stack of nodes - assert(numOctantRays <= MAX_INTERNAL_STREAM_SIZE); - - __aligned(64) TravRayKStream<K, robust> packets[MAX_INTERNAL_STREAM_SIZE/K]; - __aligned(64) Frustum<robust> frustum; - - bool commonOctant = true; - const size_t m_active = initPacketsAndFrustum((RayK<K>**)inputPackets, numOctantRays, packets, frustum, commonOctant); - if (unlikely(m_active == 0)) return; - - /* case of non-common origin */ - if (unlikely(!commonOctant)) - { - const size_t numPackets = (numOctantRays+K-1)/K; - for (size_t i = 0; i < numPackets; i++) - This->intersect(inputPackets[i]->tnear() <= inputPackets[i]->tfar, *inputPackets[i], context); - return; - } - - stack[0].mask = m_active; - stack[0].parent = 0; - stack[0].child = bvh->root; - - /////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////// - - StackItemMaskCoherent* stackPtr = stack + 1; - - while (1) pop: - { - if (unlikely(stackPtr == stack)) break; - - STAT3(normal.trav_stack_pop,1,1,1); - stackPtr--; - /*! pop next node */ - NodeRef cur = NodeRef(stackPtr->child); - size_t m_trav_active = stackPtr->mask; - assert(m_trav_active); - NodeRef parent = stackPtr->parent; - - while (1) - { - if (unlikely(cur.isLeaf())) break; - const AABBNode* __restrict__ const node = cur.getAABBNode(); - parent = cur; - - __aligned(64) size_t maskK[N]; - for (size_t i = 0; i < N; i++) - maskK[i] = m_trav_active; - vfloat<N> dist; - const size_t m_node_hit = traverseCoherentStream(m_trav_active, packets, node, frustum, maskK, dist); - if (unlikely(m_node_hit == 0)) goto pop; - - BVHNNodeTraverserStreamHitCoherent<N, types>::traverseClosestHit(cur, m_trav_active, vbool<N>((int)m_node_hit), dist, (size_t*)maskK, stackPtr); - assert(m_trav_active); - } - - /* non-root and leaf => full culling test for all rays */ - if (unlikely(parent != 0 && cur.isLeaf())) - { - const AABBNode* __restrict__ const node = parent.getAABBNode(); - size_t boxID = 0xff; - for (size_t i = 0; i < N; i++) - if (node->child(i) == cur) { boxID = i; break; } - assert(boxID < N); - assert(cur == node->child(boxID)); - m_trav_active = intersectAABBNodePacket(m_trav_active, packets, node, boxID, frustum.nf); - } - - /*! this is a leaf node */ - assert(cur != BVH::emptyNode); - STAT3(normal.trav_leaves, 1, 1, 1); - size_t num; PrimitiveK<K>* prim = (PrimitiveK<K>*)cur.leaf(num); - - size_t bits = m_trav_active; - - /*! intersect stream of rays with all primitives */ - size_t lazy_node = 0; -#if defined(__SSE4_2__) - STAT_USER(1,(popcnt(bits)+K-1)/K*4); -#endif - while(bits) - { - size_t i = bsf(bits) / K; - const size_t m_isec = ((((size_t)1 << K)-1) << (i*K)); - assert(m_isec & bits); - bits &= ~m_isec; - - TravRayKStream<K, robust>& p = packets[i]; - vbool<K> m_valid = p.tnear <= p.tfar; - PrimitiveIntersectorK<K>::intersectK(m_valid, This, *inputPackets[i], context, prim, num, lazy_node); - p.tfar = min(p.tfar, inputPackets[i]->tfar); - }; - - } // traversal + intersection - } - - template<int N, int types, bool robust, typename PrimitiveIntersector> - __forceinline void BVHNIntersectorStream<N, types, robust, PrimitiveIntersector>::occluded(Accel::Intersectors* __restrict__ This, - RayN** inputPackets, - size_t numOctantRays, - IntersectContext* context) - { - /* we may traverse an empty BVH in case all geometry was invalid */ - BVH* __restrict__ bvh = (BVH*) This->ptr; - if (bvh->root == BVH::emptyNode) - return; - - if (unlikely(context->isCoherent())) - occludedCoherent(This, (RayK<VSIZEL>**)inputPackets, numOctantRays, context); - else - occludedIncoherent(This, (RayK<VSIZEX>**)inputPackets, numOctantRays, context); - } - - template<int N, int types, bool robust, typename PrimitiveIntersector> - template<int K> - __noinline void BVHNIntersectorStream<N, types, robust, PrimitiveIntersector>::occludedCoherent(Accel::Intersectors* __restrict__ This, - RayK<K>** inputPackets, - size_t numOctantRays, - IntersectContext* context) - { - assert(context->isCoherent()); - - BVH* __restrict__ bvh = (BVH*)This->ptr; - __aligned(64) StackItemMaskCoherent stack[stackSizeSingle]; // stack of nodes - assert(numOctantRays <= MAX_INTERNAL_STREAM_SIZE); - - /* inactive rays should have been filtered out before */ - __aligned(64) TravRayKStream<K, robust> packets[MAX_INTERNAL_STREAM_SIZE/K]; - __aligned(64) Frustum<robust> frustum; - - bool commonOctant = true; - size_t m_active = initPacketsAndFrustum(inputPackets, numOctantRays, packets, frustum, commonOctant); - - /* valid rays */ - if (unlikely(m_active == 0)) return; - - /* case of non-common origin */ - if (unlikely(!commonOctant)) - { - const size_t numPackets = (numOctantRays+K-1)/K; - for (size_t i = 0; i < numPackets; i++) - This->occluded(inputPackets[i]->tnear() <= inputPackets[i]->tfar, *inputPackets[i], context); - return; - } - - stack[0].mask = m_active; - stack[0].parent = 0; - stack[0].child = bvh->root; - - /////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////// - /////////////////////////////////////////////////////////////////////////////////// - - StackItemMaskCoherent* stackPtr = stack + 1; - - while (1) pop: - { - if (unlikely(stackPtr == stack)) break; - - STAT3(normal.trav_stack_pop,1,1,1); - stackPtr--; - /*! pop next node */ - NodeRef cur = NodeRef(stackPtr->child); - size_t m_trav_active = stackPtr->mask & m_active; - if (unlikely(!m_trav_active)) continue; - assert(m_trav_active); - NodeRef parent = stackPtr->parent; - - while (1) - { - if (unlikely(cur.isLeaf())) break; - const AABBNode* __restrict__ const node = cur.getAABBNode(); - parent = cur; - - __aligned(64) size_t maskK[N]; - for (size_t i = 0; i < N; i++) - maskK[i] = m_trav_active; - - vfloat<N> dist; - const size_t m_node_hit = traverseCoherentStream(m_trav_active, packets, node, frustum, maskK, dist); - if (unlikely(m_node_hit == 0)) goto pop; - - BVHNNodeTraverserStreamHitCoherent<N, types>::traverseAnyHit(cur, m_trav_active, vbool<N>((int)m_node_hit), (size_t*)maskK, stackPtr); - assert(m_trav_active); - } - - /* non-root and leaf => full culling test for all rays */ - if (unlikely(parent != 0 && cur.isLeaf())) - { - const AABBNode* __restrict__ const node = parent.getAABBNode(); - size_t boxID = 0xff; - for (size_t i = 0; i < N; i++) - if (node->child(i) == cur) { boxID = i; break; } - assert(boxID < N); - assert(cur == node->child(boxID)); - m_trav_active = intersectAABBNodePacket(m_trav_active, packets, node, boxID, frustum.nf); - } - - /*! this is a leaf node */ - assert(cur != BVH::emptyNode); - STAT3(normal.trav_leaves, 1, 1, 1); - size_t num; PrimitiveK<K>* prim = (PrimitiveK<K>*)cur.leaf(num); - - size_t bits = m_trav_active & m_active; - /*! intersect stream of rays with all primitives */ - size_t lazy_node = 0; -#if defined(__SSE4_2__) - STAT_USER(1,(popcnt(bits)+K-1)/K*4); -#endif - while (bits) - { - size_t i = bsf(bits) / K; - const size_t m_isec = ((((size_t)1 << K)-1) << (i*K)); - assert(m_isec & bits); - bits &= ~m_isec; - TravRayKStream<K, robust>& p = packets[i]; - vbool<K> m_valid = p.tnear <= p.tfar; - vbool<K> m_hit = PrimitiveIntersectorK<K>::occludedK(m_valid, This, *inputPackets[i], context, prim, num, lazy_node); - inputPackets[i]->tfar = select(m_hit & m_valid, vfloat<K>(neg_inf), inputPackets[i]->tfar); - m_active &= ~((size_t)movemask(m_hit) << (i*K)); - } - - } // traversal + intersection - } - - - template<int N, int types, bool robust, typename PrimitiveIntersector> - template<int K> - __forceinline void BVHNIntersectorStream<N, types, robust, PrimitiveIntersector>::occludedIncoherent(Accel::Intersectors* __restrict__ This, - RayK<K>** inputPackets, - size_t numOctantRays, - IntersectContext* context) - { - assert(!context->isCoherent()); - assert(types & BVH_FLAG_ALIGNED_NODE); - - __aligned(64) TravRayKStream<K,robust> packet[MAX_INTERNAL_STREAM_SIZE/K]; - - assert(numOctantRays <= 32); - const size_t numPackets = (numOctantRays+K-1)/K; - size_t m_active = 0; - for (size_t i = 0; i < numPackets; i++) - { - const vfloat<K> tnear = inputPackets[i]->tnear(); - const vfloat<K> tfar = inputPackets[i]->tfar; - vbool<K> m_valid = (tnear <= tfar) & (tnear >= 0.0f); - m_active |= (size_t)movemask(m_valid) << (K*i); - const Vec3vf<K>& org = inputPackets[i]->org; - const Vec3vf<K>& dir = inputPackets[i]->dir; - vfloat<K> packet_min_dist = max(tnear, 0.0f); - vfloat<K> packet_max_dist = select(m_valid, tfar, neg_inf); - new (&packet[i]) TravRayKStream<K,robust>(org, dir, packet_min_dist, packet_max_dist); - } - - BVH* __restrict__ bvh = (BVH*)This->ptr; - - StackItemMaskT<NodeRef> stack[stackSizeSingle]; // stack of nodes - StackItemMaskT<NodeRef>* stackPtr = stack + 1; // current stack pointer - stack[0].ptr = bvh->root; - stack[0].mask = m_active; - - size_t terminated = ~m_active; - - /* near/far offsets based on first ray */ - const NearFarPrecalculations nf(Vec3fa(packet[0].rdir.x[0], packet[0].rdir.y[0], packet[0].rdir.z[0]), N); - - while (1) pop: - { - if (unlikely(stackPtr == stack)) break; - STAT3(shadow.trav_stack_pop,1,1,1); - stackPtr--; - NodeRef cur = NodeRef(stackPtr->ptr); - size_t cur_mask = stackPtr->mask & (~terminated); - if (unlikely(cur_mask == 0)) continue; - - while (true) - { - /*! stop if we found a leaf node */ - if (unlikely(cur.isLeaf())) break; - const AABBNode* __restrict__ const node = cur.getAABBNode(); - - const vint<N> vmask = traverseIncoherentStream(cur_mask, packet, node, nf, shiftTable); - - size_t mask = movemask(vmask != vint<N>(zero)); - if (unlikely(mask == 0)) goto pop; - - __aligned(64) unsigned int child_mask[N]; - vint<N>::storeu(child_mask, vmask); // this explicit store here causes much better code generation - - /*! one child is hit, continue with that child */ - size_t r = bscf(mask); - assert(r < N); - cur = node->child(r); - BVHN<N>::prefetch(cur,types); - cur_mask = child_mask[r]; - - /* simple in order sequence */ - assert(cur != BVH::emptyNode); - if (likely(mask == 0)) continue; - stackPtr->ptr = cur; - stackPtr->mask = cur_mask; - stackPtr++; - - for (; ;) - { - r = bscf(mask); - assert(r < N); - - cur = node->child(r); - BVHN<N>::prefetch(cur,types); - cur_mask = child_mask[r]; - assert(cur != BVH::emptyNode); - if (likely(mask == 0)) break; - stackPtr->ptr = cur; - stackPtr->mask = cur_mask; - stackPtr++; - } - } - - /*! this is a leaf node */ - assert(cur != BVH::emptyNode); - STAT3(shadow.trav_leaves,1,1,1); - size_t num; PrimitiveK<K>* prim = (PrimitiveK<K>*)cur.leaf(num); - - size_t bits = cur_mask; - size_t lazy_node = 0; - - for (; bits != 0;) - { - const size_t rayID = bscf(bits); - - RayK<K> &ray = *inputPackets[rayID / K]; - const size_t k = rayID % K; - if (PrimitiveIntersectorK<K>::occluded(This, ray, k, context, prim, num, lazy_node)) - { - ray.tfar[k] = neg_inf; - terminated |= (size_t)1 << rayID; - } - - /* lazy node */ - if (unlikely(lazy_node)) - { - stackPtr->ptr = lazy_node; - stackPtr->mask = cur_mask; - stackPtr++; - } - } - - if (unlikely(terminated == (size_t)-1)) break; - } - } - - //////////////////////////////////////////////////////////////////////////////// - /// ArrayIntersectorKStream Definitions - //////////////////////////////////////////////////////////////////////////////// - - template<bool filter> - struct Triangle4IntersectorStreamMoeller { - template<int K> using Type = ArrayIntersectorKStream<K,TriangleMIntersectorKMoeller<4 COMMA K COMMA true>>; - }; - - template<bool filter> - struct Triangle4vIntersectorStreamPluecker { - template<int K> using Type = ArrayIntersectorKStream<K,TriangleMvIntersectorKPluecker<4 COMMA K COMMA true>>; - }; - - template<bool filter> - struct Triangle4iIntersectorStreamMoeller { - template<int K> using Type = ArrayIntersectorKStream<K,TriangleMiIntersectorKMoeller<4 COMMA K COMMA true>>; - }; - - template<bool filter> - struct Triangle4iIntersectorStreamPluecker { - template<int K> using Type = ArrayIntersectorKStream<K,TriangleMiIntersectorKPluecker<4 COMMA K COMMA true>>; - }; - - template<bool filter> - struct Quad4vIntersectorStreamMoeller { - template<int K> using Type = ArrayIntersectorKStream<K,QuadMvIntersectorKMoeller<4 COMMA K COMMA true>>; - }; - - template<bool filter> - struct Quad4iIntersectorStreamMoeller { - template<int K> using Type = ArrayIntersectorKStream<K,QuadMiIntersectorKMoeller<4 COMMA K COMMA true>>; - }; - - template<bool filter> - struct Quad4vIntersectorStreamPluecker { - template<int K> using Type = ArrayIntersectorKStream<K,QuadMvIntersectorKPluecker<4 COMMA K COMMA true>>; - }; - - template<bool filter> - struct Quad4iIntersectorStreamPluecker { - template<int K> using Type = ArrayIntersectorKStream<K,QuadMiIntersectorKPluecker<4 COMMA K COMMA true>>; - }; - - struct ObjectIntersectorStream { - template<int K> using Type = ArrayIntersectorKStream<K,ObjectIntersectorK<K COMMA false>>; - }; - - struct InstanceIntersectorStream { - template<int K> using Type = ArrayIntersectorKStream<K,InstanceIntersectorK<K>>; - }; - - // ===================================================================================================== - // ===================================================================================================== - // ===================================================================================================== - - template<int N> - void BVHNIntersectorStreamPacketFallback<N>::intersect(Accel::Intersectors* __restrict__ This, - RayHitN** inputRays, - size_t numTotalRays, - IntersectContext* context) - { - if (unlikely(context->isCoherent())) - intersectK(This, (RayHitK<VSIZEL>**)inputRays, numTotalRays, context); - else - intersectK(This, (RayHitK<VSIZEX>**)inputRays, numTotalRays, context); - } - - template<int N> - void BVHNIntersectorStreamPacketFallback<N>::occluded(Accel::Intersectors* __restrict__ This, - RayN** inputRays, - size_t numTotalRays, - IntersectContext* context) - { - if (unlikely(context->isCoherent())) - occludedK(This, (RayK<VSIZEL>**)inputRays, numTotalRays, context); - else - occludedK(This, (RayK<VSIZEX>**)inputRays, numTotalRays, context); - } - - template<int N> - template<int K> - __noinline void BVHNIntersectorStreamPacketFallback<N>::intersectK(Accel::Intersectors* __restrict__ This, - RayHitK<K>** inputRays, - size_t numTotalRays, - IntersectContext* context) - { - /* fallback to packets */ - for (size_t i = 0; i < numTotalRays; i += K) - { - const vint<K> vi = vint<K>(int(i)) + vint<K>(step); - vbool<K> valid = vi < vint<K>(int(numTotalRays)); - RayHitK<K>& ray = *(inputRays[i / K]); - valid &= ray.tnear() <= ray.tfar; - This->intersect(valid, ray, context); - } - } - - template<int N> - template<int K> - __noinline void BVHNIntersectorStreamPacketFallback<N>::occludedK(Accel::Intersectors* __restrict__ This, - RayK<K>** inputRays, - size_t numTotalRays, - IntersectContext* context) - { - /* fallback to packets */ - for (size_t i = 0; i < numTotalRays; i += K) - { - const vint<K> vi = vint<K>(int(i)) + vint<K>(step); - vbool<K> valid = vi < vint<K>(int(numTotalRays)); - RayK<K>& ray = *(inputRays[i / K]); - valid &= ray.tnear() <= ray.tfar; - This->occluded(valid, ray, context); - } - } - } -} diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_stream.h b/thirdparty/embree/kernels/bvh/bvh_intersector_stream.h deleted file mode 100644 index c7e040fadb..0000000000 --- a/thirdparty/embree/kernels/bvh/bvh_intersector_stream.h +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "node_intersector_packet_stream.h" -#include "node_intersector_frustum.h" -#include "bvh_traverser_stream.h" - -namespace embree -{ - namespace isa - { - /*! BVH ray stream intersector. */ - template<int N, int types, bool robust, typename PrimitiveIntersector> - class BVHNIntersectorStream - { - /* shortcuts for frequently used types */ - template<int K> using PrimitiveIntersectorK = typename PrimitiveIntersector::template Type<K>; - template<int K> using PrimitiveK = typename PrimitiveIntersectorK<K>::PrimitiveK; - typedef BVHN<N> BVH; - typedef typename BVH::NodeRef NodeRef; - typedef typename BVH::BaseNode BaseNode; - typedef typename BVH::AABBNode AABBNode; - typedef typename BVH::AABBNodeMB AABBNodeMB; - - template<int K> - __forceinline static size_t initPacketsAndFrustum(RayK<K>** inputPackets, size_t numOctantRays, - TravRayKStream<K, robust>* packets, Frustum<robust>& frustum, bool& commonOctant) - { - const size_t numPackets = (numOctantRays+K-1)/K; - - Vec3vf<K> tmp_min_rdir(pos_inf); - Vec3vf<K> tmp_max_rdir(neg_inf); - Vec3vf<K> tmp_min_org(pos_inf); - Vec3vf<K> tmp_max_org(neg_inf); - vfloat<K> tmp_min_dist(pos_inf); - vfloat<K> tmp_max_dist(neg_inf); - - size_t m_active = 0; - for (size_t i = 0; i < numPackets; i++) - { - const vfloat<K> tnear = inputPackets[i]->tnear(); - const vfloat<K> tfar = inputPackets[i]->tfar; - vbool<K> m_valid = (tnear <= tfar) & (tnear >= 0.0f); - -#if defined(EMBREE_IGNORE_INVALID_RAYS) - m_valid &= inputPackets[i]->valid(); -#endif - - m_active |= (size_t)movemask(m_valid) << (i*K); - - vfloat<K> packet_min_dist = max(tnear, 0.0f); - vfloat<K> packet_max_dist = select(m_valid, tfar, neg_inf); - tmp_min_dist = min(tmp_min_dist, packet_min_dist); - tmp_max_dist = max(tmp_max_dist, packet_max_dist); - - const Vec3vf<K>& org = inputPackets[i]->org; - const Vec3vf<K>& dir = inputPackets[i]->dir; - - new (&packets[i]) TravRayKStream<K, robust>(org, dir, packet_min_dist, packet_max_dist); - - tmp_min_rdir = min(tmp_min_rdir, select(m_valid, packets[i].rdir, Vec3vf<K>(pos_inf))); - tmp_max_rdir = max(tmp_max_rdir, select(m_valid, packets[i].rdir, Vec3vf<K>(neg_inf))); - tmp_min_org = min(tmp_min_org , select(m_valid,org , Vec3vf<K>(pos_inf))); - tmp_max_org = max(tmp_max_org , select(m_valid,org , Vec3vf<K>(neg_inf))); - } - - m_active &= (numOctantRays == (8 * sizeof(size_t))) ? (size_t)-1 : (((size_t)1 << numOctantRays)-1); - - - const Vec3fa reduced_min_rdir(reduce_min(tmp_min_rdir.x), - reduce_min(tmp_min_rdir.y), - reduce_min(tmp_min_rdir.z)); - - const Vec3fa reduced_max_rdir(reduce_max(tmp_max_rdir.x), - reduce_max(tmp_max_rdir.y), - reduce_max(tmp_max_rdir.z)); - - const Vec3fa reduced_min_origin(reduce_min(tmp_min_org.x), - reduce_min(tmp_min_org.y), - reduce_min(tmp_min_org.z)); - - const Vec3fa reduced_max_origin(reduce_max(tmp_max_org.x), - reduce_max(tmp_max_org.y), - reduce_max(tmp_max_org.z)); - - commonOctant = - (reduced_max_rdir.x < 0.0f || reduced_min_rdir.x >= 0.0f) && - (reduced_max_rdir.y < 0.0f || reduced_min_rdir.y >= 0.0f) && - (reduced_max_rdir.z < 0.0f || reduced_min_rdir.z >= 0.0f); - - const float frustum_min_dist = reduce_min(tmp_min_dist); - const float frustum_max_dist = reduce_max(tmp_max_dist); - - frustum.init(reduced_min_origin, reduced_max_origin, - reduced_min_rdir, reduced_max_rdir, - frustum_min_dist, frustum_max_dist, - N); - - return m_active; - } - - template<int K> - __forceinline static size_t intersectAABBNodePacket(size_t m_active, - const TravRayKStream<K,robust>* packets, - const AABBNode* __restrict__ node, - size_t boxID, - const NearFarPrecalculations& nf) - { - assert(m_active); - const size_t startPacketID = bsf(m_active) / K; - const size_t endPacketID = bsr(m_active) / K; - size_t m_trav_active = 0; - for (size_t i = startPacketID; i <= endPacketID; i++) - { - const size_t m_hit = intersectNodeK<N>(node, boxID, packets[i], nf); - m_trav_active |= m_hit << (i*K); - } - return m_trav_active; - } - - template<int K> - __forceinline static size_t traverseCoherentStream(size_t m_active, - TravRayKStream<K, robust>* packets, - const AABBNode* __restrict__ node, - const Frustum<robust>& frustum, - size_t* maskK, - vfloat<N>& dist) - { - size_t m_node_hit = intersectNodeFrustum<N>(node, frustum, dist); - const size_t first_index = bsf(m_active); - const size_t first_packetID = first_index / K; - const size_t first_rayID = first_index % K; - size_t m_first_hit = intersectNode1<N>(node, packets[first_packetID], first_rayID, frustum.nf); - - /* this make traversal independent of the ordering of rays */ - size_t m_node = m_node_hit ^ m_first_hit; - while (unlikely(m_node)) - { - const size_t boxID = bscf(m_node); - const size_t m_current = m_active & intersectAABBNodePacket(m_active, packets, node, boxID, frustum.nf); - m_node_hit ^= m_current ? (size_t)0 : ((size_t)1 << boxID); - maskK[boxID] = m_current; - } - return m_node_hit; - } - - // TODO: explicit 16-wide path for KNL - template<int K> - __forceinline static vint<N> traverseIncoherentStream(size_t m_active, - TravRayKStreamFast<K>* __restrict__ packets, - const AABBNode* __restrict__ node, - const NearFarPrecalculations& nf, - const int shiftTable[32]) - { - const vfloat<N> bminX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX)); - const vfloat<N> bminY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY)); - const vfloat<N> bminZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ)); - const vfloat<N> bmaxX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX)); - const vfloat<N> bmaxY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY)); - const vfloat<N> bmaxZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ)); - assert(m_active); - vint<N> vmask(zero); - do - { - STAT3(shadow.trav_nodes,1,1,1); - const size_t rayID = bscf(m_active); - assert(rayID < MAX_INTERNAL_STREAM_SIZE); - TravRayKStream<K,robust> &p = packets[rayID / K]; - const size_t i = rayID % K; - const vint<N> bitmask(shiftTable[rayID]); - -#if defined (__aarch64__) - const vfloat<N> tNearX = madd(bminX, p.rdir.x[i], p.neg_org_rdir.x[i]); - const vfloat<N> tNearY = madd(bminY, p.rdir.y[i], p.neg_org_rdir.y[i]); - const vfloat<N> tNearZ = madd(bminZ, p.rdir.z[i], p.neg_org_rdir.z[i]); - const vfloat<N> tFarX = madd(bmaxX, p.rdir.x[i], p.neg_org_rdir.x[i]); - const vfloat<N> tFarY = madd(bmaxY, p.rdir.y[i], p.neg_org_rdir.y[i]); - const vfloat<N> tFarZ = madd(bmaxZ, p.rdir.z[i], p.neg_org_rdir.z[i]); -#else - const vfloat<N> tNearX = msub(bminX, p.rdir.x[i], p.org_rdir.x[i]); - const vfloat<N> tNearY = msub(bminY, p.rdir.y[i], p.org_rdir.y[i]); - const vfloat<N> tNearZ = msub(bminZ, p.rdir.z[i], p.org_rdir.z[i]); - const vfloat<N> tFarX = msub(bmaxX, p.rdir.x[i], p.org_rdir.x[i]); - const vfloat<N> tFarY = msub(bmaxY, p.rdir.y[i], p.org_rdir.y[i]); - const vfloat<N> tFarZ = msub(bmaxZ, p.rdir.z[i], p.org_rdir.z[i]); -#endif - - const vfloat<N> tNear = maxi(tNearX, tNearY, tNearZ, vfloat<N>(p.tnear[i])); - const vfloat<N> tFar = mini(tFarX , tFarY , tFarZ, vfloat<N>(p.tfar[i])); - - const vbool<N> hit_mask = tNear <= tFar; -#if defined(__AVX2__) - vmask = vmask | (bitmask & vint<N>(hit_mask)); -#else - vmask = select(hit_mask, vmask | bitmask, vmask); -#endif - } while(m_active); - return vmask; - } - - template<int K> - __forceinline static vint<N> traverseIncoherentStream(size_t m_active, - TravRayKStreamRobust<K>* __restrict__ packets, - const AABBNode* __restrict__ node, - const NearFarPrecalculations& nf, - const int shiftTable[32]) - { - const vfloat<N> bminX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX)); - const vfloat<N> bminY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY)); - const vfloat<N> bminZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ)); - const vfloat<N> bmaxX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX)); - const vfloat<N> bmaxY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY)); - const vfloat<N> bmaxZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ)); - assert(m_active); - vint<N> vmask(zero); - do - { - STAT3(shadow.trav_nodes,1,1,1); - const size_t rayID = bscf(m_active); - assert(rayID < MAX_INTERNAL_STREAM_SIZE); - TravRayKStream<K,robust> &p = packets[rayID / K]; - const size_t i = rayID % K; - const vint<N> bitmask(shiftTable[rayID]); - const vfloat<N> tNearX = (bminX - p.org.x[i]) * p.rdir.x[i]; - const vfloat<N> tNearY = (bminY - p.org.y[i]) * p.rdir.y[i]; - const vfloat<N> tNearZ = (bminZ - p.org.z[i]) * p.rdir.z[i]; - const vfloat<N> tFarX = (bmaxX - p.org.x[i]) * p.rdir.x[i]; - const vfloat<N> tFarY = (bmaxY - p.org.y[i]) * p.rdir.y[i]; - const vfloat<N> tFarZ = (bmaxZ - p.org.z[i]) * p.rdir.z[i]; - const vfloat<N> tNear = maxi(tNearX, tNearY, tNearZ, vfloat<N>(p.tnear[i])); - const vfloat<N> tFar = mini(tFarX , tFarY , tFarZ, vfloat<N>(p.tfar[i])); - const float round_down = 1.0f-2.0f*float(ulp); - const float round_up = 1.0f+2.0f*float(ulp); - const vbool<N> hit_mask = round_down*tNear <= round_up*tFar; -#if defined(__AVX2__) - vmask = vmask | (bitmask & vint<N>(hit_mask)); -#else - vmask = select(hit_mask, vmask | bitmask, vmask); -#endif - } while(m_active); - return vmask; - } - - - static const size_t stackSizeSingle = 1+(N-1)*BVH::maxDepth; - - public: - static void intersect(Accel::Intersectors* This, RayHitN** inputRays, size_t numRays, IntersectContext* context); - static void occluded (Accel::Intersectors* This, RayN** inputRays, size_t numRays, IntersectContext* context); - - private: - template<int K> - static void intersectCoherent(Accel::Intersectors* This, RayHitK<K>** inputRays, size_t numRays, IntersectContext* context); - - template<int K> - static void occludedCoherent(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context); - - template<int K> - static void occludedIncoherent(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context); - }; - - - /*! BVH ray stream intersector with direct fallback to packets. */ - template<int N> - class BVHNIntersectorStreamPacketFallback - { - public: - static void intersect(Accel::Intersectors* This, RayHitN** inputRays, size_t numRays, IntersectContext* context); - static void occluded (Accel::Intersectors* This, RayN** inputRays, size_t numRays, IntersectContext* context); - - private: - template<int K> - static void intersectK(Accel::Intersectors* This, RayHitK<K>** inputRays, size_t numRays, IntersectContext* context); - - template<int K> - static void occludedK(Accel::Intersectors* This, RayK<K>** inputRays, size_t numRays, IntersectContext* context); - }; - } -} diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_stream_bvh4.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector_stream_bvh4.cpp deleted file mode 100644 index c3e5f137b8..0000000000 --- a/thirdparty/embree/kernels/bvh/bvh_intersector_stream_bvh4.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#include "bvh_intersector_stream.cpp" - -namespace embree -{ - namespace isa - { - - //////////////////////////////////////////////////////////////////////////////// - /// General BVHIntersectorStreamPacketFallback Intersector - //////////////////////////////////////////////////////////////////////////////// - - DEFINE_INTERSECTORN(BVH4IntersectorStreamPacketFallback,BVHNIntersectorStreamPacketFallback<4>); - - //////////////////////////////////////////////////////////////////////////////// - /// BVH4IntersectorStream Definitions - //////////////////////////////////////////////////////////////////////////////// - - IF_ENABLED_TRIS(DEFINE_INTERSECTORN(BVH4Triangle4iIntersectorStreamMoeller, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA false COMMA Triangle4iIntersectorStreamMoeller<true>>)); - IF_ENABLED_TRIS(DEFINE_INTERSECTORN(BVH4Triangle4vIntersectorStreamPluecker, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA true COMMA Triangle4vIntersectorStreamPluecker<true>>)); - IF_ENABLED_TRIS(DEFINE_INTERSECTORN(BVH4Triangle4iIntersectorStreamPluecker, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA true COMMA Triangle4iIntersectorStreamPluecker<true>>)); - IF_ENABLED_TRIS(DEFINE_INTERSECTORN(BVH4Triangle4IntersectorStreamMoeller, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA false COMMA Triangle4IntersectorStreamMoeller<true>>)); - IF_ENABLED_TRIS(DEFINE_INTERSECTORN(BVH4Triangle4IntersectorStreamMoellerNoFilter, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA false COMMA Triangle4IntersectorStreamMoeller<false>>)); - - IF_ENABLED_QUADS(DEFINE_INTERSECTORN(BVH4Quad4vIntersectorStreamMoeller, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA false COMMA Quad4vIntersectorStreamMoeller<true>>)); - IF_ENABLED_QUADS(DEFINE_INTERSECTORN(BVH4Quad4vIntersectorStreamMoellerNoFilter,BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA false COMMA Quad4vIntersectorStreamMoeller<false>>)); - IF_ENABLED_QUADS(DEFINE_INTERSECTORN(BVH4Quad4iIntersectorStreamMoeller, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA false COMMA Quad4iIntersectorStreamMoeller<true>>)); - IF_ENABLED_QUADS(DEFINE_INTERSECTORN(BVH4Quad4vIntersectorStreamPluecker, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA true COMMA Quad4vIntersectorStreamPluecker<true>>)); - IF_ENABLED_QUADS(DEFINE_INTERSECTORN(BVH4Quad4iIntersectorStreamPluecker, BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA true COMMA Quad4iIntersectorStreamPluecker<true>>)); - - IF_ENABLED_USER(DEFINE_INTERSECTORN(BVH4VirtualIntersectorStream,BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA false COMMA ObjectIntersectorStream>)); - IF_ENABLED_INSTANCE(DEFINE_INTERSECTORN(BVH4InstanceIntersectorStream,BVHNIntersectorStream<4 COMMA BVH_AN1 COMMA false COMMA InstanceIntersectorStream>)); - } -} diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.cpp b/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.cpp deleted file mode 100644 index b858eb163f..0000000000 --- a/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.cpp +++ /dev/null @@ -1,657 +0,0 @@ -// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#include "bvh_intersector_stream_filters.h" -#include "bvh_intersector_stream.h" - -namespace embree -{ - namespace isa - { - template<int K, bool intersect> - __noinline void RayStreamFilter::filterAOS(Scene* scene, void* _rayN, size_t N, size_t stride, IntersectContext* context) - { - RayStreamAOS rayN(_rayN); - - /* use fast path for coherent ray mode */ - if (unlikely(context->isCoherent())) - { - __aligned(64) RayTypeK<K, intersect> rays[MAX_INTERNAL_STREAM_SIZE / K]; - __aligned(64) RayTypeK<K, intersect>* rayPtrs[MAX_INTERNAL_STREAM_SIZE / K]; - - for (size_t i = 0; i < N; i += MAX_INTERNAL_STREAM_SIZE) - { - const size_t size = min(N - i, MAX_INTERNAL_STREAM_SIZE); - - /* convert from AOS to SOA */ - for (size_t j = 0; j < size; j += K) - { - const vint<K> vij = vint<K>(int(i+j)) + vint<K>(step); - const vbool<K> valid = vij < vint<K>(int(N)); - const vint<K> offset = vij * int(stride); - const size_t packetIndex = j / K; - - RayTypeK<K, intersect> ray = rayN.getRayByOffset<K>(valid, offset); - ray.tnear() = select(valid, ray.tnear(), zero); - ray.tfar = select(valid, ray.tfar, neg_inf); - - rays[packetIndex] = ray; - rayPtrs[packetIndex] = &rays[packetIndex]; // rayPtrs might get reordered for occludedN - } - - /* trace stream */ - scene->intersectors.intersectN(rayPtrs, size, context); - - /* convert from SOA to AOS */ - for (size_t j = 0; j < size; j += K) - { - const vint<K> vij = vint<K>(int(i+j)) + vint<K>(step); - const vbool<K> valid = vij < vint<K>(int(N)); - const vint<K> offset = vij * int(stride); - const size_t packetIndex = j / K; - rayN.setHitByOffset(valid, offset, rays[packetIndex]); - } - } - } - else if (unlikely(!intersect)) - { - /* octant sorting for occlusion rays */ - __aligned(64) unsigned int octants[8][MAX_INTERNAL_STREAM_SIZE]; - __aligned(64) RayK<K> rays[MAX_INTERNAL_STREAM_SIZE / K]; - __aligned(64) RayK<K>* rayPtrs[MAX_INTERNAL_STREAM_SIZE / K]; - - unsigned int raysInOctant[8]; - for (unsigned int i = 0; i < 8; i++) - raysInOctant[i] = 0; - size_t inputRayID = 0; - - for (;;) - { - int curOctant = -1; - - /* sort rays into octants */ - for (; inputRayID < N;) - { - const Ray& ray = rayN.getRayByOffset(inputRayID * stride); - - /* skip invalid rays */ - if (unlikely(ray.tnear() > ray.tfar || ray.tfar < 0.0f)) { inputRayID++; continue; } // ignore invalid or already occluded rays -#if defined(EMBREE_IGNORE_INVALID_RAYS) - if (unlikely(!ray.valid())) { inputRayID++; continue; } -#endif - - const unsigned int octantID = movemask(vfloat4(Vec3fa(ray.dir)) < 0.0f) & 0x7; - - assert(octantID < 8); - octants[octantID][raysInOctant[octantID]++] = (unsigned int)inputRayID; - inputRayID++; - if (unlikely(raysInOctant[octantID] == MAX_INTERNAL_STREAM_SIZE)) - { - curOctant = octantID; - break; - } - } - - /* need to flush rays in octant? */ - if (unlikely(curOctant == -1)) - { - for (unsigned int i = 0; i < 8; i++) - if (raysInOctant[i]) { curOctant = i; break; } - } - - /* all rays traced? */ - if (unlikely(curOctant == -1)) - break; - - unsigned int* const rayIDs = &octants[curOctant][0]; - const unsigned int numOctantRays = raysInOctant[curOctant]; - assert(numOctantRays); - - for (unsigned int j = 0; j < numOctantRays; j += K) - { - const vint<K> vi = vint<K>(int(j)) + vint<K>(step); - const vbool<K> valid = vi < vint<K>(int(numOctantRays)); - const vint<K> offset = *(vint<K>*)&rayIDs[j] * int(stride); - RayK<K>& ray = rays[j/K]; - rayPtrs[j/K] = &ray; - ray = rayN.getRayByOffset<K>(valid, offset); - ray.tnear() = select(valid, ray.tnear(), zero); - ray.tfar = select(valid, ray.tfar, neg_inf); - } - - scene->intersectors.occludedN(rayPtrs, numOctantRays, context); - - for (unsigned int j = 0; j < numOctantRays; j += K) - { - const vint<K> vi = vint<K>(int(j)) + vint<K>(step); - const vbool<K> valid = vi < vint<K>(int(numOctantRays)); - const vint<K> offset = *(vint<K>*)&rayIDs[j] * int(stride); - rayN.setHitByOffset<K>(valid, offset, rays[j/K]); - } - - raysInOctant[curOctant] = 0; - } - } - else - { - /* fallback to packets */ - for (size_t i = 0; i < N; i += K) - { - const vint<K> vi = vint<K>(int(i)) + vint<K>(step); - vbool<K> valid = vi < vint<K>(int(N)); - const vint<K> offset = vi * int(stride); - - RayTypeK<K, intersect> ray = rayN.getRayByOffset<K>(valid, offset); - valid &= ray.tnear() <= ray.tfar; - - scene->intersectors.intersect(valid, ray, context); - - rayN.setHitByOffset<K>(valid, offset, ray); - } - } - } - - template<int K, bool intersect> - __noinline void RayStreamFilter::filterAOP(Scene* scene, void** _rayN, size_t N, IntersectContext* context) - { - RayStreamAOP rayN(_rayN); - - /* use fast path for coherent ray mode */ - if (unlikely(context->isCoherent())) - { - __aligned(64) RayTypeK<K, intersect> rays[MAX_INTERNAL_STREAM_SIZE / K]; - __aligned(64) RayTypeK<K, intersect>* rayPtrs[MAX_INTERNAL_STREAM_SIZE / K]; - - for (size_t i = 0; i < N; i += MAX_INTERNAL_STREAM_SIZE) - { - const size_t size = min(N - i, MAX_INTERNAL_STREAM_SIZE); - - /* convert from AOP to SOA */ - for (size_t j = 0; j < size; j += K) - { - const vint<K> vij = vint<K>(int(i+j)) + vint<K>(step); - const vbool<K> valid = vij < vint<K>(int(N)); - const size_t packetIndex = j / K; - - RayTypeK<K, intersect> ray = rayN.getRayByIndex<K>(valid, vij); - ray.tnear() = select(valid, ray.tnear(), zero); - ray.tfar = select(valid, ray.tfar, neg_inf); - - rays[packetIndex] = ray; - rayPtrs[packetIndex] = &rays[packetIndex]; // rayPtrs might get reordered for occludedN - } - - /* trace stream */ - scene->intersectors.intersectN(rayPtrs, size, context); - - /* convert from SOA to AOP */ - for (size_t j = 0; j < size; j += K) - { - const vint<K> vij = vint<K>(int(i+j)) + vint<K>(step); - const vbool<K> valid = vij < vint<K>(int(N)); - const size_t packetIndex = j / K; - - rayN.setHitByIndex<K>(valid, vij, rays[packetIndex]); - } - } - } - else if (unlikely(!intersect)) - { - /* octant sorting for occlusion rays */ - __aligned(64) unsigned int octants[8][MAX_INTERNAL_STREAM_SIZE]; - __aligned(64) RayK<K> rays[MAX_INTERNAL_STREAM_SIZE / K]; - __aligned(64) RayK<K>* rayPtrs[MAX_INTERNAL_STREAM_SIZE / K]; - - unsigned int raysInOctant[8]; - for (unsigned int i = 0; i < 8; i++) - raysInOctant[i] = 0; - size_t inputRayID = 0; - - for (;;) - { - int curOctant = -1; - - /* sort rays into octants */ - for (; inputRayID < N;) - { - const Ray& ray = rayN.getRayByIndex(inputRayID); - - /* skip invalid rays */ - if (unlikely(ray.tnear() > ray.tfar || ray.tfar < 0.0f)) { inputRayID++; continue; } // ignore invalid or already occluded rays -#if defined(EMBREE_IGNORE_INVALID_RAYS) - if (unlikely(!ray.valid())) { inputRayID++; continue; } -#endif - - const unsigned int octantID = movemask(lt_mask(ray.dir,Vec3fa(0.0f))); - - assert(octantID < 8); - octants[octantID][raysInOctant[octantID]++] = (unsigned int)inputRayID; - inputRayID++; - if (unlikely(raysInOctant[octantID] == MAX_INTERNAL_STREAM_SIZE)) - { - curOctant = octantID; - break; - } - } - - /* need to flush rays in octant? */ - if (unlikely(curOctant == -1)) - { - for (unsigned int i = 0; i < 8; i++) - if (raysInOctant[i]) { curOctant = i; break; } - } - - /* all rays traced? */ - if (unlikely(curOctant == -1)) - break; - - unsigned int* const rayIDs = &octants[curOctant][0]; - const unsigned int numOctantRays = raysInOctant[curOctant]; - assert(numOctantRays); - - for (unsigned int j = 0; j < numOctantRays; j += K) - { - const vint<K> vi = vint<K>(int(j)) + vint<K>(step); - const vbool<K> valid = vi < vint<K>(int(numOctantRays)); - const vint<K> index = *(vint<K>*)&rayIDs[j]; - RayK<K>& ray = rays[j/K]; - rayPtrs[j/K] = &ray; - ray = rayN.getRayByIndex<K>(valid, index); - ray.tnear() = select(valid, ray.tnear(), zero); - ray.tfar = select(valid, ray.tfar, neg_inf); - } - - scene->intersectors.occludedN(rayPtrs, numOctantRays, context); - - for (unsigned int j = 0; j < numOctantRays; j += K) - { - const vint<K> vi = vint<K>(int(j)) + vint<K>(step); - const vbool<K> valid = vi < vint<K>(int(numOctantRays)); - const vint<K> index = *(vint<K>*)&rayIDs[j]; - rayN.setHitByIndex<K>(valid, index, rays[j/K]); - } - - raysInOctant[curOctant] = 0; - } - } - else - { - /* fallback to packets */ - for (size_t i = 0; i < N; i += K) - { - const vint<K> vi = vint<K>(int(i)) + vint<K>(step); - vbool<K> valid = vi < vint<K>(int(N)); - - RayTypeK<K, intersect> ray = rayN.getRayByIndex<K>(valid, vi); - valid &= ray.tnear() <= ray.tfar; - - scene->intersectors.intersect(valid, ray, context); - - rayN.setHitByIndex<K>(valid, vi, ray); - } - } - } - - template<int K, bool intersect> - __noinline void RayStreamFilter::filterSOA(Scene* scene, char* rayData, size_t N, size_t numPackets, size_t stride, IntersectContext* context) - { - const size_t rayDataAlignment = (size_t)rayData % (K*sizeof(float)); - const size_t offsetAlignment = (size_t)stride % (K*sizeof(float)); - - /* fast path for packets with the correct width and data alignment */ - if (likely(N == K && - !rayDataAlignment && - !offsetAlignment)) - { - if (unlikely(context->isCoherent())) - { - __aligned(64) RayTypeK<K, intersect>* rayPtrs[MAX_INTERNAL_STREAM_SIZE / K]; - - size_t packetIndex = 0; - for (size_t i = 0; i < numPackets; i++) - { - const size_t offset = i * stride; - RayTypeK<K, intersect>& ray = *(RayTypeK<K, intersect>*)(rayData + offset); - rayPtrs[packetIndex++] = &ray; - - /* trace as stream */ - if (unlikely(packetIndex == MAX_INTERNAL_STREAM_SIZE / K)) - { - const size_t size = packetIndex*K; - scene->intersectors.intersectN(rayPtrs, size, context); - packetIndex = 0; - } - } - - /* flush remaining packets */ - if (unlikely(packetIndex > 0)) - { - const size_t size = packetIndex*K; - scene->intersectors.intersectN(rayPtrs, size, context); - } - } - else if (unlikely(!intersect)) - { - /* octant sorting for occlusion rays */ - RayStreamSOA rayN(rayData, K); - - __aligned(64) unsigned int octants[8][MAX_INTERNAL_STREAM_SIZE]; - __aligned(64) RayK<K> rays[MAX_INTERNAL_STREAM_SIZE / K]; - __aligned(64) RayK<K>* rayPtrs[MAX_INTERNAL_STREAM_SIZE / K]; - - unsigned int raysInOctant[8]; - for (unsigned int i = 0; i < 8; i++) - raysInOctant[i] = 0; - size_t inputRayID = 0; - - for (;;) - { - int curOctant = -1; - - /* sort rays into octants */ - for (; inputRayID < N*numPackets;) - { - const size_t offset = (inputRayID / K) * stride + (inputRayID % K) * sizeof(float); - - /* skip invalid rays */ - if (unlikely(!rayN.isValidByOffset(offset))) { inputRayID++; continue; } // ignore invalid or already occluded rays - #if defined(EMBREE_IGNORE_INVALID_RAYS) - __aligned(64) Ray ray = rayN.getRayByOffset(offset); - if (unlikely(!ray.valid())) { inputRayID++; continue; } - #endif - - const unsigned int octantID = (unsigned int)rayN.getOctantByOffset(offset); - - assert(octantID < 8); - octants[octantID][raysInOctant[octantID]++] = (unsigned int)offset; - inputRayID++; - if (unlikely(raysInOctant[octantID] == MAX_INTERNAL_STREAM_SIZE)) - { - curOctant = octantID; - break; - } - } - - /* need to flush rays in octant? */ - if (unlikely(curOctant == -1)) - { - for (unsigned int i = 0; i < 8; i++) - if (raysInOctant[i]) { curOctant = i; break; } - } - - /* all rays traced? */ - if (unlikely(curOctant == -1)) - break; - - unsigned int* const rayOffsets = &octants[curOctant][0]; - const unsigned int numOctantRays = raysInOctant[curOctant]; - assert(numOctantRays); - - for (unsigned int j = 0; j < numOctantRays; j += K) - { - const vint<K> vi = vint<K>(int(j)) + vint<K>(step); - const vbool<K> valid = vi < vint<K>(int(numOctantRays)); - const vint<K> offset = *(vint<K>*)&rayOffsets[j]; - RayK<K>& ray = rays[j/K]; - rayPtrs[j/K] = &ray; - ray = rayN.getRayByOffset<K>(valid, offset); - ray.tnear() = select(valid, ray.tnear(), zero); - ray.tfar = select(valid, ray.tfar, neg_inf); - } - - scene->intersectors.occludedN(rayPtrs, numOctantRays, context); - - for (unsigned int j = 0; j < numOctantRays; j += K) - { - const vint<K> vi = vint<K>(int(j)) + vint<K>(step); - const vbool<K> valid = vi < vint<K>(int(numOctantRays)); - const vint<K> offset = *(vint<K>*)&rayOffsets[j]; - rayN.setHitByOffset(valid, offset, rays[j/K]); - } - raysInOctant[curOctant] = 0; - } - } - else - { - /* fallback to packets */ - for (size_t i = 0; i < numPackets; i++) - { - const size_t offset = i * stride; - RayTypeK<K, intersect>& ray = *(RayTypeK<K, intersect>*)(rayData + offset); - const vbool<K> valid = ray.tnear() <= ray.tfar; - - scene->intersectors.intersect(valid, ray, context); - } - } - } - else - { - /* fallback to packets for arbitrary packet size and alignment */ - for (size_t i = 0; i < numPackets; i++) - { - const size_t offsetN = i * stride; - RayStreamSOA rayN(rayData + offsetN, N); - - for (size_t j = 0; j < N; j += K) - { - const size_t offset = j * sizeof(float); - vbool<K> valid = (vint<K>(int(j)) + vint<K>(step)) < vint<K>(int(N)); - RayTypeK<K, intersect> ray = rayN.getRayByOffset<K>(valid, offset); - valid &= ray.tnear() <= ray.tfar; - - scene->intersectors.intersect(valid, ray, context); - - rayN.setHitByOffset(valid, offset, ray); - } - } - } - } - - template<int K, bool intersect> - __noinline void RayStreamFilter::filterSOP(Scene* scene, const void* _rayN, size_t N, IntersectContext* context) - { - RayStreamSOP& rayN = *(RayStreamSOP*)_rayN; - - /* use fast path for coherent ray mode */ - if (unlikely(context->isCoherent())) - { - __aligned(64) RayTypeK<K, intersect> rays[MAX_INTERNAL_STREAM_SIZE / K]; - __aligned(64) RayTypeK<K, intersect>* rayPtrs[MAX_INTERNAL_STREAM_SIZE / K]; - - for (size_t i = 0; i < N; i += MAX_INTERNAL_STREAM_SIZE) - { - const size_t size = min(N - i, MAX_INTERNAL_STREAM_SIZE); - - /* convert from SOP to SOA */ - for (size_t j = 0; j < size; j += K) - { - const vint<K> vij = vint<K>(int(i+j)) + vint<K>(step); - const vbool<K> valid = vij < vint<K>(int(N)); - const size_t offset = (i+j) * sizeof(float); - const size_t packetIndex = j / K; - - RayTypeK<K, intersect> ray = rayN.getRayByOffset<K>(valid, offset); - ray.tnear() = select(valid, ray.tnear(), zero); - ray.tfar = select(valid, ray.tfar, neg_inf); - - rays[packetIndex] = ray; - rayPtrs[packetIndex] = &rays[packetIndex]; // rayPtrs might get reordered for occludedN - } - - /* trace stream */ - scene->intersectors.intersectN(rayPtrs, size, context); - - /* convert from SOA to SOP */ - for (size_t j = 0; j < size; j += K) - { - const vint<K> vij = vint<K>(int(i+j)) + vint<K>(step); - const vbool<K> valid = vij < vint<K>(int(N)); - const size_t offset = (i+j) * sizeof(float); - const size_t packetIndex = j / K; - - rayN.setHitByOffset(valid, offset, rays[packetIndex]); - } - } - } - else if (unlikely(!intersect)) - { - /* octant sorting for occlusion rays */ - __aligned(64) unsigned int octants[8][MAX_INTERNAL_STREAM_SIZE]; - __aligned(64) RayK<K> rays[MAX_INTERNAL_STREAM_SIZE / K]; - __aligned(64) RayK<K>* rayPtrs[MAX_INTERNAL_STREAM_SIZE / K]; - - unsigned int raysInOctant[8]; - for (unsigned int i = 0; i < 8; i++) - raysInOctant[i] = 0; - size_t inputRayID = 0; - - for (;;) - { - int curOctant = -1; - - /* sort rays into octants */ - for (; inputRayID < N;) - { - const size_t offset = inputRayID * sizeof(float); - /* skip invalid rays */ - if (unlikely(!rayN.isValidByOffset(offset))) { inputRayID++; continue; } // ignore invalid or already occluded rays -#if defined(EMBREE_IGNORE_INVALID_RAYS) - __aligned(64) Ray ray = rayN.getRayByOffset(offset); - if (unlikely(!ray.valid())) { inputRayID++; continue; } -#endif - - const unsigned int octantID = (unsigned int)rayN.getOctantByOffset(offset); - - assert(octantID < 8); - octants[octantID][raysInOctant[octantID]++] = (unsigned int)offset; - inputRayID++; - if (unlikely(raysInOctant[octantID] == MAX_INTERNAL_STREAM_SIZE)) - { - curOctant = octantID; - break; - } - } - - /* need to flush rays in octant? */ - if (unlikely(curOctant == -1)) - { - for (unsigned int i = 0; i < 8; i++) - if (raysInOctant[i]) { curOctant = i; break; } - } - - /* all rays traced? */ - if (unlikely(curOctant == -1)) - break; - - unsigned int* const rayOffsets = &octants[curOctant][0]; - const unsigned int numOctantRays = raysInOctant[curOctant]; - assert(numOctantRays); - - for (unsigned int j = 0; j < numOctantRays; j += K) - { - const vint<K> vi = vint<K>(int(j)) + vint<K>(step); - const vbool<K> valid = vi < vint<K>(int(numOctantRays)); - const vint<K> offset = *(vint<K>*)&rayOffsets[j]; - RayK<K>& ray = rays[j/K]; - rayPtrs[j/K] = &ray; - ray = rayN.getRayByOffset<K>(valid, offset); - ray.tnear() = select(valid, ray.tnear(), zero); - ray.tfar = select(valid, ray.tfar, neg_inf); - } - - scene->intersectors.occludedN(rayPtrs, numOctantRays, context); - - for (unsigned int j = 0; j < numOctantRays; j += K) - { - const vint<K> vi = vint<K>(int(j)) + vint<K>(step); - const vbool<K> valid = vi < vint<K>(int(numOctantRays)); - const vint<K> offset = *(vint<K>*)&rayOffsets[j]; - rayN.setHitByOffset(valid, offset, rays[j/K]); - } - - raysInOctant[curOctant] = 0; - } - } - else - { - /* fallback to packets */ - for (size_t i = 0; i < N; i += K) - { - const vint<K> vi = vint<K>(int(i)) + vint<K>(step); - vbool<K> valid = vi < vint<K>(int(N)); - const size_t offset = i * sizeof(float); - - RayTypeK<K, intersect> ray = rayN.getRayByOffset<K>(valid, offset); - valid &= ray.tnear() <= ray.tfar; - - scene->intersectors.intersect(valid, ray, context); - - rayN.setHitByOffset(valid, offset, ray); - } - } - } - - - void RayStreamFilter::intersectAOS(Scene* scene, RTCRayHit* _rayN, size_t N, size_t stride, IntersectContext* context) { - if (unlikely(context->isCoherent())) - filterAOS<VSIZEL, true>(scene, _rayN, N, stride, context); - else - filterAOS<VSIZEX, true>(scene, _rayN, N, stride, context); - } - - void RayStreamFilter::occludedAOS(Scene* scene, RTCRay* _rayN, size_t N, size_t stride, IntersectContext* context) { - if (unlikely(context->isCoherent())) - filterAOS<VSIZEL, false>(scene, _rayN, N, stride, context); - else - filterAOS<VSIZEX, false>(scene, _rayN, N, stride, context); - } - - void RayStreamFilter::intersectAOP(Scene* scene, RTCRayHit** _rayN, size_t N, IntersectContext* context) { - if (unlikely(context->isCoherent())) - filterAOP<VSIZEL, true>(scene, (void**)_rayN, N, context); - else - filterAOP<VSIZEX, true>(scene, (void**)_rayN, N, context); - } - - void RayStreamFilter::occludedAOP(Scene* scene, RTCRay** _rayN, size_t N, IntersectContext* context) { - if (unlikely(context->isCoherent())) - filterAOP<VSIZEL, false>(scene, (void**)_rayN, N, context); - else - filterAOP<VSIZEX, false>(scene, (void**)_rayN, N, context); - } - - void RayStreamFilter::intersectSOA(Scene* scene, char* rayData, size_t N, size_t numPackets, size_t stride, IntersectContext* context) { - if (unlikely(context->isCoherent())) - filterSOA<VSIZEL, true>(scene, rayData, N, numPackets, stride, context); - else - filterSOA<VSIZEX, true>(scene, rayData, N, numPackets, stride, context); - } - - void RayStreamFilter::occludedSOA(Scene* scene, char* rayData, size_t N, size_t numPackets, size_t stride, IntersectContext* context) { - if (unlikely(context->isCoherent())) - filterSOA<VSIZEL, false>(scene, rayData, N, numPackets, stride, context); - else - filterSOA<VSIZEX, false>(scene, rayData, N, numPackets, stride, context); - } - - void RayStreamFilter::intersectSOP(Scene* scene, const RTCRayHitNp* _rayN, size_t N, IntersectContext* context) { - if (unlikely(context->isCoherent())) - filterSOP<VSIZEL, true>(scene, _rayN, N, context); - else - filterSOP<VSIZEX, true>(scene, _rayN, N, context); - } - - void RayStreamFilter::occludedSOP(Scene* scene, const RTCRayNp* _rayN, size_t N, IntersectContext* context) { - if (unlikely(context->isCoherent())) - filterSOP<VSIZEL, false>(scene, _rayN, N, context); - else - filterSOP<VSIZEX, false>(scene, _rayN, N, context); - } - - - RayStreamFilterFuncs rayStreamFilterFuncs() { - return RayStreamFilterFuncs(RayStreamFilter::intersectAOS, RayStreamFilter::intersectAOP, RayStreamFilter::intersectSOA, RayStreamFilter::intersectSOP, - RayStreamFilter::occludedAOS, RayStreamFilter::occludedAOP, RayStreamFilter::occludedSOA, RayStreamFilter::occludedSOP); - } - }; -}; diff --git a/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.h b/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.h deleted file mode 100644 index e7df7c2ae2..0000000000 --- a/thirdparty/embree/kernels/bvh/bvh_intersector_stream_filters.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "../common/default.h" -#include "../common/ray.h" -#include "../common/scene.h" - -namespace embree -{ - namespace isa - { - class RayStreamFilter - { - public: - static void intersectAOS(Scene* scene, RTCRayHit* rays, size_t N, size_t stride, IntersectContext* context); - static void intersectAOP(Scene* scene, RTCRayHit** rays, size_t N, IntersectContext* context); - static void intersectSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context); - static void intersectSOP(Scene* scene, const RTCRayHitNp* rays, size_t N, IntersectContext* context); - - static void occludedAOS(Scene* scene, RTCRay* rays, size_t N, size_t stride, IntersectContext* context); - static void occludedAOP(Scene* scene, RTCRay** rays, size_t N, IntersectContext* context); - static void occludedSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context); - static void occludedSOP(Scene* scene, const RTCRayNp* rays, size_t N, IntersectContext* context); - - private: - template<int K, bool intersect> - static void filterAOS(Scene* scene, void* rays, size_t N, size_t stride, IntersectContext* context); - - template<int K, bool intersect> - static void filterAOP(Scene* scene, void** rays, size_t N, IntersectContext* context); - - template<int K, bool intersect> - static void filterSOA(Scene* scene, char* rays, size_t N, size_t numPackets, size_t stride, IntersectContext* context); - - template<int K, bool intersect> - static void filterSOP(Scene* scene, const void* rays, size_t N, IntersectContext* context); - }; - } -}; diff --git a/thirdparty/embree/kernels/bvh/bvh_refit.cpp b/thirdparty/embree/kernels/bvh/bvh_refit.cpp index bf5c8538ba..9f8554112b 100644 --- a/thirdparty/embree/kernels/bvh/bvh_refit.cpp +++ b/thirdparty/embree/kernels/bvh/bvh_refit.cpp @@ -11,6 +11,9 @@ #include "../geometry/quadv.h" #include "../geometry/object.h" #include "../geometry/instance.h" +#include "../geometry/instance_array.h" + +#include "../../common/algorithms/parallel_for.h" namespace embree { @@ -82,7 +85,7 @@ namespace embree template<int N> BBox3fa BVHNRefitter<N>::refit_toplevel(NodeRef& ref, size_t &subtrees, - const BBox3fa *const subTreeBounds, + const BBox3fa *const subTreeBounds, const size_t depth) { if (depth >= MAX_SUB_TREE_EXTRACTION_DEPTH) @@ -236,12 +239,20 @@ namespace embree #if defined(EMBREE_GEOMETRY_INSTANCE) Builder* BVH4InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode); Builder* BVH4InstanceMeshRefitSAH (void* accel, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,Instance,InstancePrimitive>((BVH4*)accel,BVH4InstanceMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); } - #if defined(__AVX__) Builder* BVH8InstanceMeshBuilderSAH (void* bvh, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode); Builder* BVH8InstanceMeshRefitSAH (void* accel, Instance* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,Instance,InstancePrimitive>((BVH8*)accel,BVH8InstanceMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); } #endif #endif +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + Builder* BVH4InstanceArrayMeshBuilderSAH (void* bvh, InstanceArray* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode); + Builder* BVH4InstanceArrayMeshRefitSAH (void* accel, InstanceArray* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<4,InstanceArray,InstanceArrayPrimitive>((BVH4*)accel,BVH4InstanceArrayMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); } + +#if defined(__AVX__) + Builder* BVH8InstanceArrayMeshBuilderSAH (void* bvh, InstanceArray* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode); + Builder* BVH8InstanceArrayMeshRefitSAH (void* accel, InstanceArray* mesh, Geometry::GTypeMask gtype, unsigned int geomID, size_t mode) { return new BVHNRefitT<8,InstanceArray,InstanceArrayPrimitive>((BVH8*)accel,BVH8InstanceArrayMeshBuilderSAH(accel,mesh,gtype,geomID,mode),mesh,mode); } +#endif +#endif } } diff --git a/thirdparty/embree/kernels/bvh/bvh_traverser_stream.h b/thirdparty/embree/kernels/bvh/bvh_traverser_stream.h deleted file mode 100644 index 852981e69d..0000000000 --- a/thirdparty/embree/kernels/bvh/bvh_traverser_stream.h +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "bvh.h" -#include "../common/ray.h" -#include "../common/stack_item.h" - -namespace embree -{ - namespace isa - { - template<int N, int types> - class BVHNNodeTraverserStreamHitCoherent - { - typedef BVHN<N> BVH; - typedef typename BVH::NodeRef NodeRef; - typedef typename BVH::BaseNode BaseNode; - - public: - template<class T> - static __forceinline void traverseClosestHit(NodeRef& cur, - size_t& m_trav_active, - const vbool<N>& vmask, - const vfloat<N>& tNear, - const T* const tMask, - StackItemMaskCoherent*& stackPtr) - { - const NodeRef parent = cur; - size_t mask = movemask(vmask); - assert(mask != 0); - const BaseNode* node = cur.baseNode(); - - /*! one child is hit, continue with that child */ - const size_t r0 = bscf(mask); - assert(r0 < 8); - cur = node->child(r0); - BVHN<N>::prefetch(cur,types); - m_trav_active = tMask[r0]; - assert(cur != BVH::emptyNode); - if (unlikely(mask == 0)) return; - - const unsigned int* const tNear_i = (unsigned int*)&tNear; - - /*! two children are hit, push far child, and continue with closer child */ - NodeRef c0 = cur; - unsigned int d0 = tNear_i[r0]; - const size_t r1 = bscf(mask); - assert(r1 < 8); - NodeRef c1 = node->child(r1); - BVHN<N>::prefetch(c1,types); - unsigned int d1 = tNear_i[r1]; - - assert(c0 != BVH::emptyNode); - assert(c1 != BVH::emptyNode); - if (likely(mask == 0)) { - if (d0 < d1) { - assert(tNear[r1] >= 0.0f); - stackPtr->mask = tMask[r1]; - stackPtr->parent = parent; - stackPtr->child = c1; - stackPtr++; - cur = c0; - m_trav_active = tMask[r0]; - return; - } - else { - assert(tNear[r0] >= 0.0f); - stackPtr->mask = tMask[r0]; - stackPtr->parent = parent; - stackPtr->child = c0; - stackPtr++; - cur = c1; - m_trav_active = tMask[r1]; - return; - } - } - - /*! slow path for more than two hits */ - size_t hits = movemask(vmask); - const vint<N> dist_i = select(vmask, (asInt(tNear) & 0xfffffff8) | vint<N>(step), 0); - const vint<N> dist_i_sorted = usort_descending(dist_i); - const vint<N> sorted_index = dist_i_sorted & 7; - - size_t i = 0; - for (;;) - { - const unsigned int index = sorted_index[i]; - assert(index < 8); - cur = node->child(index); - m_trav_active = tMask[index]; - assert(m_trav_active); - BVHN<N>::prefetch(cur,types); - bscf(hits); - if (unlikely(hits==0)) break; - i++; - assert(cur != BVH::emptyNode); - assert(tNear[index] >= 0.0f); - stackPtr->mask = m_trav_active; - stackPtr->parent = parent; - stackPtr->child = cur; - stackPtr++; - } - } - - template<class T> - static __forceinline void traverseAnyHit(NodeRef& cur, - size_t& m_trav_active, - const vbool<N>& vmask, - const T* const tMask, - StackItemMaskCoherent*& stackPtr) - { - const NodeRef parent = cur; - size_t mask = movemask(vmask); - assert(mask != 0); - const BaseNode* node = cur.baseNode(); - - /*! one child is hit, continue with that child */ - size_t r = bscf(mask); - cur = node->child(r); - BVHN<N>::prefetch(cur,types); - m_trav_active = tMask[r]; - - /* simple in order sequence */ - assert(cur != BVH::emptyNode); - if (likely(mask == 0)) return; - stackPtr->mask = m_trav_active; - stackPtr->parent = parent; - stackPtr->child = cur; - stackPtr++; - - for (; ;) - { - r = bscf(mask); - cur = node->child(r); - BVHN<N>::prefetch(cur,types); - m_trav_active = tMask[r]; - assert(cur != BVH::emptyNode); - if (likely(mask == 0)) return; - stackPtr->mask = m_trav_active; - stackPtr->parent = parent; - stackPtr->child = cur; - stackPtr++; - } - } - }; - } -} diff --git a/thirdparty/embree/kernels/bvh/node_intersector_packet_stream.h b/thirdparty/embree/kernels/bvh/node_intersector_packet_stream.h deleted file mode 100644 index 943fd7043f..0000000000 --- a/thirdparty/embree/kernels/bvh/node_intersector_packet_stream.h +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2009-2021 Intel Corporation -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "node_intersector.h" - -namespace embree -{ - namespace isa - { - ////////////////////////////////////////////////////////////////////////////////////// - // Ray packet structure used in stream traversal - ////////////////////////////////////////////////////////////////////////////////////// - - template<int K, bool robust> - struct TravRayKStream; - - /* Fast variant */ - template<int K> - struct TravRayKStream<K, false> - { - __forceinline TravRayKStream() {} - - __forceinline TravRayKStream(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar) - { - init(ray_org, ray_dir); - tnear = ray_tnear; - tfar = ray_tfar; - } - - __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir) - { - rdir = rcp_safe(ray_dir); -#if defined(__aarch64__) - neg_org_rdir = -(ray_org * rdir); -#else - org_rdir = ray_org * rdir; -#endif - } - - Vec3vf<K> rdir; -#if defined(__aarch64__) - Vec3vf<K> neg_org_rdir; -#else - Vec3vf<K> org_rdir; -#endif - vfloat<K> tnear; - vfloat<K> tfar; - }; - - template<int K> - using TravRayKStreamFast = TravRayKStream<K, false>; - - /* Robust variant */ - template<int K> - struct TravRayKStream<K, true> - { - __forceinline TravRayKStream() {} - - __forceinline TravRayKStream(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir, const vfloat<K>& ray_tnear, const vfloat<K>& ray_tfar) - { - init(ray_org, ray_dir); - tnear = ray_tnear; - tfar = ray_tfar; - } - - __forceinline void init(const Vec3vf<K>& ray_org, const Vec3vf<K>& ray_dir) - { - rdir = vfloat<K>(1.0f)/(zero_fix(ray_dir)); - org = ray_org; - } - - Vec3vf<K> rdir; - Vec3vf<K> org; - vfloat<K> tnear; - vfloat<K> tfar; - }; - - template<int K> - using TravRayKStreamRobust = TravRayKStream<K, true>; - - ////////////////////////////////////////////////////////////////////////////////////// - // Fast AABBNode intersection - ////////////////////////////////////////////////////////////////////////////////////// - - template<int N, int K> - __forceinline size_t intersectNode1(const typename BVHN<N>::AABBNode* __restrict__ node, - const TravRayKStreamFast<K>& ray, size_t k, const NearFarPrecalculations& nf) - { - const vfloat<N> bminX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX)); - const vfloat<N> bminY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY)); - const vfloat<N> bminZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ)); - const vfloat<N> bmaxX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX)); - const vfloat<N> bmaxY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY)); - const vfloat<N> bmaxZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ)); - -#if defined (__aarch64__) - const vfloat<N> rminX = madd(bminX, vfloat<N>(ray.rdir.x[k]), vfloat<N>(ray.neg_org_rdir.x[k])); - const vfloat<N> rminY = madd(bminY, vfloat<N>(ray.rdir.y[k]), vfloat<N>(ray.neg_org_rdir.y[k])); - const vfloat<N> rminZ = madd(bminZ, vfloat<N>(ray.rdir.z[k]), vfloat<N>(ray.neg_org_rdir.z[k])); - const vfloat<N> rmaxX = madd(bmaxX, vfloat<N>(ray.rdir.x[k]), vfloat<N>(ray.neg_org_rdir.x[k])); - const vfloat<N> rmaxY = madd(bmaxY, vfloat<N>(ray.rdir.y[k]), vfloat<N>(ray.neg_org_rdir.y[k])); - const vfloat<N> rmaxZ = madd(bmaxZ, vfloat<N>(ray.rdir.z[k]), vfloat<N>(ray.neg_org_rdir.z[k])); -#else - const vfloat<N> rminX = msub(bminX, vfloat<N>(ray.rdir.x[k]), vfloat<N>(ray.org_rdir.x[k])); - const vfloat<N> rminY = msub(bminY, vfloat<N>(ray.rdir.y[k]), vfloat<N>(ray.org_rdir.y[k])); - const vfloat<N> rminZ = msub(bminZ, vfloat<N>(ray.rdir.z[k]), vfloat<N>(ray.org_rdir.z[k])); - const vfloat<N> rmaxX = msub(bmaxX, vfloat<N>(ray.rdir.x[k]), vfloat<N>(ray.org_rdir.x[k])); - const vfloat<N> rmaxY = msub(bmaxY, vfloat<N>(ray.rdir.y[k]), vfloat<N>(ray.org_rdir.y[k])); - const vfloat<N> rmaxZ = msub(bmaxZ, vfloat<N>(ray.rdir.z[k]), vfloat<N>(ray.org_rdir.z[k])); -#endif - const vfloat<N> rmin = maxi(rminX, rminY, rminZ, vfloat<N>(ray.tnear[k])); - const vfloat<N> rmax = mini(rmaxX, rmaxY, rmaxZ, vfloat<N>(ray.tfar[k])); - - const vbool<N> vmask_first_hit = rmin <= rmax; - - return movemask(vmask_first_hit) & (((size_t)1 << N)-1); - } - - template<int N, int K> - __forceinline size_t intersectNodeK(const typename BVHN<N>::AABBNode* __restrict__ node, size_t i, - const TravRayKStreamFast<K>& ray, const NearFarPrecalculations& nf) - { - char* ptr = (char*)&node->lower_x + i*sizeof(float); - const vfloat<K> bminX = *(const float*)(ptr + nf.nearX); - const vfloat<K> bminY = *(const float*)(ptr + nf.nearY); - const vfloat<K> bminZ = *(const float*)(ptr + nf.nearZ); - const vfloat<K> bmaxX = *(const float*)(ptr + nf.farX); - const vfloat<K> bmaxY = *(const float*)(ptr + nf.farY); - const vfloat<K> bmaxZ = *(const float*)(ptr + nf.farZ); - -#if defined (__aarch64__) - const vfloat<K> rminX = madd(bminX, ray.rdir.x, ray.neg_org_rdir.x); - const vfloat<K> rminY = madd(bminY, ray.rdir.y, ray.neg_org_rdir.y); - const vfloat<K> rminZ = madd(bminZ, ray.rdir.z, ray.neg_org_rdir.z); - const vfloat<K> rmaxX = madd(bmaxX, ray.rdir.x, ray.neg_org_rdir.x); - const vfloat<K> rmaxY = madd(bmaxY, ray.rdir.y, ray.neg_org_rdir.y); - const vfloat<K> rmaxZ = madd(bmaxZ, ray.rdir.z, ray.neg_org_rdir.z); -#else - const vfloat<K> rminX = msub(bminX, ray.rdir.x, ray.org_rdir.x); - const vfloat<K> rminY = msub(bminY, ray.rdir.y, ray.org_rdir.y); - const vfloat<K> rminZ = msub(bminZ, ray.rdir.z, ray.org_rdir.z); - const vfloat<K> rmaxX = msub(bmaxX, ray.rdir.x, ray.org_rdir.x); - const vfloat<K> rmaxY = msub(bmaxY, ray.rdir.y, ray.org_rdir.y); - const vfloat<K> rmaxZ = msub(bmaxZ, ray.rdir.z, ray.org_rdir.z); -#endif - - const vfloat<K> rmin = maxi(rminX, rminY, rminZ, ray.tnear); - const vfloat<K> rmax = mini(rmaxX, rmaxY, rmaxZ, ray.tfar); - - const vbool<K> vmask_first_hit = rmin <= rmax; - - return movemask(vmask_first_hit); - } - - ////////////////////////////////////////////////////////////////////////////////////// - // Robust AABBNode intersection - ////////////////////////////////////////////////////////////////////////////////////// - - template<int N, int K> - __forceinline size_t intersectNode1(const typename BVHN<N>::AABBNode* __restrict__ node, - const TravRayKStreamRobust<K>& ray, size_t k, const NearFarPrecalculations& nf) - { - const vfloat<N> bminX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearX)); - const vfloat<N> bminY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearY)); - const vfloat<N> bminZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.nearZ)); - const vfloat<N> bmaxX = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farX)); - const vfloat<N> bmaxY = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farY)); - const vfloat<N> bmaxZ = vfloat<N>(*(const vfloat<N>*)((const char*)&node->lower_x + nf.farZ)); - - const vfloat<N> rminX = (bminX - vfloat<N>(ray.org.x[k])) * vfloat<N>(ray.rdir.x[k]); - const vfloat<N> rminY = (bminY - vfloat<N>(ray.org.y[k])) * vfloat<N>(ray.rdir.y[k]); - const vfloat<N> rminZ = (bminZ - vfloat<N>(ray.org.z[k])) * vfloat<N>(ray.rdir.z[k]); - const vfloat<N> rmaxX = (bmaxX - vfloat<N>(ray.org.x[k])) * vfloat<N>(ray.rdir.x[k]); - const vfloat<N> rmaxY = (bmaxY - vfloat<N>(ray.org.y[k])) * vfloat<N>(ray.rdir.y[k]); - const vfloat<N> rmaxZ = (bmaxZ - vfloat<N>(ray.org.z[k])) * vfloat<N>(ray.rdir.z[k]); - const float round_up = 1.0f+3.0f*float(ulp); // FIXME: use per instruction rounding for AVX512 - const vfloat<N> rmin = max(rminX, rminY, rminZ, vfloat<N>(ray.tnear[k])); - const vfloat<N> rmax = round_up *min(rmaxX, rmaxY, rmaxZ, vfloat<N>(ray.tfar[k])); - - const vbool<N> vmask_first_hit = rmin <= rmax; - - return movemask(vmask_first_hit) & (((size_t)1 << N)-1); - } - - template<int N, int K> - __forceinline size_t intersectNodeK(const typename BVHN<N>::AABBNode* __restrict__ node, size_t i, - const TravRayKStreamRobust<K>& ray, const NearFarPrecalculations& nf) - { - char *ptr = (char*)&node->lower_x + i*sizeof(float); - const vfloat<K> bminX = *(const float*)(ptr + nf.nearX); - const vfloat<K> bminY = *(const float*)(ptr + nf.nearY); - const vfloat<K> bminZ = *(const float*)(ptr + nf.nearZ); - const vfloat<K> bmaxX = *(const float*)(ptr + nf.farX); - const vfloat<K> bmaxY = *(const float*)(ptr + nf.farY); - const vfloat<K> bmaxZ = *(const float*)(ptr + nf.farZ); - - const vfloat<K> rminX = (bminX - ray.org.x) * ray.rdir.x; - const vfloat<K> rminY = (bminY - ray.org.y) * ray.rdir.y; - const vfloat<K> rminZ = (bminZ - ray.org.z) * ray.rdir.z; - const vfloat<K> rmaxX = (bmaxX - ray.org.x) * ray.rdir.x; - const vfloat<K> rmaxY = (bmaxY - ray.org.y) * ray.rdir.y; - const vfloat<K> rmaxZ = (bmaxZ - ray.org.z) * ray.rdir.z; - - const float round_up = 1.0f+3.0f*float(ulp); - const vfloat<K> rmin = max(rminX, rminY, rminZ, vfloat<K>(ray.tnear)); - const vfloat<K> rmax = round_up * min(rmaxX, rmaxY, rmaxZ, vfloat<K>(ray.tfar)); - - const vbool<K> vmask_first_hit = rmin <= rmax; - - return movemask(vmask_first_hit); - } - } -} diff --git a/thirdparty/embree/kernels/common/accel.h b/thirdparty/embree/kernels/common/accel.h index d24326ce92..7d959377ae 100644 --- a/thirdparty/embree/kernels/common/accel.h +++ b/thirdparty/embree/kernels/common/accel.h @@ -17,7 +17,7 @@ namespace embree { ALIGNED_CLASS_(16); public: - enum Type { TY_UNKNOWN = 0, TY_ACCELN = 1, TY_ACCEL_INSTANCE = 2, TY_BVH4 = 3, TY_BVH8 = 4 }; + enum Type { TY_UNKNOWN = 0, TY_ACCELN = 1, TY_ACCEL_INSTANCE = 2, TY_BVH4 = 3, TY_BVH8 = 4, TY_GPU = 5 }; public: AccelData (const Type type) @@ -73,61 +73,49 @@ namespace embree /*! Type of intersect function pointer for single rays. */ typedef void (*IntersectFunc)(Intersectors* This, /*!< this pointer to accel */ RTCRayHit& ray, /*!< ray to intersect */ - IntersectContext* context); + RayQueryContext* context); /*! Type of intersect function pointer for ray packets of size 4. */ typedef void (*IntersectFunc4)(const void* valid, /*!< pointer to valid mask */ Intersectors* This, /*!< this pointer to accel */ RTCRayHit4& ray, /*!< ray packet to intersect */ - IntersectContext* context); + RayQueryContext* context); /*! Type of intersect function pointer for ray packets of size 8. */ typedef void (*IntersectFunc8)(const void* valid, /*!< pointer to valid mask */ Intersectors* This, /*!< this pointer to accel */ RTCRayHit8& ray, /*!< ray packet to intersect */ - IntersectContext* context); + RayQueryContext* context); /*! Type of intersect function pointer for ray packets of size 16. */ typedef void (*IntersectFunc16)(const void* valid, /*!< pointer to valid mask */ Intersectors* This, /*!< this pointer to accel */ RTCRayHit16& ray, /*!< ray packet to intersect */ - IntersectContext* context); + RayQueryContext* context); - /*! Type of intersect function pointer for ray packets of size N. */ - typedef void (*IntersectFuncN)(Intersectors* This, /*!< this pointer to accel */ - RTCRayHitN** ray, /*!< ray stream to intersect */ - const size_t N, /*!< number of rays in stream */ - IntersectContext* context /*!< layout flags */); - - /*! Type of occlusion function pointer for single rays. */ typedef void (*OccludedFunc) (Intersectors* This, /*!< this pointer to accel */ RTCRay& ray, /*!< ray to test occlusion */ - IntersectContext* context); + RayQueryContext* context); /*! Type of occlusion function pointer for ray packets of size 4. */ typedef void (*OccludedFunc4) (const void* valid, /*!< pointer to valid mask */ Intersectors* This, /*!< this pointer to accel */ RTCRay4& ray, /*!< ray packet to test occlusion. */ - IntersectContext* context); + RayQueryContext* context); /*! Type of occlusion function pointer for ray packets of size 8. */ typedef void (*OccludedFunc8) (const void* valid, /*!< pointer to valid mask */ Intersectors* This, /*!< this pointer to accel */ RTCRay8& ray, /*!< ray packet to test occlusion. */ - IntersectContext* context); + RayQueryContext* context); /*! Type of occlusion function pointer for ray packets of size 16. */ typedef void (*OccludedFunc16) (const void* valid, /*!< pointer to valid mask */ Intersectors* This, /*!< this pointer to accel */ RTCRay16& ray, /*!< ray packet to test occlusion. */ - IntersectContext* context); + RayQueryContext* context); - /*! Type of intersect function pointer for ray packets of size N. */ - typedef void (*OccludedFuncN)(Intersectors* This, /*!< this pointer to accel */ - RTCRayN** ray, /*!< ray stream to test occlusion */ - const size_t N, /*!< number of rays in stream */ - IntersectContext* context /*!< layout flags */); typedef void (*ErrorFunc) (); struct Collider @@ -217,30 +205,13 @@ namespace embree const char* name; }; - struct IntersectorN - { - IntersectorN (ErrorFunc error = nullptr) - : intersect((IntersectFuncN)error), occluded((OccludedFuncN)error), name(nullptr) {} - - IntersectorN (IntersectFuncN intersect, OccludedFuncN occluded, const char* name) - : intersect(intersect), occluded(occluded), name(name) {} - - operator bool() const { return name; } - - public: - static const char* type; - IntersectFuncN intersect; - OccludedFuncN occluded; - const char* name; - }; - struct Intersectors { Intersectors() - : ptr(nullptr), leafIntersector(nullptr), collider(nullptr), intersector1(nullptr), intersector4(nullptr), intersector8(nullptr), intersector16(nullptr), intersectorN(nullptr) {} + : ptr(nullptr), leafIntersector(nullptr), collider(nullptr), intersector1(nullptr), intersector4(nullptr), intersector8(nullptr), intersector16(nullptr) {} Intersectors (ErrorFunc error) - : ptr(nullptr), leafIntersector(nullptr), collider(error), intersector1(error), intersector4(error), intersector8(error), intersector16(error), intersectorN(error) {} + : ptr(nullptr), leafIntersector(nullptr), collider(error), intersector1(error), intersector4(error), intersector8(error), intersector16(error) {} void print(size_t ident) { @@ -264,10 +235,6 @@ namespace embree for (size_t i=0; i<ident; i++) std::cout << " "; std::cout << "intersector16 = " << intersector16.name << std::endl; } - if (intersectorN.name) { - for (size_t i=0; i<ident; i++) std::cout << " "; - std::cout << "intersectorN = " << intersectorN.name << std::endl; - } } void select(bool filter) @@ -284,10 +251,6 @@ namespace embree if (filter) intersector16 = intersector16_filter; else intersector16 = intersector16_nofilter; } - if (intersectorN_filter) { - if (filter) intersectorN = intersectorN_filter; - else intersectorN = intersectorN_nofilter; - } } __forceinline bool pointQuery (PointQuery* query, PointQueryContext* context) { @@ -302,133 +265,138 @@ namespace embree } /*! Intersects a single ray with the scene. */ - __forceinline void intersect (RTCRayHit& ray, IntersectContext* context) { + __forceinline void intersect (RTCRayHit& ray, RayQueryContext* context) { assert(intersector1.intersect); intersector1.intersect(this,ray,context); } /*! Intersects a packet of 4 rays with the scene. */ - __forceinline void intersect4 (const void* valid, RTCRayHit4& ray, IntersectContext* context) { + __forceinline void intersect4 (const void* valid, RTCRayHit4& ray, RayQueryContext* context) { assert(intersector4.intersect); intersector4.intersect(valid,this,ray,context); } /*! Intersects a packet of 8 rays with the scene. */ - __forceinline void intersect8 (const void* valid, RTCRayHit8& ray, IntersectContext* context) { + __forceinline void intersect8 (const void* valid, RTCRayHit8& ray, RayQueryContext* context) { assert(intersector8.intersect); intersector8.intersect(valid,this,ray,context); } /*! Intersects a packet of 16 rays with the scene. */ - __forceinline void intersect16 (const void* valid, RTCRayHit16& ray, IntersectContext* context) { + __forceinline void intersect16 (const void* valid, RTCRayHit16& ray, RayQueryContext* context) { assert(intersector16.intersect); intersector16.intersect(valid,this,ray,context); } + + /*! Intersects a packet of 4 rays with the scene. */ + __forceinline void intersect (const void* valid, RTCRayHit4& ray, RayQueryContext* context) { + assert(intersector4.intersect); + intersector4.intersect(valid,this,ray,context); + } - /*! Intersects a stream of N rays in SOA layout with the scene. */ - __forceinline void intersectN (RTCRayHitN** rayN, const size_t N, IntersectContext* context) - { - assert(intersectorN.intersect); - intersectorN.intersect(this,rayN,N,context); + /*! Intersects a packet of 8 rays with the scene. */ + __forceinline void intersect (const void* valid, RTCRayHit8& ray, RayQueryContext* context) { + assert(intersector8.intersect); + intersector8.intersect(valid,this,ray,context); + } + + /*! Intersects a packet of 16 rays with the scene. */ + __forceinline void intersect (const void* valid, RTCRayHit16& ray, RayQueryContext* context) { + assert(intersector16.intersect); + intersector16.intersect(valid,this,ray,context); } #if defined(__SSE__) || defined(__ARM_NEON) - __forceinline void intersect(const vbool4& valid, RayHitK<4>& ray, IntersectContext* context) { + __forceinline void intersect(const vbool4& valid, RayHitK<4>& ray, RayQueryContext* context) { const vint<4> mask = valid.mask32(); intersect4(&mask,(RTCRayHit4&)ray,context); } #endif #if defined(__AVX__) - __forceinline void intersect(const vbool8& valid, RayHitK<8>& ray, IntersectContext* context) { + __forceinline void intersect(const vbool8& valid, RayHitK<8>& ray, RayQueryContext* context) { const vint<8> mask = valid.mask32(); intersect8(&mask,(RTCRayHit8&)ray,context); } #endif #if defined(__AVX512F__) - __forceinline void intersect(const vbool16& valid, RayHitK<16>& ray, IntersectContext* context) { + __forceinline void intersect(const vbool16& valid, RayHitK<16>& ray, RayQueryContext* context) { const vint<16> mask = valid.mask32(); intersect16(&mask,(RTCRayHit16&)ray,context); } #endif - template<int K> - __forceinline void intersectN (RayHitK<K>** rayN, const size_t N, IntersectContext* context) - { - intersectN((RTCRayHitN**)rayN,N,context); - } - /*! Tests if single ray is occluded by the scene. */ - __forceinline void occluded (RTCRay& ray, IntersectContext* context) { + __forceinline void occluded (RTCRay& ray, RayQueryContext* context) { assert(intersector1.occluded); intersector1.occluded(this,ray,context); } /*! Tests if a packet of 4 rays is occluded by the scene. */ - __forceinline void occluded4 (const void* valid, RTCRay4& ray, IntersectContext* context) { + __forceinline void occluded4 (const void* valid, RTCRay4& ray, RayQueryContext* context) { assert(intersector4.occluded); intersector4.occluded(valid,this,ray,context); } /*! Tests if a packet of 8 rays is occluded by the scene. */ - __forceinline void occluded8 (const void* valid, RTCRay8& ray, IntersectContext* context) { + __forceinline void occluded8 (const void* valid, RTCRay8& ray, RayQueryContext* context) { assert(intersector8.occluded); intersector8.occluded(valid,this,ray,context); } /*! Tests if a packet of 16 rays is occluded by the scene. */ - __forceinline void occluded16 (const void* valid, RTCRay16& ray, IntersectContext* context) { + __forceinline void occluded16 (const void* valid, RTCRay16& ray, RayQueryContext* context) { assert(intersector16.occluded); intersector16.occluded(valid,this,ray,context); } + + /*! Tests if a packet of 4 rays is occluded by the scene. */ + __forceinline void occluded (const void* valid, RTCRay4& ray, RayQueryContext* context) { + assert(intersector4.occluded); + intersector4.occluded(valid,this,ray,context); + } - /*! Tests if a stream of N rays in SOA layout is occluded by the scene. */ - __forceinline void occludedN (RTCRayN** rayN, const size_t N, IntersectContext* context) - { - assert(intersectorN.occluded); - intersectorN.occluded(this,rayN,N,context); + /*! Tests if a packet of 8 rays is occluded by the scene. */ + __forceinline void occluded (const void* valid, RTCRay8& ray, RayQueryContext* context) { + assert(intersector8.occluded); + intersector8.occluded(valid,this,ray,context); + } + + /*! Tests if a packet of 16 rays is occluded by the scene. */ + __forceinline void occluded (const void* valid, RTCRay16& ray, RayQueryContext* context) { + assert(intersector16.occluded); + intersector16.occluded(valid,this,ray,context); } #if defined(__SSE__) || defined(__ARM_NEON) - __forceinline void occluded(const vbool4& valid, RayK<4>& ray, IntersectContext* context) { + __forceinline void occluded(const vbool4& valid, RayK<4>& ray, RayQueryContext* context) { const vint<4> mask = valid.mask32(); occluded4(&mask,(RTCRay4&)ray,context); } #endif #if defined(__AVX__) - __forceinline void occluded(const vbool8& valid, RayK<8>& ray, IntersectContext* context) { + __forceinline void occluded(const vbool8& valid, RayK<8>& ray, RayQueryContext* context) { const vint<8> mask = valid.mask32(); occluded8(&mask,(RTCRay8&)ray,context); } #endif #if defined(__AVX512F__) - __forceinline void occluded(const vbool16& valid, RayK<16>& ray, IntersectContext* context) { + __forceinline void occluded(const vbool16& valid, RayK<16>& ray, RayQueryContext* context) { const vint<16> mask = valid.mask32(); occluded16(&mask,(RTCRay16&)ray,context); } #endif - template<int K> - __forceinline void occludedN (RayK<K>** rayN, const size_t N, IntersectContext* context) - { - occludedN((RTCRayN**)rayN,N,context); - } - /*! Tests if single ray is occluded by the scene. */ - __forceinline void intersect(RTCRay& ray, IntersectContext* context) { + __forceinline void intersect(RTCRay& ray, RayQueryContext* context) { occluded(ray, context); } /*! Tests if a packet of K rays is occluded by the scene. */ template<int K> - __forceinline void intersect(const vbool<K>& valid, RayK<K>& ray, IntersectContext* context) { + __forceinline void intersect(const vbool<K>& valid, RayK<K>& ray, RayQueryContext* context) { occluded(valid, ray, context); } - /*! Tests if a packet of N rays in SOA layout is occluded by the scene. */ - template<int K> - __forceinline void intersectN(RayK<K>** rayN, const size_t N, IntersectContext* context) { - occludedN(rayN, N, context); - } public: AccelData* ptr; @@ -444,9 +412,6 @@ namespace embree Intersector16 intersector16; Intersector16 intersector16_filter; Intersector16 intersector16_nofilter; - IntersectorN intersectorN; - IntersectorN intersectorN_filter; - IntersectorN intersectorN_nofilter; }; public: @@ -506,51 +471,4 @@ namespace embree (Accel::OccludedFunc16)intersector::occluded, \ TOSTRING(isa) "::" TOSTRING(symbol)); \ } - -#define DEFINE_INTERSECTORN(symbol,intersector) \ - Accel::IntersectorN symbol() { \ - return Accel::IntersectorN((Accel::IntersectFuncN)intersector::intersect, \ - (Accel::OccludedFuncN)intersector::occluded, \ - TOSTRING(isa) "::" TOSTRING(symbol)); \ - } - - /* ray stream filter interface */ - typedef void (*intersectStreamAOS_func)(Scene* scene, RTCRayHit* _rayN, const size_t N, const size_t stride, IntersectContext* context); - typedef void (*intersectStreamAOP_func)(Scene* scene, RTCRayHit** _rayN, const size_t N, IntersectContext* context); - typedef void (*intersectStreamSOA_func)(Scene* scene, char* rayN, const size_t N, const size_t streams, const size_t stream_offset, IntersectContext* context); - typedef void (*intersectStreamSOP_func)(Scene* scene, const RTCRayHitNp* rayN, const size_t N, IntersectContext* context); - - typedef void (*occludedStreamAOS_func)(Scene* scene, RTCRay* _rayN, const size_t N, const size_t stride, IntersectContext* context); - typedef void (*occludedStreamAOP_func)(Scene* scene, RTCRay** _rayN, const size_t N, IntersectContext* context); - typedef void (*occludedStreamSOA_func)(Scene* scene, char* rayN, const size_t N, const size_t streams, const size_t stream_offset, IntersectContext* context); - typedef void (*occludedStreamSOP_func)(Scene* scene, const RTCRayNp* rayN, const size_t N, IntersectContext* context); - - struct RayStreamFilterFuncs - { - RayStreamFilterFuncs() - : intersectAOS(nullptr), intersectAOP(nullptr), intersectSOA(nullptr), intersectSOP(nullptr), - occludedAOS(nullptr), occludedAOP(nullptr), occludedSOA(nullptr), occludedSOP(nullptr) {} - - RayStreamFilterFuncs(void (*ptr) ()) - : intersectAOS((intersectStreamAOS_func) ptr), intersectAOP((intersectStreamAOP_func) ptr), intersectSOA((intersectStreamSOA_func) ptr), intersectSOP((intersectStreamSOP_func) ptr), - occludedAOS((occludedStreamAOS_func) ptr), occludedAOP((occludedStreamAOP_func) ptr), occludedSOA((occludedStreamSOA_func) ptr), occludedSOP((occludedStreamSOP_func) ptr) {} - - RayStreamFilterFuncs(intersectStreamAOS_func intersectAOS, intersectStreamAOP_func intersectAOP, intersectStreamSOA_func intersectSOA, intersectStreamSOP_func intersectSOP, - occludedStreamAOS_func occludedAOS, occludedStreamAOP_func occludedAOP, occludedStreamSOA_func occludedSOA, occludedStreamSOP_func occludedSOP) - : intersectAOS(intersectAOS), intersectAOP(intersectAOP), intersectSOA(intersectSOA), intersectSOP(intersectSOP), - occludedAOS(occludedAOS), occludedAOP(occludedAOP), occludedSOA(occludedSOA), occludedSOP(occludedSOP) {} - - public: - intersectStreamAOS_func intersectAOS; - intersectStreamAOP_func intersectAOP; - intersectStreamSOA_func intersectSOA; - intersectStreamSOP_func intersectSOP; - - occludedStreamAOS_func occludedAOS; - occludedStreamAOP_func occludedAOP; - occludedStreamSOA_func occludedSOA; - occludedStreamSOP_func occludedSOP; - }; - - typedef RayStreamFilterFuncs (*RayStreamFilterFuncsType)(); } diff --git a/thirdparty/embree/kernels/common/acceln.cpp b/thirdparty/embree/kernels/common/acceln.cpp index 111c62083d..9edb684db7 100644 --- a/thirdparty/embree/kernels/common/acceln.cpp +++ b/thirdparty/embree/kernels/common/acceln.cpp @@ -3,7 +3,7 @@ #include "acceln.h" #include "ray.h" -#include "../../include/embree3/rtcore_ray.h" +#include "../../include/embree4/rtcore_ray.h" #include "../../common/algorithms/parallel_for.h" namespace embree @@ -41,7 +41,7 @@ namespace embree return changed; } - void AccelN::intersect (Accel::Intersectors* This_in, RTCRayHit& ray, IntersectContext* context) + void AccelN::intersect (Accel::Intersectors* This_in, RTCRayHit& ray, RayQueryContext* context) { AccelN* This = (AccelN*)This_in->ptr; for (size_t i=0; i<This->accels.size(); i++) @@ -49,7 +49,7 @@ namespace embree This->accels[i]->intersectors.intersect(ray,context); } - void AccelN::intersect4 (const void* valid, Accel::Intersectors* This_in, RTCRayHit4& ray, IntersectContext* context) + void AccelN::intersect4 (const void* valid, Accel::Intersectors* This_in, RTCRayHit4& ray, RayQueryContext* context) { AccelN* This = (AccelN*)This_in->ptr; for (size_t i=0; i<This->accels.size(); i++) @@ -57,7 +57,7 @@ namespace embree This->accels[i]->intersectors.intersect4(valid,ray,context); } - void AccelN::intersect8 (const void* valid, Accel::Intersectors* This_in, RTCRayHit8& ray, IntersectContext* context) + void AccelN::intersect8 (const void* valid, Accel::Intersectors* This_in, RTCRayHit8& ray, RayQueryContext* context) { AccelN* This = (AccelN*)This_in->ptr; for (size_t i=0; i<This->accels.size(); i++) @@ -65,7 +65,7 @@ namespace embree This->accels[i]->intersectors.intersect8(valid,ray,context); } - void AccelN::intersect16 (const void* valid, Accel::Intersectors* This_in, RTCRayHit16& ray, IntersectContext* context) + void AccelN::intersect16 (const void* valid, Accel::Intersectors* This_in, RTCRayHit16& ray, RayQueryContext* context) { AccelN* This = (AccelN*)This_in->ptr; for (size_t i=0; i<This->accels.size(); i++) @@ -73,15 +73,7 @@ namespace embree This->accels[i]->intersectors.intersect16(valid,ray,context); } - void AccelN::intersectN (Accel::Intersectors* This_in, RTCRayHitN** ray, const size_t N, IntersectContext* context) - { - AccelN* This = (AccelN*)This_in->ptr; - for (size_t i=0; i<This->accels.size(); i++) - if (!This->accels[i]->isEmpty()) - This->accels[i]->intersectors.intersectN(ray,N,context); - } - - void AccelN::occluded (Accel::Intersectors* This_in, RTCRay& ray, IntersectContext* context) + void AccelN::occluded (Accel::Intersectors* This_in, RTCRay& ray, RayQueryContext* context) { AccelN* This = (AccelN*)This_in->ptr; for (size_t i=0; i<This->accels.size(); i++) { @@ -91,7 +83,7 @@ namespace embree } } - void AccelN::occluded4 (const void* valid, Accel::Intersectors* This_in, RTCRay4& ray, IntersectContext* context) + void AccelN::occluded4 (const void* valid, Accel::Intersectors* This_in, RTCRay4& ray, RayQueryContext* context) { AccelN* This = (AccelN*)This_in->ptr; for (size_t i=0; i<This->accels.size(); i++) { @@ -105,7 +97,7 @@ namespace embree } } - void AccelN::occluded8 (const void* valid, Accel::Intersectors* This_in, RTCRay8& ray, IntersectContext* context) + void AccelN::occluded8 (const void* valid, Accel::Intersectors* This_in, RTCRay8& ray, RayQueryContext* context) { AccelN* This = (AccelN*)This_in->ptr; for (size_t i=0; i<This->accels.size(); i++) { @@ -121,7 +113,7 @@ namespace embree } } - void AccelN::occluded16 (const void* valid, Accel::Intersectors* This_in, RTCRay16& ray, IntersectContext* context) + void AccelN::occluded16 (const void* valid, Accel::Intersectors* This_in, RTCRay16& ray, RayQueryContext* context) { AccelN* This = (AccelN*)This_in->ptr; for (size_t i=0; i<This->accels.size(); i++) { @@ -141,15 +133,6 @@ namespace embree } } - void AccelN::occludedN (Accel::Intersectors* This_in, RTCRayN** ray, const size_t N, IntersectContext* context) - { - AccelN* This = (AccelN*)This_in->ptr; - size_t M = N; - for (size_t i=0; i<This->accels.size(); i++) - if (!This->accels[i]->isEmpty()) - This->accels[i]->intersectors.occludedN(ray,M,context); - } - void AccelN::accels_print(size_t ident) { for (size_t i=0; i<accels.size(); i++) @@ -201,7 +184,6 @@ namespace embree intersectors.intersector4 = Intersector4(&intersect4,&occluded4,valid4 ? "AccelN::intersector4" : nullptr); intersectors.intersector8 = Intersector8(&intersect8,&occluded8,valid8 ? "AccelN::intersector8" : nullptr); intersectors.intersector16 = Intersector16(&intersect16,&occluded16,valid16 ? "AccelN::intersector16": nullptr); - intersectors.intersectorN = IntersectorN(&intersectN,&occludedN,"AccelN::intersectorN"); /*! calculate bounds */ bounds = empty; diff --git a/thirdparty/embree/kernels/common/acceln.h b/thirdparty/embree/kernels/common/acceln.h index 0445b2e811..cc3406826c 100644 --- a/thirdparty/embree/kernels/common/acceln.h +++ b/thirdparty/embree/kernels/common/acceln.h @@ -22,18 +22,16 @@ namespace embree static bool pointQuery (Accel::Intersectors* This, PointQuery* query, PointQueryContext* context); public: - static void intersect (Accel::Intersectors* This, RTCRayHit& ray, IntersectContext* context); - static void intersect4 (const void* valid, Accel::Intersectors* This, RTCRayHit4& ray, IntersectContext* context); - static void intersect8 (const void* valid, Accel::Intersectors* This, RTCRayHit8& ray, IntersectContext* context); - static void intersect16 (const void* valid, Accel::Intersectors* This, RTCRayHit16& ray, IntersectContext* context); - static void intersectN (Accel::Intersectors* This, RTCRayHitN** ray, const size_t N, IntersectContext* context); + static void intersect (Accel::Intersectors* This, RTCRayHit& ray, RayQueryContext* context); + static void intersect4 (const void* valid, Accel::Intersectors* This, RTCRayHit4& ray, RayQueryContext* context); + static void intersect8 (const void* valid, Accel::Intersectors* This, RTCRayHit8& ray, RayQueryContext* context); + static void intersect16 (const void* valid, Accel::Intersectors* This, RTCRayHit16& ray, RayQueryContext* context); public: - static void occluded (Accel::Intersectors* This, RTCRay& ray, IntersectContext* context); - static void occluded4 (const void* valid, Accel::Intersectors* This, RTCRay4& ray, IntersectContext* context); - static void occluded8 (const void* valid, Accel::Intersectors* This, RTCRay8& ray, IntersectContext* context); - static void occluded16 (const void* valid, Accel::Intersectors* This, RTCRay16& ray, IntersectContext* context); - static void occludedN (Accel::Intersectors* This, RTCRayN** ray, const size_t N, IntersectContext* context); + static void occluded (Accel::Intersectors* This, RTCRay& ray, RayQueryContext* context); + static void occluded4 (const void* valid, Accel::Intersectors* This, RTCRay4& ray, RayQueryContext* context); + static void occluded8 (const void* valid, Accel::Intersectors* This, RTCRay8& ray, RayQueryContext* context); + static void occluded16 (const void* valid, Accel::Intersectors* This, RTCRay16& ray, RayQueryContext* context); public: void accels_print(size_t ident); diff --git a/thirdparty/embree/kernels/common/accelset.h b/thirdparty/embree/kernels/common/accelset.h index 1b67120c97..f78830e397 100644 --- a/thirdparty/embree/kernels/common/accelset.h +++ b/thirdparty/embree/kernels/common/accelset.h @@ -17,11 +17,15 @@ namespace embree struct IntersectFunctionNArguments : public RTCIntersectFunctionNArguments { Geometry* geometry; + RTCScene forward_scene; + RTCIntersectArguments* args; }; struct OccludedFunctionNArguments : public RTCOccludedFunctionNArguments { Geometry* geometry; + RTCScene forward_scene; + RTCIntersectArguments* args; }; /*! Base class for set of acceleration structures. */ @@ -138,10 +142,9 @@ namespace embree public: /*! Intersects a single ray with the scene. */ - __forceinline void intersect (RayHit& ray, unsigned int geomID, unsigned int primID, IntersectContext* context) + __forceinline bool intersect (RayHit& ray, unsigned int geomID, unsigned int primID, RayQueryContext* context) { assert(primID < size()); - assert(intersectorN.intersect); int mask = -1; IntersectFunctionNArguments args; @@ -153,17 +156,94 @@ namespace embree args.geomID = geomID; args.primID = primID; args.geometry = this; + args.forward_scene = nullptr; + args.args = context->args; + + IntersectFuncN intersectFunc = nullptr; + intersectFunc = intersectorN.intersect; - intersectorN.intersect(&args); + if (context->getIntersectFunction()) + intersectFunc = context->getIntersectFunction(); + + assert(intersectFunc); + intersectFunc(&args); + + return mask != 0; } /*! Tests if single ray is occluded by the scene. */ - __forceinline void occluded (Ray& ray, unsigned int geomID, unsigned int primID, IntersectContext* context) + __forceinline bool occluded (Ray& ray, unsigned int geomID, unsigned int primID, RayQueryContext* context) { assert(primID < size()); - assert(intersectorN.occluded); + + int mask = -1; + OccludedFunctionNArguments args; + args.valid = &mask; + args.geometryUserPtr = userPtr; + args.context = context->user; + args.ray = (RTCRayN*)&ray; + args.N = 1; + args.geomID = geomID; + args.primID = primID; + args.geometry = this; + args.forward_scene = nullptr; + args.args = context->args; + + OccludedFuncN occludedFunc = nullptr; + occludedFunc = intersectorN.occluded; + + if (context->getOccludedFunction()) + occludedFunc = context->getOccludedFunction(); + + assert(occludedFunc); + occludedFunc(&args); + + return mask != 0; + } + + /*! Intersects a single ray with the scene. */ + __forceinline bool intersect (RayHit& ray, unsigned int geomID, unsigned int primID, RayQueryContext* context, RTCScene& forward_scene) + { + assert(primID < size()); int mask = -1; + IntersectFunctionNArguments args; + args.valid = &mask; + args.geometryUserPtr = userPtr; + args.context = context->user; + args.rayhit = (RTCRayHitN*)&ray; + args.N = 1; + args.geomID = geomID; + args.primID = primID; + args.geometry = this; + args.forward_scene = nullptr; + args.args = nullptr; + + typedef void (*RTCIntersectFunctionSYCL)(const void* args); + RTCIntersectFunctionSYCL intersectFunc = nullptr; + +#if EMBREE_SYCL_GEOMETRY_CALLBACK + if (context->args->feature_mask & RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_GEOMETRY) + intersectFunc = (RTCIntersectFunctionSYCL) intersectorN.intersect; +#endif + + if (context->args->feature_mask & RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_ARGUMENTS) + if (context->getIntersectFunction()) + intersectFunc = (RTCIntersectFunctionSYCL) context->getIntersectFunction(); + + if (intersectFunc) + intersectFunc(&args); + + forward_scene = args.forward_scene; + return mask != 0; + } + + /*! Tests if single ray is occluded by the scene. */ + __forceinline bool occluded (Ray& ray, unsigned int geomID, unsigned int primID, RayQueryContext* context, RTCScene& forward_scene) + { + assert(primID < size()); + + int mask = -1; OccludedFunctionNArguments args; args.valid = &mask; args.geometryUserPtr = userPtr; @@ -173,16 +253,33 @@ namespace embree args.geomID = geomID; args.primID = primID; args.geometry = this; + args.forward_scene = nullptr; + args.args = nullptr; + + typedef void (*RTCOccludedFunctionSYCL)(const void* args); + RTCOccludedFunctionSYCL occludedFunc = nullptr; + +#if EMBREE_SYCL_GEOMETRY_CALLBACK + if (context->args->feature_mask & RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_GEOMETRY) + occludedFunc = (RTCOccludedFunctionSYCL) intersectorN.occluded; +#endif + + if (context->args->feature_mask & RTC_FEATURE_FLAG_USER_GEOMETRY_CALLBACK_IN_ARGUMENTS) + if (context->getOccludedFunction()) + occludedFunc = (RTCOccludedFunctionSYCL) context->getOccludedFunction(); + + if (occludedFunc) + occludedFunc(&args); - intersectorN.occluded(&args); + forward_scene = args.forward_scene; + return mask != 0; } - + /*! Intersects a packet of K rays with the scene. */ template<int K> - __forceinline void intersect (const vbool<K>& valid, RayHitK<K>& ray, unsigned int geomID, unsigned int primID, IntersectContext* context) + __forceinline void intersect (const vbool<K>& valid, RayHitK<K>& ray, unsigned int geomID, unsigned int primID, RayQueryContext* context) { assert(primID < size()); - assert(intersectorN.intersect); vint<K> mask = valid.mask32(); IntersectFunctionNArguments args; @@ -194,16 +291,24 @@ namespace embree args.geomID = geomID; args.primID = primID; args.geometry = this; - - intersectorN.intersect(&args); + args.forward_scene = nullptr; + args.args = context->args; + + IntersectFuncN intersectFunc = nullptr; + intersectFunc = intersectorN.intersect; + + if (context->getIntersectFunction()) + intersectFunc = context->getIntersectFunction(); + + assert(intersectFunc); + intersectFunc(&args); } /*! Tests if a packet of K rays is occluded by the scene. */ template<int K> - __forceinline void occluded (const vbool<K>& valid, RayK<K>& ray, unsigned int geomID, unsigned int primID, IntersectContext* context) + __forceinline void occluded (const vbool<K>& valid, RayK<K>& ray, unsigned int geomID, unsigned int primID, RayQueryContext* context) { assert(primID < size()); - assert(intersectorN.occluded); vint<K> mask = valid.mask32(); OccludedFunctionNArguments args; @@ -215,8 +320,17 @@ namespace embree args.geomID = geomID; args.primID = primID; args.geometry = this; + args.forward_scene = nullptr; + args.args = context->args; + + OccludedFuncN occludedFunc = nullptr; + occludedFunc = intersectorN.occluded; - intersectorN.occluded(&args); + if (context->getOccludedFunction()) + occludedFunc = context->getOccludedFunction(); + + assert(occludedFunc); + occludedFunc(&args); } public: diff --git a/thirdparty/embree/kernels/common/alloc.cpp b/thirdparty/embree/kernels/common/alloc.cpp index 38a76225f4..cc2f9976f2 100644 --- a/thirdparty/embree/kernels/common/alloc.cpp +++ b/thirdparty/embree/kernels/common/alloc.cpp @@ -10,7 +10,7 @@ namespace embree { __thread FastAllocator::ThreadLocal2* FastAllocator::thread_local_allocator2 = nullptr; - SpinLock FastAllocator::s_thread_local_allocators_lock; + MutexSys FastAllocator::s_thread_local_allocators_lock; std::vector<std::unique_ptr<FastAllocator::ThreadLocal2>> FastAllocator::s_thread_local_allocators; struct fast_allocator_regression_test : public RegressionTest diff --git a/thirdparty/embree/kernels/common/alloc.h b/thirdparty/embree/kernels/common/alloc.h index 12769df2c8..840d48c327 100644 --- a/thirdparty/embree/kernels/common/alloc.h +++ b/thirdparty/embree/kernels/common/alloc.h @@ -6,11 +6,9 @@ #include "default.h" #include "device.h" #include "scene.h" -#include "primref.h" +#include "../builders/primref.h" -#if defined(APPLE) && defined(__aarch64__) -#include <mutex> -#endif +#include "../../common/tasking/taskscheduler.h" namespace embree { @@ -18,7 +16,7 @@ namespace embree { /*! maximum supported alignment */ static const size_t maxAlignment = 64; - + /*! maximum allocation size */ /* default settings */ @@ -39,14 +37,14 @@ namespace embree public: /*! Constructor for usage with ThreadLocalData */ - __forceinline ThreadLocal (ThreadLocal2* parent) - : parent(parent), ptr(nullptr), cur(0), end(0), allocBlockSize(0), bytesUsed(0), bytesWasted(0) {} + __forceinline ThreadLocal (ThreadLocal2* parent) + : parent(parent), ptr(nullptr), cur(0), end(0), allocBlockSize(0), bytesUsed(0), bytesWasted(0) {} /*! initialize allocator */ - void init(FastAllocator* alloc) + void init(FastAllocator* alloc) { ptr = nullptr; - cur = end = 0; + cur = end = 0; bytesUsed = 0; bytesWasted = 0; allocBlockSize = 0; @@ -54,64 +52,62 @@ namespace embree } /* Allocate aligned memory from the threads memory block. */ - __forceinline void* malloc(FastAllocator* alloc, size_t bytes, size_t align = 16) + __forceinline void* malloc(FastAllocator* alloc, size_t bytes, size_t align = 16) { /* bind the thread local allocator to the proper FastAllocator*/ parent->bind(alloc); assert(align <= maxAlignment); - bytesUsed += bytes; + bytesUsed += bytes; /* try to allocate in local block */ - size_t ofs = (align - cur) & (align-1); + size_t ofs = (align - cur) & (align-1); cur += bytes + ofs; if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; } - cur -= bytes + ofs; - + cur -= bytes + ofs; + /* if allocation is too large allocate with parent allocator */ if (4*bytes > allocBlockSize) { return alloc->malloc(bytes,maxAlignment,false); - } + } /* get new partial block if allocation failed */ size_t blockSize = allocBlockSize; ptr = (char*) alloc->malloc(blockSize,maxAlignment,true); - bytesWasted += end-cur; - cur = 0; end = blockSize; + bytesWasted += end-cur; + cur = 0; end = blockSize; /* retry allocation */ - ofs = (align - cur) & (align-1); + ofs = (align - cur) & (align-1); cur += bytes + ofs; if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; } - cur -= bytes + ofs; + cur -= bytes + ofs; /* get new full block if allocation failed */ blockSize = allocBlockSize; ptr = (char*) alloc->malloc(blockSize,maxAlignment,false); - bytesWasted += end-cur; - cur = 0; end = blockSize; + bytesWasted += end-cur; + cur = 0; end = blockSize; /* retry allocation */ - ofs = (align - cur) & (align-1); + ofs = (align - cur) & (align-1); cur += bytes + ofs; if (likely(cur <= end)) { bytesWasted += ofs; return &ptr[cur - bytes]; } - cur -= bytes + ofs; + cur -= bytes + ofs; /* should never happen as large allocations get handled specially above */ assert(false); return nullptr; } - - /*! returns amount of used bytes */ __forceinline size_t getUsedBytes() const { return bytesUsed; } - + /*! returns amount of free bytes */ __forceinline size_t getFreeBytes() const { return end-cur; } - + /*! returns amount of wasted bytes */ __forceinline size_t getWastedBytes() const { return bytesWasted; } - + private: ThreadLocal2* parent; char* ptr; //!< pointer to memory block @@ -136,11 +132,7 @@ namespace embree { assert(alloc_i); if (alloc.load() == alloc_i) return; -#if defined(APPLE) && defined(__aarch64__) - std::scoped_lock lock(mutex); -#else - Lock<SpinLock> lock(mutex); -#endif + Lock<MutexSys> lock(mutex); //if (alloc.load() == alloc_i) return; // not required as only one thread calls bind if (alloc.load()) { alloc.load()->bytesUsed += alloc0.getUsedBytes() + alloc1.getUsedBytes(); @@ -158,11 +150,7 @@ namespace embree { assert(alloc_i); if (alloc.load() != alloc_i) return; -#if defined(APPLE) && defined(__aarch64__) - std::scoped_lock lock(mutex); -#else - Lock<SpinLock> lock(mutex); -#endif + Lock<MutexSys> lock(mutex); if (alloc.load() != alloc_i) return; // required as a different thread calls unbind alloc.load()->bytesUsed += alloc0.getUsedBytes() + alloc1.getUsedBytes(); alloc.load()->bytesFree += alloc0.getFreeBytes() + alloc1.getFreeBytes(); @@ -173,26 +161,47 @@ namespace embree } public: -#if defined(APPLE) && defined(__aarch64__) - std::mutex mutex; -#else - SpinLock mutex; //!< required as unbind is called from other threads -#endif + MutexSys mutex; std::atomic<FastAllocator*> alloc; //!< parent allocator ThreadLocal alloc0; ThreadLocal alloc1; }; - FastAllocator (Device* device, bool osAllocation) - : device(device), slotMask(0), usedBlocks(nullptr), freeBlocks(nullptr), use_single_mode(false), defaultBlockSize(PAGE_SIZE), estimatedSize(0), - growSize(PAGE_SIZE), maxGrowSize(maxAllocationSize), log2_grow_size_scale(0), bytesUsed(0), bytesFree(0), bytesWasted(0), atype(osAllocation ? EMBREE_OS_MALLOC : ALIGNED_MALLOC), - primrefarray(device,0) + FastAllocator (Device* device, + bool osAllocation, + bool useUSM = false, + bool blockAllocation = true) + : device(device) + , slotMask(0) + , defaultBlockSize(PAGE_SIZE) + , estimatedSize(0) + , growSize(PAGE_SIZE) + , maxGrowSize(maxAllocationSize) + , usedBlocks(nullptr) + , freeBlocks(nullptr) + , useUSM(useUSM) + , blockAllocation(blockAllocation) + , use_single_mode(false) + , log2_grow_size_scale(0) + , bytesUsed(0) + , bytesFree(0) + , bytesWasted(0) + , atype(osAllocation ? EMBREE_OS_MALLOC : ALIGNED_MALLOC) + , primrefarray(device,0) { + // -- GODOT start -- + // if (osAllocation && useUSM) + // throw std::runtime_error("USM allocation cannot be combined with OS allocation."); + if (osAllocation && useUSM) { + abort(); + } + // -- GODOT end -- + for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++) { threadUsedBlocks[i] = nullptr; threadBlocks[i] = nullptr; - assert(!slotMutex[i].isLocked()); + //assert(!slotMutex[i].isLocked()); } } @@ -233,11 +242,7 @@ namespace embree ThreadLocal2* alloc = thread_local_allocator2; if (alloc == nullptr) { thread_local_allocator2 = alloc = new ThreadLocal2; -#if defined(APPLE) && defined(__aarch64__) - std::scoped_lock lock(s_thread_local_allocators_lock); -#else - Lock<SpinLock> lock(s_thread_local_allocators_lock); -#endif + Lock<MutexSys> lock(s_thread_local_allocators_lock); s_thread_local_allocators.push_back(make_unique(alloc)); } return alloc; @@ -247,11 +252,7 @@ namespace embree __forceinline void join(ThreadLocal2* alloc) { -#if defined(APPLE) && defined(__aarch64__) - std::scoped_lock lock(s_thread_local_allocators_lock); -#else - Lock<SpinLock> lock(thread_local_allocators_lock); -#endif + Lock<MutexSys> lock(s_thread_local_allocators_lock); thread_local_allocators.push_back(alloc); } @@ -412,7 +413,7 @@ namespace embree slotMask = MAX_THREAD_USED_BLOCK_SLOTS-1; // FIXME: remove if (usedBlocks.load() || freeBlocks.load()) { reset(); return; } if (bytesReserve == 0) bytesReserve = bytesAllocate; - freeBlocks = Block::create(device,bytesAllocate,bytesReserve,nullptr,atype); + freeBlocks = Block::create(device,useUSM,bytesAllocate,bytesReserve,nullptr,atype); estimatedSize = bytesEstimate; initGrowSizeAndNumSlots(bytesEstimate,true); } @@ -478,8 +479,8 @@ namespace embree bytesUsed.store(0); bytesFree.store(0); bytesWasted.store(0); - if (usedBlocks.load() != nullptr) usedBlocks.load()->clear_list(device); usedBlocks = nullptr; - if (freeBlocks.load() != nullptr) freeBlocks.load()->clear_list(device); freeBlocks = nullptr; + if (usedBlocks.load() != nullptr) usedBlocks.load()->clear_list(device,useUSM); usedBlocks = nullptr; + if (freeBlocks.load() != nullptr) freeBlocks.load()->clear_list(device,useUSM); freeBlocks = nullptr; for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++) { threadUsedBlocks[i] = nullptr; threadBlocks[i] = nullptr; @@ -503,9 +504,16 @@ namespace embree /* allocate using current block */ size_t threadID = TaskScheduler::threadID(); size_t slot = threadID & slotMask; - Block* myUsedBlocks = threadUsedBlocks[slot]; + Block* myUsedBlocks = threadUsedBlocks[slot]; if (myUsedBlocks) { void* ptr = myUsedBlocks->malloc(device,bytes,align,partial); + // -- GODOT start -- + // if (ptr == nullptr && !blockAllocation) + // throw std::bad_alloc(); + if (ptr == nullptr && !blockAllocation) { + abort(); + } + // -- GODOT end -- if (ptr) return ptr; } @@ -516,16 +524,12 @@ namespace embree /* parallel block creation in case of no freeBlocks, avoids single global mutex */ if (likely(freeBlocks.load() == nullptr)) { -#if defined(APPLE) && defined(__aarch64__) - std::scoped_lock lock(slotMutex[slot]); -#else - Lock<SpinLock> lock(slotMutex[slot]); -#endif + Lock<MutexSys> lock(slotMutex[slot]); if (myUsedBlocks == threadUsedBlocks[slot]) { const size_t alignedBytes = (bytes+(align-1)) & ~(align-1); const size_t allocSize = max(min(growSize,maxGrowSize),alignedBytes); assert(allocSize >= bytes); - threadBlocks[slot] = threadUsedBlocks[slot] = Block::create(device,allocSize,allocSize,threadBlocks[slot],atype); // FIXME: a large allocation might throw away a block here! + threadBlocks[slot] = threadUsedBlocks[slot] = Block::create(device,useUSM,allocSize,allocSize,threadBlocks[slot],atype); // FIXME: a large allocation might throw away a block here! // FIXME: a direct allocation should allocate inside the block here, and not in the next loop! a different thread could do some allocation and make the large allocation fail. } continue; @@ -533,24 +537,20 @@ namespace embree /* if this fails allocate new block */ { -#if defined(APPLE) && defined(__aarch64__) - std::scoped_lock lock(mutex); -#else - Lock<SpinLock> lock(mutex); -#endif - if (myUsedBlocks == threadUsedBlocks[slot]) - { + Lock<MutexSys> lock(mutex); + if (myUsedBlocks == threadUsedBlocks[slot]) + { if (freeBlocks.load() != nullptr) { - Block* nextFreeBlock = freeBlocks.load()->next; - freeBlocks.load()->next = usedBlocks; - __memory_barrier(); - usedBlocks = freeBlocks.load(); + Block* nextFreeBlock = freeBlocks.load()->next; + freeBlocks.load()->next = usedBlocks; + __memory_barrier(); + usedBlocks = freeBlocks.load(); threadUsedBlocks[slot] = freeBlocks.load(); - freeBlocks = nextFreeBlock; - } else { + freeBlocks = nextFreeBlock; + } else { const size_t allocSize = min(growSize*incGrowSizeScale(),maxGrowSize); - usedBlocks = threadUsedBlocks[slot] = Block::create(device,allocSize,allocSize,usedBlocks,atype); // FIXME: a large allocation should get delivered directly, like above! - } + usedBlocks = threadUsedBlocks[slot] = Block::create(device,useUSM,allocSize,allocSize,usedBlocks,atype); // FIXME: a large allocation should get delivered directly, like above! + } } } } @@ -559,11 +559,7 @@ namespace embree /*! add new block */ void addBlock(void* ptr, ssize_t bytes) { -#if defined(APPLE) && defined(__aarch64__) - std::scoped_lock lock(mutex); -#else - Lock<SpinLock> lock(mutex); -#endif + Lock<MutexSys> lock(mutex); const size_t sizeof_Header = offsetof(Block,data[0]); void* aptr = (void*) ((((size_t)ptr)+maxAlignment-1) & ~(maxAlignment-1)); size_t ofs = (size_t) aptr - (size_t) ptr; @@ -723,7 +719,12 @@ namespace embree void print_blocks() { - std::cout << " estimatedSize = " << estimatedSize << ", slotMask = " << slotMask << ", use_single_mode = " << use_single_mode << ", maxGrowSize = " << maxGrowSize << ", defaultBlockSize = " << defaultBlockSize << std::endl; + std::cout << " estimatedSize = " << estimatedSize + << ", slotMask = " << slotMask + << ", use_single_mode = " << use_single_mode + << ", maxGrowSize = " << maxGrowSize + << ", defaultBlockSize = " << defaultBlockSize + << std::endl; std::cout << " used blocks = "; if (usedBlocks.load() != nullptr) usedBlocks.load()->print_list(); @@ -738,7 +739,19 @@ namespace embree struct Block { - static Block* create(MemoryMonitorInterface* device, size_t bytesAllocate, size_t bytesReserve, Block* next, AllocationType atype) + __forceinline static void* blockAlignedMalloc(Device* device, bool useUSM, size_t bytesAllocate, size_t bytesAlignment) + { + if (useUSM) return device->malloc(bytesAllocate, bytesAlignment); + else return alignedMalloc (bytesAllocate, bytesAlignment); + } + + __forceinline static void blockAlignedFree(Device* device, bool useUSM, void* ptr) + { + if (useUSM) return device->free(ptr); + else return alignedFree(ptr); + } + + static Block* create(Device* device, bool useUSM, size_t bytesAllocate, size_t bytesReserve, Block* next, AllocationType atype) { /* We avoid using os_malloc for small blocks as this could * cause a risk of fragmenting the virtual address space and @@ -766,7 +779,7 @@ namespace embree { const size_t alignment = maxAlignment; if (device) device->memoryMonitor(bytesAllocate+alignment,false); - ptr = alignedMalloc(bytesAllocate,alignment); + ptr = blockAlignedMalloc(device,useUSM,bytesAllocate,alignment); /* give hint to transparently convert these pages to 2MB pages */ const size_t ptr_aligned_begin = ((size_t)ptr) & ~size_t(PAGE_SIZE_2M-1); @@ -780,7 +793,7 @@ namespace embree { const size_t alignment = maxAlignment; if (device) device->memoryMonitor(bytesAllocate+alignment,false); - ptr = alignedMalloc(bytesAllocate,alignment); + ptr = blockAlignedMalloc(device,useUSM,bytesAllocate,alignment); return new (ptr) Block(ALIGNED_MALLOC,bytesAllocate-sizeof_Header,bytesAllocate-sizeof_Header,next,alignment); } } @@ -812,23 +825,23 @@ namespace embree return head; } - void clear_list(MemoryMonitorInterface* device) + void clear_list(Device* device, bool useUSM) { Block* block = this; while (block) { Block* next = block->next; - block->clear_block(device); + block->clear_block(device, useUSM); block = next; } } - void clear_block (MemoryMonitorInterface* device) + void clear_block (Device* device, bool useUSM) { const size_t sizeof_Header = offsetof(Block,data[0]); const ssize_t sizeof_Alloced = wasted+sizeof_Header+getBlockAllocatedBytes(); if (atype == ALIGNED_MALLOC) { - alignedFree(this); + blockAlignedFree(device, useUSM, this); if (device) device->memoryMonitor(-sizeof_Alloced,true); } @@ -847,16 +860,16 @@ namespace embree size_t bytes = bytes_in; assert(align <= maxAlignment); bytes = (bytes+(align-1)) & ~(align-1); - if (unlikely(cur+bytes > reserveEnd && !partial)) return nullptr; - const size_t i = cur.fetch_add(bytes); + if (unlikely(cur+bytes > reserveEnd && !partial)) return nullptr; + const size_t i = cur.fetch_add(bytes); if (unlikely(i+bytes > reserveEnd && !partial)) return nullptr; if (unlikely(i > reserveEnd)) return nullptr; bytes_in = bytes = min(bytes,reserveEnd-i); - - if (i+bytes > allocEnd) { + + if (i+bytes > allocEnd) { if (device) device->memoryMonitor(i+bytes-max(i,allocEnd),true); } - return &data[i]; + return &data[i]; } void* ptr() { @@ -874,7 +887,7 @@ namespace embree } size_t getBlockFreeBytes() const { - return getBlockAllocatedBytes() - getBlockUsedBytes(); + return getBlockAllocatedBytes() - getBlockUsedBytes(); } size_t getBlockAllocatedBytes() const { @@ -963,40 +976,40 @@ namespace embree char data[1]; //!< here starts memory to use for allocations }; + public: + static const size_t blockHeaderSize = offsetof(Block,data[0]); + private: Device* device; - SpinLock mutex; size_t slotMask; + size_t defaultBlockSize; + size_t estimatedSize; + size_t growSize; + size_t maxGrowSize; + + MutexSys mutex; + MutexSys slotMutex[MAX_THREAD_USED_BLOCK_SLOTS]; std::atomic<Block*> threadUsedBlocks[MAX_THREAD_USED_BLOCK_SLOTS]; + std::atomic<Block*> threadBlocks[MAX_THREAD_USED_BLOCK_SLOTS]; std::atomic<Block*> usedBlocks; std::atomic<Block*> freeBlocks; - std::atomic<Block*> threadBlocks[MAX_THREAD_USED_BLOCK_SLOTS]; -#if defined(APPLE) && defined(__aarch64__) - std::mutex slotMutex[MAX_THREAD_USED_BLOCK_SLOTS]; -#else - PaddedSpinLock slotMutex[MAX_THREAD_USED_BLOCK_SLOTS]; -#endif - + bool useUSM; + bool blockAllocation = true; bool use_single_mode; - size_t defaultBlockSize; - size_t estimatedSize; - size_t growSize; - size_t maxGrowSize; + std::atomic<size_t> log2_grow_size_scale; //!< log2 of scaling factor for grow size // FIXME: remove std::atomic<size_t> bytesUsed; std::atomic<size_t> bytesFree; std::atomic<size_t> bytesWasted; + static __thread ThreadLocal2* thread_local_allocator2; - static SpinLock s_thread_local_allocators_lock; + static MutexSys s_thread_local_allocators_lock; static std::vector<std::unique_ptr<ThreadLocal2>> s_thread_local_allocators; -#if defined(APPLE) && defined(__aarch64__) - std::mutex thread_local_allocators_lock; -#else - SpinLock thread_local_allocators_lock; -#endif + std::vector<ThreadLocal2*> thread_local_allocators; AllocationType atype; + mvector<PrimRef> primrefarray; //!< primrefarray used to allocate nodes }; } diff --git a/thirdparty/embree/kernels/common/buffer.h b/thirdparty/embree/kernels/common/buffer.h index 793012c04d..831f5815e8 100644 --- a/thirdparty/embree/kernels/common/buffer.h +++ b/thirdparty/embree/kernels/common/buffer.h @@ -13,8 +13,8 @@ namespace embree { public: /*! Buffer construction */ - Buffer() - : device(nullptr), ptr(nullptr), numBytes(0), shared(false) {} + //Buffer() + //: device(nullptr), ptr(nullptr), numBytes(0), shared(false) {} /*! Buffer construction */ Buffer(Device* device, size_t numBytes_in, void* ptr_in = nullptr) @@ -77,19 +77,17 @@ namespace embree /*! allocated buffer */ void alloc() { - if (device) - device->memoryMonitor(this->bytes(), false); + device->memoryMonitor(this->bytes(), false); size_t b = (this->bytes()+15) & ssize_t(-16); - ptr = (char*)alignedMalloc(b,16); + ptr = (char*)device->malloc(b,16); } /*! frees the buffer */ void free() { if (shared) return; - alignedFree(ptr); - if (device) - device->memoryMonitor(-ssize_t(this->bytes()), true); + device->free(ptr); + device->memoryMonitor(-ssize_t(this->bytes()), true); ptr = nullptr; } @@ -246,6 +244,24 @@ namespace embree public: typedef Vec3fa value_type; +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + + /*! access to the ith element of the buffer */ + __forceinline const Vec3fa operator [](size_t i) const + { + assert(i<num); + return Vec3fa::loadu(ptr_ofs + i*stride); + } + + /*! writes the i'th element */ + __forceinline void store(size_t i, const Vec3fa& v) + { + assert(i<num); + Vec3fa::storeu(ptr_ofs + i*stride, v); + } + +#else + /*! access to the ith element of the buffer */ __forceinline const Vec3fa operator [](size_t i) const { @@ -259,5 +275,6 @@ namespace embree assert(i<num); vfloat4::storeu((float*)(ptr_ofs + i*stride), (vfloat4)v); } +#endif }; } diff --git a/thirdparty/embree/kernels/common/builder.h b/thirdparty/embree/kernels/common/builder.h index 07fe7b069b..4f6a226810 100644 --- a/thirdparty/embree/kernels/common/builder.h +++ b/thirdparty/embree/kernels/common/builder.h @@ -7,7 +7,7 @@ #include "accel.h" namespace embree -{ +{ #define MODE_HIGH_QUALITY (1<<8) /*! virtual interface for all hierarchy builders */ diff --git a/thirdparty/embree/kernels/common/context.h b/thirdparty/embree/kernels/common/context.h index ccd88bdeac..936d03e54d 100644 --- a/thirdparty/embree/kernels/common/context.h +++ b/thirdparty/embree/kernels/common/context.h @@ -11,35 +11,62 @@ namespace embree { class Scene; - struct IntersectContext + struct RayQueryContext { public: - __forceinline IntersectContext(Scene* scene, RTCIntersectContext* user_context) - : scene(scene), user(user_context) {} + + __forceinline RayQueryContext(Scene* scene, RTCRayQueryContext* user_context, RTCIntersectArguments* args) + : scene(scene), user(user_context), args(args) {} + + __forceinline RayQueryContext(Scene* scene, RTCRayQueryContext* user_context, RTCOccludedArguments* args) + : scene(scene), user(user_context), args((RTCIntersectArguments*)args) {} __forceinline bool hasContextFilter() const { - return user->filter != nullptr; + return args->filter != nullptr; + } + + RTCFilterFunctionN getFilter() const { + return args->filter; + } + + RTCIntersectFunctionN getIntersectFunction() const { + return args->intersect; + } + + RTCOccludedFunctionN getOccludedFunction() const { + return (RTCOccludedFunctionN) args->intersect; } __forceinline bool isCoherent() const { - return embree::isCoherent(user->flags); + return embree::isCoherent(args->flags); } __forceinline bool isIncoherent() const { - return embree::isIncoherent(user->flags); + return embree::isIncoherent(args->flags); } - + + __forceinline bool enforceArgumentFilterFunction() const { + return args->flags & RTC_RAY_QUERY_FLAG_INVOKE_ARGUMENT_FILTER; + } + +#if RTC_MIN_WIDTH + __forceinline float getMinWidthDistanceFactor() const { + return args->minWidthDistanceFactor; + } +#endif + public: - Scene* scene; - RTCIntersectContext* user; + Scene* scene = nullptr; + RTCRayQueryContext* user = nullptr; + RTCIntersectArguments* args = nullptr; }; template<int M, typename Geometry> - __forceinline Vec4vf<M> enlargeRadiusToMinWidth(const IntersectContext* context, const Geometry* geom, const Vec3vf<M>& ray_org, const Vec4vf<M>& v) + __forceinline Vec4vf<M> enlargeRadiusToMinWidth(const RayQueryContext* context, const Geometry* geom, const Vec3vf<M>& ray_org, const Vec4vf<M>& v) { #if RTC_MIN_WIDTH const vfloat<M> d = length(Vec3vf<M>(v) - ray_org); - const vfloat<M> r = clamp(context->user->minWidthDistanceFactor*d, v.w, geom->maxRadiusScale*v.w); + const vfloat<M> r = clamp(context->getMinWidthDistanceFactor()*d, v.w, geom->maxRadiusScale*v.w); return Vec4vf<M>(v.x,v.y,v.z,r); #else return v; @@ -47,16 +74,21 @@ namespace embree } template<typename Geometry> - __forceinline Vec3ff enlargeRadiusToMinWidth(const IntersectContext* context, const Geometry* geom, const Vec3fa& ray_org, const Vec3ff& v) + __forceinline Vec3ff enlargeRadiusToMinWidth(const RayQueryContext* context, const Geometry* geom, const Vec3fa& ray_org, const Vec3ff& v) { #if RTC_MIN_WIDTH const float d = length(Vec3fa(v) - ray_org); - const float r = clamp(context->user->minWidthDistanceFactor*d, v.w, geom->maxRadiusScale*v.w); + const float r = clamp(context->getMinWidthDistanceFactor()*d, v.w, geom->maxRadiusScale*v.w); return Vec3ff(v.x,v.y,v.z,r); #else return v; #endif } + + template<typename Geometry> + __forceinline Vec3ff enlargeRadiusToMinWidth(const RayQueryContext* context, const Geometry* geom, const Vec3fa& ray_org, const Vec4f& v) { + return enlargeRadiusToMinWidth(context,geom,ray_org,Vec3ff(v.x,v.y,v.z,v.w)); + } enum PointQueryType { @@ -66,7 +98,7 @@ namespace embree }; typedef bool (*PointQueryFunction)(struct RTCPointQueryFunctionArguments* args); - + struct PointQueryContext { public: @@ -78,6 +110,7 @@ namespace embree float similarityScale, void* userPtr) : scene(scene) + , tstate(nullptr) , query_ws(query_ws) , query_type(query_type) , func(func) @@ -88,16 +121,24 @@ namespace embree , geomID(RTC_INVALID_GEOMETRY_ID) , query_radius(query_ws->radius) { + update(); + } + + public: + __forceinline void update() + { if (query_type == POINT_QUERY_TYPE_AABB) { assert(similarityScale == 0.f); updateAABB(); } + else{ + query_radius = Vec3fa(query_ws->radius * similarityScale); + } if (userContext->instStackSize == 0) { assert(similarityScale == 1.f); } } - public: __forceinline void updateAABB() { if (likely(query_ws->radius == (float)inf || userContext->instStackSize == 0)) { @@ -113,12 +154,13 @@ namespace embree public: Scene* scene; + void* tstate; PointQuery* query_ws; // the original world space point query PointQueryType query_type; PointQueryFunction func; RTCPointQueryContext* userContext; - const float similarityScale; + float similarityScale; void* userPtr; diff --git a/thirdparty/embree/kernels/common/default.h b/thirdparty/embree/kernels/common/default.h index f15d61b768..3b00ad3c88 100644 --- a/thirdparty/embree/kernels/common/default.h +++ b/thirdparty/embree/kernels/common/default.h @@ -13,11 +13,11 @@ #include "../../common/sys/mutex.h" #include "../../common/sys/vector.h" #include "../../common/sys/array.h" -#include "../../common/sys/string.h" +#include "../../common/sys/estring.h" #include "../../common/sys/regression.h" #include "../../common/sys/vector.h" -#include "../../common/math/math.h" +#include "../../common/math/emath.h" #include "../../common/math/transcendental.h" #include "../../common/simd/simd.h" #include "../../common/math/vec2.h" @@ -35,8 +35,6 @@ #include "../../common/math/range.h" #include "../../common/lexers/tokenstream.h" -#include "../../common/tasking/taskscheduler.h" - #define COMMA , #include "../config.h" @@ -217,7 +215,7 @@ namespace embree __forceinline int getTimeSegment(float time, float numTimeSegments, float& ftime) { const float timeScaled = time * numTimeSegments; - const float itimef = clamp(floorf(timeScaled), 0.0f, numTimeSegments-1.0f); + const float itimef = clamp(floor(timeScaled), 0.0f, numTimeSegments-1.0f); ftime = timeScaled - itimef; return int(itimef); } @@ -225,7 +223,7 @@ namespace embree __forceinline int getTimeSegment(float time, float start_time, float end_time, float numTimeSegments, float& ftime) { const float timeScaled = (time-start_time)/(end_time-start_time) * numTimeSegments; - const float itimef = clamp(floorf(timeScaled), 0.0f, numTimeSegments-1.0f); + const float itimef = clamp(floor(timeScaled), 0.0f, numTimeSegments-1.0f); ftime = timeScaled - itimef; return int(itimef); } diff --git a/thirdparty/embree/kernels/common/device.cpp b/thirdparty/embree/kernels/common/device.cpp index 833ec65139..07214532a1 100644 --- a/thirdparty/embree/kernels/common/device.cpp +++ b/thirdparty/embree/kernels/common/device.cpp @@ -2,6 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 #include "device.h" + +#include "../../common/tasking/taskscheduler.h" + #include "../hash.h" #include "scene_triangle_mesh.h" #include "scene_user_geometry.h" @@ -19,9 +22,12 @@ #include "../bvh/bvh4_factory.h" #include "../bvh/bvh8_factory.h" -#include "../../common/tasking/taskscheduler.h" #include "../../common/sys/alloc.h" +#if defined(EMBREE_SYCL_SUPPORT) +# include "../level_zero/ze_wrapper.h" +#endif + namespace embree { /*! some global variables that can be set via rtcSetParameter1i for debugging purposes */ @@ -30,13 +36,18 @@ namespace embree ssize_t Device::debug_int2 = 0; ssize_t Device::debug_int3 = 0; - DECLARE_SYMBOL2(RayStreamFilterFuncs,rayStreamFilterFuncs); - static MutexSys g_mutex; static std::map<Device*,size_t> g_cache_size_map; static std::map<Device*,size_t> g_num_threads_map; + + struct TaskArena + { +#if USE_TASK_ARENA + std::unique_ptr<tbb::task_arena> arena; +#endif + }; - Device::Device (const char* cfg) + Device::Device (const char* cfg) : arena(new TaskArena()) { /* check that CPU supports lowest ISA */ if (!hasISA(ISA)) { @@ -48,12 +59,12 @@ namespace embree case CPU::UNKNOWN: frequency_level = FREQUENCY_SIMD256; break; case CPU::XEON_ICE_LAKE: frequency_level = FREQUENCY_SIMD256; break; case CPU::CORE_ICE_LAKE: frequency_level = FREQUENCY_SIMD256; break; - case CPU::CORE_TIGER_LAKE: frequency_level = FREQUENCY_SIMD128; break; - case CPU::CORE_COMET_LAKE: frequency_level = FREQUENCY_SIMD128; break; - case CPU::CORE_CANNON_LAKE:frequency_level = FREQUENCY_SIMD128; break; - case CPU::CORE_KABY_LAKE: frequency_level = FREQUENCY_SIMD128; break; + case CPU::CORE_TIGER_LAKE: frequency_level = FREQUENCY_SIMD256; break; + case CPU::CORE_COMET_LAKE: frequency_level = FREQUENCY_SIMD256; break; + case CPU::CORE_CANNON_LAKE:frequency_level = FREQUENCY_SIMD256; break; + case CPU::CORE_KABY_LAKE: frequency_level = FREQUENCY_SIMD256; break; case CPU::XEON_SKY_LAKE: frequency_level = FREQUENCY_SIMD128; break; - case CPU::CORE_SKY_LAKE: frequency_level = FREQUENCY_SIMD128; break; + case CPU::CORE_SKY_LAKE: frequency_level = FREQUENCY_SIMD256; break; case CPU::XEON_BROADWELL: frequency_level = FREQUENCY_SIMD256; break; case CPU::CORE_BROADWELL: frequency_level = FREQUENCY_SIMD256; break; case CPU::XEON_HASWELL: frequency_level = FREQUENCY_SIMD256; break; @@ -66,11 +77,7 @@ namespace embree case CPU::CORE1: frequency_level = FREQUENCY_SIMD128; break; case CPU::XEON_PHI_KNIGHTS_MILL : frequency_level = FREQUENCY_SIMD512; break; case CPU::XEON_PHI_KNIGHTS_LANDING: frequency_level = FREQUENCY_SIMD512; break; -#if defined(__APPLE__) - case CPU::ARM: frequency_level = FREQUENCY_SIMD256; break; // Apple M1 supports high throughput for SIMD4 -#else - case CPU::ARM: frequency_level = FREQUENCY_SIMD128; break; -#endif + case CPU::ARM: frequency_level = FREQUENCY_SIMD256; break; } /* initialize global state */ @@ -126,13 +133,6 @@ namespace embree /* setup tasking system */ initTaskingSystem(numThreads); - - /* ray stream SOA to AOS conversion */ -#if defined(EMBREE_RAY_PACKETS) - RayStreamFilterFuncsType rayStreamFilterFuncs; - SELECT_SYMBOL_DEFAULT_SSE42_AVX_AVX2_AVX512(enabled_cpu_features,rayStreamFilterFuncs); - rayStreamFilters = rayStreamFilterFuncs(); -#endif } Device::~Device () @@ -174,6 +174,9 @@ namespace embree #if defined (EMBREE_BACKFACE_CULLING_CURVES) v += "backfacecullingcurves "; #endif +#if defined (EMBREE_BACKFACE_CULLING_SPHERES) + v += "backfacecullingspheres "; +#endif #if defined(EMBREE_FILTER_FUNCTION) v += "intersection_filter "; #endif @@ -367,7 +370,7 @@ namespace embree #if USE_TASK_ARENA const size_t nThreads = min(maxNumThreads,TaskScheduler::threadCount()); const size_t uThreads = min(max(numUserThreads,(size_t)1),nThreads); - arena = make_unique(new tbb::task_arena((int)nThreads,(unsigned int)uThreads)); + arena->arena = make_unique(new tbb::task_arena((int)nThreads,(unsigned int)uThreads)); #endif } @@ -386,8 +389,21 @@ namespace embree TaskScheduler::create(maxNumThreads,State::set_affinity,State::start_threads); } #if USE_TASK_ARENA - arena.reset(); + arena->arena.reset(); +#endif + } + + void Device::execute(bool join, const std::function<void()>& func) + { +#if USE_TASK_ARENA + if (join) { + arena->arena->execute(func); + } + else #endif + { + func(); + } } void Device::setProperty(const RTCDeviceProperty prop, ssize_t val) @@ -450,12 +466,6 @@ namespace embree case RTC_DEVICE_PROPERTY_NATIVE_RAY16_SUPPORTED: return 0; #endif -#if defined(EMBREE_RAY_PACKETS) - case RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED: return 1; -#else - case RTC_DEVICE_PROPERTY_RAY_STREAM_SUPPORTED: return 0; -#endif - #if defined(EMBREE_RAY_MASK) case RTC_DEVICE_PROPERTY_RAY_MASK_SUPPORTED: return 1; #else @@ -474,6 +484,12 @@ namespace embree case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_CURVES_ENABLED: return 0; #endif +#if defined(EMBREE_BACKFACE_CULLING_SPHERES) + case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED: return 1; +#else + case RTC_DEVICE_PROPERTY_BACKFACE_CULLING_SPHERES_ENABLED: return 0; +#endif + #if defined(EMBREE_COMPACT_POLYS) case RTC_DEVICE_PROPERTY_COMPACT_POLYS_ENABLED: return 1; #else @@ -557,4 +573,158 @@ namespace embree default: throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "unknown readable property"); break; }; } + + void* Device::malloc(size_t size, size_t align) { + return alignedMalloc(size,align); + } + + void Device::free(void* ptr) { + alignedFree(ptr); + } + + +#if defined(EMBREE_SYCL_SUPPORT) + + DeviceGPU::DeviceGPU(sycl::context sycl_context, const char* cfg) + : Device(cfg), gpu_context(sycl_context) + { + /* initialize ZeWrapper */ + if (ZeWrapper::init() != ZE_RESULT_SUCCESS) + throw_RTCError(RTC_ERROR_UNKNOWN, "cannot initialize ZeWrapper"); + + /* take first device as default device */ + auto devices = gpu_context.get_devices(); + if (devices.size() == 0) + throw_RTCError(RTC_ERROR_UNKNOWN, "SYCL context contains no device"); + gpu_device = devices[0]; + + /* check if RTAS build extension is available */ + sycl::platform platform = gpu_device.get_platform(); + ze_driver_handle_t hDriver = sycl::get_native<sycl::backend::ext_oneapi_level_zero>(platform); + + uint32_t count = 0; + std::vector<ze_driver_extension_properties_t> extensions; + ze_result_t result = ZeWrapper::zeDriverGetExtensionProperties(hDriver,&count,extensions.data()); + if (result != ZE_RESULT_SUCCESS) + throw_RTCError(RTC_ERROR_UNKNOWN, "zeDriverGetExtensionProperties failed"); + + extensions.resize(count); + result = ZeWrapper::zeDriverGetExtensionProperties(hDriver,&count,extensions.data()); + if (result != ZE_RESULT_SUCCESS) + throw_RTCError(RTC_ERROR_UNKNOWN, "zeDriverGetExtensionProperties failed"); + +#if defined(EMBREE_SYCL_L0_RTAS_BUILDER) + bool ze_rtas_builder = false; + for (uint32_t i=0; i<extensions.size(); i++) + { + if (strncmp("ZE_experimental_rtas_builder",extensions[i].name,sizeof(extensions[i].name)) == 0) + ze_rtas_builder = true; + } + if (!ze_rtas_builder) + throw_RTCError(RTC_ERROR_UNKNOWN, "ZE_experimental_rtas_builder extension not found"); + + result = ZeWrapper::initRTASBuilder(hDriver,ZeWrapper::LEVEL_ZERO); + if (result == ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE) + throw_RTCError(RTC_ERROR_UNKNOWN, "cannot load ZE_experimental_rtas_builder extension"); + if (result != ZE_RESULT_SUCCESS) + throw_RTCError(RTC_ERROR_UNKNOWN, "cannot initialize ZE_experimental_rtas_builder extension"); +#else + ZeWrapper::initRTASBuilder(hDriver,ZeWrapper::INTERNAL); +#endif + + if (State::verbosity(1)) + { + if (ZeWrapper::rtas_builder == ZeWrapper::INTERNAL) + std::cout << " Internal RTAS Builder" << std::endl; + else + std::cout << " Level Zero RTAS Builder" << std::endl; + } + + /* check if extension library can get loaded */ + ze_rtas_parallel_operation_exp_handle_t hParallelOperation; + result = ZeWrapper::zeRTASParallelOperationCreateExp(hDriver, &hParallelOperation); + if (result == ZE_RESULT_ERROR_DEPENDENCY_UNAVAILABLE) + throw_RTCError(RTC_ERROR_UNKNOWN, "Level Zero RTAS Build Extension cannot get loaded"); + if (result == ZE_RESULT_SUCCESS) + ZeWrapper::zeRTASParallelOperationDestroyExp(hParallelOperation); + + gpu_maxWorkGroupSize = getGPUDevice().get_info<sycl::info::device::max_work_group_size>(); + gpu_maxComputeUnits = getGPUDevice().get_info<sycl::info::device::max_compute_units>(); + + if (State::verbosity(1)) + { + sycl::platform platform = gpu_context.get_platform(); + std::cout << " Platform : " << platform.get_info<sycl::info::platform::name>() << std::endl; + std::cout << " Device : " << getGPUDevice().get_info<sycl::info::device::name>() << std::endl; + std::cout << " Max Work Group Size : " << gpu_maxWorkGroupSize << std::endl; + std::cout << " Max Compute Units : " << gpu_maxComputeUnits << std::endl; + std::cout << std::endl; + } + + dispatchGlobalsPtr = zeRTASInitExp(gpu_device, gpu_context); + } + + DeviceGPU::~DeviceGPU() + { + rthwifCleanup(this,dispatchGlobalsPtr,gpu_context); + } + + void DeviceGPU::enter() { + enableUSMAllocEmbree(&gpu_context,&gpu_device); + } + + void DeviceGPU::leave() { + disableUSMAllocEmbree(); + } + + void* DeviceGPU::malloc(size_t size, size_t align) { + return alignedSYCLMalloc(&gpu_context,&gpu_device,size,align,EMBREE_USM_SHARED_DEVICE_READ_ONLY); + } + + void DeviceGPU::free(void* ptr) { + alignedSYCLFree(&gpu_context,ptr); + } + + void DeviceGPU::setSYCLDevice(const sycl::device sycl_device_in) { + gpu_device = sycl_device_in; + } + +#endif + + DeviceEnterLeave::DeviceEnterLeave (RTCDevice hdevice) + : device((Device*)hdevice) + { + assert(device); + device->refInc(); + device->enter(); + } + + DeviceEnterLeave::DeviceEnterLeave (RTCScene hscene) + : device(((Scene*)hscene)->device) + { + assert(device); + device->refInc(); + device->enter(); + } + + DeviceEnterLeave::DeviceEnterLeave (RTCGeometry hgeometry) + : device(((Geometry*)hgeometry)->device) + { + assert(device); + device->refInc(); + device->enter(); + } + + DeviceEnterLeave::DeviceEnterLeave (RTCBuffer hbuffer) + : device(((Buffer*)hbuffer)->device) + { + assert(device); + device->refInc(); + device->enter(); + } + + DeviceEnterLeave::~DeviceEnterLeave() { + device->leave(); + device->refDec(); + } } diff --git a/thirdparty/embree/kernels/common/device.h b/thirdparty/embree/kernels/common/device.h index 21c42c654d..c9e8888a5a 100644 --- a/thirdparty/embree/kernels/common/device.h +++ b/thirdparty/embree/kernels/common/device.h @@ -11,10 +11,57 @@ namespace embree { class BVH4Factory; class BVH8Factory; + struct TaskArena; class Device : public State, public MemoryMonitorInterface { ALIGNED_CLASS_(16); + + public: + + /*! allocator that performs unified shared memory allocations */ + template<typename T, size_t alignment> + struct allocator + { + typedef T value_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + allocator() {} + + allocator(Device* device) + : device(device) {} + + __forceinline pointer allocate( size_type n ) { + assert(device); + return (pointer) device->malloc(n*sizeof(T),alignment); + } + + __forceinline void deallocate( pointer p, size_type n ) { + if (device) device->free(p); + } + + __forceinline void construct( pointer p, const_reference val ) { + new (p) T(val); + } + + __forceinline void destroy( pointer p ) { + p->~T(); + } + + Device* device = nullptr; + }; + + /*! vector class that performs aligned allocations from Device object */ + template<typename T> + using vector = vector_t<T,allocator<T,std::alignment_of<T>::value>>; + + template<typename T, size_t alignment> + using avector = vector_t<T,allocator<T,alignment>>; public: @@ -54,6 +101,18 @@ namespace embree /*! gets a property */ ssize_t getProperty(const RTCDeviceProperty prop); + /*! enter device by setting up some global state */ + virtual void enter() {} + + /*! leave device by setting up some global state */ + virtual void leave() {} + + /*! buffer allocation */ + virtual void* malloc(size_t size, size_t align); + + /*! buffer deallocation */ + virtual void free(void* ptr); + private: /*! initializes the tasking system */ @@ -62,6 +121,13 @@ namespace embree /*! shuts down the tasking system */ void exitTaskingSystem(); + std::unique_ptr<TaskArena> arena; + + public: + + // use tasking system arena to execute func + void execute(bool join, const std::function<void()>& func); + /*! some variables that can be set via rtcSetParameter1i for debugging purposes */ public: static ssize_t debug_int0; @@ -74,12 +140,55 @@ namespace embree #if defined(EMBREE_TARGET_SIMD8) std::unique_ptr<BVH8Factory> bvh8_factory; #endif - -#if USE_TASK_ARENA - std::unique_ptr<tbb::task_arena> arena; + }; + +#if defined(EMBREE_SYCL_SUPPORT) + + class DeviceGPU : public Device + { + public: + + DeviceGPU(sycl::context sycl_context, const char* cfg); + ~DeviceGPU(); + + virtual void enter() override; + virtual void leave() override; + virtual void* malloc(size_t size, size_t align) override; + virtual void free(void* ptr) override; + + /* set SYCL device */ + void setSYCLDevice(const sycl::device sycl_device); + + private: + sycl::context gpu_context; + sycl::device gpu_device; + + unsigned int gpu_maxWorkGroupSize; + unsigned int gpu_maxComputeUnits; + + public: + void* dispatchGlobalsPtr = nullptr; + + public: + inline sycl::device &getGPUDevice() { return gpu_device; } + inline sycl::context &getGPUContext() { return gpu_context; } + + inline unsigned int getGPUMaxWorkGroupSize() { return gpu_maxWorkGroupSize; } + + void init_rthw_level_zero(); + void init_rthw_opencl(); + }; + #endif - - /* ray streams filter */ - RayStreamFilterFuncs rayStreamFilters; + + struct DeviceEnterLeave + { + DeviceEnterLeave (RTCDevice hdevice); + DeviceEnterLeave (RTCScene hscene); + DeviceEnterLeave (RTCGeometry hgeometry); + DeviceEnterLeave (RTCBuffer hbuffer); + ~DeviceEnterLeave(); + private: + Device* device; }; } diff --git a/thirdparty/embree/kernels/common/geometry.cpp b/thirdparty/embree/kernels/common/geometry.cpp index d8d3f65a5c..79a6eb00d7 100644 --- a/thirdparty/embree/kernels/common/geometry.cpp +++ b/thirdparty/embree/kernels/common/geometry.cpp @@ -45,12 +45,13 @@ namespace embree Geometry::Geometry (Device* device, GType gtype, unsigned int numPrimitives, unsigned int numTimeSteps) : device(device), userPtr(nullptr), numPrimitives(numPrimitives), numTimeSteps(unsigned(numTimeSteps)), fnumTimeSegments(float(numTimeSteps-1)), time_range(0.0f,1.0f), - mask(-1), + mask(1), gtype(gtype), gsubtype(GTY_SUBTYPE_DEFAULT), quality(RTC_BUILD_QUALITY_MEDIUM), state((unsigned)State::MODIFIED), enabled(true), + argumentFilterEnabled(false), intersectionFilterN(nullptr), occlusionFilterN(nullptr), pointQueryFunc(nullptr) { device->refInc(); @@ -88,6 +89,11 @@ namespace embree Geometry::update(); } + BBox1f Geometry::getTimeRange () const + { + return time_range; + } + void Geometry::update() { ++modCounter_; // FIXME: required? @@ -227,11 +233,11 @@ namespace embree } } } - + bool Geometry::pointQuery(PointQuery* query, PointQueryContext* context) { assert(context->primID < size()); - + RTCPointQueryFunctionArguments args; args.query = (RTCPointQuery*)context->query_ws; args.userPtr = context->userPtr; @@ -239,7 +245,7 @@ namespace embree args.geomID = context->geomID; args.context = context->userContext; args.similarityScale = context->similarityScale; - + bool update = false; if(context->func) update |= context->func(&args); if(pointQueryFunc) update |= pointQueryFunc(&args); diff --git a/thirdparty/embree/kernels/common/geometry.h b/thirdparty/embree/kernels/common/geometry.h index 593990f5b1..00e3c5ede3 100644 --- a/thirdparty/embree/kernels/common/geometry.h +++ b/thirdparty/embree/kernels/common/geometry.h @@ -8,6 +8,7 @@ #include "buffer.h" #include "../common/point_query.h" #include "../builders/priminfo.h" +#include "../builders/priminfo_mb.h" namespace embree { @@ -26,12 +27,14 @@ namespace embree numUserGeometries(0), numMBUserGeometries(0), numInstancesCheap(0), numMBInstancesCheap(0), numInstancesExpensive(0), numMBInstancesExpensive(0), - numGrids(0), numMBGrids(0), + numInstanceArrays(0), numMBInstanceArrays(0), + numGrids(0), numMBGrids(0), + numSubGrids(0), numMBSubGrids(0), numPoints(0), numMBPoints(0) {} __forceinline size_t size() const { - return numTriangles + numQuads + numBezierCurves + numLineSegments + numSubdivPatches + numUserGeometries + numInstancesCheap + numInstancesExpensive + numGrids + numPoints - + numMBTriangles + numMBQuads + numMBBezierCurves + numMBLineSegments + numMBSubdivPatches + numMBUserGeometries + numMBInstancesCheap + numMBInstancesExpensive + numMBGrids + numMBPoints; + return numTriangles + numQuads + numBezierCurves + numLineSegments + numSubdivPatches + numUserGeometries + numInstancesCheap + numInstancesExpensive + numInstanceArrays + numGrids + numPoints + + numMBTriangles + numMBQuads + numMBBezierCurves + numMBLineSegments + numMBSubdivPatches + numMBUserGeometries + numMBInstancesCheap + numMBInstancesExpensive + numMBInstanceArrays + numMBGrids + numMBPoints; } __forceinline unsigned int enabledGeometryTypesMask() const @@ -44,8 +47,9 @@ namespace embree if (numUserGeometries) mask |= 1 << 4; if (numInstancesCheap) mask |= 1 << 5; if (numInstancesExpensive) mask |= 1 << 6; - if (numGrids) mask |= 1 << 7; - if (numPoints) mask |= 1 << 8; + if (numInstanceArrays) mask |= 1 << 7; + if (numGrids) mask |= 1 << 8; + if (numPoints) mask |= 1 << 9; unsigned int maskMB = 0; if (numMBTriangles) maskMB |= 1 << 0; @@ -55,8 +59,9 @@ namespace embree if (numMBUserGeometries) maskMB |= 1 << 4; if (numMBInstancesCheap) maskMB |= 1 << 5; if (numMBInstancesExpensive) maskMB |= 1 << 6; - if (numMBGrids) maskMB |= 1 << 7; - if (numMBPoints) maskMB |= 1 << 8; + if (numMBInstanceArrays) maskMB |= 1 << 7; + if (numMBGrids) maskMB |= 1 << 8; + if (numMBPoints) maskMB |= 1 << 9; return (mask<<8) + maskMB; } @@ -81,8 +86,12 @@ namespace embree ret.numMBInstancesCheap = numMBInstancesCheap + rhs.numMBInstancesCheap; ret.numInstancesExpensive = numInstancesExpensive + rhs.numInstancesExpensive; ret.numMBInstancesExpensive = numMBInstancesExpensive + rhs.numMBInstancesExpensive; + ret.numInstanceArrays = numInstanceArrays + rhs.numInstanceArrays; + ret.numMBInstanceArrays = numMBInstanceArrays + rhs.numMBInstanceArrays; ret.numGrids = numGrids + rhs.numGrids; ret.numMBGrids = numMBGrids + rhs.numMBGrids; + ret.numSubGrids = numSubGrids + rhs.numSubGrids; + ret.numMBSubGrids = numMBSubGrids + rhs.numMBSubGrids; ret.numPoints = numPoints + rhs.numPoints; ret.numMBPoints = numMBPoints + rhs.numMBPoints; @@ -106,8 +115,12 @@ namespace embree size_t numMBInstancesCheap; //!< number of enabled motion blurred cheap instances size_t numInstancesExpensive; //!< number of enabled expensive instances size_t numMBInstancesExpensive; //!< number of enabled motion blurred expensive instances + size_t numInstanceArrays; //!< number of enabled instance arrays + size_t numMBInstanceArrays; //!< number of enabled motion blurred instance arrays size_t numGrids; //!< number of enabled grid geometries size_t numMBGrids; //!< number of enabled motion blurred grid geometries + size_t numSubGrids; //!< number of enabled grid geometries + size_t numMBSubGrids; //!< number of enabled motion blurred grid geometries size_t numPoints; //!< number of enabled points size_t numMBPoints; //!< number of enabled motion blurred points }; @@ -115,6 +128,8 @@ namespace embree /*! Base class all geometries are derived from */ class Geometry : public RefCount { + ALIGNED_CLASS_USM_(16); + friend class Scene; public: @@ -154,6 +169,7 @@ namespace embree GTY_USER_GEOMETRY = 29, GTY_INSTANCE_CHEAP = 30, GTY_INSTANCE_EXPENSIVE = 31, + GTY_INSTANCE_ARRAY = 24, GTY_END = 32, GTY_BASIS_LINEAR = 0, @@ -222,7 +238,10 @@ namespace embree MTY_INSTANCE_CHEAP = 1ul << GTY_INSTANCE_CHEAP, MTY_INSTANCE_EXPENSIVE = 1ul << GTY_INSTANCE_EXPENSIVE, - MTY_INSTANCE = MTY_INSTANCE_CHEAP | MTY_INSTANCE_EXPENSIVE + MTY_INSTANCE = MTY_INSTANCE_CHEAP | MTY_INSTANCE_EXPENSIVE, + MTY_INSTANCE_ARRAY = 1ul << GTY_INSTANCE_ARRAY, + + MTY_ALL = -1 }; static const char* gtype_names[GTY_END]; @@ -248,8 +267,13 @@ namespace embree /*! tests if geometry is disabled */ __forceinline bool isDisabled() const { return !isEnabled(); } + /* checks if argument version of filter functions are enabled */ + __forceinline bool hasArgumentFilterFunctions() const { + return argumentFilterEnabled; + } + /*! tests if that geometry has some filter function set */ - __forceinline bool hasFilterFunctions () const { + __forceinline bool hasGeometryFilterFunctions () const { return (intersectionFilterN != nullptr) || (occlusionFilterN != nullptr); } @@ -265,6 +289,11 @@ namespace embree /*! returns geometry type mask */ __forceinline GTypeMask getTypeMask() const { return (GTypeMask)(1 << gtype); } + /*! returns true of geometry contains motion blur */ + __forceinline bool hasMotionBlur () const { + return numTimeSteps > 1; + } + /*! returns number of primitives */ __forceinline size_t size() const { return numPrimitives; } @@ -277,6 +306,9 @@ namespace embree /*! sets motion blur time range */ void setTimeRange (const BBox1f range); + /*! gets motion blur time range */ + BBox1f getTimeRange () const; + /*! sets number of vertex attributes */ virtual void setVertexAttributeCount (unsigned int N) { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry"); @@ -447,6 +479,11 @@ namespace embree /*! Set occlusion filter function for ray packets of size N. */ virtual void setOcclusionFilterFunctionN (RTCFilterFunctionN filterN); + /* Enables argument version of intersection or occlusion filter function. */ + virtual void enableFilterFunctionFromArguments (bool enable) { + argumentFilterEnabled = enable; + } + /*! for instances only */ public: @@ -455,6 +492,11 @@ namespace embree throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry"); } + /*! Sets the instanced scenes */ + virtual void setInstancedScenes(const RTCScene* scenes, size_t numScenes) { + throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry"); + } + /*! Sets transformation of the instance */ virtual void setTransform(const AffineSpace3fa& transform, unsigned int timeStep) { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry"); @@ -467,7 +509,12 @@ namespace embree /*! Returns the transformation of the instance */ virtual AffineSpace3fa getTransform(float time) { - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry"); + throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry"); + } + + /*! Returns the transformation of the instance */ + virtual AffineSpace3fa getTransform(size_t instance, float time) { + throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation not supported for this geometry"); } /*! for user geometries only */ @@ -498,18 +545,47 @@ namespace embree public: - virtual PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const { + virtual PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefArray not implemented for this geometry"); } + PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const { + return createPrimRefArray(prims.data(),r,k,geomID); + } + + PrimInfo createPrimRefArray(avector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const { + return createPrimRefArray(prims.data(),r,k,geomID); + } + + virtual PrimInfo createPrimRefArray(mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids, const range<size_t>& r, size_t k, unsigned int geomID) const { + return createPrimRefArray(prims,r,k,geomID); + } + virtual PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefMBArray not implemented for this geometry"); } + /*! Calculates the PrimRef over the complete time interval */ + virtual PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { + throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefMBArray not implemented for this geometry"); + } + + PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { + return createPrimRefArrayMB(prims.data(),t0t1,r,k,geomID); + } + + PrimInfo createPrimRefArrayMB(avector<PrimRef>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { + return createPrimRefArrayMB(prims.data(),t0t1,r,k,geomID); + } + virtual PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"createPrimRefMBArray not implemented for this geometry"); } + virtual PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, mvector<SubGridBuildData>& sgrids, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { + return createPrimRefMBArray(prims,t0t1,r,k,geomID); + } + virtual LinearSpace3fa computeAlignedSpace(const size_t primID) const { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"computeAlignedSpace not implemented for this geometry"); } @@ -541,6 +617,10 @@ namespace embree virtual LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vlinearBounds not implemented for this geometry"); } + + virtual LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range, const SubGridBuildData * const sgrids) const { + return vlinearBounds(primID,time_range); + } virtual LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"vlinearBounds not implemented for this geometry"); @@ -566,13 +646,14 @@ namespace embree unsigned int mask; //!< for masking out geometry unsigned int modCounter_ = 1; //!< counter for every modification - used to rebuild scenes when geo is modified - + struct { GType gtype : 8; //!< geometry type GSubType gsubtype : 8; //!< geometry subtype RTCBuildQuality quality : 3; //!< build quality for geometry unsigned state : 2; - bool enabled : 1; //!< true if geometry is enabled + bool enabled : 1; //!< true if geometry is enabled + bool argumentFilterEnabled : 1; //!< true if argument filter functions are enabled for this geometry }; RTCFilterFunctionN intersectionFilterN; diff --git a/thirdparty/embree/kernels/common/hit.h b/thirdparty/embree/kernels/common/hit.h index fd1a9d6391..cbaeb9b73a 100644 --- a/thirdparty/embree/kernels/common/hit.h +++ b/thirdparty/embree/kernels/common/hit.h @@ -17,14 +17,26 @@ namespace embree __forceinline HitK() {} /* Constructs a hit */ - __forceinline HitK(const RTCIntersectContext* context, const vuint<K>& geomID, const vuint<K>& primID, const vfloat<K>& u, const vfloat<K>& v, const Vec3vf<K>& Ng) + __forceinline HitK(const RTCRayQueryContext* context, const vuint<K>& geomID, const vuint<K>& primID, const vfloat<K>& u, const vfloat<K>& v, const Vec3vf<K>& Ng) : Ng(Ng), u(u), v(v), primID(primID), geomID(geomID) { - for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) { instID[l] = RTC_INVALID_GEOMETRY_ID; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instPrimID[l] = RTC_INVALID_GEOMETRY_ID; +#endif + } + instance_id_stack::copy_UV<K>(context->instID, instID); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UV<K>(context->instPrimID, instPrimID); +#endif } + /* Constructs a hit */ + __forceinline HitK(const RTCRayQueryContext* context, const vuint<K>& geomID, const vuint<K>& primID, const Vec2vf<K>& uv, const Vec3vf<K>& Ng) + : HitK(context,geomID,primID,uv.x,uv.y,Ng) {} + /* Returns the size of the hit */ static __forceinline size_t size() { return K; } @@ -35,6 +47,9 @@ namespace embree vuint<K> primID; // primitive ID vuint<K> geomID; // geometry ID vuint<K> instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K> instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance primitive ID +#endif }; /* Specialization for a single hit */ @@ -45,12 +60,19 @@ namespace embree __forceinline HitK() {} /* Constructs a hit */ - __forceinline HitK(const RTCIntersectContext* context, unsigned int geomID, unsigned int primID, float u, float v, const Vec3fa& Ng) + __forceinline HitK(const RTCRayQueryContext* context, unsigned int geomID, unsigned int primID, float u, float v, const Vec3fa& Ng) : Ng(Ng.x,Ng.y,Ng.z), u(u), v(v), primID(primID), geomID(geomID) { - instance_id_stack::copy_UU(context->instID, instID); + instance_id_stack::copy_UU(context, context->instID, instID); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UU(context, context->instPrimID, instPrimID); +#endif } + /* Constructs a hit */ + __forceinline HitK(const RTCRayQueryContext* context, unsigned int geomID, unsigned int primID, const Vec2f& uv, const Vec3fa& Ng) + : HitK<1>(context,geomID,primID,uv.x,uv.y,Ng) {} + /* Returns the size of the hit */ static __forceinline size_t size() { return 1; } @@ -61,6 +83,9 @@ namespace embree unsigned int primID; // primitive ID unsigned int geomID; // geometry ID unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance primitive ID +#endif }; /* Shortcuts */ @@ -68,6 +93,7 @@ namespace embree typedef HitK<4> Hit4; typedef HitK<8> Hit8; typedef HitK<16> Hit16; + typedef HitK<VSIZEX> Hitx; /* Outputs hit to stream */ template<int K> @@ -84,6 +110,13 @@ namespace embree { cout << " " << ray.instID[l]; } +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + cout << " instPrimID ="; + for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + { + cout << " " << ray.instPrimID[l]; + } +#endif cout << embree_endl; return cout << "}"; } @@ -97,10 +130,13 @@ namespace embree ray.primID = hit.primID; ray.geomID = hit.geomID; instance_id_stack::copy_UU(hit.instID, ray.instID); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UU(hit.instPrimID, ray.instPrimID); +#endif } template<int K> - __forceinline void copyHitToRay(const vbool<K> &mask, RayHitK<K> &ray, const HitK<K> &hit) + __forceinline void copyHitToRay(const vbool<K>& mask, RayHitK<K>& ray, const HitK<K>& hit) { vfloat<K>::storeu(mask,&ray.Ng.x, hit.Ng.x); vfloat<K>::storeu(mask,&ray.Ng.y, hit.Ng.y); @@ -110,5 +146,8 @@ namespace embree vuint<K>::storeu(mask,&ray.primID, hit.primID); vuint<K>::storeu(mask,&ray.geomID, hit.geomID); instance_id_stack::copy_VV<K>(hit.instID, ray.instID, mask); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_VV<K>(hit.instPrimID, ray.instPrimID, mask); +#endif } } diff --git a/thirdparty/embree/kernels/common/instance_stack.h b/thirdparty/embree/kernels/common/instance_stack.h index d3c0a643f1..32b57b48a3 100644 --- a/thirdparty/embree/kernels/common/instance_stack.h +++ b/thirdparty/embree/kernels/common/instance_stack.h @@ -19,40 +19,108 @@ static_assert(RTC_MAX_INSTANCE_LEVEL_COUNT > 0, /* * Push an instance to the stack. */ -RTC_FORCEINLINE bool push(RTCIntersectContext* context, - unsigned instanceId) +template<typename Context> +RTC_FORCEINLINE bool push(Context context, + unsigned instanceId, + unsigned instancePrimId) { #if RTC_MAX_INSTANCE_LEVEL_COUNT > 1 const bool spaceAvailable = context->instStackSize < RTC_MAX_INSTANCE_LEVEL_COUNT; - /* We assert here because instances are silently dropped when the stack is full. + /* We assert here because instances are silently dropped when the stack is full. This might be quite hard to find in production. */ - assert(spaceAvailable); - if (likely(spaceAvailable)) - context->instID[context->instStackSize++] = instanceId; + assert(spaceAvailable); + if (likely(spaceAvailable)) { + context->instID[context->instStackSize] = instanceId; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + context->instPrimID[context->instStackSize] = instancePrimId; +#endif + context->instStackSize++; + } return spaceAvailable; #else const bool spaceAvailable = (context->instID[0] == RTC_INVALID_GEOMETRY_ID); - assert(spaceAvailable); - if (likely(spaceAvailable)) + assert(spaceAvailable); + if (likely(spaceAvailable)) { context->instID[0] = instanceId; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + context->instPrimID[0] = instancePrimId; +#endif + } return spaceAvailable; #endif } - /* * Pop the last instance pushed to the stack. * Do not call on an empty stack. */ -RTC_FORCEINLINE void pop(RTCIntersectContext* context) +template<typename Context> +RTC_FORCEINLINE void pop(Context context) { assert(context); #if RTC_MAX_INSTANCE_LEVEL_COUNT > 1 assert(context->instStackSize > 0); - context->instID[--context->instStackSize] = RTC_INVALID_GEOMETRY_ID; + --context->instStackSize; + context->instID[context->instStackSize] = RTC_INVALID_GEOMETRY_ID; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + context->instPrimID[context->instStackSize] = RTC_INVALID_GEOMETRY_ID; +#endif #else assert(context->instID[0] != RTC_INVALID_GEOMETRY_ID); context->instID[0] = RTC_INVALID_GEOMETRY_ID; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + context->instPrimID[0] = RTC_INVALID_GEOMETRY_ID; +#endif +#endif +} + + +/* Push an instance to the stack. Used for point queries*/ +RTC_FORCEINLINE bool push(RTCPointQueryContext* context, + unsigned int instanceId, + unsigned int instancePrimId, + AffineSpace3fa const& w2i, + AffineSpace3fa const& i2w) +{ + assert(context); + const size_t stackSize = context->instStackSize; + assert(stackSize < RTC_MAX_INSTANCE_LEVEL_COUNT); + context->instID[stackSize] = instanceId; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + context->instPrimID[stackSize] = instancePrimId; +#endif + + AffineSpace3fa_store_unaligned(w2i,(AffineSpace3fa*)context->world2inst[stackSize]); + AffineSpace3fa_store_unaligned(i2w,(AffineSpace3fa*)context->inst2world[stackSize]); + +#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1 + if (unlikely(stackSize > 0)) + { + const AffineSpace3fa world2inst = AffineSpace3fa_load_unaligned((AffineSpace3fa*)context->world2inst[stackSize ]) + * AffineSpace3fa_load_unaligned((AffineSpace3fa*)context->world2inst[stackSize-1]); + const AffineSpace3fa inst2world = AffineSpace3fa_load_unaligned((AffineSpace3fa*)context->inst2world[stackSize-1]) + * AffineSpace3fa_load_unaligned((AffineSpace3fa*)context->inst2world[stackSize ]); + AffineSpace3fa_store_unaligned(world2inst,(AffineSpace3fa*)context->world2inst[stackSize]); + AffineSpace3fa_store_unaligned(inst2world,(AffineSpace3fa*)context->inst2world[stackSize]); + } +#endif + context->instStackSize++; + return true; +} + +template<> +RTC_FORCEINLINE void pop(RTCPointQueryContext* context) +{ + assert(context); +#if RTC_MAX_INSTANCE_LEVEL_COUNT > 1 + assert(context->instStackSize > 0); +#else + assert(context->instID[0] != RTC_INVALID_GEOMETRY_ID); +#endif + --context->instStackSize; + context->instID[context->instStackSize] = RTC_INVALID_GEOMETRY_ID; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + context->instPrimID[context->instStackSize] = RTC_INVALID_GEOMETRY_ID; #endif } @@ -77,6 +145,24 @@ RTC_FORCEINLINE void copy_UU(const unsigned* src, unsigned* tgt) #endif } +RTC_FORCEINLINE void copy_UU(const RTCRayQueryContext* context, const unsigned* src, unsigned* tgt) +{ +#if (RTC_MAX_INSTANCE_LEVEL_COUNT == 1) + tgt[0] = src[0]; + +#else + + unsigned int depth = context->instStackSize; + + for (unsigned l = 0; l < depth; ++l) + tgt[l] = src[l]; + + for (unsigned l = depth; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + tgt[l] = RTC_INVALID_GEOMETRY_ID; + +#endif +} + template <int K> RTC_FORCEINLINE void copy_UV(const unsigned* src, vuint<K>* tgt) { diff --git a/thirdparty/embree/kernels/common/point_query.h b/thirdparty/embree/kernels/common/point_query.h index 7d55c91fff..e92e22ae36 100644 --- a/thirdparty/embree/kernels/common/point_query.h +++ b/thirdparty/embree/kernels/common/point_query.h @@ -120,6 +120,7 @@ namespace embree typedef PointQueryK<4> PointQuery4; typedef PointQueryK<8> PointQuery8; typedef PointQueryK<16> PointQuery16; + typedef PointQueryK<VSIZEX> PointQueryx; struct PointQueryN; /* Outputs point query to stream */ diff --git a/thirdparty/embree/kernels/common/ray.h b/thirdparty/embree/kernels/common/ray.h index 3c8ee3989c..c886013354 100644 --- a/thirdparty/embree/kernels/common/ray.h +++ b/thirdparty/embree/kernels/common/ray.h @@ -10,8 +10,6 @@ namespace embree { - static const size_t MAX_INTERNAL_STREAM_SIZE = 32; - /* Ray structure for K rays */ template<int K> struct RayK @@ -97,16 +95,24 @@ namespace embree : RayK<K>(org, dir, tnear, tfar, time, mask, id, flags), geomID(RTC_INVALID_GEOMETRY_ID) { - for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) { instID[l] = RTC_INVALID_GEOMETRY_ID; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instPrimID[l] = RTC_INVALID_GEOMETRY_ID; +#endif + } } __forceinline RayHitK(const RayK<K>& ray) : RayK<K>(ray), geomID(RTC_INVALID_GEOMETRY_ID) { - for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) { instID[l] = RTC_INVALID_GEOMETRY_ID; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instPrimID[l] = RTC_INVALID_GEOMETRY_ID; +#endif + } } __forceinline RayHitK<K>& operator =(const RayK<K>& ray) @@ -121,8 +127,12 @@ namespace embree flags = ray.flags; geomID = RTC_INVALID_GEOMETRY_ID; - for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) { instID[l] = RTC_INVALID_GEOMETRY_ID; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instPrimID[l] = RTC_INVALID_GEOMETRY_ID; +#endif + } return *this; } @@ -159,7 +169,10 @@ namespace embree vuint<K> primID; // primitive ID vuint<K> geomID; // geometry ID vuint<K> instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID - }; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K> instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance prim ID +#endif +}; /* Specialization for a single ray */ template<> @@ -178,6 +191,11 @@ namespace embree return all(le_mask(abs(Vec3fa(org)), Vec3fa(FLT_LARGE)) & le_mask(abs(Vec3fa(dir)), Vec3fa(FLT_LARGE))) && abs(tnear()) <= float(inf) && abs(tfar) <= float(inf); } + /* checks if occlusion ray is done */ + __forceinline bool occluded() const { + return tfar < 0.0f; + } + /* Ray data */ Vec3ff org; // 3 floats for ray origin, 1 float for tnear //float tnear; // start of ray segment @@ -251,6 +269,9 @@ namespace embree unsigned int primID; // primitive ID unsigned int geomID; // geometry ID unsigned int instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance primitive ID +#endif }; /* Converts ray packet to single rays */ @@ -293,6 +314,9 @@ namespace embree ray.primID = primID[i]; ray.geomID = geomID[i]; instance_id_stack::copy_VU<K>(instID, ray.instID, i); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_VU<K>(instPrimID, ray.instPrimID, i); +#endif } /* Converts single rays to ray packet */ @@ -332,6 +356,9 @@ namespace embree primID[i] = ray.primID; geomID[i] = ray.geomID; instance_id_stack::copy_UV<K>(ray.instID, instID, i); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UV<K>(ray.instPrimID, instPrimID, i); +#endif } /* copies a ray packet element into another element*/ @@ -354,6 +381,9 @@ namespace embree primID[dest] = primID[source]; geomID[dest] = geomID[source]; instance_id_stack::copy_VV<K>(instID, instID, source, dest); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_VV<K>(instPrimID, instPrimID, source, dest); +#endif } /* Shortcuts */ @@ -361,12 +391,14 @@ namespace embree typedef RayK<4> Ray4; typedef RayK<8> Ray8; typedef RayK<16> Ray16; + typedef RayK<VSIZEX> Rayx; struct RayN; typedef RayHitK<1> RayHit; typedef RayHitK<4> RayHit4; typedef RayHitK<8> RayHit8; typedef RayHitK<16> RayHit16; + typedef RayHitK<VSIZEX> RayHitx; struct RayHitN; template<int K, bool intersect> @@ -428,6 +460,13 @@ namespace embree { cout << " " << ray.instID[l]; } +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + cout << " instPrimID ="; + for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + { + cout << " " << ray.instPrimID[l]; + } +#endif cout << embree_endl; return cout << "}"; } @@ -464,6 +503,9 @@ namespace embree __forceinline unsigned int* primID(size_t offset = 0) { return (unsigned int*)&ptr[17*4*N+offset]; }; // primitive ID __forceinline unsigned int* geomID(size_t offset = 0) { return (unsigned int*)&ptr[18*4*N+offset]; }; // geometry ID __forceinline unsigned int* instID(size_t level, size_t offset = 0) { return (unsigned int*)&ptr[19*4*N+level*4*N+offset]; }; // instance ID +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + __forceinline unsigned int* instPrimID(size_t level, size_t offset = 0) { return (unsigned int*)&ptr[19*4*N+RTC_MAX_INSTANCE_LEVEL_COUNT*4*N+level*4*N+offset]; }; // instance primitive ID +#endif __forceinline Ray getRayByOffset(size_t offset) { @@ -578,9 +620,16 @@ namespace embree geomID(offset)[k] = ray.geomID[k]; instID(0, offset)[k] = ray.instID[0][k]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instPrimID(0, offset)[k] = ray.instPrimID[0][k]; +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l) { instID(l, offset)[k] = ray.instID[l][k]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instPrimID(l, offset)[k] = ray.instPrimID[l][k]; +#endif + } #endif } } @@ -592,9 +641,16 @@ namespace embree vuint<K>::storeu(valid, geomID(offset), ray.geomID); vuint<K>::storeu(valid, instID(0, offset), ray.instID[0]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::storeu(valid, instPrimID(0, offset), ray.instPrimID[0]); +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) { vuint<K>::storeu(valid, instID(l, offset), ray.instID[l]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::storeu(valid, instPrimID(l, offset), ray.instPrimID[l]); +#endif + } #endif } } @@ -698,9 +754,16 @@ namespace embree vuint<K>::template scatter<1>(valid, geomID(), offset, ray.geomID); vuint<K>::template scatter<1>(valid, instID(0), offset, ray.instID[0]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::template scatter<1>(valid, instPrimID(0), offset, ray.instPrimID[0]); +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) { vuint<K>::template scatter<1>(valid, instID(l), offset, ray.instID[l]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::template scatter<1>(valid, instPrimID(l), offset, ray.instPrimID[l]); +#endif + } #endif #else size_t valid_bits = movemask(valid); @@ -720,9 +783,16 @@ namespace embree *geomID(ofs) = ray.geomID[k]; *instID(0, ofs) = ray.instID[0][k]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + *instPrimID(0, ofs) = ray.instPrimID[0][k]; +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l) { *instID(l, ofs) = ray.instID[l][k]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + *instPrimID(l, ofs) = ray.instPrimID[l][k]; +#endif + } #endif } #endif @@ -792,8 +862,12 @@ namespace embree primID = (unsigned int*)&t.primID; geomID = (unsigned int*)&t.geomID; - for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) + for (unsigned l = 0; l < RTC_MAX_INSTANCE_LEVEL_COUNT; ++l) { instID[l] = (unsigned int*)&t.instID[l]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instPrimID[l] = (unsigned int*)&t.instPrimID[l]; +#endif + } } __forceinline Ray getRayByOffset(size_t offset) @@ -859,9 +933,16 @@ namespace embree if (likely(instID[0])) { *(unsigned int* __restrict__)((char*)instID[0] + offset) = ray.instID[0]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + *(unsigned int* __restrict__)((char*)instPrimID[0] + offset) = ray.instPrimID[0]; +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID; ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID; ++l) { *(unsigned int* __restrict__)((char*)instID[l] + offset) = ray.instID[l]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + *(unsigned int* __restrict__)((char*)instPrimID[l] + offset) = ray.instPrimID[l]; +#endif + } #endif } } @@ -892,9 +973,16 @@ namespace embree if (likely(instID[0])) { vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)instID[0] + offset), ray.instID[0]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)instPrimID[0] + offset), ray.instPrimID[0]); +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) { vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)instID[l] + offset), ray.instID[l]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::storeu(valid, (unsigned int* __restrict__)((char*)instPrimID[l] + offset), ray.instPrimID[l]); +#endif + } #endif } } @@ -1008,9 +1096,16 @@ namespace embree if (likely(instID[0])) { vuint<K>::template scatter<1>(valid, (unsigned int*)instID[0], offset, ray.instID[0]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::template scatter<1>(valid, (unsigned int*)instPrimID[0], offset, ray.instPrimID[0]); +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) { vuint<K>::template scatter<1>(valid, (unsigned int*)instID[l], offset, ray.instID[l]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::template scatter<1>(valid, (unsigned int*)instPrimID[l], offset, ray.instPrimID[l]); +#endif + } #endif } #else @@ -1032,9 +1127,16 @@ namespace embree if (likely(instID[0])) { *(unsigned int* __restrict__)((char*)instID[0] + ofs) = ray.instID[0][k]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + *(unsigned int* __restrict__)((char*)instPrimID[0] + ofs) = ray.instPrimID[0][k]; +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && ray.instID[l-1][k] != RTC_INVALID_GEOMETRY_ID; ++l) { *(unsigned int* __restrict__)((char*)instID[l] + ofs) = ray.instID[l][k]; +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + *(unsigned int* __restrict__)((char*)instPrimID[l] + ofs) = ray.instPrimID[l][k]; +#endif + } #endif } } @@ -1091,7 +1193,10 @@ namespace embree unsigned int* __restrict__ primID; // primitive ID unsigned int* __restrict__ geomID; // geometry ID - unsigned int* __restrict__ instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID (optional) + unsigned int* __restrict__ instID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance ID +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + unsigned int* __restrict__ instPrimID[RTC_MAX_INSTANCE_LEVEL_COUNT]; // instance primitive ID (optional) +#endif }; @@ -1134,9 +1239,16 @@ namespace embree vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->geomID, offset, ray.geomID); vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->instID[0], offset, ray.instID[0]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->instPrimID[0], offset, ray.instPrimID[0]); +#endif #if (RTC_MAX_INSTANCE_LEVEL_COUNT > 1) - for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) + for (unsigned l = 1; l < RTC_MAX_INSTANCE_LEVEL_COUNT && any(valid & (ray.instID[l-1] != RTC_INVALID_GEOMETRY_ID)); ++l) { vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->instID[l], offset, ray.instID[l]); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + vuint<K>::template scatter<1>(valid, (unsigned int*)&((RayHit*)ptr)->instPrimID[l], offset, ray.instPrimID[l]); +#endif + } #endif #else size_t valid_bits = movemask(valid); @@ -1154,6 +1266,9 @@ namespace embree ray_k->geomID = ray.geomID[k]; instance_id_stack::copy_VU<K>(ray.instID, ray_k->instID, k); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_VU<K>(ray.instPrimID, ray_k->instPrimID, k); +#endif } #endif } @@ -1183,7 +1298,7 @@ namespace embree Ray* __restrict__ ptr; }; - + template<> __forceinline Ray4 RayStreamAOS::getRayByOffset<4>(const vint4& offset) { @@ -1219,7 +1334,7 @@ namespace embree return ray; } - + #if defined(__AVX__) template<> __forceinline Ray8 RayStreamAOS::getRayByOffset<8>(const vint8& offset) @@ -1358,6 +1473,9 @@ namespace embree ray_k->primID = ray.primID[k]; ray_k->geomID = ray.geomID[k]; instance_id_stack::copy_VU<K>(ray.instID, ray_k->instID, k); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_VU<K>(ray.instPrimID, ray_k->instPrimID, k); +#endif } } } @@ -1383,7 +1501,7 @@ namespace embree Ray** __restrict__ ptr; }; - + template<> __forceinline Ray4 RayStreamAOP::getRayByIndex<4>(const vint4& index) { @@ -1419,7 +1537,7 @@ namespace embree return ray; } - + #if defined(__AVX__) template<> __forceinline Ray8 RayStreamAOP::getRayByIndex<8>(const vint8& index) diff --git a/thirdparty/embree/kernels/common/rtcore.cpp b/thirdparty/embree/kernels/common/rtcore.cpp index a6ea55bfc4..eb8d2c0a58 100644 --- a/thirdparty/embree/kernels/common/rtcore.cpp +++ b/thirdparty/embree/kernels/common/rtcore.cpp @@ -8,11 +8,14 @@ #include "scene.h" #include "context.h" #include "../geometry/filter.h" -#include "../../include/embree3/rtcore_ray.h" +#include "../../include/embree4/rtcore_ray.h" using namespace embree; RTC_NAMESPACE_BEGIN; +#define RTC_ENTER_DEVICE(arg) \ + DeviceEnterLeave enterleave(arg); + /* mutex to make API thread safe */ static MutexSys g_mutex; @@ -27,6 +30,57 @@ RTC_NAMESPACE_BEGIN; return (RTCDevice) nullptr; } +#if defined(EMBREE_SYCL_SUPPORT) + + RTC_API RTCDevice rtcNewSYCLDeviceInternal(sycl::context sycl_context, const char* config) + { + RTC_CATCH_BEGIN; + RTC_TRACE(rtcNewSYCLDevice); + Lock<MutexSys> lock(g_mutex); + + DeviceGPU* device = new DeviceGPU(sycl_context,config); + return (RTCDevice) device->refInc(); + RTC_CATCH_END(nullptr); + return (RTCDevice) nullptr; + } + + RTC_API bool rtcIsSYCLDeviceSupported(const sycl::device device) + { + RTC_CATCH_BEGIN; + RTC_TRACE(rtcIsSYCLDeviceSupported); + return rthwifIsSYCLDeviceSupported(device) > 0; + RTC_CATCH_END(nullptr); + return false; + } + + RTC_API int rtcSYCLDeviceSelector(const sycl::device device) + { + RTC_CATCH_BEGIN; + RTC_TRACE(rtcSYCLDeviceSelector); + return rthwifIsSYCLDeviceSupported(device); + RTC_CATCH_END(nullptr); + return -1; + } + + RTC_API void rtcSetDeviceSYCLDevice(RTCDevice hdevice, const sycl::device sycl_device) + { + RTC_CATCH_BEGIN; + RTC_TRACE(rtcSetDeviceSYCLDevice); + RTC_VERIFY_HANDLE(hdevice); + + Lock<MutexSys> lock(g_mutex); + + DeviceGPU* device = dynamic_cast<DeviceGPU*>((Device*) hdevice); + if (device == nullptr) + throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "passed device must be an Embree SYCL device") + + device->setSYCLDevice(sycl_device); + + RTC_CATCH_END(nullptr); + } + +#endif + RTC_API void rtcRetainDevice(RTCDevice hdevice) { Device* device = (Device*) hdevice; @@ -108,6 +162,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcNewBuffer); RTC_VERIFY_HANDLE(hdevice); + RTC_ENTER_DEVICE(hdevice); Buffer* buffer = new Buffer((Device*)hdevice, byteSize); return (RTCBuffer)buffer->refInc(); RTC_CATCH_END((Device*)hdevice); @@ -119,6 +174,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcNewSharedBuffer); RTC_VERIFY_HANDLE(hdevice); + RTC_ENTER_DEVICE(hdevice); Buffer* buffer = new Buffer((Device*)hdevice, byteSize, ptr); return (RTCBuffer)buffer->refInc(); RTC_CATCH_END((Device*)hdevice); @@ -131,6 +187,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetBufferData); RTC_VERIFY_HANDLE(hbuffer); + RTC_ENTER_DEVICE(hbuffer); return buffer->data(); RTC_CATCH_END2(buffer); return nullptr; @@ -142,6 +199,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcRetainBuffer); RTC_VERIFY_HANDLE(hbuffer); + RTC_ENTER_DEVICE(hbuffer); buffer->refInc(); RTC_CATCH_END2(buffer); } @@ -152,6 +210,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcReleaseBuffer); RTC_VERIFY_HANDLE(hbuffer); + RTC_ENTER_DEVICE(hbuffer); buffer->refDec(); RTC_CATCH_END2(buffer); } @@ -161,6 +220,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcNewScene); RTC_VERIFY_HANDLE(hdevice); + RTC_ENTER_DEVICE(hdevice); Scene* scene = new Scene((Device*)hdevice); return (RTCScene) scene->refInc(); RTC_CATCH_END((Device*)hdevice); @@ -184,6 +244,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetSceneProgressMonitorFunction); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); Lock<MutexSys> lock(g_mutex); scene->setProgressMonitorFunction(progress,ptr); RTC_CATCH_END2(scene); @@ -195,13 +256,18 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetSceneBuildQuality); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); + // -- GODOT start -- + // if (quality != RTC_BUILD_QUALITY_LOW && + // quality != RTC_BUILD_QUALITY_MEDIUM && + // quality != RTC_BUILD_QUALITY_HIGH) + // throw std::runtime_error("invalid build quality"); if (quality != RTC_BUILD_QUALITY_LOW && quality != RTC_BUILD_QUALITY_MEDIUM && - quality != RTC_BUILD_QUALITY_HIGH) - // -- GODOT start -- - // throw std::runtime_error("invalid build quality"); + quality != RTC_BUILD_QUALITY_HIGH) { abort(); - // -- GODOT end -- + } + // -- GODOT end -- scene->setBuildQuality(quality); RTC_CATCH_END2(scene); } @@ -212,6 +278,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetSceneFlags); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); scene->setSceneFlags(flags); RTC_CATCH_END2(scene); } @@ -222,6 +289,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetSceneFlags); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); return scene->getSceneFlags(); RTC_CATCH_END2(scene); return RTC_SCENE_FLAG_NONE; @@ -233,6 +301,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcCommitScene); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); scene->commit(false); RTC_CATCH_END2(scene); } @@ -243,6 +312,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcJoinCommitScene); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); scene->commit(true); RTC_CATCH_END2(scene); } @@ -253,6 +323,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetSceneBounds); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); BBox3fa bounds = scene->bounds.bounds(); bounds_o->lower_x = bounds.lower.x; @@ -272,6 +343,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetSceneBounds); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); if (bounds_o == nullptr) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid destination pointer"); if (scene->isModified()) @@ -447,7 +519,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_END2_FALSE(scene); } - RTC_API void rtcIntersect1 (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit* rayhit) + RTC_API void rtcIntersect1 (RTCScene hscene, RTCRayHit* rayhit, RTCIntersectArguments* args) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; @@ -458,7 +530,21 @@ RTC_NAMESPACE_BEGIN; if (((size_t)rayhit) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes"); #endif STAT3(normal.travs,1,1,1); - IntersectContext context(scene,user_context); + + RTCIntersectArguments defaultArgs; + if (unlikely(args == nullptr)) { + rtcInitIntersectArguments(&defaultArgs); + args = &defaultArgs; + } + RTCRayQueryContext* user_context = args->context; + + RTCRayQueryContext defaultContext; + if (unlikely(user_context == nullptr)) { + rtcInitRayQueryContext(&defaultContext); + user_context = &defaultContext; + } + RayQueryContext context(scene,user_context,args); + scene->intersectors.intersect(*rayhit,&context); #if defined(DEBUG) ((RayHit*)rayhit)->verifyHit(); @@ -466,7 +552,45 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_END2(scene); } - RTC_API void rtcIntersect4 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit4* rayhit) + RTC_API void rtcForwardIntersect1 (const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay* iray_, unsigned int instID) + { + rtcForwardIntersect1Ex(args, hscene, iray_, instID, 0); + } + + RTC_API void rtcForwardIntersect1Ex(const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay* iray_, unsigned int instID, unsigned int instPrimID) + { + Scene* scene = (Scene*) hscene; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcForwardIntersect1Ex); +#if defined(DEBUG) + RTC_VERIFY_HANDLE(hscene); + if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); + if (((size_t)iray_) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes"); +#endif + + Ray* iray = (Ray*) iray_; + RayHit* oray = (RayHit*)args->rayhit; + RTCRayQueryContext* user_context = args->context; + const Vec3ff ray_org_tnear = oray->org; + const Vec3ff ray_dir_time = oray->dir; + oray->org = iray->org; + oray->dir = iray->dir; + STAT3(normal.travs,1,1,1); + + RTCIntersectArguments* iargs = ((IntersectFunctionNArguments*) args)->args; + RayQueryContext context(scene,user_context,iargs); + + instance_id_stack::push(user_context, instID, instPrimID); + scene->intersectors.intersect(*(RTCRayHit*)oray,&context); + instance_id_stack::pop(user_context); + + oray->org = ray_org_tnear; + oray->dir = ray_dir_time; + + RTC_CATCH_END2(scene); + } + + RTC_API void rtcIntersect4 (const int* valid, RTCScene hscene, RTCRayHit4* rayhit, RTCIntersectArguments* args) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; @@ -481,23 +605,119 @@ RTC_NAMESPACE_BEGIN; STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;); STAT3(normal.travs,cnt,cnt,cnt); - IntersectContext context(scene,user_context); -#if !defined(EMBREE_RAY_PACKETS) - RayHit4* ray4 = (RayHit4*) rayhit; - for (size_t i=0; i<4; i++) { - if (!valid[i]) continue; - RayHit ray1; ray4->get(i,ray1); - scene->intersectors.intersect((RTCRayHit&)ray1,&context); - ray4->set(i,ray1); + RTCIntersectArguments defaultArgs; + if (unlikely(args == nullptr)) { + rtcInitIntersectArguments(&defaultArgs); + args = &defaultArgs; + } + RTCRayQueryContext* user_context = args->context; + + RTCRayQueryContext defaultContext; + if (unlikely(user_context == nullptr)) { + rtcInitRayQueryContext(&defaultContext); + user_context = &defaultContext; + } + RayQueryContext context(scene,user_context,args); + + if (likely(scene->intersectors.intersector4)) + scene->intersectors.intersect4(valid,*rayhit,&context); + + else { + RayHit4* ray4 = (RayHit4*) rayhit; + for (size_t i=0; i<4; i++) { + if (!valid[i]) continue; + RayHit ray1; ray4->get(i,ray1); + scene->intersectors.intersect((RTCRayHit&)ray1,&context); + ray4->set(i,ray1); + } } -#else - scene->intersectors.intersect4(valid,*rayhit,&context); -#endif RTC_CATCH_END2(scene); } + + template<int N> void copy(float* dst, float* src); + + template<> + __forceinline void copy<4>(float* dst, float* src) { + vfloat4::storeu(&dst[0],vfloat4::loadu(&src[0])); + } + + template<> + __forceinline void copy<8>(float* dst, float* src) { + vfloat4::storeu(&dst[0],vfloat4::loadu(&src[0])); + vfloat4::storeu(&dst[4],vfloat4::loadu(&src[4])); + } + + template<> + __forceinline void copy<16>(float* dst, float* src) { + vfloat4::storeu(&dst[0],vfloat4::loadu(&src[0])); + vfloat4::storeu(&dst[4],vfloat4::loadu(&src[4])); + vfloat4::storeu(&dst[8],vfloat4::loadu(&src[8])); + vfloat4::storeu(&dst[12],vfloat4::loadu(&src[12])); + } + + template<typename RTCRay, typename RTCRayHit, int N> + __forceinline void rtcForwardIntersectN(const int* valid, const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay* iray, unsigned int instID, unsigned int instPrimID) + { + Scene* scene = (Scene*) hscene; + RTCRayHit* oray = (RTCRayHit*)args->rayhit; + RTCRayQueryContext* user_context = args->context; + + __aligned(16) float ray_org_x[N]; + __aligned(16) float ray_org_y[N]; + __aligned(16) float ray_org_z[N]; + __aligned(16) float ray_dir_x[N]; + __aligned(16) float ray_dir_y[N]; + __aligned(16) float ray_dir_z[N]; + + copy<N>(ray_org_x,oray->ray.org_x); + copy<N>(ray_org_y,oray->ray.org_y); + copy<N>(ray_org_z,oray->ray.org_z); + copy<N>(ray_dir_x,oray->ray.dir_x); + copy<N>(ray_dir_y,oray->ray.dir_y); + copy<N>(ray_dir_z,oray->ray.dir_z); + + copy<N>(oray->ray.org_x,iray->org_x); + copy<N>(oray->ray.org_y,iray->org_y); + copy<N>(oray->ray.org_z,iray->org_z); + copy<N>(oray->ray.dir_x,iray->dir_x); + copy<N>(oray->ray.dir_y,iray->dir_y); + copy<N>(oray->ray.dir_z,iray->dir_z); + + STAT(size_t cnt=0; for (size_t i=0; i<N; i++) cnt += ((int*)valid)[i] == -1;); + STAT3(normal.travs,cnt,cnt,cnt); + + RTCIntersectArguments* iargs = ((IntersectFunctionNArguments*) args)->args; + RayQueryContext context(scene,user_context,iargs); + + instance_id_stack::push(user_context, instID, instPrimID); + scene->intersectors.intersect(valid,*oray,&context); + instance_id_stack::pop(user_context); + + copy<N>(oray->ray.org_x,ray_org_x); + copy<N>(oray->ray.org_y,ray_org_y); + copy<N>(oray->ray.org_z,ray_org_z); + copy<N>(oray->ray.dir_x,ray_dir_x); + copy<N>(oray->ray.dir_y,ray_dir_y); + copy<N>(oray->ray.dir_z,ray_dir_z); + } + + RTC_API void rtcForwardIntersect4(const int* valid, const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay4* iray, unsigned int instID) + { + RTC_TRACE(rtcForwardIntersect4); + return rtcForwardIntersect4Ex(valid, args, hscene, iray, instID, 0); + } + + RTC_API void rtcForwardIntersect4Ex(const int* valid, const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay4* iray, unsigned int instID, unsigned int instPrimID) + { + Scene* scene = (Scene*) hscene; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcForwardIntersect4); + rtcForwardIntersectN<RTCRay4,RTCRayHit4,4>(valid,args,hscene,iray,instID,instPrimID); + RTC_CATCH_END2(scene); + } - RTC_API void rtcIntersect8 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit8* rayhit) + RTC_API void rtcIntersect8 (const int* valid, RTCScene hscene, RTCRayHit8* rayhit, RTCIntersectArguments* args) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; @@ -512,25 +732,53 @@ RTC_NAMESPACE_BEGIN; STAT(size_t cnt=0; for (size_t i=0; i<8; i++) cnt += ((int*)valid)[i] == -1;); STAT3(normal.travs,cnt,cnt,cnt); - IntersectContext context(scene,user_context); -#if !defined(EMBREE_RAY_PACKETS) - RayHit8* ray8 = (RayHit8*) rayhit; - for (size_t i=0; i<8; i++) { - if (!valid[i]) continue; - RayHit ray1; ray8->get(i,ray1); - scene->intersectors.intersect((RTCRayHit&)ray1,&context); - ray8->set(i,ray1); + RTCIntersectArguments defaultArgs; + if (unlikely(args == nullptr)) { + rtcInitIntersectArguments(&defaultArgs); + args = &defaultArgs; } -#else - if (likely(scene->intersectors.intersector8)) + RTCRayQueryContext* user_context = args->context; + + RTCRayQueryContext defaultContext; + if (unlikely(user_context == nullptr)) { + rtcInitRayQueryContext(&defaultContext); + user_context = &defaultContext; + } + RayQueryContext context(scene,user_context,args); + + if (likely(scene->intersectors.intersector8)) scene->intersectors.intersect8(valid,*rayhit,&context); + else - scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,8,1,sizeof(RTCRayHit8),&context); -#endif + { + RayHit8* ray8 = (RayHit8*) rayhit; + for (size_t i=0; i<8; i++) { + if (!valid[i]) continue; + RayHit ray1; ray8->get(i,ray1); + scene->intersectors.intersect((RTCRayHit&)ray1,&context); + ray8->set(i,ray1); + } + } + RTC_CATCH_END2(scene); } - - RTC_API void rtcIntersect16 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit16* rayhit) + + RTC_API void rtcForwardIntersect8(const int* valid, const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay8* iray, unsigned int instID) + { + RTC_TRACE(rtcForwardIntersect8); + return rtcForwardIntersect8Ex(valid, args, hscene, iray, instID, 0); + } + + RTC_API void rtcForwardIntersect8Ex(const int* valid, const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay8* iray, unsigned int instID, unsigned int instPrimID) + { + Scene* scene = (Scene*) hscene; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcForwardIntersect8Ex); + rtcForwardIntersectN<RTCRay8,RTCRayHit8,8>(valid,args,hscene,iray,instID,instPrimID); + RTC_CATCH_END2(scene); + } + + RTC_API void rtcIntersect16 (const int* valid, RTCScene hscene, RTCRayHit16* rayhit, RTCIntersectArguments* args) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; @@ -545,179 +793,121 @@ RTC_NAMESPACE_BEGIN; STAT(size_t cnt=0; for (size_t i=0; i<16; i++) cnt += ((int*)valid)[i] == -1;); STAT3(normal.travs,cnt,cnt,cnt); - IntersectContext context(scene,user_context); -#if !defined(EMBREE_RAY_PACKETS) - RayHit16* ray16 = (RayHit16*) rayhit; - for (size_t i=0; i<16; i++) { - if (!valid[i]) continue; - RayHit ray1; ray16->get(i,ray1); - scene->intersectors.intersect((RTCRayHit&)ray1,&context); - ray16->set(i,ray1); + RTCIntersectArguments defaultArgs; + if (unlikely(args == nullptr)) { + rtcInitIntersectArguments(&defaultArgs); + args = &defaultArgs; } -#else + RTCRayQueryContext* user_context = args->context; + + RTCRayQueryContext defaultContext; + if (unlikely(user_context == nullptr)) { + rtcInitRayQueryContext(&defaultContext); + user_context = &defaultContext; + } + RayQueryContext context(scene,user_context,args); + if (likely(scene->intersectors.intersector16)) scene->intersectors.intersect16(valid,*rayhit,&context); - else - scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,16,1,sizeof(RTCRayHit16),&context); -#endif - RTC_CATCH_END2(scene); - } - - RTC_API void rtcIntersect1M (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit* rayhit, unsigned int M, size_t byteStride) - { - Scene* scene = (Scene*) hscene; - RTC_CATCH_BEGIN; - RTC_TRACE(rtcIntersect1M); - -#if defined (EMBREE_RAY_PACKETS) -#if defined(DEBUG) - RTC_VERIFY_HANDLE(hscene); - if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)rayhit ) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes"); -#endif - STAT3(normal.travs,M,M,M); - IntersectContext context(scene,user_context); - /* fast codepath for single rays */ - if (likely(M == 1)) { - if (likely(rayhit->ray.tnear <= rayhit->ray.tfar)) - scene->intersectors.intersect(*rayhit,&context); - } - - /* codepath for streams */ else { - scene->device->rayStreamFilters.intersectAOS(scene,rayhit,M,byteStride,&context); + RayHit16* ray16 = (RayHit16*) rayhit; + for (size_t i=0; i<16; i++) { + if (!valid[i]) continue; + RayHit ray1; ray16->get(i,ray1); + scene->intersectors.intersect((RTCRayHit&)ray1,&context); + ray16->set(i,ray1); + } } -#else - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect1M not supported"); -#endif + RTC_CATCH_END2(scene); } - RTC_API void rtcIntersect1Mp (RTCScene hscene, RTCIntersectContext* user_context, RTCRayHit** rn, unsigned int M) + RTC_API void rtcForwardIntersect16(const int* valid, const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay16* iray, unsigned int instID) + { + RTC_TRACE(rtcForwardIntersect16); + return rtcForwardIntersect16Ex(valid, args, hscene, iray, instID, 0); + } + + RTC_API void rtcForwardIntersect16Ex(const int* valid, const RTCIntersectFunctionNArguments* args, RTCScene hscene, RTCRay16* iray, unsigned int instID, unsigned int instPrimID) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; - RTC_TRACE(rtcIntersect1Mp); - -#if defined (EMBREE_RAY_PACKETS) -#if defined(DEBUG) - RTC_VERIFY_HANDLE(hscene); - if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)rn) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes"); -#endif - STAT3(normal.travs,M,M,M); - IntersectContext context(scene,user_context); - - /* fast codepath for single rays */ - if (likely(M == 1)) { - if (likely(rn[0]->ray.tnear <= rn[0]->ray.tfar)) - scene->intersectors.intersect(*rn[0],&context); - } - - /* codepath for streams */ - else { - scene->device->rayStreamFilters.intersectAOP(scene,rn,M,&context); - } -#else - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect1Mp not supported"); -#endif + RTC_TRACE(rtcForwardIntersect16Ex); + rtcForwardIntersectN<RTCRay16,RTCRayHit16,16>(valid,args,hscene,iray,instID,instPrimID); RTC_CATCH_END2(scene); } - RTC_API void rtcIntersectNM (RTCScene hscene, RTCIntersectContext* user_context, struct RTCRayHitN* rayhit, unsigned int N, unsigned int M, size_t byteStride) + RTC_API void rtcOccluded1 (RTCScene hscene, RTCRay* ray, RTCOccludedArguments* args) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; - RTC_TRACE(rtcIntersectNM); - -#if defined (EMBREE_RAY_PACKETS) + RTC_TRACE(rtcOccluded1); + STAT3(shadow.travs,1,1,1); #if defined(DEBUG) RTC_VERIFY_HANDLE(hscene); if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)rayhit) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes"); + if (((size_t)ray) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes"); #endif - STAT3(normal.travs,N*M,N*M,N*M); - IntersectContext context(scene,user_context); - /* code path for single ray streams */ - if (likely(N == 1)) - { - /* fast code path for streams of size 1 */ - if (likely(M == 1)) { - if (likely(((RTCRayHit*)rayhit)->ray.tnear <= ((RTCRayHit*)rayhit)->ray.tfar)) - scene->intersectors.intersect(*(RTCRayHit*)rayhit,&context); - } - /* normal codepath for single ray streams */ - else { - scene->device->rayStreamFilters.intersectAOS(scene,(RTCRayHit*)rayhit,M,byteStride,&context); - } + RTCOccludedArguments defaultArgs; + if (unlikely(args == nullptr)) { + rtcInitOccludedArguments(&defaultArgs); + args = &defaultArgs; } - /* code path for ray packet streams */ - else { - scene->device->rayStreamFilters.intersectSOA(scene,(char*)rayhit,N,M,byteStride,&context); + RTCRayQueryContext* user_context = args->context; + + RTCRayQueryContext defaultContext; + if (unlikely(user_context == nullptr)) { + rtcInitRayQueryContext(&defaultContext); + user_context = &defaultContext; } -#else - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectNM not supported"); -#endif + RayQueryContext context(scene,user_context,args); + + scene->intersectors.occluded(*ray,&context); RTC_CATCH_END2(scene); } - RTC_API void rtcIntersectNp (RTCScene hscene, RTCIntersectContext* user_context, const RTCRayHitNp* rayhit, unsigned int N) + RTC_API void rtcForwardOccluded1 (const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay* iray_, unsigned int instID) { - Scene* scene = (Scene*) hscene; - RTC_CATCH_BEGIN; - RTC_TRACE(rtcIntersectNp); - -#if defined (EMBREE_RAY_PACKETS) -#if defined(DEBUG) - RTC_VERIFY_HANDLE(hscene); - if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)rayhit->ray.org_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_x not aligned to 4 bytes"); - if (((size_t)rayhit->ray.org_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_y not aligned to 4 bytes"); - if (((size_t)rayhit->ray.org_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.org_z not aligned to 4 bytes"); - if (((size_t)rayhit->ray.dir_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_x not aligned to 4 bytes"); - if (((size_t)rayhit->ray.dir_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_y not aligned to 4 bytes"); - if (((size_t)rayhit->ray.dir_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_z not aligned to 4 bytes"); - if (((size_t)rayhit->ray.tnear ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.dir_x not aligned to 4 bytes"); - if (((size_t)rayhit->ray.tfar ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.tnear not aligned to 4 bytes"); - if (((size_t)rayhit->ray.time ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.time not aligned to 4 bytes"); - if (((size_t)rayhit->ray.mask ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->ray.mask not aligned to 4 bytes"); - if (((size_t)rayhit->hit.Ng_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_x not aligned to 4 bytes"); - if (((size_t)rayhit->hit.Ng_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_y not aligned to 4 bytes"); - if (((size_t)rayhit->hit.Ng_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.Ng_z not aligned to 4 bytes"); - if (((size_t)rayhit->hit.u ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.u not aligned to 4 bytes"); - if (((size_t)rayhit->hit.v ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.v not aligned to 4 bytes"); - if (((size_t)rayhit->hit.geomID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.geomID not aligned to 4 bytes"); - if (((size_t)rayhit->hit.primID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.primID not aligned to 4 bytes"); - if (((size_t)rayhit->hit.instID) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "rayhit->hit.instID not aligned to 4 bytes"); -#endif - STAT3(normal.travs,N,N,N); - IntersectContext context(scene,user_context); - scene->device->rayStreamFilters.intersectSOP(scene,rayhit,N,&context); -#else - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersectNp not supported"); -#endif - RTC_CATCH_END2(scene); + RTC_TRACE(rtcForwardOccluded1); + return rtcForwardOccluded1Ex(args, hscene, iray_, instID, 0); } - - RTC_API void rtcOccluded1 (RTCScene hscene, RTCIntersectContext* user_context, RTCRay* ray) + + RTC_API void rtcForwardOccluded1Ex(const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay* iray_, unsigned int instID, unsigned int instPrimID) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; - RTC_TRACE(rtcOccluded1); + RTC_TRACE(rtcForwardOccluded1Ex); STAT3(shadow.travs,1,1,1); #if defined(DEBUG) RTC_VERIFY_HANDLE(hscene); if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)ray) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes"); + if (((size_t)iray_) & 0x0F) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 16 bytes"); #endif - IntersectContext context(scene,user_context); - scene->intersectors.occluded(*ray,&context); + + Ray* iray = (Ray*)iray_; + Ray* oray = (Ray*)args->ray; + RTCRayQueryContext* user_context = args->context; + const Vec3ff ray_org_tnear = oray->org; + const Vec3ff ray_dir_time = oray->dir; + oray->org = iray->org; + oray->dir = iray->dir; + + RTCIntersectArguments* iargs = ((OccludedFunctionNArguments*) args)->args; + RayQueryContext context(scene,user_context,iargs); + + instance_id_stack::push(user_context, instID, instPrimID); + scene->intersectors.occluded(*(RTCRay*)oray,&context); + instance_id_stack::pop(user_context); + + oray->org = ray_org_tnear; + oray->dir = ray_dir_time; + RTC_CATCH_END2(scene); } - - RTC_API void rtcOccluded4 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay4* ray) + + RTC_API void rtcOccluded4 (const int* valid, RTCScene hscene, RTCRay4* ray, RTCOccludedArguments* args) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; @@ -732,23 +922,98 @@ RTC_NAMESPACE_BEGIN; STAT(size_t cnt=0; for (size_t i=0; i<4; i++) cnt += ((int*)valid)[i] == -1;); STAT3(shadow.travs,cnt,cnt,cnt); - IntersectContext context(scene,user_context); -#if !defined(EMBREE_RAY_PACKETS) - RayHit4* ray4 = (RayHit4*) ray; - for (size_t i=0; i<4; i++) { - if (!valid[i]) continue; - RayHit ray1; ray4->get(i,ray1); - scene->intersectors.occluded((RTCRay&)ray1,&context); - ray4->geomID[i] = ray1.geomID; + RTCOccludedArguments defaultArgs; + if (unlikely(args == nullptr)) { + rtcInitOccludedArguments(&defaultArgs); + args = &defaultArgs; + } + RTCRayQueryContext* user_context = args->context; + + RTCRayQueryContext defaultContext; + if (unlikely(user_context == nullptr)) { + rtcInitRayQueryContext(&defaultContext); + user_context = &defaultContext; + } + RayQueryContext context(scene,user_context,args); + + if (likely(scene->intersectors.intersector4)) + scene->intersectors.occluded4(valid,*ray,&context); + + else { + RayHit4* ray4 = (RayHit4*) ray; + for (size_t i=0; i<4; i++) { + if (!valid[i]) continue; + RayHit ray1; ray4->get(i,ray1); + scene->intersectors.occluded((RTCRay&)ray1,&context); + ray4->geomID[i] = ray1.geomID; + } } -#else - scene->intersectors.occluded4(valid,*ray,&context); -#endif RTC_CATCH_END2(scene); } + + template<typename RTCRay, int N> + __forceinline void rtcForwardOccludedN (const int* valid, const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay* iray, unsigned int instID, unsigned int instPrimID) + { + Scene* scene = (Scene*) hscene; + RTCRay* oray = (RTCRay*)args->ray; + RTCRayQueryContext* user_context = args->context; + + __aligned(16) float ray_org_x[N]; + __aligned(16) float ray_org_y[N]; + __aligned(16) float ray_org_z[N]; + __aligned(16) float ray_dir_x[N]; + __aligned(16) float ray_dir_y[N]; + __aligned(16) float ray_dir_z[N]; + + copy<N>(ray_org_x,oray->org_x); + copy<N>(ray_org_y,oray->org_y); + copy<N>(ray_org_z,oray->org_z); + copy<N>(ray_dir_x,oray->dir_x); + copy<N>(ray_dir_y,oray->dir_y); + copy<N>(ray_dir_z,oray->dir_z); + + copy<N>(oray->org_x,iray->org_x); + copy<N>(oray->org_y,iray->org_y); + copy<N>(oray->org_z,iray->org_z); + copy<N>(oray->dir_x,iray->dir_x); + copy<N>(oray->dir_y,iray->dir_y); + copy<N>(oray->dir_z,iray->dir_z); + + STAT(size_t cnt=0; for (size_t i=0; i<N; i++) cnt += ((int*)valid)[i] == -1;); + STAT3(normal.travs,cnt,cnt,cnt); + + RTCIntersectArguments* iargs = ((IntersectFunctionNArguments*) args)->args; + RayQueryContext context(scene,user_context,iargs); + + instance_id_stack::push(user_context, instID, instPrimID); + scene->intersectors.occluded(valid,*oray,&context); + instance_id_stack::pop(user_context); + + copy<N>(oray->org_x,ray_org_x); + copy<N>(oray->org_y,ray_org_y); + copy<N>(oray->org_z,ray_org_z); + copy<N>(oray->dir_x,ray_dir_x); + copy<N>(oray->dir_y,ray_dir_y); + copy<N>(oray->dir_z,ray_dir_z); + } + + RTC_API void rtcForwardOccluded4(const int* valid, const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay4* iray, unsigned int instID) + { + RTC_TRACE(rtcForwardOccluded4); + return rtcForwardOccluded4Ex(valid, args, hscene, iray, instID, 0); + } + + RTC_API void rtcForwardOccluded4Ex(const int* valid, const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay4* iray, unsigned int instID, unsigned int instPrimID) + { + Scene* scene = (Scene*) hscene; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcForwardOccluded4); + rtcForwardOccludedN<RTCRay4,4>(valid,args,hscene,iray,instID,instPrimID); + RTC_CATCH_END2(scene); + } - RTC_API void rtcOccluded8 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay8* ray) + RTC_API void rtcOccluded8 (const int* valid, RTCScene hscene, RTCRay8* ray, RTCOccludedArguments* args) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; @@ -763,26 +1028,52 @@ RTC_NAMESPACE_BEGIN; STAT(size_t cnt=0; for (size_t i=0; i<8; i++) cnt += ((int*)valid)[i] == -1;); STAT3(shadow.travs,cnt,cnt,cnt); - IntersectContext context(scene,user_context); -#if !defined(EMBREE_RAY_PACKETS) - RayHit8* ray8 = (RayHit8*) ray; - for (size_t i=0; i<8; i++) { - if (!valid[i]) continue; - RayHit ray1; ray8->get(i,ray1); - scene->intersectors.occluded((RTCRay&)ray1,&context); - ray8->set(i,ray1); + RTCOccludedArguments defaultArgs; + if (unlikely(args == nullptr)) { + rtcInitOccludedArguments(&defaultArgs); + args = &defaultArgs; } -#else + RTCRayQueryContext* user_context = args->context; + + RTCRayQueryContext defaultContext; + if (unlikely(user_context == nullptr)) { + rtcInitRayQueryContext(&defaultContext); + user_context = &defaultContext; + } + RayQueryContext context(scene,user_context,args); + if (likely(scene->intersectors.intersector8)) scene->intersectors.occluded8(valid,*ray,&context); - else - scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,8,1,sizeof(RTCRay8),&context); -#endif + + else { + RayHit8* ray8 = (RayHit8*) ray; + for (size_t i=0; i<8; i++) { + if (!valid[i]) continue; + RayHit ray1; ray8->get(i,ray1); + scene->intersectors.occluded((RTCRay&)ray1,&context); + ray8->set(i,ray1); + } + } RTC_CATCH_END2(scene); } - - RTC_API void rtcOccluded16 (const int* valid, RTCScene hscene, RTCIntersectContext* user_context, RTCRay16* ray) + + RTC_API void rtcForwardOccluded8(const int* valid, const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay8* iray, unsigned int instID) + { + RTC_TRACE(rtcForwardOccluded8); + return rtcForwardOccluded8Ex(valid, args, hscene, iray, instID, 0); + } + + RTC_API void rtcForwardOccluded8Ex(const int* valid, const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay8* iray, unsigned int instID, unsigned int instPrimID) + { + Scene* scene = (Scene*) hscene; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcForwardOccluded8Ex); + rtcForwardOccludedN<RTCRay8,8>(valid, args, hscene, iray, instID, instPrimID); + RTC_CATCH_END2(scene); + } + + RTC_API void rtcOccluded16 (const int* valid, RTCScene hscene, RTCRay16* ray, RTCOccludedArguments* args) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; @@ -797,159 +1088,58 @@ RTC_NAMESPACE_BEGIN; STAT(size_t cnt=0; for (size_t i=0; i<16; i++) cnt += ((int*)valid)[i] == -1;); STAT3(shadow.travs,cnt,cnt,cnt); - IntersectContext context(scene,user_context); -#if !defined(EMBREE_RAY_PACKETS) - RayHit16* ray16 = (RayHit16*) ray; - for (size_t i=0; i<16; i++) { - if (!valid[i]) continue; - RayHit ray1; ray16->get(i,ray1); - scene->intersectors.occluded((RTCRay&)ray1,&context); - ray16->set(i,ray1); + RTCOccludedArguments defaultArgs; + if (unlikely(args == nullptr)) { + rtcInitOccludedArguments(&defaultArgs); + args = &defaultArgs; } -#else + RTCRayQueryContext* user_context = args->context; + + RTCRayQueryContext defaultContext; + if (unlikely(user_context == nullptr)) { + rtcInitRayQueryContext(&defaultContext); + user_context = &defaultContext; + } + RayQueryContext context(scene,user_context,args); + if (likely(scene->intersectors.intersector16)) scene->intersectors.occluded16(valid,*ray,&context); - else - scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,16,1,sizeof(RTCRay16),&context); -#endif - - RTC_CATCH_END2(scene); - } - - RTC_API void rtcOccluded1M(RTCScene hscene, RTCIntersectContext* user_context, RTCRay* ray, unsigned int M, size_t byteStride) - { - Scene* scene = (Scene*) hscene; - RTC_CATCH_BEGIN; - RTC_TRACE(rtcOccluded1M); -#if defined (EMBREE_RAY_PACKETS) -#if defined(DEBUG) - RTC_VERIFY_HANDLE(hscene); - if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes"); -#endif - STAT3(shadow.travs,M,M,M); - IntersectContext context(scene,user_context); - /* fast codepath for streams of size 1 */ - if (likely(M == 1)) { - if (likely(ray->tnear <= ray->tfar)) - scene->intersectors.occluded (*ray,&context); - } - /* codepath for normal streams */ else { - scene->device->rayStreamFilters.occludedAOS(scene,ray,M,byteStride,&context); + RayHit16* ray16 = (RayHit16*) ray; + for (size_t i=0; i<16; i++) { + if (!valid[i]) continue; + RayHit ray1; ray16->get(i,ray1); + scene->intersectors.occluded((RTCRay&)ray1,&context); + ray16->set(i,ray1); + } } -#else - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccluded1M not supported"); -#endif - RTC_CATCH_END2(scene); - } - RTC_API void rtcOccluded1Mp(RTCScene hscene, RTCIntersectContext* user_context, RTCRay** ray, unsigned int M) - { - Scene* scene = (Scene*) hscene; - RTC_CATCH_BEGIN; - RTC_TRACE(rtcOccluded1Mp); - -#if defined (EMBREE_RAY_PACKETS) -#if defined(DEBUG) - RTC_VERIFY_HANDLE(hscene); - if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes"); -#endif - STAT3(shadow.travs,M,M,M); - IntersectContext context(scene,user_context); - - /* fast codepath for streams of size 1 */ - if (likely(M == 1)) { - if (likely(ray[0]->tnear <= ray[0]->tfar)) - scene->intersectors.occluded (*ray[0],&context); - } - /* codepath for normal streams */ - else { - scene->device->rayStreamFilters.occludedAOP(scene,ray,M,&context); - } -#else - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccluded1Mp not supported"); -#endif RTC_CATCH_END2(scene); } - RTC_API void rtcOccludedNM(RTCScene hscene, RTCIntersectContext* user_context, RTCRayN* ray, unsigned int N, unsigned int M, size_t byteStride) + RTC_API void rtcForwardOccluded16(const int* valid, const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay16* iray, unsigned int instID) { - Scene* scene = (Scene*) hscene; - RTC_CATCH_BEGIN; - RTC_TRACE(rtcOccludedNM); - -#if defined (EMBREE_RAY_PACKETS) -#if defined(DEBUG) - RTC_VERIFY_HANDLE(hscene); - if (byteStride < sizeof(RTCRayHit)) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"byteStride too small"); - if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)ray) & 0x03) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "ray not aligned to 4 bytes"); -#endif - STAT3(shadow.travs,N*M,N*N,N*N); - IntersectContext context(scene,user_context); - - /* codepath for single rays */ - if (likely(N == 1)) - { - /* fast path for streams of size 1 */ - if (likely(M == 1)) { - if (likely(((RTCRay*)ray)->tnear <= ((RTCRay*)ray)->tfar)) - scene->intersectors.occluded (*(RTCRay*)ray,&context); - } - /* codepath for normal ray streams */ - else { - scene->device->rayStreamFilters.occludedAOS(scene,(RTCRay*)ray,M,byteStride,&context); - } - } - /* code path for ray packet streams */ - else { - scene->device->rayStreamFilters.occludedSOA(scene,(char*)ray,N,M,byteStride,&context); - } -#else - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccludedNM not supported"); -#endif - RTC_CATCH_END2(scene); + RTC_TRACE(rtcForwardOccluded16); + return rtcForwardOccluded16Ex(valid, args, hscene, iray, instID, 0); } - RTC_API void rtcOccludedNp(RTCScene hscene, RTCIntersectContext* user_context, const RTCRayNp* ray, unsigned int N) + RTC_API void rtcForwardOccluded16Ex(const int* valid, const RTCOccludedFunctionNArguments* args, RTCScene hscene, RTCRay16* iray, unsigned int instID, unsigned int instPrimID) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; - RTC_TRACE(rtcOccludedNp); - -#if defined (EMBREE_RAY_PACKETS) -#if defined(DEBUG) - RTC_VERIFY_HANDLE(hscene); - if (scene->isModified()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); - if (((size_t)ray->org_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_x not aligned to 4 bytes"); - if (((size_t)ray->org_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_y not aligned to 4 bytes"); - if (((size_t)ray->org_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "org_z not aligned to 4 bytes"); - if (((size_t)ray->dir_x ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_x not aligned to 4 bytes"); - if (((size_t)ray->dir_y ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_y not aligned to 4 bytes"); - if (((size_t)ray->dir_z ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_z not aligned to 4 bytes"); - if (((size_t)ray->tnear ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "dir_x not aligned to 4 bytes"); - if (((size_t)ray->tfar ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "tnear not aligned to 4 bytes"); - if (((size_t)ray->time ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "time not aligned to 4 bytes"); - if (((size_t)ray->mask ) & 0x03 ) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT, "mask not aligned to 4 bytes"); -#endif - STAT3(shadow.travs,N,N,N); - IntersectContext context(scene,user_context); - scene->device->rayStreamFilters.occludedSOP(scene,ray,N,&context); -#else - throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcOccludedNp not supported"); -#endif + RTC_TRACE(rtcForwardOccluded16Ex); + rtcForwardOccludedN<RTCRay16,16>(valid, args, hscene, iray, instID, instPrimID); RTC_CATCH_END2(scene); } - + RTC_API void rtcRetainScene (RTCScene hscene) { Scene* scene = (Scene*) hscene; RTC_CATCH_BEGIN; RTC_TRACE(rtcRetainScene); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); scene->refInc(); RTC_CATCH_END2(scene); } @@ -960,6 +1150,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcReleaseScene); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); scene->refDec(); RTC_CATCH_END2(scene); } @@ -972,10 +1163,23 @@ RTC_NAMESPACE_BEGIN; RTC_TRACE(rtcSetGeometryInstancedScene); RTC_VERIFY_HANDLE(hgeometry); RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hgeometry); geometry->setInstancedScene(scene); RTC_CATCH_END2(geometry); } + RTC_API void rtcSetGeometryInstancedScenes(RTCGeometry hgeometry, RTCScene* scenes, size_t numScenes) + { + Geometry* geometry = (Geometry*) hgeometry; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcSetGeometryInstancedScene); + RTC_VERIFY_HANDLE(hgeometry); + RTC_VERIFY_HANDLE(scenes); + RTC_ENTER_DEVICE(hgeometry); + geometry->setInstancedScenes(scenes, numScenes); + RTC_CATCH_END2(geometry); + } + AffineSpace3fa loadTransform(RTCFormat format, const float* xfm) { AffineSpace3fa space = one; @@ -1009,43 +1213,14 @@ RTC_NAMESPACE_BEGIN; return space; } - void storeTransform(const AffineSpace3fa& space, RTCFormat format, float* xfm) - { - switch (format) - { - case RTC_FORMAT_FLOAT3X4_ROW_MAJOR: - xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vy.x; xfm[ 2] = space.l.vz.x; xfm[ 3] = space.p.x; - xfm[ 4] = space.l.vx.y; xfm[ 5] = space.l.vy.y; xfm[ 6] = space.l.vz.y; xfm[ 7] = space.p.y; - xfm[ 8] = space.l.vx.z; xfm[ 9] = space.l.vy.z; xfm[10] = space.l.vz.z; xfm[11] = space.p.z; - break; - - case RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR: - xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vx.y; xfm[ 2] = space.l.vx.z; - xfm[ 3] = space.l.vy.x; xfm[ 4] = space.l.vy.y; xfm[ 5] = space.l.vy.z; - xfm[ 6] = space.l.vz.x; xfm[ 7] = space.l.vz.y; xfm[ 8] = space.l.vz.z; - xfm[ 9] = space.p.x; xfm[10] = space.p.y; xfm[11] = space.p.z; - break; - - case RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR: - xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vx.y; xfm[ 2] = space.l.vx.z; xfm[ 3] = 0.f; - xfm[ 4] = space.l.vy.x; xfm[ 5] = space.l.vy.y; xfm[ 6] = space.l.vy.z; xfm[ 7] = 0.f; - xfm[ 8] = space.l.vz.x; xfm[ 9] = space.l.vz.y; xfm[10] = space.l.vz.z; xfm[11] = 0.f; - xfm[12] = space.p.x; xfm[13] = space.p.y; xfm[14] = space.p.z; xfm[15] = 1.f; - break; - - default: - throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid matrix format"); - break; - } - } - - RTC_API void rtcSetGeometryTransform(RTCGeometry hgeometry, unsigned int timeStep, RTCFormat format, const void* xfm) +RTC_API void rtcSetGeometryTransform(RTCGeometry hgeometry, unsigned int timeStep, RTCFormat format, const void* xfm) { Geometry* geometry = (Geometry*) hgeometry; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryTransform); RTC_VERIFY_HANDLE(hgeometry); RTC_VERIFY_HANDLE(xfm); + RTC_ENTER_DEVICE(hgeometry); const AffineSpace3fa transform = loadTransform(format, (const float*)xfm); geometry->setTransform(transform, timeStep); RTC_CATCH_END2(geometry); @@ -1058,6 +1233,7 @@ RTC_NAMESPACE_BEGIN; RTC_TRACE(rtcSetGeometryTransformQuaternion); RTC_VERIFY_HANDLE(hgeometry); RTC_VERIFY_HANDLE(qd); + RTC_ENTER_DEVICE(hgeometry); AffineSpace3fx transform; transform.l.vx.x = qd->scale_x; @@ -1090,21 +1266,46 @@ RTC_NAMESPACE_BEGIN; Geometry* geometry = (Geometry*) hgeometry; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetGeometryTransform); + //RTC_ENTER_DEVICE(hgeometry); // no allocation required const AffineSpace3fa transform = geometry->getTransform(time); storeTransform(transform, format, (float*)xfm); RTC_CATCH_END2(geometry); } - RTC_API void rtcFilterIntersection(const struct RTCIntersectFunctionNArguments* const args_i, const struct RTCFilterFunctionNArguments* filter_args) + RTC_API void rtcGetGeometryTransformEx(RTCGeometry hgeometry, unsigned int instPrimID, float time, RTCFormat format, void* xfm) + { + Geometry* geometry = (Geometry*) hgeometry; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcGetGeometryTransformEx); + //RTC_ENTER_DEVICE(hgeometry); // no allocation required + const AffineSpace3fa transform = geometry->getTransform(instPrimID, time); + storeTransform(transform, format, (float*)xfm); + RTC_CATCH_END2(geometry); + } + + RTC_API void rtcGetGeometryTransformFromScene(RTCScene hscene, unsigned int geomID, float time, RTCFormat format, void* xfm) + { + Scene* scene = (Scene*) hscene; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcGetGeometryTransformFromScene); + //RTC_ENTER_DEVICE(hscene); // no allocation required + const AffineSpace3fa transform = scene->get(geomID)->getTransform(time); + storeTransform(transform, format, (float*)xfm); + RTC_CATCH_END2(scene); + } + + RTC_API void rtcInvokeIntersectFilterFromGeometry(const struct RTCIntersectFunctionNArguments* const args_i, const struct RTCFilterFunctionNArguments* filter_args) { IntersectFunctionNArguments* args = (IntersectFunctionNArguments*) args_i; - isa::reportIntersection1(args, filter_args); + if (args->geometry->intersectionFilterN) + args->geometry->intersectionFilterN(filter_args); } - RTC_API void rtcFilterOcclusion(const struct RTCOccludedFunctionNArguments* const args_i, const struct RTCFilterFunctionNArguments* filter_args) + RTC_API void rtcInvokeOccludedFilterFromGeometry(const struct RTCOccludedFunctionNArguments* const args_i, const struct RTCFilterFunctionNArguments* filter_args) { OccludedFunctionNArguments* args = (OccludedFunctionNArguments*) args_i; - isa::reportOcclusion1(args,filter_args); + if (args->geometry->occlusionFilterN) + args->geometry->occlusionFilterN(filter_args); } RTC_API RTCGeometry rtcNewGeometry (RTCDevice hdevice, RTCGeometryType type) @@ -1112,6 +1313,7 @@ RTC_NAMESPACE_BEGIN; Device* device = (Device*) hdevice; RTC_CATCH_BEGIN; RTC_TRACE(rtcNewGeometry); + RTC_ENTER_DEVICE(hdevice); RTC_VERIFY_HANDLE(hdevice); switch (type) @@ -1262,6 +1464,18 @@ RTC_NAMESPACE_BEGIN; #endif } + case RTC_GEOMETRY_TYPE_INSTANCE_ARRAY: + { +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + createInstanceArrayTy createInstanceArray = nullptr; + SELECT_SYMBOL_DEFAULT_AVX_AVX2_AVX512(device->enabled_cpu_features,createInstanceArray); + Geometry* geom = createInstanceArray(device); + return (RTCGeometry) geom->refInc(); +#else + throw_RTCError(RTC_ERROR_UNKNOWN,"RTC_GEOMETRY_TYPE_INSTANCE_ARRAY is not supported"); +#endif + } + case RTC_GEOMETRY_TYPE_GRID: { #if defined(EMBREE_GEOMETRY_GRID) @@ -1288,6 +1502,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryUserPrimitiveCount); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); if (unlikely(geometry->getType() != Geometry::GTY_USER_GEOMETRY)) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"operation only allowed for user geometries"); @@ -1302,6 +1517,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryTimeStepCount); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); if (timeStepCount > RTC_MAX_TIME_STEP_COUNT) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"number of time steps is out of range"); @@ -1316,6 +1532,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryTimeRange); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); if (startTime > endTime) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"startTime has to be smaller or equal to the endTime"); @@ -1330,6 +1547,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryVertexAttributeCount); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setVertexAttributeCount(N); RTC_CATCH_END2(geometry); } @@ -1340,6 +1558,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryTopologyCount); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setTopologyCount(N); RTC_CATCH_END2(geometry); } @@ -1350,14 +1569,20 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryBuildQuality); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); + // -- GODOT start -- + // if (quality != RTC_BUILD_QUALITY_LOW && + // quality != RTC_BUILD_QUALITY_MEDIUM && + // quality != RTC_BUILD_QUALITY_HIGH && + // quality != RTC_BUILD_QUALITY_REFIT) + // throw std::runtime_error("invalid build quality"); if (quality != RTC_BUILD_QUALITY_LOW && quality != RTC_BUILD_QUALITY_MEDIUM && quality != RTC_BUILD_QUALITY_HIGH && - quality != RTC_BUILD_QUALITY_REFIT) - // -- GODOT start -- - // throw std::runtime_error("invalid build quality"); + quality != RTC_BUILD_QUALITY_REFIT) { abort(); - // -- GODOT end -- + } + // -- GODOT end -- geometry->setBuildQuality(quality); RTC_CATCH_END2(geometry); } @@ -1383,6 +1608,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryMask); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setMask(mask); RTC_CATCH_END2(geometry); } @@ -1393,6 +1619,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometrySubdivisionMode); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setSubdivisionMode(topologyID,mode); RTC_CATCH_END2(geometry); } @@ -1403,6 +1630,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryVertexAttributeTopology); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setVertexAttributeTopology(vertexAttributeID, topologyID); RTC_CATCH_END2(geometry); } @@ -1415,6 +1643,7 @@ RTC_NAMESPACE_BEGIN; RTC_TRACE(rtcSetGeometryBuffer); RTC_VERIFY_HANDLE(hgeometry); RTC_VERIFY_HANDLE(hbuffer); + RTC_ENTER_DEVICE(hgeometry); if (geometry->device != buffer->device) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices"); @@ -1432,10 +1661,11 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetSharedGeometryBuffer); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); if (itemCount > 0xFFFFFFFFu) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"buffer too large"); - + Ref<Buffer> buffer = new Buffer(geometry->device, itemCount*byteStride, (char*)ptr + byteOffset); geometry->setBuffer(type, slot, format, buffer, 0, byteStride, (unsigned int)itemCount); RTC_CATCH_END2(geometry); @@ -1447,6 +1677,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetNewGeometryBuffer); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); if (itemCount > 0xFFFFFFFFu) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"buffer too large"); @@ -1469,6 +1700,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetGeometryBufferData); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); return geometry->getBuffer(type, slot); RTC_CATCH_END2(geometry); return nullptr; @@ -1480,6 +1712,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcEnableGeometry); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->enable(); RTC_CATCH_END2(geometry); } @@ -1490,6 +1723,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcUpdateGeometryBuffer); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->updateBuffer(type, slot); RTC_CATCH_END2(geometry); } @@ -1500,6 +1734,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcDisableGeometry); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->disable(); RTC_CATCH_END2(geometry); } @@ -1510,6 +1745,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryTessellationRate); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setTessellationRate(tessellationRate); RTC_CATCH_END2(geometry); } @@ -1520,6 +1756,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryUserData); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setUserData(ptr); RTC_CATCH_END2(geometry); } @@ -1530,17 +1767,34 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetGeometryUserData); RTC_VERIFY_HANDLE(hgeometry); + //RTC_ENTER_DEVICE(hgeometry); // do not enable for performance reasons ! return geometry->getUserData(); RTC_CATCH_END2(geometry); return nullptr; } + RTC_API void* rtcGetGeometryUserDataFromScene (RTCScene hscene, unsigned int geomID) + { + Scene* scene = (Scene*) hscene; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcGetGeometryUserDataFromScene); +#if defined(DEBUG) + RTC_VERIFY_HANDLE(hscene); + RTC_VERIFY_GEOMID(geomID); +#endif + //RTC_ENTER_DEVICE(hscene); // do not enable for performance reasons + return scene->get(geomID)->getUserData(); + RTC_CATCH_END2(scene); + return nullptr; + } + RTC_API void rtcSetGeometryBoundsFunction (RTCGeometry hgeometry, RTCBoundsFunction bounds, void* userPtr) { Geometry* geometry = (Geometry*) hgeometry; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryBoundsFunction); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setBoundsFunction(bounds,userPtr); RTC_CATCH_END2(geometry); } @@ -1551,6 +1805,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryDisplacementFunction); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setDisplacementFunction(displacement); RTC_CATCH_END2(geometry); } @@ -1561,6 +1816,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryIntersectFunction); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setIntersectFunctionN(intersect); RTC_CATCH_END2(geometry); } @@ -1571,6 +1827,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryPointQueryFunction); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setPointQueryFunction(pointQuery); RTC_CATCH_END2(geometry); } @@ -1580,6 +1837,7 @@ RTC_NAMESPACE_BEGIN; Geometry* geometry = (Geometry*) hgeometry; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetGeometryFirstHalfEdge); + //RTC_ENTER_DEVICE(hgeometry); // do not enable for performance reasons return geometry->getFirstHalfEdge(faceID); RTC_CATCH_END2(geometry); return -1; @@ -1590,6 +1848,7 @@ RTC_NAMESPACE_BEGIN; Geometry* geometry = (Geometry*) hgeometry; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetGeometryFace); + //RTC_ENTER_DEVICE(hgeometry); // do not enable for performance reasons return geometry->getFace(edgeID); RTC_CATCH_END2(geometry); return -1; @@ -1600,6 +1859,7 @@ RTC_NAMESPACE_BEGIN; Geometry* geometry = (Geometry*) hgeometry; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetGeometryNextHalfEdge); + //RTC_ENTER_DEVICE(hgeometry); // do not enable for performance reasons return geometry->getNextHalfEdge(edgeID); RTC_CATCH_END2(geometry); return -1; @@ -1610,6 +1870,7 @@ RTC_NAMESPACE_BEGIN; Geometry* geometry = (Geometry*) hgeometry; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetGeometryPreviousHalfEdge); + //RTC_ENTER_DEVICE(hgeometry); // do not enable for performance reasons return geometry->getPreviousHalfEdge(edgeID); RTC_CATCH_END2(geometry); return -1; @@ -1620,6 +1881,7 @@ RTC_NAMESPACE_BEGIN; Geometry* geometry = (Geometry*) hgeometry; RTC_CATCH_BEGIN; RTC_TRACE(rtcGetGeometryOppositeHalfEdge); + //RTC_ENTER_DEVICE(hgeometry); // do not enable for performance reasons return geometry->getOppositeHalfEdge(topologyID,edgeID); RTC_CATCH_END2(geometry); return -1; @@ -1631,6 +1893,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetOccludedFunctionN); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setOccludedFunctionN(occluded); RTC_CATCH_END2(geometry); } @@ -1641,6 +1904,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryIntersectFilterFunction); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setIntersectionFilterFunctionN(filter); RTC_CATCH_END2(geometry); } @@ -1651,10 +1915,22 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcSetGeometryOccludedFilterFunction); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->setOcclusionFilterFunctionN(filter); RTC_CATCH_END2(geometry); } + RTC_API void rtcSetGeometryEnableFilterFunctionFromArguments (RTCGeometry hgeometry, bool enable) + { + Geometry* geometry = (Geometry*) hgeometry; + RTC_CATCH_BEGIN; + RTC_TRACE(rtcSetGeometryEnableFilterFunctionFromArguments); + RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); + geometry->enableFilterFunctionFromArguments(enable); + RTC_CATCH_END2(geometry); + } + RTC_API void rtcInterpolate(const RTCInterpolateArguments* const args) { Geometry* geometry = (Geometry*) args->geometry; @@ -1663,6 +1939,7 @@ RTC_NAMESPACE_BEGIN; #if defined(DEBUG) RTC_VERIFY_HANDLE(args->geometry); #endif + //RTC_ENTER_DEVICE(hgeometry); // do not enable for performance reasons geometry->interpolate(args); RTC_CATCH_END2(geometry); } @@ -1675,6 +1952,7 @@ RTC_NAMESPACE_BEGIN; #if defined(DEBUG) RTC_VERIFY_HANDLE(args->geometry); #endif + // RTC_ENTER_DEVICE(hgeometry); // do not enable for performance reasons geometry->interpolateN(args); RTC_CATCH_END2(geometry); } @@ -1685,6 +1963,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcCommitGeometry); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); return geometry->commit(); RTC_CATCH_END2(geometry); } @@ -1697,6 +1976,7 @@ RTC_NAMESPACE_BEGIN; RTC_TRACE(rtcAttachGeometry); RTC_VERIFY_HANDLE(hscene); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); if (scene->device != geometry->device) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices"); return scene->bind(RTC_INVALID_GEOMETRY_ID,geometry); @@ -1713,6 +1993,7 @@ RTC_NAMESPACE_BEGIN; RTC_VERIFY_HANDLE(hscene); RTC_VERIFY_HANDLE(hgeometry); RTC_VERIFY_GEOMID(geomID); + RTC_ENTER_DEVICE(hscene); if (scene->device != geometry->device) throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"inputs are from different devices"); scene->bind(geomID,geometry); @@ -1726,6 +2007,7 @@ RTC_NAMESPACE_BEGIN; RTC_TRACE(rtcDetachGeometry); RTC_VERIFY_HANDLE(hscene); RTC_VERIFY_GEOMID(geomID); + RTC_ENTER_DEVICE(hscene); scene->detachGeometry(geomID); RTC_CATCH_END2(scene); } @@ -1736,6 +2018,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcRetainGeometry); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->refInc(); RTC_CATCH_END2(geometry); } @@ -1746,6 +2029,7 @@ RTC_NAMESPACE_BEGIN; RTC_CATCH_BEGIN; RTC_TRACE(rtcReleaseGeometry); RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); geometry->refDec(); RTC_CATCH_END2(geometry); } @@ -1759,6 +2043,7 @@ RTC_NAMESPACE_BEGIN; RTC_VERIFY_HANDLE(hscene); RTC_VERIFY_GEOMID(geomID); #endif + //RTC_ENTER_DEVICE(hscene); // do not enable for performance reasons return (RTCGeometry) scene->get(geomID); RTC_CATCH_END2(scene); return nullptr; diff --git a/thirdparty/embree/kernels/common/rtcore.h b/thirdparty/embree/kernels/common/rtcore.h index ac58a84d6f..47526482c1 100644 --- a/thirdparty/embree/kernels/common/rtcore.h +++ b/thirdparty/embree/kernels/common/rtcore.h @@ -3,26 +3,14 @@ #pragma once -#include "../../include/embree3/rtcore.h" +#include "../../include/embree4/rtcore.h" RTC_NAMESPACE_USE namespace embree { /*! decoding of intersection flags */ - __forceinline bool isCoherent (RTCIntersectContextFlags flags) { return (flags & RTC_INTERSECT_CONTEXT_FLAG_COHERENT) == RTC_INTERSECT_CONTEXT_FLAG_COHERENT; } - __forceinline bool isIncoherent(RTCIntersectContextFlags flags) { return (flags & RTC_INTERSECT_CONTEXT_FLAG_COHERENT) == RTC_INTERSECT_CONTEXT_FLAG_INCOHERENT; } - -#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR >= 8) -# define USE_TASK_ARENA 1 -#else -# define USE_TASK_ARENA 0 -#endif - -#if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION >= 11009) // TBB 2019 Update 9 -# define TASKING_TBB_USE_TASK_ISOLATION 1 -#else -# define TASKING_TBB_USE_TASK_ISOLATION 0 -#endif + __forceinline bool isCoherent (RTCRayQueryFlags flags) { return (flags & RTC_RAY_QUERY_FLAG_COHERENT) == RTC_RAY_QUERY_FLAG_COHERENT; } + __forceinline bool isIncoherent(RTCRayQueryFlags flags) { return (flags & RTC_RAY_QUERY_FLAG_COHERENT) == RTC_RAY_QUERY_FLAG_INCOHERENT; } /*! Macros used in the rtcore API implementation */ // -- GODOT start -- @@ -30,8 +18,8 @@ namespace embree #define RTC_CATCH_END(device) #define RTC_CATCH_END2(scene) #define RTC_CATCH_END2_FALSE(scene) return false; - #if 0 +// -- GODOT end -- #define RTC_CATCH_BEGIN try { #define RTC_CATCH_END(device) \ @@ -47,7 +35,7 @@ namespace embree #define RTC_CATCH_END2(scene) \ } catch (std::bad_alloc&) { \ - Device* device = scene ? scene->device : nullptr; \ + Device* device = scene ? scene->device : nullptr; \ Device::process_error(device,RTC_ERROR_OUT_OF_MEMORY,"out of memory"); \ } catch (rtcore_error& e) { \ Device* device = scene ? scene->device : nullptr; \ @@ -78,9 +66,9 @@ namespace embree Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \ return false; \ } -#endif -// -- GODOT end -- +#endif + #define RTC_VERIFY_HANDLE(handle) \ if (handle == nullptr) { \ throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"invalid argument"); \ @@ -137,5 +125,38 @@ namespace embree // -- GODOT end -- #define RTC_BUILD_ARGUMENTS_HAS(settings,member) \ - (settings.byteSize > (offsetof(RTCBuildArguments,member)+sizeof(settings.member))) + (settings.byteSize > (offsetof(RTCBuildArguments,member)+sizeof(settings.member))) + + + inline void storeTransform(const AffineSpace3fa& space, RTCFormat format, float* xfm) + { + switch (format) + { + case RTC_FORMAT_FLOAT3X4_ROW_MAJOR: + xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vy.x; xfm[ 2] = space.l.vz.x; xfm[ 3] = space.p.x; + xfm[ 4] = space.l.vx.y; xfm[ 5] = space.l.vy.y; xfm[ 6] = space.l.vz.y; xfm[ 7] = space.p.y; + xfm[ 8] = space.l.vx.z; xfm[ 9] = space.l.vy.z; xfm[10] = space.l.vz.z; xfm[11] = space.p.z; + break; + + case RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR: + xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vx.y; xfm[ 2] = space.l.vx.z; + xfm[ 3] = space.l.vy.x; xfm[ 4] = space.l.vy.y; xfm[ 5] = space.l.vy.z; + xfm[ 6] = space.l.vz.x; xfm[ 7] = space.l.vz.y; xfm[ 8] = space.l.vz.z; + xfm[ 9] = space.p.x; xfm[10] = space.p.y; xfm[11] = space.p.z; + break; + + case RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR: + xfm[ 0] = space.l.vx.x; xfm[ 1] = space.l.vx.y; xfm[ 2] = space.l.vx.z; xfm[ 3] = 0.f; + xfm[ 4] = space.l.vy.x; xfm[ 5] = space.l.vy.y; xfm[ 6] = space.l.vy.z; xfm[ 7] = 0.f; + xfm[ 8] = space.l.vz.x; xfm[ 9] = space.l.vz.y; xfm[10] = space.l.vz.z; xfm[11] = 0.f; + xfm[12] = space.p.x; xfm[13] = space.p.y; xfm[14] = space.p.z; xfm[15] = 1.f; + break; + + default: +#if !defined(__SYCL_DEVICE_ONLY__) + throw_RTCError(RTC_ERROR_INVALID_OPERATION, "invalid matrix format"); +#endif + break; + } + } } diff --git a/thirdparty/embree/kernels/common/scene.cpp b/thirdparty/embree/kernels/common/scene.cpp index 65d31d0f81..10cb3c4bec 100644 --- a/thirdparty/embree/kernels/common/scene.cpp +++ b/thirdparty/embree/kernels/common/scene.cpp @@ -3,12 +3,35 @@ #include "scene.h" +#include "../../common/tasking/taskscheduler.h" + #include "../bvh/bvh4_factory.h" #include "../bvh/bvh8_factory.h" + #include "../../common/algorithms/parallel_reduce.h" - + +#if defined(EMBREE_SYCL_SUPPORT) +# include "../sycl/rthwif_embree_builder.h" +#endif + + namespace embree { + + struct TaskGroup { + /*! global lock step task scheduler */ +#if defined(TASKING_INTERNAL) + MutexSys schedulerMutex; + Ref<TaskScheduler> scheduler; +#elif defined(TASKING_TBB) && TASKING_TBB_USE_TASK_ISOLATION + tbb::isolated_task_group group; +#elif defined(TASKING_TBB) + tbb::task_group group; +#elif defined(TASKING_PPL) + concurrency::task_group group; +#endif + }; + /* error raising rtcIntersect and rtcOccluded functions */ void missing_rtcCommit() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"scene not committed"); } void invalid_rtcIntersect1() { throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcIntersect and rtcOccluded not enabled"); } @@ -22,13 +45,20 @@ namespace embree flags_modified(true), enabled_geometry_types(0), scene_flags(RTC_SCENE_FLAG_NONE), quality_flags(RTC_BUILD_QUALITY_MEDIUM), - is_build(false), modified(true), + modified(true), + taskGroup(new TaskGroup()), progressInterface(this), progress_monitor_function(nullptr), progress_monitor_ptr(nullptr), progress_monitor_counter(0) { device->refInc(); intersectors = Accel::Intersectors(missing_rtcCommit); + /* use proper device and context for SYCL allocations */ +#if defined(EMBREE_SYCL_SUPPORT) + if (DeviceGPU* gpu_device = dynamic_cast<DeviceGPU*>(device)) + hwaccel = AccelBuffer(AccelAllocator<char>(device,gpu_device->getGPUDevice(),gpu_device->getGPUContext()),0); +#endif + /* one can overwrite flags through device for debugging */ if (device->quality_flags != -1) quality_flags = (RTCBuildQuality) device->quality_flags; @@ -90,10 +120,11 @@ namespace embree void Scene::createTriangleAccel() { #if defined(EMBREE_GEOMETRY_TRIANGLE) + if (device->tri_accel == "default") { if (quality_flags != RTC_BUILD_QUALITY_LOW) - { + { int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel(); switch (mode) { case /*0b00*/ 0: @@ -168,11 +199,13 @@ namespace embree #endif else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown triangle acceleration structure "+device->tri_accel); #endif + } void Scene::createTriangleMBAccel() { #if defined(EMBREE_GEOMETRY_TRIANGLE) + if (device->tri_accel_mb == "default") { int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel(); @@ -211,6 +244,7 @@ namespace embree void Scene::createQuadAccel() { #if defined(EMBREE_GEOMETRY_QUAD) + if (device->quad_accel == "default") { if (quality_flags != RTC_BUILD_QUALITY_LOW) @@ -292,6 +326,7 @@ namespace embree void Scene::createQuadMBAccel() { #if defined(EMBREE_GEOMETRY_QUAD) + if (device->quad_accel_mb == "default") { int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel(); @@ -329,6 +364,7 @@ namespace embree void Scene::createHairAccel() { #if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT) + if (device->hair_accel == "default") { int mode = 2*(int)isCompactAccel() + 1*(int)isRobustAccel(); @@ -366,6 +402,7 @@ namespace embree void Scene::createHairMBAccel() { #if defined(EMBREE_GEOMETRY_CURVE) || defined(EMBREE_GEOMETRY_POINT) + if (device->hair_accel_mb == "default") { #if defined (EMBREE_TARGET_SIMD8) @@ -416,7 +453,8 @@ namespace embree void Scene::createUserGeometryAccel() { #if defined(EMBREE_GEOMETRY_USER) - if (device->object_accel == "default") + + if (device->object_accel == "default") { #if defined (EMBREE_TARGET_SIMD8) if (device->canUseAVX() && !isCompactAccel()) @@ -448,6 +486,7 @@ namespace embree void Scene::createUserGeometryMBAccel() { #if defined(EMBREE_GEOMETRY_USER) + if (device->object_accel_mb == "default" ) { #if defined (EMBREE_TARGET_SIMD8) if (device->canUseAVX() && !isCompactAccel()) @@ -467,6 +506,7 @@ namespace embree void Scene::createInstanceAccel() { #if defined(EMBREE_GEOMETRY_INSTANCE) + // if (device->object_accel == "default") { #if defined (EMBREE_TARGET_SIMD8) @@ -494,6 +534,7 @@ namespace embree void Scene::createInstanceMBAccel() { #if defined(EMBREE_GEOMETRY_INSTANCE) + //if (device->instance_accel_mb == "default") { #if defined (EMBREE_TARGET_SIMD8) @@ -550,10 +591,58 @@ namespace embree #endif } + void Scene::createInstanceArrayAccel() + { +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + + // if (device->object_accel == "default") + { +#if defined (EMBREE_TARGET_SIMD8) + if (device->canUseAVX() && !isCompactAccel()) { + if (quality_flags != RTC_BUILD_QUALITY_LOW) { + accels_add(device->bvh8_factory->BVH8InstanceArray(this, BVHFactory::BuildVariant::STATIC)); + } else { + accels_add(device->bvh8_factory->BVH8InstanceArray(this, BVHFactory::BuildVariant::DYNAMIC)); + } + } + else +#endif + { + if (quality_flags != RTC_BUILD_QUALITY_LOW) { + accels_add(device->bvh4_factory->BVH4InstanceArray(this, BVHFactory::BuildVariant::STATIC)); + } else { + accels_add(device->bvh4_factory->BVH4InstanceArray(this, BVHFactory::BuildVariant::DYNAMIC)); + } + } + } + // else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance accel "+device->instance_accel); +#endif + } + + void Scene::createInstanceArrayMBAccel() + { +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + + //if (device->instance_accel_mb == "default") + { +#if defined (EMBREE_TARGET_SIMD8) + if (device->canUseAVX() && !isCompactAccel()) + accels_add(device->bvh8_factory->BVH8InstanceArrayMB(this)); + else +#endif + accels_add(device->bvh4_factory->BVH4InstanceArrayMB(this)); + } + //else throw_RTCError(RTC_ERROR_INVALID_ARGUMENT,"unknown instance mblur accel "+device->instance_accel_mb); +#endif + } + + void Scene::createGridAccel() { - BVHFactory::IntersectVariant ivariant = isRobustAccel() ? BVHFactory::IntersectVariant::ROBUST : BVHFactory::IntersectVariant::FAST; #if defined(EMBREE_GEOMETRY_GRID) + + BVHFactory::IntersectVariant ivariant = isRobustAccel() ? BVHFactory::IntersectVariant::ROBUST : BVHFactory::IntersectVariant::FAST; + if (device->grid_accel == "default") { #if defined (EMBREE_TARGET_SIMD8) @@ -579,6 +668,7 @@ namespace embree void Scene::createGridMBAccel() { #if defined(EMBREE_GEOMETRY_GRID) + if (device->grid_accel_mb == "default") { accels_add(device->bvh4_factory->BVH4GridMB(this,BVHFactory::BuildVariant::STATIC)); @@ -588,13 +678,13 @@ namespace embree #endif } - + void Scene::clear() { } unsigned Scene::bind(unsigned geomID, Ref<Geometry> geometry) { - Lock<SpinLock> lock(geometriesMutex); + Lock<MutexSys> lock(geometriesMutex); if (geomID == RTC_INVALID_GEOMETRY_ID) { geomID = id_pool.allocate(); if (geomID == RTC_INVALID_GEOMETRY_ID) @@ -620,7 +710,7 @@ namespace embree void Scene::detachGeometry(size_t geomID) { - Lock<SpinLock> lock(geometriesMutex); + Lock<MutexSys> lock(geometriesMutex); if (geomID >= geometries.size()) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"invalid geometry ID"); @@ -637,45 +727,11 @@ namespace embree geometryModCounters_[geomID] = 0; } - void Scene::updateInterface() - { - is_build = true; - } - - void Scene::commit_task () + void Scene::build_cpu_accels() { - checkIfModifiedAndSet (); - if (!isModified()) { - return; - } - - /* print scene statistics */ - if (device->verbosity(2)) - printStatistics(); - - progress_monitor_counter = 0; - - /* gather scene stats and call preCommit function of each geometry */ - this->world = parallel_reduce (size_t(0), geometries.size(), GeometryCounts (), - [this](const range<size_t>& r)->GeometryCounts - { - GeometryCounts c; - for (auto i=r.begin(); i<r.end(); ++i) - { - if (geometries[i] && geometries[i]->isEnabled()) - { - geometries[i]->preCommit(); - geometries[i]->addElementsToCount (c); - c.numFilterFunctions += (int) geometries[i]->hasFilterFunctions(); - } - } - return c; - }, - std::plus<GeometryCounts>() - ); - /* select acceleration structures to build */ unsigned int new_enabled_geometry_types = world.enabledGeometryTypesMask(); + if (flags_modified || new_enabled_geometry_types != enabled_geometry_types) { accels_init(); @@ -685,7 +741,7 @@ namespace embree parallel_for(geometryModCounters_.size(), [&] ( const size_t i ) { geometryModCounters_[i] = 0; }); - + if (getNumPrimitives(TriangleMesh::geom_type,false)) createTriangleAccel(); if (getNumPrimitives(TriangleMesh::geom_type,true)) createTriangleMBAccel(); if (getNumPrimitives(QuadMesh::geom_type,false)) createQuadAccel(); @@ -702,7 +758,9 @@ namespace embree if (getNumPrimitives(Geometry::MTY_INSTANCE_CHEAP,true)) createInstanceMBAccel(); if (getNumPrimitives(Geometry::MTY_INSTANCE_EXPENSIVE,false)) createInstanceExpensiveAccel(); if (getNumPrimitives(Geometry::MTY_INSTANCE_EXPENSIVE,true)) createInstanceExpensiveMBAccel(); - + if (getNumPrimitives(Geometry::MTY_INSTANCE_ARRAY,false)) createInstanceArrayAccel(); + if (getNumPrimitives(Geometry::MTY_INSTANCE_ARRAY,true)) createInstanceArrayMBAccel(); + flags_modified = false; enabled_geometry_types = new_enabled_geometry_types; } @@ -719,6 +777,61 @@ namespace embree flags_modified = true; // in non-dynamic mode we have to re-create accels } + if (device->verbosity(2)) { + std::cout << "created scene intersector" << std::endl; + accels_print(2); + std::cout << "selected scene intersector" << std::endl; + intersectors.print(2); + } + } + + void Scene::build_gpu_accels() + { +#if defined(EMBREE_SYCL_SUPPORT) + const BBox3f aabb = rthwifBuild(this,hwaccel); + bounds = LBBox<embree::Vec3fa>(aabb); + hwaccel_bounds = aabb; +#endif + } + + void Scene::commit_task () + { + checkIfModifiedAndSet(); + if (!isModified()) return; + + /* print scene statistics */ + if (device->verbosity(2)) + printStatistics(); + + progress_monitor_counter = 0; + + /* gather scene stats and call preCommit function of each geometry */ + this->world = parallel_reduce (size_t(0), geometries.size(), GeometryCounts (), + [this](const range<size_t>& r)->GeometryCounts + { + GeometryCounts c; + for (auto i=r.begin(); i<r.end(); ++i) + { + if (geometries[i] && geometries[i]->isEnabled()) + { + geometries[i]->preCommit(); + geometries[i]->addElementsToCount (c); + c.numFilterFunctions += (int) geometries[i]->hasArgumentFilterFunctions(); + c.numFilterFunctions += (int) geometries[i]->hasGeometryFilterFunctions(); + } + } + return c; + }, + std::plus<GeometryCounts>() + ); + +#if defined(EMBREE_SYCL_SUPPORT) + if (DeviceGPU* gpu_device = dynamic_cast<DeviceGPU*>(device)) + build_gpu_accels(); + else +#endif + build_cpu_accels(); + /* call postCommit function of each geometry */ parallel_for(geometries.size(), [&] ( const size_t i ) { if (geometries[i] && geometries[i]->isEnabled()) { @@ -727,16 +840,7 @@ namespace embree geometryModCounters_[i] = geometries[i]->getModCounter(); } }); - - updateInterface(); - if (device->verbosity(2)) { - std::cout << "created scene intersector" << std::endl; - accels_print(2); - std::cout << "selected scene intersector" << std::endl; - intersectors.print(2); - } - setModified(false); } @@ -771,11 +875,11 @@ namespace embree /* allocates own taskscheduler for each build */ Ref<TaskScheduler> scheduler = nullptr; { - Lock<MutexSys> lock(schedulerMutex); - scheduler = this->scheduler; + Lock<MutexSys> lock(taskGroup->schedulerMutex); + scheduler = taskGroup->scheduler; if (scheduler == null) { buildLock.lock(); - this->scheduler = scheduler = new TaskScheduler; + taskGroup->scheduler = scheduler = new TaskScheduler; } } @@ -792,13 +896,13 @@ namespace embree /* initiate build */ // -- GODOT start -- // try { - scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(schedulerMutex); this->scheduler = nullptr; }, 1, !join); + TaskScheduler::TaskGroupContext context; + scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(taskGroup->schedulerMutex); taskGroup->scheduler = nullptr; }, &context, 1, !join); // } // catch (...) { // accels_clear(); - // updateInterface(); - // Lock<MutexSys> lock(schedulerMutex); - // this->scheduler = nullptr; + // Lock<MutexSys> lock(taskGroup->schedulerMutex); + // taskGroup->scheduler = nullptr; // throw; // } // -- GODOT end -- @@ -809,7 +913,7 @@ namespace embree #if defined(TASKING_TBB) void Scene::commit (bool join) - { + { #if defined(TASKING_TBB) && (TBB_INTERFACE_VERSION_MAJOR < 8) if (join) throw_RTCError(RTC_ERROR_INVALID_OPERATION,"rtcJoinCommitScene not supported with this TBB version"); @@ -827,16 +931,7 @@ namespace embree #endif do { - -#if USE_TASK_ARENA - if (join) { - device->arena->execute([&]{ group.wait(); }); - } - else -#endif - { - group.wait(); - } + device->execute(join, [&](){ taskGroup->group.wait(); }); pause_cpu(); yield(); @@ -857,26 +952,14 @@ namespace embree tbb::task_group_context ctx( tbb::task_group_context::isolated, tbb::task_group_context::default_traits | tbb::task_group_context::fp_settings ); #endif //ctx.set_priority(tbb::priority_high); - -#if USE_TASK_ARENA - if (join) - { - device->arena->execute([&]{ - group.run([&]{ - tbb::parallel_for (size_t(0), size_t(1), size_t(1), [&] (size_t) { commit_task(); }, ctx); - }); - group.wait(); - }); - } - else -#endif + device->execute(join, [&]() { - group.run([&]{ + taskGroup->group.run([&]{ tbb::parallel_for (size_t(0), size_t(1), size_t(1), [&] (size_t) { commit_task(); }, ctx); }); - group.wait(); - } - + taskGroup->group.wait(); + }); + /* reset MXCSR register again */ _mm_setcsr(mxcsr); } @@ -886,7 +969,6 @@ namespace embree _mm_setcsr(mxcsr); accels_clear(); - updateInterface(); throw; } } @@ -915,10 +997,10 @@ namespace embree try { - group.run([&]{ + taskGroup->group.run([&]{ concurrency::parallel_for(size_t(0), size_t(1), size_t(1), [&](size_t) { commit_task(); }); }); - group.wait(); + taskGroup->group.wait(); /* reset MXCSR register again */ _mm_setcsr(mxcsr); @@ -929,7 +1011,6 @@ namespace embree _mm_setcsr(mxcsr); accels_clear(); - updateInterface(); throw; } } diff --git a/thirdparty/embree/kernels/common/scene.h b/thirdparty/embree/kernels/common/scene.h index 5ed80a63f6..d9acca1065 100644 --- a/thirdparty/embree/kernels/common/scene.h +++ b/thirdparty/embree/kernels/common/scene.h @@ -6,11 +6,11 @@ #include "default.h" #include "device.h" #include "builder.h" -#include "../../common/algorithms/parallel_any_of.h" #include "scene_triangle_mesh.h" #include "scene_quad_mesh.h" #include "scene_user_geometry.h" #include "scene_instance.h" +#include "scene_instance_array.h" #include "scene_curves.h" #include "scene_line_segments.h" #include "scene_subdiv_mesh.h" @@ -21,12 +21,18 @@ #include "acceln.h" #include "geometry.h" +#if defined(EMBREE_SYCL_SUPPORT) +#include "../sycl/rthwif_embree_builder.h" +#endif + namespace embree { + struct TaskGroup; + /*! Base class all scenes are derived from */ class Scene : public AccelN { - ALIGNED_CLASS_(std::alignment_of<Scene>::value); + ALIGNED_CLASS_USM_(std::alignment_of<Scene>::value); public: template<typename Ty, bool mblur = false> @@ -140,6 +146,7 @@ namespace embree ~Scene () noexcept; private: + /*! class is non-copyable */ Scene (const Scene& other) DELETED; // do not implement Scene& operator= (const Scene& other) DELETED; // do not implement @@ -159,6 +166,8 @@ namespace embree void createInstanceMBAccel(); void createInstanceExpensiveAccel(); void createInstanceExpensiveMBAccel(); + void createInstanceArrayAccel(); + void createInstanceArrayMBAccel(); void createGridAccel(); void createGridMBAccel(); @@ -176,13 +185,13 @@ namespace embree void setSceneFlags(RTCSceneFlags scene_flags); RTCSceneFlags getSceneFlags() const; - + + void build_cpu_accels(); + void build_gpu_accels(); void commit (bool join); void commit_task (); void build () {} - void updateInterface(); - /* return number of geometries */ __forceinline size_t size() const { return geometries.size(); } @@ -205,20 +214,9 @@ namespace embree } protected: - - __forceinline void checkIfModifiedAndSet () - { - if (isModified ()) return; - - auto geometryIsModified = [this](size_t geomID)->bool { - return isGeometryModified(geomID); - }; - if (parallel_any_of (size_t(0), geometries.size (), geometryIsModified)) { - setModified (); - } - } - + void checkIfModifiedAndSet (); + public: /* get mesh by ID */ @@ -247,7 +245,7 @@ namespace embree } __forceinline Ref<Geometry> get_locked(size_t i) { - Lock<SpinLock> lock(geometriesMutex); + Lock<MutexSys> lock(geometriesMutex); assert(i < geometries.size()); return geometries[i]; } @@ -259,8 +257,8 @@ namespace embree __forceinline bool isStaticAccel() const { return !(scene_flags & RTC_SCENE_FLAG_DYNAMIC); } __forceinline bool isDynamicAccel() const { return scene_flags & RTC_SCENE_FLAG_DYNAMIC; } - __forceinline bool hasContextFilterFunction() const { - return scene_flags & RTC_SCENE_FLAG_CONTEXT_FILTER_FUNCTION; + __forceinline bool hasArgumentFilterFunction() const { + return scene_flags & RTC_SCENE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS; } __forceinline bool hasGeometryFilterFunction() { @@ -268,21 +266,21 @@ namespace embree } __forceinline bool hasFilterFunction() { - return hasContextFilterFunction() || hasGeometryFilterFunction(); + return hasArgumentFilterFunction() || hasGeometryFilterFunction(); } - /* test if scene got already build */ - __forceinline bool isBuild() const { return is_build; } + void* createQBVH6Accel(); + + public: + Device* device; public: IDPool<unsigned,0xFFFFFFFE> id_pool; - vector<Ref<Geometry>> geometries; //!< list of all user geometries - vector<unsigned int> geometryModCounters_; - vector<float*> vertices; + Device::vector<Ref<Geometry>> geometries = device; //!< list of all user geometries + avector<unsigned int> geometryModCounters_; + Device::vector<float*> vertices = device; public: - Device* device; - /* these are to detect if we need to recreate the acceleration structures */ bool flags_modified; unsigned int enabled_geometry_types; @@ -290,24 +288,20 @@ namespace embree RTCSceneFlags scene_flags; RTCBuildQuality quality_flags; MutexSys buildMutex; - SpinLock geometriesMutex; - bool is_build; + MutexSys geometriesMutex; + +#if defined(EMBREE_SYCL_SUPPORT) + public: + BBox3f hwaccel_bounds = empty; + AccelBuffer hwaccel; +#endif + private: bool modified; //!< true if scene got modified public: - - /*! global lock step task scheduler */ -#if defined(TASKING_INTERNAL) - MutexSys schedulerMutex; - Ref<TaskScheduler> scheduler; -#elif defined(TASKING_TBB) && TASKING_TBB_USE_TASK_ISOLATION - tbb::isolated_task_group group; -#elif defined(TASKING_TBB) - tbb::task_group group; -#elif defined(TASKING_PPL) - concurrency::task_group group; -#endif + + std::unique_ptr<TaskGroup> taskGroup; public: struct BuildProgressMonitorInterface : public BuildProgressMonitor { @@ -363,12 +357,28 @@ namespace embree if (mask & Geometry::MTY_INSTANCE_EXPENSIVE) count += mblur ? world.numMBInstancesExpensive : world.numInstancesExpensive; - + + if (mask & Geometry::MTY_INSTANCE_ARRAY) + count += mblur ? world.numMBInstanceArrays : world.numInstanceArrays; + if (mask & Geometry::MTY_GRID_MESH) count += mblur ? world.numMBGrids : world.numGrids; return count; } + + __forceinline size_t getNumSubPrimitives(Geometry::GTypeMask mask, bool mblur) const + { + size_t count = 0; + + if (mask & Geometry::MTY_GRID_MESH) + count += mblur ? world.numMBSubGrids : world.numSubGrids; + + Geometry::GTypeMask new_mask = (Geometry::GTypeMask)(mask & ~Geometry::MTY_GRID_MESH); + count += getNumPrimitives(new_mask, mblur); + + return count; + } template<typename Mesh, bool mblur> __forceinline unsigned getNumTimeSteps() diff --git a/thirdparty/embree/kernels/common/scene_curves.h b/thirdparty/embree/kernels/common/scene_curves.h index a1ea45d3c7..fd6ed81d7d 100644 --- a/thirdparty/embree/kernels/common/scene_curves.h +++ b/thirdparty/embree/kernels/common/scene_curves.h @@ -119,6 +119,15 @@ namespace embree p3 = vertex(i+3,itime); } + /*! gathers the curve normals starting with i'th vertex */ + __forceinline void gather_normals(Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i) const + { + n0 = normal(i+0); + n1 = normal(i+1); + n2 = normal(i+2); + n3 = normal(i+3); + } + /*! gathers the curve starting with i'th vertex */ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i) const { @@ -178,6 +187,13 @@ namespace embree } /*! loads curve vertices for specified time */ + __forceinline void gather_safe(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, size_t i, float time) const + { + if (hasMotionBlur()) gather(p0,p1,p2,p3,i,time); + else gather(p0,p1,p2,p3,i); + } + + /*! loads curve vertices for specified time */ __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i, float time) const { float ftime; @@ -199,8 +215,15 @@ namespace embree n3 = madd(Vec3ff(t0),an3,t1*bn3); } + /*! loads curve vertices for specified time for mblur and non-mblur case */ + __forceinline void gather_safe(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3, size_t i, float time) const + { + if (hasMotionBlur()) gather(p0,p1,p2,p3,n0,n1,n2,n3,i,time); + else gather(p0,p1,p2,p3,n0,n1,n2,n3,i); + } + template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa> - __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const + __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(RayQueryContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const { Vec3ff v0,v1,v2,v3; Vec3fa n0,n1,n2,n3; unsigned int vertexID = curve(primID); @@ -212,7 +235,7 @@ namespace embree } template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa> - __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const + __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurve(RayQueryContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const { float ftime; const size_t itime = timeSegment(time, ftime); @@ -221,6 +244,19 @@ namespace embree return clerp(curve0,curve1,ftime); } + template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa> + __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedCurveSafe(RayQueryContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const + { + float ftime = 0.0f; + const size_t itime = hasMotionBlur() ? timeSegment(time, ftime) : 0; + const TensorLinearCubicBezierSurface3fa curve0 = getNormalOrientedCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context,ray_org,primID,itime+0); + if (hasMotionBlur()) { + const TensorLinearCubicBezierSurface3fa curve1 = getNormalOrientedCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context,ray_org,primID,itime+1); + return clerp(curve0,curve1,ftime); + } + return curve0; + } + /*! gathers the hermite curve starting with i'th vertex */ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i) const { @@ -255,6 +291,13 @@ namespace embree t1 = madd(Vec3ff(f0),at1,f1*bt1); } + /*! loads curve vertices for specified time for mblur and non-mblur geometry */ + __forceinline void gather_hermite_safe(Vec3ff& p0, Vec3ff& t0, Vec3ff& p1, Vec3ff& t1, size_t i, float time) const + { + if (hasMotionBlur()) gather_hermite(p0,t0,p1,t1,i,time); + else gather_hermite(p0,t0,p1,t1,i); + } + /*! gathers the hermite curve starting with i'th vertex */ __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i) const { @@ -282,7 +325,7 @@ namespace embree } /*! loads curve vertices for specified time */ - __forceinline void gather_hermite(Vec3ff& p0, Vec3fa& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3fa& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, float time) const + __forceinline void gather_hermite(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, float time) const { float ftime; const size_t itime = timeSegment(time, ftime); @@ -301,8 +344,15 @@ namespace embree dn1= madd(Vec3ff(f0),adn1,f1*bdn1); } + /*! loads curve vertices for specified time */ + __forceinline void gather_hermite_safe(Vec3ff& p0, Vec3ff& t0, Vec3fa& n0, Vec3fa& dn0, Vec3ff& p1, Vec3ff& t1, Vec3fa& n1, Vec3fa& dn1, size_t i, float time) const + { + if (hasMotionBlur()) gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,i,time); + else gather_hermite(p0,t0,n0,dn0,p1,t1,n1,dn1,i); + } + template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa> - __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const + __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(RayQueryContext* context, const Vec3fa& ray_org, const unsigned int primID, const size_t itime) const { Vec3ff v0,t0,v1,t1; Vec3fa n0,dn0,n1,dn1; unsigned int vertexID = curve(primID); @@ -315,7 +365,7 @@ namespace embree } template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa> - __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(IntersectContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const + __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurve(RayQueryContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const { float ftime; const size_t itime = timeSegment(time, ftime); @@ -324,6 +374,24 @@ namespace embree return clerp(curve0,curve1,ftime); } + template<typename SourceCurve3ff, typename SourceCurve3fa, typename TensorLinearCubicBezierSurface3fa> + __forceinline TensorLinearCubicBezierSurface3fa getNormalOrientedHermiteCurveSafe(RayQueryContext* context, const Vec3fa& ray_org, const unsigned int primID, const float time) const + { + float ftime = 0.0f; + const size_t itime = hasMotionBlur() ? timeSegment(time, ftime) : 0; + const TensorLinearCubicBezierSurface3fa curve0 = getNormalOrientedHermiteCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,itime+0); + if (hasMotionBlur()) { + const TensorLinearCubicBezierSurface3fa curve1 = getNormalOrientedHermiteCurve<SourceCurve3ff, SourceCurve3fa, TensorLinearCubicBezierSurface3fa>(context, ray_org, primID,itime+1); + return clerp(curve0,curve1,ftime); + } + return curve0; + } + + /* returns the projected area */ + __forceinline float projectedPrimitiveArea(const size_t i) const { + return 1.0f; + } + private: void resizeBuffers(unsigned int numSteps); @@ -333,12 +401,12 @@ namespace embree BufferView<Vec3fa> normals0; //!< fast access to first normal buffer BufferView<Vec3ff> tangents0; //!< fast access to first tangent buffer BufferView<Vec3fa> dnormals0; //!< fast access to first normal derivative buffer - vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep - vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep - vector<BufferView<Vec3ff>> tangents; //!< tangent array for each timestep - vector<BufferView<Vec3fa>> dnormals; //!< normal derivative array for each timestep + Device::vector<BufferView<Vec3ff>> vertices = device; //!< vertex array for each timestep + Device::vector<BufferView<Vec3fa>> normals = device; //!< normal array for each timestep + Device::vector<BufferView<Vec3ff>> tangents = device; //!< tangent array for each timestep + Device::vector<BufferView<Vec3fa>> dnormals = device; //!< normal derivative array for each timestep BufferView<char> flags; //!< start, end flag per segment - vector<BufferView<char>> vertexAttribs; //!< user buffers + Device::vector<BufferView<char>> vertexAttribs = device; //!< user buffers int tessellationRate; //!< tessellation rate for flat curve float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii }; @@ -486,7 +554,7 @@ namespace embree src = vertices[bufferSlot].getPtr(); stride = vertices[bufferSlot].getStride(); } - + for (unsigned int i=0; i<valueCount; i+=N) { size_t ofs = i*sizeof(float); diff --git a/thirdparty/embree/kernels/common/scene_grid_mesh.h b/thirdparty/embree/kernels/common/scene_grid_mesh.h index fb6fed445b..eb2048b286 100644 --- a/thirdparty/embree/kernels/common/scene_grid_mesh.h +++ b/thirdparty/embree/kernels/common/scene_grid_mesh.h @@ -133,12 +133,26 @@ namespace embree } } } - + void addElementsToCount (GeometryCounts & counts) const; - __forceinline unsigned int getNumSubGrids(const size_t gridID) + __forceinline unsigned int getNumTotalQuads() const { - const Grid &g = grid(gridID); + size_t quads = 0; + for (size_t primID=0; primID<numPrimitives; primID++) + quads += getNumQuads(primID); + return quads; + } + + __forceinline unsigned int getNumQuads(const size_t gridID) const + { + const Grid& g = grid(gridID); + return (unsigned int) max((int)1,((int)g.resX-1) * ((int)g.resY-1)); + } + + __forceinline unsigned int getNumSubGrids(const size_t gridID) const + { + const Grid& g = grid(gridID); return max((unsigned int)1,((unsigned int)g.resX >> 1) * ((unsigned int)g.resY >> 1)); } @@ -174,6 +188,18 @@ namespace embree return vertices[itime][i]; } + /*! returns i'th vertex of for specified time */ + __forceinline const Vec3fa vertex(size_t i, float time) const + { + float ftime; + const size_t itime = timeSegment(time, ftime); + const float t0 = 1.0f - ftime; + const float t1 = ftime; + Vec3fa v0 = vertex(i, itime+0); + Vec3fa v1 = vertex(i, itime+1); + return madd(Vec3fa(t0),v0,t1*v1); + } + /*! returns i'th vertex of itime'th timestep */ __forceinline const char* vertexPtr(size_t i, size_t itime) const { return vertices[itime].getPtr(i); @@ -198,6 +224,56 @@ namespace embree return vertex(index,itime); } + /*! returns i'th vertex of the itime'th timestep */ + __forceinline const Vec3fa grid_vertex(const Grid& g, size_t x, size_t y, float time) const { + const size_t index = grid_vertex_index(g,x,y); + return vertex(index,time); + } + + /*! gathers quad vertices */ + __forceinline void gather_quad_vertices(Vec3fa& v0, Vec3fa& v1, Vec3fa& v2, Vec3fa& v3, const Grid& g, size_t x, size_t y) const + { + v0 = grid_vertex(g,x+0,y+0); + v1 = grid_vertex(g,x+1,y+0); + v2 = grid_vertex(g,x+1,y+1); + v3 = grid_vertex(g,x+0,y+1); + } + + /*! gathers quad vertices for specified time */ + __forceinline void gather_quad_vertices(Vec3fa& v0, Vec3fa& v1, Vec3fa& v2, Vec3fa& v3, const Grid& g, size_t x, size_t y, float time) const + { + v0 = grid_vertex(g,x+0,y+0,time); + v1 = grid_vertex(g,x+1,y+0,time); + v2 = grid_vertex(g,x+1,y+1,time); + v3 = grid_vertex(g,x+0,y+1,time); + } + + /*! gathers quad vertices for mblur and non-mblur meshes */ + __forceinline void gather_quad_vertices_safe(Vec3fa& v0, Vec3fa& v1, Vec3fa& v2, Vec3fa& v3, const Grid& g, size_t x, size_t y, float time) const + { + if (hasMotionBlur()) gather_quad_vertices(v0,v1,v2,v3,g,x,y,time); + else gather_quad_vertices(v0,v1,v2,v3,g,x,y); + } + + /*! calculates the build bounds of the i'th quad, if it's valid */ + __forceinline bool buildBoundsQuad(const Grid& g, size_t sx, size_t sy, BBox3fa& bbox) const + { + BBox3fa b(empty); + for (size_t t=0; t<numTimeSteps; t++) + { + for (size_t y=sy;y<sy+2;y++) + for (size_t x=sx;x<sx+2;x++) + { + const Vec3fa v = grid_vertex(g,x,y,t); + if (unlikely(!isvalid(v))) return false; + b.extend(v); + } + } + + bbox = b; + return true; + } + /*! calculates the build bounds of the i'th primitive, if it's valid */ __forceinline bool buildBounds(const Grid& g, size_t sx, size_t sy, BBox3fa& bbox) const { @@ -254,7 +330,6 @@ namespace embree return true; } - __forceinline BBox3fa bounds(const Grid& g, size_t sx, size_t sy, size_t itime) const { BBox3fa box(empty); @@ -274,11 +349,22 @@ namespace embree return LBBox3fa([&] (size_t itime) { return bounds(g,sx,sy,itime); }, dt, time_range, fnumTimeSegments); } + __forceinline float projectedPrimitiveArea(const size_t i) const { + return pos_inf; + } + public: BufferView<Grid> grids; //!< array of triangles BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer - vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep - vector<RawBufferView> vertexAttribs; //!< vertex attributes + Device::vector<BufferView<Vec3fa>> vertices = device; //!< vertex array for each timestep + Device::vector<RawBufferView> vertexAttribs = device; //!< vertex attributes + +#if defined(EMBREE_SYCL_SUPPORT) + + public: + struct PrimID_XY { uint32_t primID; uint16_t x,y; }; + Device::vector<PrimID_XY> quadID_to_primID_xy = device; //!< maps a quad to the primitive ID and grid coordinates +#endif }; namespace isa @@ -287,6 +373,94 @@ namespace embree { GridMeshISA (Device* device) : GridMesh(device) {} + + LBBox3fa vlinearBounds(size_t buildID, const BBox1f& time_range, const SubGridBuildData * const sgrids) const override { + const SubGridBuildData &subgrid = sgrids[buildID]; + const unsigned int primID = subgrid.primID; + const size_t x = subgrid.x(); + const size_t y = subgrid.y(); + return linearBounds(grid(primID),x,y,time_range); + } + +#if defined(EMBREE_SYCL_SUPPORT) + PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const override + { + PrimInfo pinfo(empty); + for (size_t j=r.begin(); j<r.end(); j++) + { + BBox3fa bounds = empty; + const PrimID_XY& quad = quadID_to_primID_xy[j]; + if (!buildBoundsQuad(grids[quad.primID],quad.x,quad.y,bounds)) continue; + const PrimRef prim(bounds,geomID,unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } +#endif + + PrimInfo createPrimRefArray(mvector<PrimRef>& prims, mvector<SubGridBuildData>& sgrids, const range<size_t>& r, size_t k, unsigned int geomID) const override + { + PrimInfo pinfo(empty); + for (size_t j=r.begin(); j<r.end(); j++) + { + if (!valid(j)) continue; + const GridMesh::Grid &g = grid(j); + + for (unsigned int y=0; y<g.resY-1u; y+=2) + { + for (unsigned int x=0; x<g.resX-1u; x+=2) + { + BBox3fa bounds = empty; + if (!buildBounds(g,x,y,bounds)) continue; // get bounds of subgrid + const PrimRef prim(bounds,(unsigned)geomID,(unsigned)k); + pinfo.add_center2(prim); + sgrids[k] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j)); + prims[k++] = prim; + } + } + } + return pinfo; + } + +#if defined(EMBREE_SYCL_SUPPORT) + PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const override + { + const BBox1f t0t1 = BBox1f::intersect(getTimeRange(), time_range); + PrimInfo pinfo(empty); + for (size_t j=r.begin(); j<r.end(); j++) + { + const PrimID_XY& quad = quadID_to_primID_xy[j]; + const LBBox3fa lbounds = linearBounds(grids[quad.primID],quad.x,quad.y,t0t1); + const PrimRef prim(lbounds.bounds(), unsigned(geomID), unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } +#endif + + PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, mvector<SubGridBuildData>& sgrids, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const override + { + PrimInfoMB pinfoMB(empty); + for (size_t j=r.begin(); j<r.end(); j++) + { + if (!valid(j, timeSegmentRange(t0t1))) continue; + const GridMesh::Grid &g = grid(j); + + for (unsigned int y=0; y<g.resY-1u; y+=2) + { + for (unsigned int x=0; x<g.resX-1u; x+=2) + { + const PrimRefMB prim(linearBounds(g,x,y,t0t1),numTimeSegments(),time_range,numTimeSegments(),unsigned(geomID),unsigned(k)); + pinfoMB.add_primref(prim); + sgrids[k] = SubGridBuildData(x | g.get3x3FlagsX(x), y | g.get3x3FlagsY(y), unsigned(j)); + prims[k++] = prim; + } + } + } + return pinfoMB; + } }; } diff --git a/thirdparty/embree/kernels/common/scene_instance.h b/thirdparty/embree/kernels/common/scene_instance.h index 773f2b6fec..1176018777 100644 --- a/thirdparty/embree/kernels/common/scene_instance.h +++ b/thirdparty/embree/kernels/common/scene_instance.h @@ -13,7 +13,7 @@ namespace embree /*! Instanced acceleration structure */ struct Instance : public Geometry { - ALIGNED_STRUCT_(16); + //ALIGNED_STRUCT_(16); static const Geometry::GTypeMask geom_type = Geometry::MTY_INSTANCE; public: @@ -50,6 +50,7 @@ namespace embree virtual void setTransform(const AffineSpace3fa& local2world, unsigned int timeStep) override; virtual void setQuaternionDecomposition(const AffineSpace3ff& qd, unsigned int timeStep) override; virtual AffineSpace3fa getTransform(float time) override; + virtual AffineSpace3fa getTransform(size_t, float time) override; virtual void setMask (unsigned mask) override; virtual void build() {} virtual void addElementsToCount (GeometryCounts & counts) const override; @@ -132,10 +133,13 @@ namespace embree __forceinline AffineSpace3fa getLocal2World(float t) const { - float ftime; const unsigned int itime = timeSegment(t, ftime); - if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION)) - return slerp(local2world[itime+0],local2world[itime+1],ftime); - return lerp(local2world[itime+0],local2world[itime+1],ftime); + if (numTimeSegments() > 0) { + float ftime; const unsigned int itime = timeSegment(t, ftime); + if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION)) + return slerp(local2world[itime+0],local2world[itime+1],ftime); + return lerp(local2world[itime+0],local2world[itime+1],ftime); + } + return getLocal2World(); } __forceinline AffineSpace3fa getWorld2Local() const { @@ -143,7 +147,9 @@ namespace embree } __forceinline AffineSpace3fa getWorld2Local(float t) const { - return rcp(getLocal2World(t)); + if (numTimeSegments() > 0) + return rcp(getLocal2World(t)); + return getWorld2Local(); } template<int K> @@ -154,6 +160,10 @@ namespace embree return getWorld2LocalLerp<K>(valid, t); } + __forceinline float projectedPrimitiveArea(const size_t i) const { + return area(bounds(i)); + } + private: template<int K> @@ -220,7 +230,11 @@ namespace embree InstanceISA (Device* device) : Instance(device) {} - PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const + LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const { + return linearBounds(primID,time_range); + } + + PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const { assert(r.begin() == 0); assert(r.end() == 1); @@ -252,7 +266,23 @@ namespace embree prims[k++] = prim; return pinfo; } - + + PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const + { + assert(r.begin() == 0); + assert(r.end() == 1); + + PrimInfo pinfo(empty); + const BBox1f t0t1 = intersect(getTimeRange(), time_range); + if (t0t1.empty()) return pinfo; + + const BBox3fa bounds = linearBounds(0, t0t1).bounds(); + const PrimRef prim(bounds, geomID, unsigned(0)); + pinfo.add_center2(prim); + prims[k++] = prim; + return pinfo; + } + PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { assert(r.begin() == 0); diff --git a/thirdparty/embree/kernels/common/scene_instance_array.h b/thirdparty/embree/kernels/common/scene_instance_array.h new file mode 100644 index 0000000000..3cf4d68feb --- /dev/null +++ b/thirdparty/embree/kernels/common/scene_instance_array.h @@ -0,0 +1,385 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "geometry.h" +#include "accel.h" + +namespace embree +{ + struct MotionDerivativeCoefficients; + + /*! Instanced acceleration structure */ + struct InstanceArray : public Geometry + { + //ALIGNED_STRUCT_(16); + static const Geometry::GTypeMask geom_type = Geometry::MTY_INSTANCE_ARRAY; + + public: + InstanceArray (Device* device, unsigned int numTimeSteps = 1); + ~InstanceArray(); + + private: + InstanceArray (const InstanceArray& other) DELETED; // do not implement + InstanceArray& operator= (const InstanceArray& other) DELETED; // do not implement + + private: + LBBox3fa nonlinearBounds(size_t i, + const BBox1f& time_range_in, + const BBox1f& geom_time_range, + float geom_time_segments) const; + + BBox3fa boundSegment(size_t i, size_t itime, + BBox3fa const& obbox0, BBox3fa const& obbox1, + BBox3fa const& bbox0, BBox3fa const& bbox1, + float t_min, float t_max) const; + + /* calculates the (correct) interpolated bounds */ + __forceinline BBox3fa bounds(size_t i, size_t itime0, size_t itime1, float f) const + { + if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION)) + return xfmBounds(slerp(l2w(i, itime0), l2w(i, itime1), f), + lerp(getObjectBounds(i, itime0), getObjectBounds(i, itime1), f)); + return xfmBounds(lerp(l2w(i, itime0), l2w(i, itime1), f), + lerp(getObjectBounds(i, itime0), getObjectBounds(i, itime1), f)); + } + + public: + + virtual void setBuffer(RTCBufferType type, unsigned int slot, RTCFormat format, const Ref<Buffer>& buffer, size_t offset, size_t stride, unsigned int num) override; + virtual void* getBuffer(RTCBufferType type, unsigned int slot) override; + virtual void updateBuffer(RTCBufferType type, unsigned int slot) override; + + virtual void setNumTimeSteps (unsigned int numTimeSteps) override; + virtual void setInstancedScene(const Ref<Scene>& scene) override; + virtual void setInstancedScenes(const RTCScene* scenes, size_t numScenes) override; + virtual AffineSpace3fa getTransform(size_t, float time) override; + virtual void setMask (unsigned mask) override; + virtual void build() {} + virtual void addElementsToCount (GeometryCounts & counts) const override; + virtual void commit() override; + + public: + + /*! calculates the bounds of instance */ + __forceinline BBox3fa bounds(size_t i) const { + if (!valid(i)) + return BBox3fa(); + + if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION)) + return xfmBounds(quaternionDecompositionToAffineSpace(l2w(i, 0)),getObject(i)->bounds.bounds()); + return xfmBounds(l2w(i, 0),getObject(i)->bounds.bounds()); + } + + /*! gets the bounds of the instanced scene */ + __forceinline BBox3fa getObjectBounds(size_t i, size_t itime) const { + if (!valid(i)) + return BBox3fa(); + + return getObject(i)->getBounds(timeStep(itime)); + } + + /*! calculates the bounds of instance */ + __forceinline BBox3fa bounds(size_t i, size_t itime) const { + if (!valid(i)) + return BBox3fa(); + + if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION)) + return xfmBounds(quaternionDecompositionToAffineSpace(l2w(i, itime)),getObjectBounds(i, itime)); + return xfmBounds(l2w(i, itime),getObjectBounds(i, itime)); + } + + /*! calculates the linear bounds of the i'th primitive for the specified time range */ + __forceinline LBBox3fa linearBounds(size_t i, const BBox1f& dt) const { + if (!valid(i)) + return LBBox3fa(); + + LBBox3fa lbbox = nonlinearBounds(i, dt, time_range, fnumTimeSegments); + return lbbox; + } + + /*! calculates the build bounds of the i'th item, if it's valid */ + __forceinline bool buildBounds(size_t i, BBox3fa* bbox = nullptr) const + { + if (!valid(i)) + return false; + + const BBox3fa b = bounds(i); + if (bbox) *bbox = b; + return isvalid(b); + } + + /*! calculates the build bounds of the i'th item at the itime'th time segment, if it's valid */ + __forceinline bool buildBounds(size_t i, size_t itime, BBox3fa& bbox) const + { + if (!valid(i)) + return false; + + const LBBox3fa bounds = linearBounds(i,itime); + bbox = bounds.bounds (); + return isvalid(bounds); + } + + /* gets version info of topology */ + unsigned int getTopologyVersion() const { + return numPrimitives; + } + + /* returns true if topology changed */ + bool topologyChanged(unsigned int otherVersion) const { + return numPrimitives != otherVersion; + } + + /*! check if the i'th primitive is valid between the specified time range */ + __forceinline bool valid(size_t i) const + { + if (object) return true; + return (object_ids[i] != (unsigned int)(-1)); + } + + /*! check if the i'th primitive is valid between the specified time range */ + __forceinline bool valid(size_t i, const range<size_t>& itime_range) const + { + for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++) + if (!isvalid(bounds(i,itime))) return false; + + return true; + } + + __forceinline AffineSpace3fa getLocal2World(size_t i) const + { + if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION)) + return quaternionDecompositionToAffineSpace(l2w(i,0)); + return l2w(i, 0); + } + + __forceinline AffineSpace3fa getLocal2World(size_t i, float t) const + { + if (numTimeSegments() > 0) { + float ftime; const unsigned int itime = timeSegment(t, ftime); + if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION)) + return slerp(l2w(i, itime+0),l2w(i, itime+1),ftime); + return lerp(l2w(i, itime+0),l2w(i, itime+1),ftime); + } + return getLocal2World(i); + } + + __forceinline AffineSpace3fa getWorld2Local(size_t i) const { + return rcp(getLocal2World(i)); + } + + __forceinline AffineSpace3fa getWorld2Local(size_t i, float t) const { + return rcp(getLocal2World(i, t)); + } + + template<int K> + __forceinline AffineSpace3vf<K> getWorld2Local(size_t i, const vbool<K>& valid, const vfloat<K>& t) const + { + if (unlikely(gsubtype == GTY_SUBTYPE_INSTANCE_QUATERNION)) + return getWorld2LocalSlerp<K>(i, valid, t); + return getWorld2LocalLerp<K>(i, valid, t); + } + + __forceinline float projectedPrimitiveArea(const size_t i) const { + return area(bounds(i)); + } + + inline Accel* getObject(size_t i) const { + if (object) { + return object; + } + + assert(objects); + assert(i < numPrimitives); + if (object_ids[i] == (unsigned int)(-1)) + return nullptr; + + assert(object_ids[i] < numObjects); + return objects[object_ids[i]]; + } + + private: + + template<int K> + __forceinline AffineSpace3vf<K> getWorld2LocalSlerp(size_t i, const vbool<K>& valid, const vfloat<K>& t) const + { + vfloat<K> ftime; + const vint<K> itime_k = timeSegment<K>(t, ftime); + assert(any(valid)); + const size_t index = bsf(movemask(valid)); + const int itime = itime_k[index]; + if (likely(all(valid, itime_k == vint<K>(itime)))) { + return rcp(slerp(AffineSpace3vff<K>(l2w(i, itime+0)), + AffineSpace3vff<K>(l2w(i, itime+1)), + ftime)); + } + else { + AffineSpace3vff<K> space0,space1; + vbool<K> valid1 = valid; + while (any(valid1)) { + vbool<K> valid2; + const int itime = next_unique(valid1, itime_k, valid2); + space0 = select(valid2, AffineSpace3vff<K>(l2w(i, itime+0)), space0); + space1 = select(valid2, AffineSpace3vff<K>(l2w(i, itime+1)), space1); + } + return rcp(slerp(space0, space1, ftime)); + } + } + + template<int K> + __forceinline AffineSpace3vf<K> getWorld2LocalLerp(size_t i, const vbool<K>& valid, const vfloat<K>& t) const + { + vfloat<K> ftime; + const vint<K> itime_k = timeSegment<K>(t, ftime); + assert(any(valid)); + const size_t index = bsf(movemask(valid)); + const int itime = itime_k[index]; + if (likely(all(valid, itime_k == vint<K>(itime)))) { + return rcp(lerp(AffineSpace3vf<K>((AffineSpace3fa)l2w(i, itime+0)), + AffineSpace3vf<K>((AffineSpace3fa)l2w(i, itime+1)), + ftime)); + } else { + AffineSpace3vf<K> space0,space1; + vbool<K> valid1 = valid; + while (any(valid1)) { + vbool<K> valid2; + const int itime = next_unique(valid1, itime_k, valid2); + space0 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)l2w(i, itime+0)), space0); + space1 = select(valid2, AffineSpace3vf<K>((AffineSpace3fa)l2w(i, itime+1)), space1); + } + return rcp(lerp(space0, space1, ftime)); + } + } + + private: + + __forceinline AffineSpace3ff l2w(size_t i, size_t itime) const { + if (l2w_buf[itime].getFormat() == RTC_FORMAT_FLOAT4X4_COLUMN_MAJOR) { + return *(AffineSpace3ff*)(l2w_buf[itime].getPtr(i)); + } + else if(l2w_buf[itime].getFormat() == RTC_FORMAT_QUATERNION_DECOMPOSITION) { + AffineSpace3ff transform; + QuaternionDecomposition* qd = (QuaternionDecomposition*)l2w_buf[itime].getPtr(i); + transform.l.vx.x = qd->scale_x; + transform.l.vy.y = qd->scale_y; + transform.l.vz.z = qd->scale_z; + transform.l.vy.x = qd->skew_xy; + transform.l.vz.x = qd->skew_xz; + transform.l.vz.y = qd->skew_yz; + transform.l.vx.y = qd->translation_x; + transform.l.vx.z = qd->translation_y; + transform.l.vy.z = qd->translation_z; + transform.p.x = qd->shift_x; + transform.p.y = qd->shift_y; + transform.p.z = qd->shift_z; + // normalize quaternion + Quaternion3f q(qd->quaternion_r, qd->quaternion_i, qd->quaternion_j, qd->quaternion_k); + q = normalize(q); + transform.l.vx.w = q.i; + transform.l.vy.w = q.j; + transform.l.vz.w = q.k; + transform.p.w = q.r; + return transform; + } + else if (l2w_buf[itime].getFormat() == RTC_FORMAT_FLOAT3X4_COLUMN_MAJOR) { + AffineSpace3f* l2w = reinterpret_cast<AffineSpace3f*>(l2w_buf[itime].getPtr(i)); + return AffineSpace3ff(*l2w); + } + else if (l2w_buf[itime].getFormat() == RTC_FORMAT_FLOAT3X4_ROW_MAJOR) { + float* data = reinterpret_cast<float*>(l2w_buf[itime].getPtr(i)); + AffineSpace3f l2w; + l2w.l.vx.x = data[0]; l2w.l.vy.x = data[1]; l2w.l.vz.x = data[2]; l2w.p.x = data[3]; + l2w.l.vx.y = data[4]; l2w.l.vy.y = data[5]; l2w.l.vz.y = data[6]; l2w.p.y = data[7]; + l2w.l.vx.z = data[8]; l2w.l.vy.z = data[9]; l2w.l.vz.z = data[10]; l2w.p.z = data[11]; + return l2w; + } + assert(false); + return AffineSpace3ff(); + } + + inline AffineSpace3ff l2w(size_t i) const { + return l2w(i, 0); + } + + private: + Accel* object; //!< fast path if only one scene is instanced + Accel** objects; + uint32_t numObjects; + Device::vector<RawBufferView> l2w_buf = device; //!< transformation from local space to world space for each timestep (either normal matrix or quaternion decomposition) + BufferView<uint32_t> object_ids; //!< array of scene ids per instance array primitive + }; + + namespace isa + { + struct InstanceArrayISA : public InstanceArray + { + InstanceArrayISA (Device* device) + : InstanceArray(device) {} + + LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const { + return linearBounds(primID,time_range); + } + + PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfo pinfo(empty); + for (size_t j = r.begin(); j < r.end(); j++) { + BBox3fa bounds = empty; + if (!buildBounds(j, &bounds) || !valid(j)) + continue; + const PrimRef prim(bounds, geomID, unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } + + PrimInfo createPrimRefArrayMB(mvector<PrimRef>& prims, size_t itime, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfo pinfo(empty); + for (size_t j = r.begin(); j < r.end(); j++) { + BBox3fa bounds = empty; + if (!buildBounds(j, itime, bounds)) + continue; + const PrimRef prim(bounds, geomID, unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } + + PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfo pinfo(empty); + const BBox1f t0t1 = BBox1f::intersect(getTimeRange(), time_range); + if (t0t1.empty()) return pinfo; + + for (size_t j = r.begin(); j < r.end(); j++) { + LBBox3fa lbounds = linearBounds(j, t0t1); + if (!isvalid(lbounds.bounds())) + continue; + const PrimRef prim(lbounds.bounds(), geomID, unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } + + PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfoMB pinfo(empty); + for (size_t j = r.begin(); j < r.end(); j++) { + if (!valid(j, timeSegmentRange(t0t1))) + continue; + const PrimRefMB prim(linearBounds(j, t0t1), this->numTimeSegments(), this->time_range, this->numTimeSegments(), geomID, unsigned(j)); + pinfo.add_primref(prim); + prims[k++] = prim; + } + return pinfo; + } + }; + } + + DECLARE_ISA_FUNCTION(InstanceArray*, createInstanceArray, Device*); +} diff --git a/thirdparty/embree/kernels/common/scene_line_segments.h b/thirdparty/embree/kernels/common/scene_line_segments.h index 3c9fdb39db..e58fd1b7eb 100644 --- a/thirdparty/embree/kernels/common/scene_line_segments.h +++ b/thirdparty/embree/kernels/common/scene_line_segments.h @@ -84,6 +84,14 @@ namespace embree return segments[i]; } +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + /*! returns the i'th segment */ + template<int M> + __forceinline const vuint<M> vsegment(const vuint<M>& i) const { + return segments[i.v]; + } +#endif + /*! returns the segment to the left of the i'th segment */ __forceinline bool segmentLeftExists(size_t i) const { assert (flags); @@ -136,6 +144,219 @@ namespace embree return vertices[itime][i].w; } + /*! gathers the curve starting with i'th vertex */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, unsigned int vid) const + { + p0 = vertex(vid+0); + p1 = vertex(vid+1); + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + template<int M> + __forceinline void vgather(Vec4vf<M>& p0, Vec4vf<M>& p1, const vuint<M>& vid) const + { + p0 = vertex(vid.v+0); + p1 = vertex(vid.v+1); + } +#endif + + /*! gathers the curve starting with i'th vertex of itime'th timestep */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, unsigned int vid, size_t itime) const + { + p0 = vertex(vid+0,itime); + p1 = vertex(vid+1,itime); + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + template<int M> + __forceinline void vgather(Vec4vf<M>& p0, Vec4vf<M>& p1, const vuint<M>& vid, const vint<M>& itime) const + { + p0 = vertex(vid.v+0,itime.v); + p1 = vertex(vid.v+1,itime.v); + } +#endif + + /*! loads curve vertices for specified time */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, unsigned int vid, float time) const + { + float ftime; + const size_t itime = timeSegment(time, ftime); + + const float t0 = 1.0f - ftime; + const float t1 = ftime; + Vec3ff a0,a1; gather(a0,a1,vid,itime); + Vec3ff b0,b1; gather(b0,b1,vid,itime+1); + p0 = madd(Vec3ff(t0),a0,t1*b0); + p1 = madd(Vec3ff(t0),a1,t1*b1); + } + + /*! loads curve vertices for specified time for mblur and non-mblur case */ + __forceinline void gather_safe(Vec3ff& p0, Vec3ff& p1, unsigned int vid, float time) const + { + if (hasMotionBlur()) gather(p0,p1,vid,time); + else gather(p0,p1,vid); + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + template<int M> + __forceinline void vgather(Vec4vf<M>& p0, Vec4vf<M>& p1, const vuint<M>& vid, const vfloat<M>& time) const + { + vfloat<M> ftime; + const vint<M> itime = timeSegment<M>(time, ftime); + + const vfloat<M> t0 = 1.0f - ftime; + const vfloat<M> t1 = ftime; + Vec4vf<M> a0,a1; vgather<M>(a0,a1,vid,itime); + Vec4vf<M> b0,b1; vgather<M>(b0,b1,vid,itime+1); + p0 = madd(Vec4vf<M>(t0),a0,t1*b0); + p1 = madd(Vec4vf<M>(t0),a1,t1*b1); + } +#endif + + /*! gathers the cone curve starting with i'th vertex */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, bool& cL, bool& cR, unsigned int primID, unsigned int vid) const + { + gather(p0,p1,vid); + cL = !segmentLeftExists (primID); + cR = !segmentRightExists(primID); + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + template<int M> + __forceinline void vgather(Vec4vf<M>& p0, Vec4vf<M>& p1, vbool<M>& cL, vbool<M>& cR, const vuint<M>& primID, const vuint<M>& vid) const + { + vgather<M>(p0,p1,vid); + cL = !segmentLeftExists (primID.v); + cR = !segmentRightExists(primID.v); + } +#endif + + /*! gathers the cone curve starting with i'th vertex of itime'th timestep */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, bool& cL, bool& cR, unsigned int primID, size_t vid, size_t itime) const + { + gather(p0,p1,vid,itime); + cL = !segmentLeftExists (primID); + cR = !segmentRightExists(primID); + } + + /*! loads cone curve vertices for specified time */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, bool& cL, bool& cR, unsigned int primID, size_t vid, float time) const + { + gather(p0,p1,vid,time); + cL = !segmentLeftExists (primID); + cR = !segmentRightExists(primID); + } + + /*! loads cone curve vertices for specified time for mblur and non-mblur geometry */ + __forceinline void gather_safe(Vec3ff& p0, Vec3ff& p1, bool& cL, bool& cR, unsigned int primID, size_t vid, float time) const + { + if (hasMotionBlur()) gather(p0,p1,cL,cR,primID,vid,time); + else gather(p0,p1,cL,cR,primID,vid); + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + template<int M> + __forceinline void vgather(Vec4vf<M>& p0, Vec4vf<M>& p1, vbool<M>& cL, vbool<M>& cR, const vuint<M>& primID, const vuint<M>& vid, const vfloat<M>& time) const + { + vgather<M>(p0,p1,vid,time); + cL = !segmentLeftExists (primID.v); + cR = !segmentRightExists(primID.v); + } +#endif + + /*! gathers the curve starting with i'th vertex */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, unsigned int primID, size_t vid) const + { + p0 = vertex(vid+0); + p1 = vertex(vid+1); + p2 = segmentLeftExists (primID) ? vertex(vid-1) : Vec3ff(inf); + p3 = segmentRightExists(primID) ? vertex(vid+2) : Vec3ff(inf); + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + template<int M> + __forceinline void vgather(Vec4vf<M>& p0, Vec4vf<M>& p1, Vec4vf<M>& p2, Vec4vf<M>& p3, const vuint<M>& primID, const vuint<M>& vid) const + { + p0 = vertex(vid.v+0); + p1 = vertex(vid.v+1); + vbool<M> left = segmentLeftExists (primID.v); + vbool<M> right = segmentRightExists(primID.v); + vuint<M> i2 = select(left, vid-1,vid+0); + vuint<M> i3 = select(right,vid+2,vid+1); + p2 = vertex(i2.v); + p3 = vertex(i3.v); + p2 = select(left, p2,Vec4vf<M>(inf)); + p3 = select(right,p3,Vec4vf<M>(inf)); + } +#endif + + /*! gathers the curve starting with i'th vertex of itime'th timestep */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, unsigned int primID, size_t vid, size_t itime) const + { + p0 = vertex(vid+0,itime); + p1 = vertex(vid+1,itime); + p2 = segmentLeftExists (primID) ? vertex(vid-1,itime) : Vec3ff(inf); + p3 = segmentRightExists(primID) ? vertex(vid+2,itime) : Vec3ff(inf); + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + template<int M> + __forceinline void vgather(Vec4vf<M>& p0, Vec4vf<M>& p1, Vec4vf<M>& p2, Vec4vf<M>& p3, const vuint<M>& primID, const vuint<M>& vid, const vint<M>& itime) const + { + p0 = vertex(vid.v+0, itime.v); + p1 = vertex(vid.v+1, itime.v); + vbool<M> left = segmentLeftExists (primID.v); + vbool<M> right = segmentRightExists(primID.v); + vuint<M> i2 = select(left, vid-1,vid+0); + vuint<M> i3 = select(right,vid+2,vid+1); + p2 = vertex(i2.v, itime.v); + p3 = vertex(i3.v, itime.v); + p2 = select(left, p2,Vec4vf<M>(inf)); + p3 = select(right,p3,Vec4vf<M>(inf)); + } +#endif + + /*! loads curve vertices for specified time */ + __forceinline void gather(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, unsigned int primID, size_t vid, float time) const + { + float ftime; + const size_t itime = timeSegment(time, ftime); + + const float t0 = 1.0f - ftime; + const float t1 = ftime; + Vec3ff a0,a1,a2,a3; gather(a0,a1,a2,a3,primID,vid,itime); + Vec3ff b0,b1,b2,b3; gather(b0,b1,b2,b3,primID,vid,itime+1); + p0 = madd(Vec3ff(t0),a0,t1*b0); + p1 = madd(Vec3ff(t0),a1,t1*b1); + p2 = madd(Vec3ff(t0),a2,t1*b2); + p3 = madd(Vec3ff(t0),a3,t1*b3); + } + + /*! loads curve vertices for specified time for mblur and non-mblur geometry */ + __forceinline void gather_safe(Vec3ff& p0, Vec3ff& p1, Vec3ff& p2, Vec3ff& p3, unsigned int primID, size_t vid, float time) const + { + if (hasMotionBlur()) gather(p0,p1,p2,p3,primID,vid,time); + else gather(p0,p1,p2,p3,primID,vid); + } + +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + template<int M> + __forceinline void vgather(Vec4vf<M>& p0, Vec4vf<M>& p1, Vec4vf<M>& p2, Vec4vf<M>& p3, const vuint<M>& primID, const vuint<M>& vid, const vfloat<M>& time) const + { + vfloat<M> ftime; + const vint<M> itime = timeSegment<M>(time, ftime); + + const vfloat<M> t0 = 1.0f - ftime; + const vfloat<M> t1 = ftime; + Vec4vf<M> a0,a1,a2,a3; vgather<M>(a0,a1,a2,a3,primID,vid,itime); + Vec4vf<M> b0,b1,b2,b3; vgather<M>(b0,b1,b2,b3,primID,vid,itime+1); + p0 = madd(Vec4vf<M>(t0),a0,t1*b0); + p1 = madd(Vec4vf<M>(t0),a1,t1*b1); + p2 = madd(Vec4vf<M>(t0),a2,t1*b2); + p3 = madd(Vec4vf<M>(t0),a3,t1*b3); + } +#endif + /*! calculates bounding box of i'th line segment */ __forceinline BBox3fa bounds(const Vec3ff& v0, const Vec3ff& v1) const { @@ -183,6 +404,18 @@ namespace embree return bounds(w0,w1); } + /*! calculates bounding box of i'th segment */ + __forceinline BBox3fa bounds(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t i, size_t itime = 0) const + { + const float r_scale = r_scale0*scale; + const unsigned int index = segment(i); + const Vec3ff v0 = vertex(index+0,itime); + const Vec3ff v1 = vertex(index+1,itime); + const Vec3ff w0(xfmVector(space,(v0-ofs)*Vec3fa(scale)),maxRadiusScale*v0.w*r_scale); + const Vec3ff w1(xfmVector(space,(v1-ofs)*Vec3fa(scale)),maxRadiusScale*v1.w*r_scale); + return bounds(w0,w1); + } + /*! check if the i'th primitive is valid at the itime'th timestep */ __forceinline bool valid(size_t i, size_t itime) const { return valid(i, make_range(itime, itime)); @@ -193,13 +426,17 @@ namespace embree { const unsigned int index = segment(i); if (index+1 >= numVertices()) return false; - + +#if !defined(__SYCL_DEVICE_ONLY__) + for (size_t itime = itime_range.begin(); itime <= itime_range.end(); itime++) { const Vec3ff v0 = vertex(index+0,itime); if (unlikely(!isvalid4(v0))) return false; const Vec3ff v1 = vertex(index+1,itime); if (unlikely(!isvalid4(v1))) return false; if (min(v0.w,v1.w) < 0.0f) return false; } +#endif + return true; } @@ -235,6 +472,11 @@ namespace embree } /*! calculates the linear bounds of the i'th primitive for the specified time range */ + __forceinline LBBox3fa linearBounds(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t primID, const BBox1f& dt) const { + return LBBox3fa([&] (size_t itime) { return bounds(ofs, scale, r_scale0, space, primID, itime); }, dt, this->time_range, fnumTimeSegments); + } + + /*! calculates the linear bounds of the i'th primitive for the specified time range */ __forceinline bool linearBounds(size_t i, const BBox1f& time_range, LBBox3fa& bbox) const { if (!valid(i, timeSegmentRange(time_range))) return false; @@ -252,9 +494,9 @@ namespace embree BufferView<Vec3ff> vertices0; //!< fast access to first vertex buffer BufferView<Vec3fa> normals0; //!< fast access to first normal buffer BufferView<char> flags; //!< start, end flag per segment - vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep - vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep - vector<BufferView<char>> vertexAttribs; //!< user buffers + Device::vector<BufferView<Vec3ff>> vertices = device; //!< vertex array for each timestep + Device::vector<BufferView<Vec3fa>> normals = device; //!< normal array for each timestep + Device::vector<BufferView<char>> vertexAttribs = device; //!< user buffers int tessellationRate; //!< tessellation rate for bezier curve float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii }; @@ -266,6 +508,28 @@ namespace embree LineSegmentsISA (Device* device, Geometry::GType gtype) : LineSegments(device,gtype) {} + LinearSpace3fa computeAlignedSpace(const size_t primID) const + { + const Vec3fa dir = normalize(computeDirection(primID)); + if (is_finite(dir)) return frame(dir); + else return LinearSpace3fa(one); + } + + LinearSpace3fa computeAlignedSpaceMB(const size_t primID, const BBox1f time_range) const + { + Vec3fa axisz(0,0,1); + Vec3fa axisy(0,1,0); + + const range<int> tbounds = this->timeSegmentRange(time_range); + if (tbounds.size() == 0) return frame(axisz); + + const size_t itime = (tbounds.begin()+tbounds.end())/2; + + const Vec3fa dir = normalize(computeDirection(primID,itime)); + if (is_finite(dir)) return frame(dir); + else return LinearSpace3fa(one); + } + Vec3fa computeDirection(unsigned int primID) const { const unsigned vtxID = segment(primID); @@ -282,7 +546,7 @@ namespace embree return v1-v0; } - PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const + PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfo pinfo(empty); for (size_t j=r.begin(); j<r.end(); j++) @@ -309,7 +573,24 @@ namespace embree } return pinfo; } - + + PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfo pinfo(empty); + const BBox1f t0t1 = BBox1f::intersect(getTimeRange(), time_range); + if (t0t1.empty()) return pinfo; + + for (size_t j = r.begin(); j < r.end(); j++) { + LBBox3fa lbounds = empty; + if (!linearBounds(j, t0t1, lbounds)) + continue; + const PrimRef prim(lbounds.bounds(), geomID, unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } + PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfoMB pinfo(empty); @@ -331,6 +612,10 @@ namespace embree return bounds(space,i); } + BBox3fa vbounds(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t i, size_t itime = 0) const { + return bounds(ofs,scale,r_scale0,space,i,itime); + } + LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const { return linearBounds(primID,time_range); } @@ -338,6 +623,10 @@ namespace embree LBBox3fa vlinearBounds(const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const { return linearBounds(space,primID,time_range); } + + LBBox3fa vlinearBounds(const Vec3fa& ofs, const float scale, const float r_scale0, const LinearSpace3fa& space, size_t primID, const BBox1f& time_range) const { + return linearBounds(ofs,scale,r_scale0,space,primID,time_range); + } }; } diff --git a/thirdparty/embree/kernels/common/scene_points.h b/thirdparty/embree/kernels/common/scene_points.h index 017e098a51..937a8f1806 100644 --- a/thirdparty/embree/kernels/common/scene_points.h +++ b/thirdparty/embree/kernels/common/scene_points.h @@ -68,6 +68,25 @@ namespace embree return vertices[itime][i]; } + /*! returns i'th vertex of for specified time */ + __forceinline Vec3ff vertex(size_t i, float time) const + { + float ftime; + const size_t itime = timeSegment(time, ftime); + const float t0 = 1.0f - ftime; + const float t1 = ftime; + Vec3ff v0 = vertex(i, itime+0); + Vec3ff v1 = vertex(i, itime+1); + return madd(Vec3ff(t0),v0,t1*v1); + } + + /*! returns i'th vertex of for specified time */ + __forceinline Vec3ff vertex_safe(size_t i, float time) const + { + if (hasMotionBlur()) return vertex(i,time); + else return vertex(i); + } + /*! returns i'th vertex of itime'th timestep */ __forceinline const char* vertexPtr(size_t i, size_t itime) const { return vertices[itime].getPtr(i); @@ -78,11 +97,49 @@ namespace embree return normals[itime][i]; } + /*! returns i'th normal of for specified time */ + __forceinline Vec3fa normal(size_t i, float time) const + { + float ftime; + const size_t itime = timeSegment(time, ftime); + const float t0 = 1.0f - ftime; + const float t1 = ftime; + Vec3fa n0 = normal(i, itime+0); + Vec3fa n1 = normal(i, itime+1); + return madd(Vec3fa(t0),n0,t1*n1); + } + + /*! returns i'th normal of for specified time */ + __forceinline Vec3fa normal_safe(size_t i, float time) const + { + if (hasMotionBlur()) return normal(i,time); + else return normal(i); + } + /*! returns i'th radius of itime'th timestep */ __forceinline float radius(size_t i, size_t itime) const { return vertices[itime][i].w; } + /*! returns i'th radius of for specified time */ + __forceinline float radius(size_t i, float time) const + { + float ftime; + const size_t itime = timeSegment(time, ftime); + const float t0 = 1.0f - ftime; + const float t1 = ftime; + float r0 = radius(i, itime+0); + float r1 = radius(i, itime+1); + return madd(t0,r0,t1*r1); + } + + /*! returns i'th radius of for specified time */ + __forceinline float radius_safe(size_t i, float time) const + { + if (hasMotionBlur()) return radius(i,time); + else return radius(i); + } + /*! calculates bounding box of i'th line segment */ __forceinline BBox3fa bounds(const Vec3ff& v0) const { return enlarge(BBox3fa(v0), maxRadiusScale*Vec3fa(v0.w)); @@ -185,13 +242,18 @@ namespace embree __forceinline float * getCompactVertexArray () const { return (float*) vertices0.getPtr(); } + + __forceinline float projectedPrimitiveArea(const size_t i) const { + const float R = radius(i); + return 1 + 2*M_PI*R*R; + } public: BufferView<Vec3ff> vertices0; //!< fast access to first vertex buffer BufferView<Vec3fa> normals0; //!< fast access to first normal buffer - vector<BufferView<Vec3ff>> vertices; //!< vertex array for each timestep - vector<BufferView<Vec3fa>> normals; //!< normal array for each timestep - vector<BufferView<char>> vertexAttribs; //!< user buffers + Device::vector<BufferView<Vec3ff>> vertices = device; //!< vertex array for each timestep + Device::vector<BufferView<Vec3fa>> normals = device; //!< normal array for each timestep + Device::vector<BufferView<char>> vertexAttribs = device; //!< user buffers float maxRadiusScale = 1.0; //!< maximal min-width scaling of curve radii }; @@ -211,7 +273,7 @@ namespace embree return Vec3fa(1, 0, 0); } - PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const + PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfo pinfo(empty); for (size_t j = r.begin(); j < r.end(); j++) { @@ -239,6 +301,23 @@ namespace embree return pinfo; } + PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfo pinfo(empty); + const BBox1f t0t1 = BBox1f::intersect(getTimeRange(), time_range); + if (t0t1.empty()) return pinfo; + + for (size_t j = r.begin(); j < r.end(); j++) { + LBBox3fa lbounds = empty; + if (!linearBounds(j, t0t1, lbounds)) + continue; + const PrimRef prim(lbounds.bounds(), geomID, unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } + PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, diff --git a/thirdparty/embree/kernels/common/scene_quad_mesh.h b/thirdparty/embree/kernels/common/scene_quad_mesh.h index bd8eeaaeb7..09a8b8ddd9 100644 --- a/thirdparty/embree/kernels/common/scene_quad_mesh.h +++ b/thirdparty/embree/kernels/common/scene_quad_mesh.h @@ -17,12 +17,18 @@ namespace embree /*! triangle indices */ struct Quad { - uint32_t v[4]; + Quad() {} + + Quad (uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3) { + v[0] = v0; v[1] = v1; v[2] = v2; v[3] = v3; + } /*! outputs triangle indices */ __forceinline friend embree_ostream operator<<(embree_ostream cout, const Quad& q) { return cout << "Quad {" << q.v[0] << ", " << q.v[1] << ", " << q.v[2] << ", " << q.v[3] << " }"; } + + uint32_t v[4]; }; public: @@ -135,6 +141,18 @@ namespace embree return vertices[itime].getPtr(i); } + /*! returns i'th vertex of for specified time */ + __forceinline Vec3fa vertex(size_t i, float time) const + { + float ftime; + const size_t itime = timeSegment(time, ftime); + const float t0 = 1.0f - ftime; + const float t1 = ftime; + Vec3fa v0 = vertex(i, itime+0); + Vec3fa v1 = vertex(i, itime+1); + return madd(Vec3fa(t0),v0,t1*v1); + } + /*! calculates the bounds of the i'th quad */ __forceinline BBox3fa bounds(size_t i) const { @@ -196,7 +214,7 @@ namespace embree if (q.v[2] >= numVertices()) return false; if (q.v[3] >= numVertices()) return false; - for (unsigned int t=0; t<numTimeSteps; t++) + for (size_t t=0; t<numTimeSteps; t++) { const Vec3fa v0 = vertex(q.v[0],t); const Vec3fa v1 = vertex(q.v[1],t); @@ -279,8 +297,8 @@ namespace embree public: BufferView<Quad> quads; //!< array of quads BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer - vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep - vector<BufferView<char>> vertexAttribs; //!< vertex attribute buffers + Device::vector<BufferView<Vec3fa>> vertices = device; //!< vertex array for each timestep + Device::vector<RawBufferView> vertexAttribs = device; //!< vertex attribute buffers }; namespace isa @@ -290,7 +308,11 @@ namespace embree QuadMeshISA (Device* device) : QuadMesh(device) {} - PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const + LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const { + return linearBounds(primID,time_range); + } + + PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfo pinfo(empty); for (size_t j=r.begin(); j<r.end(); j++) @@ -317,7 +339,24 @@ namespace embree } return pinfo; } - + + PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfo pinfo(empty); + const BBox1f t0t1 = BBox1f::intersect(getTimeRange(), time_range); + if (t0t1.empty()) return pinfo; + + for (size_t j = r.begin(); j < r.end(); j++) { + LBBox3fa lbounds = empty; + if (!linearBounds(j, t0t1, lbounds)) + continue; + const PrimRef prim(lbounds.bounds(), geomID, unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } + PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfoMB pinfo(empty); diff --git a/thirdparty/embree/kernels/common/scene_subdiv_mesh.h b/thirdparty/embree/kernels/common/scene_subdiv_mesh.h index 1db170196d..b213a9b7ba 100644 --- a/thirdparty/embree/kernels/common/scene_subdiv_mesh.h +++ b/thirdparty/embree/kernels/common/scene_subdiv_mesh.h @@ -9,11 +9,13 @@ #include "../subdiv/tessellation_cache.h" #include "../subdiv/catmullclark_coefficients.h" #include "../subdiv/patch.h" -#include "../../common/algorithms/parallel_map.h" -#include "../../common/algorithms/parallel_set.h" namespace embree { + struct HoleSet; + struct VertexCreaseMap; + struct EdgeCreaseMap; + class SubdivMesh : public Geometry { ALIGNED_CLASS_(16); @@ -49,6 +51,7 @@ namespace embree /*! subdiv mesh construction */ SubdivMesh(Device* device); + ~SubdivMesh(); public: void setMask (unsigned mask); @@ -272,7 +275,7 @@ namespace embree mvector<uint32_t> halfEdgeFace; /*! set with all holes */ - parallel_set<uint32_t> holeSet; + std::unique_ptr<HoleSet> holeSet; /*! fast lookup table to detect invalid faces */ mvector<char> invalid_face; @@ -299,10 +302,10 @@ namespace embree private: /*! map with all vertex creases */ - parallel_map<uint32_t,float> vertexCreaseMap; + std::unique_ptr<VertexCreaseMap> vertexCreaseMap; /*! map with all edge creases */ - parallel_map<uint64_t,float> edgeCreaseMap; + std::unique_ptr<EdgeCreaseMap> edgeCreaseMap; protected: diff --git a/thirdparty/embree/kernels/common/scene_triangle_mesh.cpp b/thirdparty/embree/kernels/common/scene_triangle_mesh.cpp index 3bbd7e51ae..6cdd542a65 100644 --- a/thirdparty/embree/kernels/common/scene_triangle_mesh.cpp +++ b/thirdparty/embree/kernels/common/scene_triangle_mesh.cpp @@ -134,7 +134,7 @@ namespace embree Geometry::update(); } - void TriangleMesh::commit() + void TriangleMesh::commit() { /* verify that stride of all time steps are identical */ for (unsigned int t=0; t<numTimeSteps; t++) diff --git a/thirdparty/embree/kernels/common/scene_triangle_mesh.h b/thirdparty/embree/kernels/common/scene_triangle_mesh.h index ad3f602fde..0d28219b96 100644 --- a/thirdparty/embree/kernels/common/scene_triangle_mesh.h +++ b/thirdparty/embree/kernels/common/scene_triangle_mesh.h @@ -129,6 +129,18 @@ namespace embree return vertices[itime].getPtr(i); } + /*! returns i'th vertex of for specified time */ + __forceinline Vec3fa vertex(size_t i, float time) const + { + float ftime; + const size_t itime = timeSegment(time, ftime); + const float t0 = 1.0f - ftime; + const float t1 = ftime; + Vec3fa v0 = vertex(i, itime+0); + Vec3fa v1 = vertex(i, itime+1); + return madd(Vec3fa(t0),v0,t1*v1); + } + /*! calculates the bounds of the i'th triangle */ __forceinline BBox3fa bounds(size_t i) const { @@ -260,8 +272,8 @@ namespace embree public: BufferView<Triangle> triangles; //!< array of triangles BufferView<Vec3fa> vertices0; //!< fast access to first vertex buffer - vector<BufferView<Vec3fa>> vertices; //!< vertex array for each timestep - vector<RawBufferView> vertexAttribs; //!< vertex attributes + Device::vector<BufferView<Vec3fa>> vertices = device; //!< vertex array for each timestep + Device::vector<RawBufferView> vertexAttribs = device; //!< vertex attributes }; namespace isa @@ -271,7 +283,11 @@ namespace embree TriangleMeshISA (Device* device) : TriangleMesh(device) {} - PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const + LBBox3fa vlinearBounds(size_t primID, const BBox1f& time_range) const { + return linearBounds(primID,time_range); + } + + PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfo pinfo(empty); for (size_t j=r.begin(); j<r.end(); j++) @@ -298,7 +314,24 @@ namespace embree } return pinfo; } - + + PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfo pinfo(empty); + const BBox1f t0t1 = BBox1f::intersect(getTimeRange(), time_range); + if (t0t1.empty()) return pinfo; + + for (size_t j = r.begin(); j < r.end(); j++) { + LBBox3fa lbounds = empty; + if (!linearBounds(j, t0t1, lbounds)) + continue; + const PrimRef prim(lbounds.bounds(), geomID, unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } + PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfoMB pinfo(empty); diff --git a/thirdparty/embree/kernels/common/scene_user_geometry.h b/thirdparty/embree/kernels/common/scene_user_geometry.h index 2867b18b79..033476f658 100644 --- a/thirdparty/embree/kernels/common/scene_user_geometry.h +++ b/thirdparty/embree/kernels/common/scene_user_geometry.h @@ -21,6 +21,8 @@ namespace embree virtual void setOccludedFunctionN (RTCOccludedFunctionN occluded); virtual void build() {} virtual void addElementsToCount (GeometryCounts & counts) const; + + __forceinline float projectedPrimitiveArea(const size_t i) const { return 0.0f; } }; namespace isa @@ -30,7 +32,7 @@ namespace embree UserGeometryISA (Device* device) : UserGeometry(device) {} - PrimInfo createPrimRefArray(mvector<PrimRef>& prims, const range<size_t>& r, size_t k, unsigned int geomID) const + PrimInfo createPrimRefArray(PrimRef* prims, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfo pinfo(empty); for (size_t j=r.begin(); j<r.end(); j++) @@ -57,7 +59,24 @@ namespace embree } return pinfo; } - + + PrimInfo createPrimRefArrayMB(PrimRef* prims, const BBox1f& time_range, const range<size_t>& r, size_t k, unsigned int geomID) const + { + PrimInfo pinfo(empty); + const BBox1f t0t1 = BBox1f::intersect(getTimeRange(), time_range); + if (t0t1.empty()) return pinfo; + + for (size_t j = r.begin(); j < r.end(); j++) { + LBBox3fa lbounds = empty; + if (!linearBounds(j, t0t1, lbounds)) + continue; + const PrimRef prim(lbounds.bounds(), geomID, unsigned(j)); + pinfo.add_center2(prim); + prims[k++] = prim; + } + return pinfo; + } + PrimInfoMB createPrimRefMBArray(mvector<PrimRefMB>& prims, const BBox1f& t0t1, const range<size_t>& r, size_t k, unsigned int geomID) const { PrimInfoMB pinfo(empty); diff --git a/thirdparty/embree/kernels/common/scene_verify.cpp b/thirdparty/embree/kernels/common/scene_verify.cpp new file mode 100644 index 0000000000..1db7844f4f --- /dev/null +++ b/thirdparty/embree/kernels/common/scene_verify.cpp @@ -0,0 +1,24 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#include "scene.h" + +#include "../../common/algorithms/parallel_any_of.h" + +namespace embree +{ + +void Scene::checkIfModifiedAndSet () +{ + if (isModified ()) return; + + auto geometryIsModified = [this](size_t geomID)->bool { + return isGeometryModified(geomID); + }; + + if (parallel_any_of (size_t(0), geometries.size (), geometryIsModified)) { + setModified (); + } +} + +}
\ No newline at end of file diff --git a/thirdparty/embree/kernels/common/stat.cpp b/thirdparty/embree/kernels/common/stat.cpp index ebb77cd534..9a8c8fac4e 100644 --- a/thirdparty/embree/kernels/common/stat.cpp +++ b/thirdparty/embree/kernels/common/stat.cpp @@ -17,7 +17,7 @@ namespace embree #endif } - void Stat::print(std::ostream& cout) + void Stat::print(embree_ostream cout) { Counters& cntrs = instance.cntrs; Counters::Data& data = instance.cntrs.code; diff --git a/thirdparty/embree/kernels/common/state.cpp b/thirdparty/embree/kernels/common/state.cpp index db6b803041..1d73ae9629 100644 --- a/thirdparty/embree/kernels/common/state.cpp +++ b/thirdparty/embree/kernels/common/state.cpp @@ -192,10 +192,17 @@ namespace embree const char* symbols[3] = { "=", ",", "|" }; bool State::parseFile(const FileName& fileName) - { - FILE* f = fopen(fileName.c_str(),"r"); - if (!f) return false; - Ref<Stream<int> > file = new FileStream(f,fileName); + { + Ref<Stream<int> > file; + // -- GODOT start -- + // try { + file = new FileStream(fileName); + // } + // catch (std::runtime_error& e) { + // (void) e; + // return false; + // } + // -- GODOT end -- std::vector<std::string> syms; for (size_t i=0; i<sizeof(symbols)/sizeof(void*); i++) @@ -393,7 +400,7 @@ namespace embree grid_accel = cin->get().Identifier(); else if (tok == Token::Id("grid_accel_mb") && cin->trySymbol("=")) grid_accel_mb = cin->get().Identifier(); - + else if (tok == Token::Id("verbose") && cin->trySymbol("=")) verbose = cin->get().Int(); else if (tok == Token::Id("benchmark") && cin->trySymbol("=")) @@ -419,7 +426,7 @@ namespace embree } while (cin->trySymbol("|")); } } - + else if (tok == Token::Id("max_spatial_split_replications") && cin->trySymbol("=")) max_spatial_split_replications = cin->get().Float(); diff --git a/thirdparty/embree/kernels/common/state.h b/thirdparty/embree/kernels/common/state.h index 33bcc843b2..8c34614185 100644 --- a/thirdparty/embree/kernels/common/state.h +++ b/thirdparty/embree/kernels/common/state.h @@ -189,7 +189,7 @@ namespace embree memory_monitor_function = fptr; memory_monitor_userptr = uptr; } - + RTCMemoryMonitorFunction memory_monitor_function; void* memory_monitor_userptr; }; diff --git a/thirdparty/embree/kernels/config.h b/thirdparty/embree/kernels/config.h index 84ac27d103..5979b543c9 100644 --- a/thirdparty/embree/kernels/config.h +++ b/thirdparty/embree/kernels/config.h @@ -1,22 +1,26 @@ // Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -/* #undef EMBREE_RAY_MASK */ -/* #undef EMBREE_STAT_COUNTERS */ -/* #undef EMBREE_BACKFACE_CULLING */ -/* #undef EMBREE_BACKFACE_CULLING_CURVES */ +#include "../include/embree4/rtcore_config.h" + +// #cmakedefine EMBREE_RAY_MASK +// #cmakedefine EMBREE_STAT_COUNTERS +// #cmakedefine EMBREE_BACKFACE_CULLING +// #cmakedefine EMBREE_BACKFACE_CULLING_CURVES +// #cmakedefine EMBREE_BACKFACE_CULLING_SPHERES #define EMBREE_FILTER_FUNCTION -/* #undef EMBREE_IGNORE_INVALID_RAYS */ +// #cmakedefine EMBREE_IGNORE_INVALID_RAYS #define EMBREE_GEOMETRY_TRIANGLE -/* #undef EMBREE_GEOMETRY_QUAD */ -/* #undef EMBREE_GEOMETRY_CURVE */ -/* #undef EMBREE_GEOMETRY_SUBDIVISION */ -/* #undef EMBREE_GEOMETRY_USER */ -/* #undef EMBREE_GEOMETRY_INSTANCE */ -/* #undef EMBREE_GEOMETRY_GRID */ -/* #undef EMBREE_GEOMETRY_POINT */ +// #cmakedefine EMBREE_GEOMETRY_QUAD +// #cmakedefine EMBREE_GEOMETRY_CURVE +// #cmakedefine EMBREE_GEOMETRY_SUBDIVISION +// #cmakedefine EMBREE_GEOMETRY_USER +// #cmakedefine EMBREE_GEOMETRY_INSTANCE +// EMBREE_GEOMETRY_INSTANCE_ARRAY is defined in rtcore_config.h +// #cmakedefine EMBREE_GEOMETRY_GRID +// #cmakedefine EMBREE_GEOMETRY_POINT #define EMBREE_RAY_PACKETS -/* #undef EMBREE_COMPACT_POLYS */ +// #cmakedefine EMBREE_COMPACT_POLYS #define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0 #define EMBREE_DISC_POINT_SELF_INTERSECTION_AVOIDANCE @@ -69,8 +73,18 @@ #define IF_ENABLED_INSTANCE(x) #endif +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + #define IF_ENABLED_INSTANCE_ARRAY(x) x +#else + #define IF_ENABLED_INSTANCE_ARRAY(x) +#endif + #if defined(EMBREE_GEOMETRY_GRID) #define IF_ENABLED_GRIDS(x) x #else #define IF_ENABLED_GRIDS(x) #endif + + + + diff --git a/thirdparty/embree/kernels/geometry/coneline_intersector.h b/thirdparty/embree/kernels/geometry/coneline_intersector.h index 90f3792eff..696ea41ebc 100644 --- a/thirdparty/embree/kernels/geometry/coneline_intersector.h +++ b/thirdparty/embree/kernels/geometry/coneline_intersector.h @@ -159,7 +159,7 @@ namespace embree template<typename Epilog> static __forceinline bool intersect(const vbool<M>& valid_i, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const LineSegments* geom, const Precalculations& pre, const Vec4vf<M>& v0i, const Vec4vf<M>& v1i, @@ -190,7 +190,7 @@ namespace embree template<typename Epilog> static __forceinline bool intersect(const vbool<M>& valid_i, RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const LineSegments* geom, const Precalculations& pre, const Vec4vf<M>& v0i, const Vec4vf<M>& v1i, diff --git a/thirdparty/embree/kernels/geometry/conelinei_intersector.h b/thirdparty/embree/kernels/geometry/conelinei_intersector.h index 6a985ebcad..c919fe9f7b 100644 --- a/thirdparty/embree/kernels/geometry/conelinei_intersector.h +++ b/thirdparty/embree/kernels/geometry/conelinei_intersector.h @@ -16,7 +16,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculations1 Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -27,7 +27,7 @@ namespace embree ConeCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -51,7 +51,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculations1 Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -62,7 +62,7 @@ namespace embree ConeCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,cL,cR,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -86,7 +86,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculationsK<K> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -97,7 +97,7 @@ namespace embree ConeCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -115,7 +115,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculationsK<K> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -126,7 +126,7 @@ namespace embree ConeCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,cL,cR,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); diff --git a/thirdparty/embree/kernels/geometry/curveNi_intersector.h b/thirdparty/embree/kernels/geometry/curveNi_intersector.h index c0b66515c1..137ec06d0c 100644 --- a/thirdparty/embree/kernels/geometry/curveNi_intersector.h +++ b/thirdparty/embree/kernels/geometry/curveNi_intersector.h @@ -5,6 +5,12 @@ #include "curveNi.h" +#include "roundline_intersector.h" +#include "coneline_intersector.h" +#include "curve_intersector_ribbon.h" +#include "curve_intersector_oriented.h" +#include "curve_intersector_sweep.h" + namespace embree { namespace isa @@ -20,9 +26,14 @@ namespace embree static __forceinline vbool<M> intersect(Ray& ray, const Primitive& prim, vfloat<M>& tNear_o) { const size_t N = prim.N; +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + const Vec3fa offset = *prim.offset(N); + const float scale = *prim.scale(N); +#else const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N)); const Vec3fa offset = Vec3fa(offset_scale); const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale)); +#endif const Vec3fa org1 = (ray.org-offset)*scale; const Vec3fa dir1 = ray.dir*scale; @@ -50,7 +61,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -84,7 +95,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -121,7 +132,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_n(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_n(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -157,7 +168,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_n(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_n(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -196,7 +207,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_h(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_h(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -217,7 +228,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_h(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_h(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -241,7 +252,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_hn(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_hn(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -262,7 +273,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_hn(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_hn(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -297,10 +308,14 @@ namespace embree static __forceinline vbool<M> intersect(RayK<K>& ray, const size_t k, const Primitive& prim, vfloat<M>& tNear_o) { const size_t N = prim.N; +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + const Vec3fa offset = *prim.offset(N); + const float scale = *prim.scale(N); +#else const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N)); const Vec3fa offset = Vec3fa(offset_scale); const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale)); - +#endif const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]); const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]); const Vec3fa org1 = (ray_org-offset)*scale; @@ -330,7 +345,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -364,7 +379,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -401,7 +416,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_n(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_n(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -437,7 +452,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_n(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_n(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -476,7 +491,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_h(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_h(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -497,7 +512,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_h(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_h(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -521,7 +536,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_hn(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_hn(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -542,7 +557,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_hn(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_hn(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -565,5 +580,69 @@ namespace embree return false; } }; + + __forceinline void convert_to_bezier(const Geometry::GType gtype, + Vec3ff& v0, Vec3ff& v1, Vec3ff& v2, Vec3ff& v3, + Vec3fa& n0, Vec3fa& n1, Vec3fa& n2, Vec3fa& n3) + { + const Geometry::GType basis = (Geometry::GType)(gtype & Geometry::GTY_BASIS_MASK); + const Geometry::GType stype = (Geometry::GType)(gtype & Geometry::GTY_SUBTYPE_MASK); + + if (basis == Geometry::GTY_BASIS_BSPLINE) { + BezierCurveT<Vec3ff> bezier; + convert(BSplineCurveT<Vec3ff>(v0,v1,v2,v3),bezier); + v0 = bezier.v0; v1 = bezier.v1; v2 = bezier.v2; v3 = bezier.v3; + } + else if (basis == Geometry::GTY_BASIS_HERMITE) { + BezierCurveT<Vec3ff> bezier; + convert(HermiteCurveT<Vec3ff>(v0,v1,v2,v3),bezier); + v0 = bezier.v0; v1 = bezier.v1; v2 = bezier.v2; v3 = bezier.v3; + } + else if (basis == Geometry::GTY_BASIS_CATMULL_ROM) { + BezierCurveT<Vec3ff> bezier; + convert(CatmullRomCurveT<Vec3ff>(v0,v1,v2,v3),bezier); + v0 = bezier.v0; v1 = bezier.v1; v2 = bezier.v2; v3 = bezier.v3; + } + + if (stype == Geometry::GTY_SUBTYPE_ORIENTED_CURVE) + { + if (basis == Geometry::GTY_BASIS_BSPLINE) { + BezierCurveT<Vec3fa> bezier; + convert(BSplineCurveT<Vec3fa>(n0,n1,n2,n3),bezier); + n0 = bezier.v0; n1 = bezier.v1; n2 = bezier.v2; n3 = bezier.v3; + } + else if (basis == Geometry::GTY_BASIS_HERMITE) { + BezierCurveT<Vec3fa> bezier; + convert(HermiteCurveT<Vec3fa>(n0,n1,n2,n3),bezier); + n0 = bezier.v0; n1 = bezier.v1; n2 = bezier.v2; n3 = bezier.v3; + } + else if (basis == Geometry::GTY_BASIS_CATMULL_ROM) { + BezierCurveT<Vec3fa> bezier; + convert(CatmullRomCurveT<Vec3fa>(n0,n1,n2,n3),bezier); + n0 = bezier.v0; n1 = bezier.v1; n2 = bezier.v2; n3 = bezier.v3; + } + } + } + + __forceinline void convert_to_bezier(const Geometry::GType gtype, Vec3ff& v0, Vec3ff& v1, Vec3ff& v2, Vec3ff& v3) + { + const Geometry::GType basis = (Geometry::GType)(gtype & Geometry::GTY_BASIS_MASK); + + if (basis == Geometry::GTY_BASIS_BSPLINE) { + BezierCurveT<Vec3ff> bezier; + convert(BSplineCurveT<Vec3ff>(v0,v1,v2,v3),bezier); + v0 = bezier.v0; v1 = bezier.v1; v2 = bezier.v2; v3 = bezier.v3; + } + else if (basis == Geometry::GTY_BASIS_HERMITE) { + BezierCurveT<Vec3ff> bezier; + convert(HermiteCurveT<Vec3ff>(v0,v1,v2,v3),bezier); + v0 = bezier.v0; v1 = bezier.v1; v2 = bezier.v2; v3 = bezier.v3; + } + else if (basis == Geometry::GTY_BASIS_CATMULL_ROM) { + BezierCurveT<Vec3ff> bezier; + convert(CatmullRomCurveT<Vec3ff>(v0,v1,v2,v3),bezier); + v0 = bezier.v0; v1 = bezier.v1; v2 = bezier.v2; v3 = bezier.v3; + } + } } } diff --git a/thirdparty/embree/kernels/geometry/curveNi_mb_intersector.h b/thirdparty/embree/kernels/geometry/curveNi_mb_intersector.h index bab796b33b..4c14c2f004 100644 --- a/thirdparty/embree/kernels/geometry/curveNi_mb_intersector.h +++ b/thirdparty/embree/kernels/geometry/curveNi_mb_intersector.h @@ -6,6 +6,12 @@ #include "curveNi_mb.h" #include "../subdiv/linear_bezier_patch.h" +#include "roundline_intersector.h" +#include "coneline_intersector.h" +#include "curve_intersector_ribbon.h" +#include "curve_intersector_oriented.h" +#include "curve_intersector_sweep.h" + namespace embree { namespace isa @@ -21,9 +27,14 @@ namespace embree static __forceinline vbool<M> intersect(Ray& ray, const Primitive& prim, vfloat<M>& tNear_o) { const size_t N = prim.N; +#if __SYCL_DEVICE_ONLY__ + const Vec3f offset = *prim.offset(N); + const float scale = *prim.scale(N); +#else const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N)); const Vec3fa offset = Vec3fa(offset_scale); const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale)); +#endif const Vec3fa org1 = (ray.org-offset)*scale; const Vec3fa dir1 = ray.dir*scale; @@ -73,7 +84,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -95,7 +106,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -120,7 +131,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_n(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_n(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -141,7 +152,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_n(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_n(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -166,7 +177,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_h(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_h(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -187,7 +198,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_h(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_h(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -211,7 +222,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_hn(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_hn(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -232,7 +243,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_hn(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_hn(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,prim,tNear); @@ -267,10 +278,14 @@ namespace embree static __forceinline vbool<M> intersect(RayK<K>& ray, const size_t k, const Primitive& prim, vfloat<M>& tNear_o) { const size_t N = prim.N; +#if __SYCL_DEVICE_ONLY__ + const Vec3f offset = *prim.offset(N); + const float scale = *prim.scale(N); +#else const vfloat4 offset_scale = vfloat4::loadu(prim.offset(N)); const Vec3fa offset = Vec3fa(offset_scale); const Vec3fa scale = Vec3fa(shuffle<3,3,3,3>(offset_scale)); - +#endif const Vec3fa ray_org(ray.org.x[k],ray.org.y[k],ray.org.z[k]); const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]); const Vec3fa org1 = (ray_org-offset)*scale; @@ -322,7 +337,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; @@ -345,7 +360,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -370,7 +385,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_n(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_n(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; @@ -393,7 +408,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_n(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_n(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -419,7 +434,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_h(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_h(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; @@ -441,7 +456,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_h(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_h(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); @@ -465,7 +480,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline void intersect_hn(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_hn(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; @@ -488,7 +503,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_hn(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_hn(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = intersect(ray,k,prim,tNear); diff --git a/thirdparty/embree/kernels/geometry/curveNv_intersector.h b/thirdparty/embree/kernels/geometry/curveNv_intersector.h index 2742725aec..cfbd1a029c 100644 --- a/thirdparty/embree/kernels/geometry/curveNv_intersector.h +++ b/thirdparty/embree/kernels/geometry/curveNv_intersector.h @@ -17,7 +17,7 @@ namespace embree typedef CurvePrecalculations1 Precalculations; template<typename Intersector, typename Epilog> - static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_t(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = CurveNiIntersector1<M>::intersect(ray,prim,tNear); @@ -54,7 +54,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_t(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = CurveNiIntersector1<M>::intersect(ray,prim,tNear); @@ -101,7 +101,7 @@ namespace embree typedef CurvePrecalculationsK<K> Precalculations; template<typename Intersector, typename Epilog> - static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect_t(Precalculations& pre, RayHitK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = CurveNiIntersectorK<M,K>::intersect(ray,k,prim,tNear); @@ -138,7 +138,7 @@ namespace embree } template<typename Intersector, typename Epilog> - static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded_t(Precalculations& pre, RayK<K>& ray, const size_t k, RayQueryContext* context, const Primitive& prim) { vfloat<M> tNear; vbool<M> valid = CurveNiIntersectorK<M,K>::intersect(ray,k,prim,tNear); diff --git a/thirdparty/embree/kernels/geometry/curve_intersector.h b/thirdparty/embree/kernels/geometry/curve_intersector.h index 1e8ac26125..a258befb5e 100644 --- a/thirdparty/embree/kernels/geometry/curve_intersector.h +++ b/thirdparty/embree/kernels/geometry/curve_intersector.h @@ -24,7 +24,7 @@ namespace embree typedef CurvePrecalculations1 Precalculations; template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -34,7 +34,7 @@ namespace embree } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -50,7 +50,7 @@ namespace embree typedef unsigned char Primitive; typedef CurvePrecalculationsK<K> Precalculations; - static __forceinline void intersect(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -60,7 +60,7 @@ namespace embree while (mask) leafIntersector.intersect<K>(&pre,&ray,bscf(mask),context,prim); } - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -76,7 +76,7 @@ namespace embree return valid_o; } - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -85,7 +85,7 @@ namespace embree leafIntersector.intersect<K>(&pre,&ray,k,context,prim); } - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_distance.h b/thirdparty/embree/kernels/geometry/curve_intersector_distance.h index 748a9511a5..80e1760289 100644 --- a/thirdparty/embree/kernels/geometry/curve_intersector_distance.h +++ b/thirdparty/embree/kernels/geometry/curve_intersector_distance.h @@ -45,15 +45,56 @@ namespace embree vfloat<M> vv; vfloat<M> vt; }; - + template<typename NativeCurve3fa> + struct DistanceCurveHit<NativeCurve3fa,1> + { + enum { M = 1 }; + + __forceinline DistanceCurveHit() {} + + __forceinline DistanceCurveHit(const vbool<M>& valid, const vfloat<M>& U, const vfloat<M>& V, const vfloat<M>& T, const int i, const int N, + const NativeCurve3fa& curve3D) + : U(U), V(V), T(T), i(i), N(N), curve3D(curve3D), valid(valid) {} + + __forceinline void finalize() + { + vu = (vfloat<M>(step)+U+vfloat<M>(float(i)))*(1.0f/float(N)); + vv = V; + vt = T; + } + + __forceinline Vec2f uv () const { return Vec2f(vu,vv); } + __forceinline float t () const { return vt; } + __forceinline Vec3fa Ng() const { return curve3D.eval_du(vu); } + + public: + vfloat<M> U; + vfloat<M> V; + vfloat<M> T; + int i, N; + NativeCurve3fa curve3D; + + public: + vbool<M> valid; + vfloat<M> vu; + vfloat<M> vv; + vfloat<M> vt; + }; + + template<typename NativeCurve3fa, int W = VSIZEX> struct DistanceCurve1Intersector1 { + using vboolx = vbool<W>; + using vintx = vint<W>; + using vfloatx = vfloat<W>; + using Vec4vfx = Vec4vf<W>; + template<typename Epilog> - __forceinline bool intersect(const CurvePrecalculations1& pre,Ray& ray, - IntersectContext* context, + __forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, - const Vec3fa& v0, const Vec3fa& v1, const Vec3fa& v2, const Vec3fa& v3, + const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3, const Epilog& epilog) { const int N = geom->tessellationRate; @@ -65,8 +106,8 @@ namespace embree /* evaluate the bezier curve */ vboolx valid = vfloatx(step) < vfloatx(float(N)); - const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(0,N); - const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(0,N); + const Vec4vfx p0 = curve2D.template eval0<W>(0,N); + const Vec4vfx p1 = curve2D.template eval1<W>(0,N); /* approximative intersection with cone */ const Vec4vfx v = p1-p0; @@ -86,19 +127,19 @@ namespace embree /* update hit information */ bool ishit = false; if (unlikely(any(valid))) { - DistanceCurveHit<NativeCurve3fa,VSIZEX> hit(valid,u,0.0f,t,0,N,curve3D); + DistanceCurveHit<NativeCurve3fa,W> hit(valid,u,0.0f,t,0,N,curve3D); ishit = ishit | epilog(valid,hit); } - if (unlikely(VSIZEX < N)) + if (unlikely(W < N)) { /* process SIMD-size many segments per iteration */ - for (int i=VSIZEX; i<N; i+=VSIZEX) + for (int i=W; i<N; i+=W) { /* evaluate the bezier curve */ vboolx valid = vintx(i)+vintx(step) < vintx(N); - const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(i,N); - const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(i,N); + const Vec4vfx p0 = curve2D.template eval0<W>(i,N); + const Vec4vfx p1 = curve2D.template eval1<W>(i,N); /* approximative intersection with cone */ const Vec4vfx v = p1-p0; @@ -117,7 +158,7 @@ namespace embree /* update hit information */ if (unlikely(any(valid))) { - DistanceCurveHit<NativeCurve3fa,VSIZEX> hit(valid,u,0.0f,t,i,N,curve3D); + DistanceCurveHit<NativeCurve3fa,W> hit(valid,u,0.0f,t,i,N,curve3D); ishit = ishit | epilog(valid,hit); } } diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_oriented.h b/thirdparty/embree/kernels/geometry/curve_intersector_oriented.h index 75532f5ae0..cdab06ea5e 100644 --- a/thirdparty/embree/kernels/geometry/curve_intersector_oriented.h +++ b/thirdparty/embree/kernels/geometry/curve_intersector_oriented.h @@ -14,7 +14,7 @@ namespace embree { namespace isa { - template<typename Ray, typename Epilog> + template<typename Ray, typename Epilog, int N = VSIZEX-1, int V = VSIZEX> struct TensorLinearCubicBezierSurfaceIntersector { const LinearSpace3fa& ray_space; @@ -235,7 +235,7 @@ namespace embree if (!clip_v(cu,cv)) return; return solve_newton_raphson(cu,cv); } - + __forceinline void solve_newton_raphson_recursion(BBox1f cu, BBox1f cv) { unsigned int sptr = 0; @@ -259,8 +259,8 @@ namespace embree if (mask) sptr++; // there are still items on the stack /* process next element recurse into each hit curve segment */ - const float u0 = float(i+0)*(1.0f/(VSIZEX-1)); - const float u1 = float(i+1)*(1.0f/(VSIZEX-1)); + const float u0 = float(i+0)*(1.0f/(N)); + const float u1 = float(i+1)*(1.0f/(N)); const BBox1f cui(lerp(cu.lower,cu.upper,u0),lerp(cu.lower,cu.upper,u1)); cu = cui; } @@ -280,28 +280,37 @@ namespace embree #endif entry: - - /* split the curve into VSIZEX-1 segments in u-direction */ - vboolx valid = true; - TensorLinearCubicBezierSurface<Vec2vfx> subcurves = curve2d.clip_v(cv).vsplit_u(valid,cu); - - /* slabs test in u-direction */ - Vec2vfx ndv = cross(subcurves.axis_v()); - BBox<vfloatx> boundsv = subcurves.vxfm(ndv).bounds(); - valid &= boundsv.lower <= eps; - valid &= boundsv.upper >= -eps; - if (none(valid)) continue; - - /* slabs test in v-direction */ - Vec2vfx ndu = cross(subcurves.axis_u()); - BBox<vfloatx> boundsu = subcurves.vxfm(ndu).bounds(); - valid &= boundsu.lower <= eps; - valid &= boundsu.upper >= -eps; - if (none(valid)) continue; + + /* split the curve into N segments in u-direction */ + unsigned int mask = 0; + for (int i=0; i<N;) + { + int i0 = i; + vbool<V> valid = true; + TensorLinearCubicBezierSurface<Vec2vf<V>> subcurves = curve2d.clip_v(cv).template vsplit_u<V>(valid,cu,i,N); + + /* slabs test in u-direction */ + Vec2vf<V> ndv = cross(subcurves.axis_v()); + BBox<vfloat<V>> boundsv = subcurves.template vxfm<V>(ndv).bounds(); + valid &= boundsv.lower <= eps; + valid &= boundsv.upper >= -eps; + if (none(valid)) continue; + + /* slabs test in v-direction */ + Vec2vf<V> ndu = cross(subcurves.axis_u()); + BBox<vfloat<V>> boundsu = subcurves.template vxfm<V>(ndu).bounds(); + valid &= boundsu.lower <= eps; + valid &= boundsu.upper >= -eps; + if (none(valid)) continue; + + mask |= movemask(valid) << i0; + } + + if (!mask) continue; /* push valid segments to stack */ assert(sptr < stack_size); - mask_stack [sptr] = movemask(valid); + mask_stack [sptr] = mask; cu_stack [sptr] = cu; cv_stack [sptr] = cv; sptr++; @@ -318,7 +327,7 @@ namespace embree }; - template<template<typename Ty> class SourceCurve> + template<template<typename Ty> class SourceCurve, int N = VSIZEX-1, int V = VSIZEX> struct OrientedCurve1Intersector1 { //template<typename Ty> using Curve = SourceCurve<Ty>; @@ -329,33 +338,32 @@ namespace embree __forceinline OrientedCurve1Intersector1(const Ray& ray, const void* ptr) {} - template<typename Epilog> - __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray, - IntersectContext* context, + template<typename Ray, typename Epilog> + __forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, const Vec3ff& v0i, const Vec3ff& v1i, const Vec3ff& v2i, const Vec3ff& v3i, const Vec3fa& n0i, const Vec3fa& n1i, const Vec3fa& n2i, const Vec3fa& n3i, const Epilog& epilog) const { STAT3(normal.trav_prims,1,1,1); - SourceCurve3ff ccurve(v0i,v1i,v2i,v3i); SourceCurve3fa ncurve(n0i,n1i,n2i,n3i); ccurve = enlargeRadiusToMinWidth(context,geom,ray.org,ccurve); TensorLinearCubicBezierSurface3fa curve = TensorLinearCubicBezierSurface3fa::fromCenterAndNormalCurve(ccurve,ncurve); //return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_bezier_clipping(); - return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_newton_raphson_main(); + return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog,N,V>(pre.ray_space,ray,curve,epilog).solve_newton_raphson_main(); } - template<typename Epilog> - __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray, - IntersectContext* context, + template<typename Ray, typename Epilog> + __forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, const TensorLinearCubicBezierSurface3fa& curve, const Epilog& epilog) const { STAT3(normal.trav_prims,1,1,1); //return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_bezier_clipping(); - return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog>(pre.ray_space,ray,curve,epilog).solve_newton_raphson_main(); + return TensorLinearCubicBezierSurfaceIntersector<Ray,Epilog,N,V>(pre.ray_space,ray,curve,epilog).solve_newton_raphson_main(); } }; @@ -384,7 +392,7 @@ namespace embree template<typename Epilog> __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k, - IntersectContext* context, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, const Vec3ff& v0i, const Vec3ff& v1i, const Vec3ff& v2i, const Vec3ff& v3i, const Vec3fa& n0i, const Vec3fa& n1i, const Vec3fa& n2i, const Vec3fa& n3i, @@ -402,7 +410,7 @@ namespace embree template<typename Epilog> __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k, - IntersectContext* context, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, const TensorLinearCubicBezierSurface3fa& curve, const Epilog& epilog) diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_ribbon.h b/thirdparty/embree/kernels/geometry/curve_intersector_ribbon.h index c3272e99fd..423fd5b08d 100644 --- a/thirdparty/embree/kernels/geometry/curve_intersector_ribbon.h +++ b/thirdparty/embree/kernels/geometry/curve_intersector_ribbon.h @@ -53,21 +53,23 @@ namespace embree }; /* calculate squared distance of point p0 to line p1->p2 */ - __forceinline std::pair<vfloatx,vfloatx> sqr_point_line_distance(const Vec2vfx& p0, const Vec2vfx& p1, const Vec2vfx& p2) + template<int M> + __forceinline std::pair<vfloat<M>,vfloat<M>> sqr_point_line_distance(const Vec2vf<M>& p0, const Vec2vf<M>& p1, const Vec2vf<M>& p2) { - const vfloatx num = det(p2-p1,p1-p0); - const vfloatx den2 = dot(p2-p1,p2-p1); + const vfloat<M> num = det(p2-p1,p1-p0); + const vfloat<M> den2 = dot(p2-p1,p2-p1); return std::make_pair(num*num,den2); } /* performs culling against a cylinder */ - __forceinline vboolx cylinder_culling_test(const Vec2vfx& p0, const Vec2vfx& p1, const Vec2vfx& p2, const vfloatx& r) + template<int M> + __forceinline vbool<M> cylinder_culling_test(const Vec2vf<M>& p0, const Vec2vf<M>& p1, const Vec2vf<M>& p2, const vfloat<M>& r) { - const std::pair<vfloatx,vfloatx> d = sqr_point_line_distance(p0,p1,p2); + const std::pair<vfloat<M>,vfloat<M>> d = sqr_point_line_distance<M>(p0,p1,p2); return d.first <= r*r*d.second; } - template<typename NativeCurve3ff, typename Epilog> + template<int M = VSIZEX, typename NativeCurve3ff, typename Epilog> __forceinline bool intersect_ribbon(const Vec3fa& ray_org, const Vec3fa& ray_dir, const float ray_tnear, const float& ray_tfar, const LinearSpace3fa& ray_space, const float& depth_scale, const NativeCurve3ff& curve3D, const int N, @@ -76,89 +78,96 @@ namespace embree /* transform control points into ray space */ const NativeCurve3ff curve2D = curve3D.xfm_pr(ray_space,ray_org); float eps = 4.0f*float(ulp)*reduce_max(max(abs(curve2D.v0),abs(curve2D.v1),abs(curve2D.v2),abs(curve2D.v3))); - - /* evaluate the bezier curve */ + + int i=0; bool ishit = false; - vboolx valid = vfloatx(step) < vfloatx(float(N)); - const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(0,N); - const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(0,N); - valid &= cylinder_culling_test(zero,Vec2vfx(p0.x,p0.y),Vec2vfx(p1.x,p1.y),max(p0.w,p1.w)); - if (any(valid)) +#if !defined(__SYCL_DEVICE_ONLY__) { - Vec3vfx dp0dt = curve2D.template derivative0<VSIZEX>(0,N); - Vec3vfx dp1dt = curve2D.template derivative1<VSIZEX>(0,N); - dp0dt = select(reduce_max(abs(dp0dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp0dt); - dp1dt = select(reduce_max(abs(dp1dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp1dt); - const Vec3vfx n0(dp0dt.y,-dp0dt.x,0.0f); - const Vec3vfx n1(dp1dt.y,-dp1dt.x,0.0f); - const Vec3vfx nn0 = normalize(n0); - const Vec3vfx nn1 = normalize(n1); - const Vec3vfx lp0 = madd(p0.w,nn0,Vec3vfx(p0)); - const Vec3vfx lp1 = madd(p1.w,nn1,Vec3vfx(p1)); - const Vec3vfx up0 = nmadd(p0.w,nn0,Vec3vfx(p0)); - const Vec3vfx up1 = nmadd(p1.w,nn1,Vec3vfx(p1)); + /* evaluate the bezier curve */ + vbool<M> valid = vfloat<M>(step) < vfloat<M>(float(N)); + const Vec4vf<M> p0 = curve2D.template eval0<M>(0,N); + const Vec4vf<M> p1 = curve2D.template eval1<M>(0,N); + valid &= cylinder_culling_test<M>(zero,Vec2vf<M>(p0.x,p0.y),Vec2vf<M>(p1.x,p1.y),max(p0.w,p1.w)); - vfloatx vu,vv,vt; - vboolx valid0 = intersect_quad_backface_culling<VSIZEX>(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt); - - if (any(valid0)) + if (any(valid)) { - /* ignore self intersections */ - if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) { - vfloatx r = lerp(p0.w, p1.w, vu); - valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale; - } + Vec3vf<M> dp0dt = curve2D.template derivative0<M>(0,N); + Vec3vf<M> dp1dt = curve2D.template derivative1<M>(0,N); + dp0dt = select(reduce_max(abs(dp0dt)) < vfloat<M>(eps),Vec3vf<M>(p1-p0),dp0dt); + dp1dt = select(reduce_max(abs(dp1dt)) < vfloat<M>(eps),Vec3vf<M>(p1-p0),dp1dt); + const Vec3vf<M> n0(dp0dt.y,-dp0dt.x,0.0f); + const Vec3vf<M> n1(dp1dt.y,-dp1dt.x,0.0f); + const Vec3vf<M> nn0 = normalize(n0); + const Vec3vf<M> nn1 = normalize(n1); + const Vec3vf<M> lp0 = madd(p0.w,nn0,Vec3vf<M>(p0)); + const Vec3vf<M> lp1 = madd(p1.w,nn1,Vec3vf<M>(p1)); + const Vec3vf<M> up0 = nmadd(p0.w,nn0,Vec3vf<M>(p0)); + const Vec3vf<M> up1 = nmadd(p1.w,nn1,Vec3vf<M>(p1)); + + vfloat<M> vu,vv,vt; + vbool<M> valid0 = intersect_quad_backface_culling<M>(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt); if (any(valid0)) { - vv = madd(2.0f,vv,vfloatx(-1.0f)); - RibbonHit<NativeCurve3ff,VSIZEX> bhit(valid0,vu,vv,vt,0,N,curve3D); - ishit |= epilog(bhit.valid,bhit); + /* ignore self intersections */ + if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) { + vfloat<M> r = lerp(p0.w, p1.w, vu); + valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale; + } + + if (any(valid0)) + { + vv = madd(2.0f,vv,vfloat<M>(-1.0f)); + RibbonHit<NativeCurve3ff,M> bhit(valid0,vu,vv,vt,0,N,curve3D); + ishit |= epilog(bhit.valid,bhit); + } } } + i += M; } - if (unlikely(VSIZEX < N)) + if (unlikely(i < N)) +#endif { /* process SIMD-size many segments per iteration */ - for (int i=VSIZEX; i<N; i+=VSIZEX) + for (; i<N; i+=M) { /* evaluate the bezier curve */ - vboolx valid = vintx(i)+vintx(step) < vintx(N); - const Vec4vfx p0 = curve2D.template eval0<VSIZEX>(i,N); - const Vec4vfx p1 = curve2D.template eval1<VSIZEX>(i,N); - valid &= cylinder_culling_test(zero,Vec2vfx(p0.x,p0.y),Vec2vfx(p1.x,p1.y),max(p0.w,p1.w)); + vbool<M> valid = vint<M>(i)+vint<M>(step) < vint<M>(N); + const Vec4vf<M> p0 = curve2D.template eval0<M>(i,N); + const Vec4vf<M> p1 = curve2D.template eval1<M>(i,N); + valid &= cylinder_culling_test<M>(zero,Vec2vf<M>(p0.x,p0.y),Vec2vf<M>(p1.x,p1.y),max(p0.w,p1.w)); if (none(valid)) continue; - Vec3vfx dp0dt = curve2D.template derivative0<VSIZEX>(i,N); - Vec3vfx dp1dt = curve2D.template derivative1<VSIZEX>(i,N); - dp0dt = select(reduce_max(abs(dp0dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp0dt); - dp1dt = select(reduce_max(abs(dp1dt)) < vfloatx(eps),Vec3vfx(p1-p0),dp1dt); - const Vec3vfx n0(dp0dt.y,-dp0dt.x,0.0f); - const Vec3vfx n1(dp1dt.y,-dp1dt.x,0.0f); - const Vec3vfx nn0 = normalize(n0); - const Vec3vfx nn1 = normalize(n1); - const Vec3vfx lp0 = madd(p0.w,nn0,Vec3vfx(p0)); - const Vec3vfx lp1 = madd(p1.w,nn1,Vec3vfx(p1)); - const Vec3vfx up0 = nmadd(p0.w,nn0,Vec3vfx(p0)); - const Vec3vfx up1 = nmadd(p1.w,nn1,Vec3vfx(p1)); + Vec3vf<M> dp0dt = curve2D.template derivative0<M>(i,N); + Vec3vf<M> dp1dt = curve2D.template derivative1<M>(i,N); + dp0dt = select(reduce_max(abs(dp0dt)) < vfloat<M>(eps),Vec3vf<M>(p1-p0),dp0dt); + dp1dt = select(reduce_max(abs(dp1dt)) < vfloat<M>(eps),Vec3vf<M>(p1-p0),dp1dt); + const Vec3vf<M> n0(dp0dt.y,-dp0dt.x,0.0f); + const Vec3vf<M> n1(dp1dt.y,-dp1dt.x,0.0f); + const Vec3vf<M> nn0 = normalize(n0); + const Vec3vf<M> nn1 = normalize(n1); + const Vec3vf<M> lp0 = madd(p0.w,nn0,Vec3vf<M>(p0)); + const Vec3vf<M> lp1 = madd(p1.w,nn1,Vec3vf<M>(p1)); + const Vec3vf<M> up0 = nmadd(p0.w,nn0,Vec3vf<M>(p0)); + const Vec3vf<M> up1 = nmadd(p1.w,nn1,Vec3vf<M>(p1)); - vfloatx vu,vv,vt; - vboolx valid0 = intersect_quad_backface_culling<VSIZEX>(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt); + vfloat<M> vu,vv,vt; + vbool<M> valid0 = intersect_quad_backface_culling<M>(valid,zero,Vec3fa(0,0,1),ray_tnear,ray_tfar,lp0,lp1,up1,up0,vu,vv,vt); if (any(valid0)) { /* ignore self intersections */ if (EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR != 0.0f) { - vfloatx r = lerp(p0.w, p1.w, vu); + vfloat<M> r = lerp(p0.w, p1.w, vu); valid0 &= vt > float(EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR)*r*depth_scale; } if (any(valid0)) { - vv = madd(2.0f,vv,vfloatx(-1.0f)); - RibbonHit<NativeCurve3ff,VSIZEX> bhit(valid0,vu,vv,vt,i,N,curve3D); + vv = madd(2.0f,vv,vfloat<M>(-1.0f)); + RibbonHit<NativeCurve3ff,M> bhit(valid0,vu,vv,vt,i,N,curve3D); ishit |= epilog(bhit.valid,bhit); } } @@ -167,14 +176,14 @@ namespace embree return ishit; } - template<template<typename Ty> class NativeCurve> + template<template<typename Ty> class NativeCurve, int M = VSIZEX> struct RibbonCurve1Intersector1 { typedef NativeCurve<Vec3ff> NativeCurve3ff; - template<typename Epilog> + template<typename Ray, typename Epilog> __forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3, const Epilog& epilog) @@ -182,21 +191,21 @@ namespace embree const int N = geom->tessellationRate; NativeCurve3ff curve(v0,v1,v2,v3); curve = enlargeRadiusToMinWidth(context,geom,ray.org,curve); - return intersect_ribbon<NativeCurve3ff>(ray.org,ray.dir,ray.tnear(),ray.tfar, + return intersect_ribbon<M,NativeCurve3ff>(ray.org,ray.dir,ray.tnear(),ray.tfar, pre.ray_space,pre.depth_scale, curve,N, epilog); } }; - template<template<typename Ty> class NativeCurve, int K> + template<template<typename Ty> class NativeCurve, int K, int M = VSIZEX> struct RibbonCurve1IntersectorK { typedef NativeCurve<Vec3ff> NativeCurve3ff; template<typename Epilog> __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3, const Epilog& epilog) @@ -206,7 +215,7 @@ namespace embree const Vec3fa ray_dir(ray.dir.x[k],ray.dir.y[k],ray.dir.z[k]); NativeCurve3ff curve(v0,v1,v2,v3); curve = enlargeRadiusToMinWidth(context,geom,ray_org,curve); - return intersect_ribbon<NativeCurve3ff>(ray_org,ray_dir,ray.tnear()[k],ray.tfar[k], + return intersect_ribbon<M,NativeCurve3ff>(ray_org,ray_dir,ray.tnear()[k],ray.tfar[k], pre.ray_space[k],pre.depth_scale[k], curve,N, epilog); diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_sweep.h b/thirdparty/embree/kernels/geometry/curve_intersector_sweep.h index ed827d583f..5581822551 100644 --- a/thirdparty/embree/kernels/geometry/curve_intersector_sweep.h +++ b/thirdparty/embree/kernels/geometry/curve_intersector_sweep.h @@ -14,7 +14,9 @@ namespace embree namespace isa { static const size_t numJacobianIterations = 5; -#if defined(__AVX__) +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + static const size_t numBezierSubdivisions = 2; +#elif defined(__AVX__) static const size_t numBezierSubdivisions = 2; #else static const size_t numBezierSubdivisions = 3; @@ -132,10 +134,15 @@ namespace embree return false; } +#if !defined(__SYCL_DEVICE_ONLY__) + template<typename NativeCurve3ff, typename Ray, typename Epilog> - bool intersect_bezier_recursive_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve, - float u0, float u1, unsigned int depth, const Epilog& epilog) + __forceinline bool intersect_bezier_recursive_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve, const Epilog& epilog) { + float u0 = 0.0f; + float u1 = 1.0f; + unsigned int depth = 1; + #if defined(__AVX__) enum { VSIZEX_ = 8 }; typedef vbool8 vboolx; // maximally 8-wide to work around KNL issues @@ -147,8 +154,6 @@ namespace embree typedef vint4 vintx; typedef vfloat4 vfloatx; #endif - typedef Vec3<vfloatx> Vec3vfx; - typedef Vec4<vfloatx> Vec4vfx; unsigned int maxDepth = numBezierSubdivisions; bool found = false; @@ -295,14 +300,156 @@ namespace embree return found; } +#else + + template<typename NativeCurve3ff, typename Ray, typename Epilog> + __forceinline bool intersect_bezier_recursive_jacobian(const Ray& ray, const float dt, const NativeCurve3ff& curve, const Epilog& epilog) + { + const Vec3fa org = zero; + const Vec3fa dir = ray.dir; + const unsigned int max_depth = 7; + + bool found = false; + + struct ShortStack + { + /* pushes both children */ + __forceinline void push() { + depth++; + } + + /* pops next node */ + __forceinline void pop() { + short_stack += (1<<(31-depth)); + depth = 31-bsf(short_stack); + } + + unsigned int depth = 0; + unsigned int short_stack = 0; + }; + + ShortStack stack; + + do + { + const float u0 = (stack.short_stack+0*(1<<(31-stack.depth)))/float(0x80000000); + const float u1 = (stack.short_stack+1*(1<<(31-stack.depth)))/float(0x80000000); + + /* subdivide bezier curve */ + Vec3ff P0, dP0du; curve.eval(u0,P0,dP0du); dP0du = dP0du * (u1-u0); + Vec3ff P3, dP3du; curve.eval(u1,P3,dP3du); dP3du = dP3du * (u1-u0); + const Vec3ff P1 = P0 + dP0du*(1.0f/3.0f); + const Vec3ff P2 = P3 - dP3du*(1.0f/3.0f); + + /* check if curve is well behaved, by checking deviation of tangents from straight line */ + const Vec3ff W = Vec3ff(P3-P0,0.0f); + const Vec3ff dQ0 = abs(3.0f*(P1-P0) - W); + const Vec3ff dQ1 = abs(3.0f*(P2-P1) - W); + const Vec3ff dQ2 = abs(3.0f*(P3-P2) - W); + const Vec3ff max_dQ = max(dQ0,dQ1,dQ2); + const float m = max(max_dQ.x,max_dQ.y,max_dQ.z); //,max_dQ.w); + const float l = length(Vec3f(W)); + const bool well_behaved = m < 0.2f*l; + + if (!well_behaved && stack.depth < max_depth) { + stack.push(); + continue; + } + + /* calculate bounding cylinders */ + const float rr1 = sqr_point_to_line_distance(Vec3f(dP0du),Vec3f(P3-P0)); + const float rr2 = sqr_point_to_line_distance(Vec3f(dP3du),Vec3f(P3-P0)); + const float maxr12 = sqrt(max(rr1,rr2)); + const float one_plus_ulp = 1.0f+2.0f*float(ulp); + const float one_minus_ulp = 1.0f-2.0f*float(ulp); + float r_outer = max(P0.w,P1.w,P2.w,P3.w)+maxr12; + float r_inner = min(P0.w,P1.w,P2.w,P3.w)-maxr12; + r_outer = one_plus_ulp*r_outer; + r_inner = max(0.0f,one_minus_ulp*r_inner); + const Cylinder cylinder_outer(Vec3f(P0),Vec3f(P3),r_outer); + const Cylinder cylinder_inner(Vec3f(P0),Vec3f(P3),r_inner); + + /* intersect with outer cylinder */ + BBox<float> tc_outer; float u_outer0; Vec3fa Ng_outer0; float u_outer1; Vec3fa Ng_outer1; + if (!cylinder_outer.intersect(org,dir,tc_outer,u_outer0,Ng_outer0,u_outer1,Ng_outer1)) + { + stack.pop(); + continue; + } + + /* intersect with cap-planes */ + BBox<float> tp(ray.tnear()-dt,ray.tfar-dt); + tp = embree::intersect(tp,tc_outer); + BBox<float> h0 = HalfPlane(Vec3f(P0),+Vec3f(dP0du)).intersect(org,dir); + tp = embree::intersect(tp,h0); + BBox<float> h1 = HalfPlane(Vec3f(P3),-Vec3f(dP3du)).intersect(org,dir); + tp = embree::intersect(tp,h1); + if (tp.lower > tp.upper) + { + stack.pop(); + continue; + } + + bool valid = true; + + /* clamp and correct u parameter */ + u_outer0 = clamp(u_outer0,float(0.0f),float(1.0f)); + u_outer1 = clamp(u_outer1,float(0.0f),float(1.0f)); + u_outer0 = lerp(u0,u1,u_outer0); + u_outer1 = lerp(u0,u1,u_outer1); + + /* intersect with inner cylinder */ + BBox<float> tc_inner; + float u_inner0 = zero; Vec3fa Ng_inner0 = zero; float u_inner1 = zero; Vec3fa Ng_inner1 = zero; + const bool valid_inner = cylinder_inner.intersect(org,dir,tc_inner,u_inner0,Ng_inner0,u_inner1,Ng_inner1); + + /* subtract the inner interval from the current hit interval */ + BBox<float> tp0, tp1; + subtract(tp,tc_inner,tp0,tp1); + bool valid0 = valid & (tp0.lower <= tp0.upper); + bool valid1 = valid & (tp1.lower <= tp1.upper); + if (!(valid0 | valid1)) + { + stack.pop(); + continue; + } + + /* at the unstable area we subdivide deeper */ + const bool unstable0 = valid0 && ((!valid_inner) | (abs(dot(Vec3fa(ray.dir),Ng_inner0)) < 0.3f)); + const bool unstable1 = valid1 && ((!valid_inner) | (abs(dot(Vec3fa(ray.dir),Ng_inner1)) < 0.3f)); + + if ((unstable0 | unstable1) && (stack.depth < max_depth)) { + stack.push(); + continue; + } + + if (valid0) + found |= intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer0,tp0.lower,epilog); + + /* the far hit cannot be closer, thus skip if we hit entry already */ + valid1 &= tp1.lower+dt <= ray.tfar; + + /* iterate over second hit */ + if (valid1) + found |= intersect_bezier_iterative_jacobian(ray,dt,curve,u_outer1,tp1.upper,epilog); + + stack.pop(); + + } while (stack.short_stack != 0x80000000); + + return found; + } + +#endif + template<template<typename Ty> class NativeCurve> struct SweepCurve1Intersector1 { typedef NativeCurve<Vec3ff> NativeCurve3ff; - template<typename Epilog> - __noinline bool intersect(const CurvePrecalculations1& pre, Ray& ray, - IntersectContext* context, + template<typename Ray, typename Epilog> + __forceinline bool intersect(const CurvePrecalculations1& pre, Ray& ray, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3, const Epilog& epilog) @@ -315,7 +462,7 @@ namespace embree const float dt = dot(curve0.center()-ray.org,ray.dir)*rcp(dot(ray.dir,ray.dir)); const Vec3ff ref(madd(Vec3fa(dt),ray.dir,ray.org),0.0f); const NativeCurve3ff curve1 = curve0-ref; - return intersect_bezier_recursive_jacobian(ray,dt,curve1,0.0f,1.0f,1,epilog); + return intersect_bezier_recursive_jacobian(ray,dt,curve1,epilog); } }; @@ -343,7 +490,7 @@ namespace embree template<typename Epilog> __forceinline bool intersect(const CurvePrecalculationsK<K>& pre, RayK<K>& vray, size_t k, - IntersectContext* context, + RayQueryContext* context, const CurveGeometry* geom, const unsigned int primID, const Vec3ff& v0, const Vec3ff& v1, const Vec3ff& v2, const Vec3ff& v3, const Epilog& epilog) @@ -357,7 +504,7 @@ namespace embree const float dt = dot(curve0.center()-ray.org,ray.dir)*rcp(dot(ray.dir,ray.dir)); const Vec3ff ref(madd(Vec3fa(dt),ray.dir,ray.org),0.0f); const NativeCurve3ff curve1 = curve0-ref; - return intersect_bezier_recursive_jacobian(ray,dt,curve1,0.0f,1.0f,1,epilog); + return intersect_bezier_recursive_jacobian(ray,dt,curve1,epilog); } }; } diff --git a/thirdparty/embree/kernels/geometry/curve_intersector_virtual.h b/thirdparty/embree/kernels/geometry/curve_intersector_virtual.h index cffa8e46ad..cbdcadac0c 100644 --- a/thirdparty/embree/kernels/geometry/curve_intersector_virtual.h +++ b/thirdparty/embree/kernels/geometry/curve_intersector_virtual.h @@ -5,7 +5,7 @@ #include "primitive.h" #include "../subdiv/bezier_curve.h" -#include "../common/primref.h" +#include "../builders/primref.h" #include "curve_intersector_precalculations.h" #include "../bvh/node_intersector1.h" #include "../bvh/node_intersector_packet.h" @@ -37,28 +37,28 @@ namespace embree { struct VirtualCurveIntersector { - typedef void (*Intersect1Ty)(void* pre, void* ray, IntersectContext* context, const void* primitive); - typedef bool (*Occluded1Ty )(void* pre, void* ray, IntersectContext* context, const void* primitive); + typedef void (*Intersect1Ty)(void* pre, void* ray, RayQueryContext* context, const void* primitive); + typedef bool (*Occluded1Ty )(void* pre, void* ray, RayQueryContext* context, const void* primitive); - typedef void (*Intersect4Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive); - typedef bool (*Occluded4Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive); + typedef void (*Intersect4Ty)(void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive); + typedef bool (*Occluded4Ty) (void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive); - typedef void (*Intersect8Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive); - typedef bool (*Occluded8Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive); + typedef void (*Intersect8Ty)(void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive); + typedef bool (*Occluded8Ty) (void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive); - typedef void (*Intersect16Ty)(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive); - typedef bool (*Occluded16Ty) (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive); + typedef void (*Intersect16Ty)(void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive); + typedef bool (*Occluded16Ty) (void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive); public: struct Intersectors { Intersectors() {} // WARNING: Do not zero initialize this, as we otherwise get problems with thread unsafe local static variable initialization (e.g. on VS2013) in curve_intersector_virtual.cpp. - template<int K> void intersect(void* pre, void* ray, IntersectContext* context, const void* primitive); - template<int K> bool occluded (void* pre, void* ray, IntersectContext* context, const void* primitive); + template<int K> void intersect(void* pre, void* ray, RayQueryContext* context, const void* primitive); + template<int K> bool occluded (void* pre, void* ray, RayQueryContext* context, const void* primitive); - template<int K> void intersect(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive); - template<int K> bool occluded (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive); + template<int K> void intersect(void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive); + template<int K> bool occluded (void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive); public: Intersect1Ty intersect1; @@ -74,20 +74,20 @@ namespace embree Intersectors vtbl[Geometry::GTY_END]; }; - template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<1> (void* pre, void* ray, IntersectContext* context, const void* primitive) { assert(intersect1); intersect1(pre,ray,context,primitive); } - template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<1> (void* pre, void* ray, IntersectContext* context, const void* primitive) { assert(occluded1); return occluded1(pre,ray,context,primitive); } + template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<1> (void* pre, void* ray, RayQueryContext* context, const void* primitive) { assert(intersect1); intersect1(pre,ray,context,primitive); } + template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<1> (void* pre, void* ray, RayQueryContext* context, const void* primitive) { assert(occluded1); return occluded1(pre,ray,context,primitive); } - template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<4>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect4); intersect4(pre,ray,k,context,primitive); } - template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<4> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded4); return occluded4(pre,ray,k,context,primitive); } + template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<4>(void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive) { assert(intersect4); intersect4(pre,ray,k,context,primitive); } + template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<4> (void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive) { assert(occluded4); return occluded4(pre,ray,k,context,primitive); } #if defined(__AVX__) - template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<8>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect8); intersect8(pre,ray,k,context,primitive); } - template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<8> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded8); return occluded8(pre,ray,k,context,primitive); } + template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<8>(void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive) { assert(intersect8); intersect8(pre,ray,k,context,primitive); } + template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<8> (void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive) { assert(occluded8); return occluded8(pre,ray,k,context,primitive); } #endif #if defined(__AVX512F__) - template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<16>(void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(intersect16); intersect16(pre,ray,k,context,primitive); } - template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<16> (void* pre, void* ray, size_t k, IntersectContext* context, const void* primitive) { assert(occluded16); return occluded16(pre,ray,k,context,primitive); } + template<> __forceinline void VirtualCurveIntersector::Intersectors::intersect<16>(void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive) { assert(intersect16); intersect16(pre,ray,k,context,primitive); } + template<> __forceinline bool VirtualCurveIntersector::Intersectors::occluded<16> (void* pre, void* ray, size_t k, RayQueryContext* context, const void* primitive) { assert(occluded16); return occluded16(pre,ray,k,context,primitive); } #endif namespace isa @@ -98,7 +98,7 @@ namespace embree typedef CurvePrecalculations1 Precalculations; template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -108,7 +108,7 @@ namespace embree } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -125,7 +125,7 @@ namespace embree typedef CurvePrecalculationsK<K> Precalculations; template<bool robust> - static __forceinline void intersect(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -136,7 +136,7 @@ namespace embree } template<bool robust> - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -153,7 +153,7 @@ namespace embree } template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); @@ -163,7 +163,7 @@ namespace embree } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { assert(num == 1); RTCGeometryType ty = (RTCGeometryType)(*prim); diff --git a/thirdparty/embree/kernels/geometry/disc_intersector.h b/thirdparty/embree/kernels/geometry/disc_intersector.h index ec6fa9c4f3..2997d36202 100644 --- a/thirdparty/embree/kernels/geometry/disc_intersector.h +++ b/thirdparty/embree/kernels/geometry/disc_intersector.h @@ -23,18 +23,24 @@ namespace embree __forceinline void finalize() {} - __forceinline Vec2f uv(const size_t i) const - { + __forceinline Vec2f uv(const size_t i) const { return Vec2f(vu[i], vv[i]); } - __forceinline float t(const size_t i) const - { + __forceinline Vec2vf<M> uv() const { + return Vec2vf<M>(vu, vv); + } + __forceinline float t(const size_t i) const { return vt[i]; } - __forceinline Vec3fa Ng(const size_t i) const - { + __forceinline vfloat<M> t() const { + return vt; + } + __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i], vNg.y[i], vNg.z[i]); } + __forceinline Vec3vf<M> Ng() const { + return vNg; + } public: vfloat<M> vu; @@ -43,16 +49,45 @@ namespace embree Vec3vf<M> vNg; }; + template<> + struct DiscIntersectorHitM<1> + { + __forceinline DiscIntersectorHitM() {} + + __forceinline DiscIntersectorHitM(const float& u, const float& v, const float& t, const Vec3fa& Ng) + : vu(u), vv(v), vt(t), vNg(Ng) {} + + __forceinline void finalize() {} + + __forceinline Vec2f uv() const { + return Vec2f(vu, vv); + } + + __forceinline float t() const { + return vt; + } + + __forceinline Vec3fa Ng() const { + return vNg; + } + + public: + float vu; + float vv; + float vt; + Vec3fa vNg; + }; + template<int M> struct DiscIntersector1 { typedef CurvePrecalculations1 Precalculations; - template<typename Epilog> + template<typename Ray, typename Epilog> static __forceinline bool intersect( const vbool<M>& valid_i, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const Points* geom, const Precalculations& pre, const Vec4vf<M>& v0i, @@ -97,10 +132,10 @@ namespace embree return epilog(valid, hit); } - template<typename Epilog> + template<typename Ray, typename Epilog> static __forceinline bool intersect(const vbool<M>& valid_i, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const Points* geom, const Precalculations& pre, const Vec4vf<M>& v0i, @@ -145,7 +180,7 @@ namespace embree static __forceinline bool intersect(const vbool<M>& valid_i, RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const Points* geom, const Precalculations& pre, const Vec4vf<M>& v0i, @@ -194,7 +229,7 @@ namespace embree static __forceinline bool intersect(const vbool<M>& valid_i, RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const Points* geom, const Precalculations& pre, const Vec4vf<M>& v0i, diff --git a/thirdparty/embree/kernels/geometry/disci_intersector.h b/thirdparty/embree/kernels/geometry/disci_intersector.h index bb9d396f6e..1ae4a66330 100644 --- a/thirdparty/embree/kernels/geometry/disci_intersector.h +++ b/thirdparty/embree/kernels/geometry/disci_intersector.h @@ -19,7 +19,7 @@ namespace embree static __forceinline void intersect(const Precalculations& pre, RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& Disc) { STAT3(normal.trav_prims, 1, 1, 1); @@ -32,7 +32,7 @@ namespace embree static __forceinline bool occluded(const Precalculations& pre, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& Disc) { STAT3(shadow.trav_prims, 1, 1, 1); @@ -52,7 +52,7 @@ namespace embree static __forceinline void intersect(const Precalculations& pre, RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& Disc) { STAT3(normal.trav_prims, 1, 1, 1); @@ -65,7 +65,7 @@ namespace embree static __forceinline bool occluded(const Precalculations& pre, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& Disc) { STAT3(shadow.trav_prims, 1, 1, 1); @@ -84,7 +84,7 @@ namespace embree typedef CurvePrecalculationsK<K> Precalculations; static __forceinline void intersect( - const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc) + const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& Disc) { STAT3(normal.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(Disc.geomID()); @@ -96,7 +96,7 @@ namespace embree } static __forceinline bool occluded( - const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc) + const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& Disc) { STAT3(shadow.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(Disc.geomID()); @@ -115,7 +115,7 @@ namespace embree typedef CurvePrecalculationsK<K> Precalculations; static __forceinline void intersect( - const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc) + const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& Disc) { STAT3(normal.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(Disc.geomID()); @@ -127,7 +127,7 @@ namespace embree } static __forceinline bool occluded( - const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc) + const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& Disc) { STAT3(shadow.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(Disc.geomID()); @@ -146,7 +146,7 @@ namespace embree static __forceinline void intersect(const Precalculations& pre, RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& Disc) { STAT3(normal.trav_prims, 1, 1, 1); @@ -160,7 +160,7 @@ namespace embree static __forceinline bool occluded(const Precalculations& pre, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& Disc) { STAT3(shadow.trav_prims, 1, 1, 1); @@ -181,7 +181,7 @@ namespace embree static __forceinline void intersect(const Precalculations& pre, RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& Disc) { STAT3(normal.trav_prims, 1, 1, 1); @@ -195,7 +195,7 @@ namespace embree static __forceinline bool occluded(const Precalculations& pre, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& Disc) { STAT3(shadow.trav_prims, 1, 1, 1); @@ -215,7 +215,7 @@ namespace embree typedef CurvePrecalculationsK<K> Precalculations; static __forceinline void intersect( - const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc) + const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& Disc) { STAT3(normal.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(Disc.geomID()); @@ -228,7 +228,7 @@ namespace embree } static __forceinline bool occluded( - const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc) + const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& Disc) { STAT3(shadow.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(Disc.geomID()); @@ -248,7 +248,7 @@ namespace embree typedef CurvePrecalculationsK<K> Precalculations; static __forceinline void intersect( - const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc) + const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& Disc) { STAT3(normal.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(Disc.geomID()); @@ -261,7 +261,7 @@ namespace embree } static __forceinline bool occluded( - const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& Disc) + const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& Disc) { STAT3(shadow.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(Disc.geomID()); diff --git a/thirdparty/embree/kernels/geometry/filter.h b/thirdparty/embree/kernels/geometry/filter.h index d64320bf78..773c2bfeb8 100644 --- a/thirdparty/embree/kernels/geometry/filter.h +++ b/thirdparty/embree/kernels/geometry/filter.h @@ -12,20 +12,20 @@ namespace embree { namespace isa { - __forceinline bool runIntersectionFilter1Helper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context) + __forceinline bool runIntersectionFilter1Helper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, RayQueryContext* context) { if (geometry->intersectionFilterN) { - assert(context->scene->hasGeometryFilterFunction()); geometry->intersectionFilterN(args); if (args->valid[0] == 0) return false; } - - if (context->user->filter) { - assert(context->scene->hasContextFilterFunction()); - context->user->filter(args); + + if (context->getFilter()) + { + if (context->enforceArgumentFilterFunction() || geometry->hasArgumentFilterFunctions()) + context->getFilter()(args); if (args->valid[0] == 0) return false; @@ -35,7 +35,7 @@ namespace embree return true; } - __forceinline bool runIntersectionFilter1(const Geometry* const geometry, RayHit& ray, IntersectContext* context, Hit& hit) + __forceinline bool runIntersectionFilter1(const Geometry* const geometry, RayHit& ray, RayQueryContext* context, Hit& hit) { RTCFilterFunctionNArguments args; int mask = -1; @@ -48,39 +48,29 @@ namespace embree return runIntersectionFilter1Helper(&args,geometry,context); } - __forceinline void reportIntersection1(IntersectFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args) - { -#if defined(EMBREE_FILTER_FUNCTION) - if (args->geometry->intersectionFilterN) - args->geometry->intersectionFilterN(filter_args); - - if (args->context->filter) - args->context->filter(filter_args); -#endif - } - - __forceinline bool runOcclusionFilter1Helper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context) + __forceinline bool runOcclusionFilter1Helper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, RayQueryContext* context) { if (geometry->occlusionFilterN) { - assert(context->scene->hasGeometryFilterFunction()); geometry->occlusionFilterN(args); if (args->valid[0] == 0) return false; } - - if (context->user->filter) { - assert(context->scene->hasContextFilterFunction()); - context->user->filter(args); + + if (context->getFilter()) + { + if (context->enforceArgumentFilterFunction() || geometry->hasArgumentFilterFunctions()) + context->getFilter()(args); if (args->valid[0] == 0) return false; } + return true; } - __forceinline bool runOcclusionFilter1(const Geometry* const geometry, Ray& ray, IntersectContext* context, Hit& hit) + __forceinline bool runOcclusionFilter1(const Geometry* const geometry, Ray& ray, RayQueryContext* context, Hit& hit) { RTCFilterFunctionNArguments args; int mask = -1; @@ -93,33 +83,19 @@ namespace embree return runOcclusionFilter1Helper(&args,geometry,context); } - __forceinline void reportOcclusion1(OccludedFunctionNArguments* args, const RTCFilterFunctionNArguments* filter_args) - { -#if defined(EMBREE_FILTER_FUNCTION) - if (args->geometry->occlusionFilterN) - args->geometry->occlusionFilterN(filter_args); - - if (args->context->filter) - args->context->filter(filter_args); -#endif - } - template<int K> - __forceinline vbool<K> runIntersectionFilterHelper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context) + __forceinline vbool<K> runIntersectionFilterHelper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, RayQueryContext* context) { vint<K>* mask = (vint<K>*) args->valid; if (geometry->intersectionFilterN) - { - assert(context->scene->hasGeometryFilterFunction()); geometry->intersectionFilterN(args); - } - + vbool<K> valid_o = *mask != vint<K>(zero); if (none(valid_o)) return valid_o; - if (context->user->filter) { - assert(context->scene->hasContextFilterFunction()); - context->user->filter(args); + if (context->getFilter()) { + if (context->enforceArgumentFilterFunction() || geometry->hasArgumentFilterFunctions()) + context->getFilter()(args); } valid_o = *mask != vint<K>(zero); @@ -130,7 +106,7 @@ namespace embree } template<int K> - __forceinline vbool<K> runIntersectionFilter(const vbool<K>& valid, const Geometry* const geometry, RayHitK<K>& ray, IntersectContext* context, HitK<K>& hit) + __forceinline vbool<K> runIntersectionFilter(const vbool<K>& valid, const Geometry* const geometry, RayHitK<K>& ray, RayQueryContext* context, HitK<K>& hit) { RTCFilterFunctionNArguments args; vint<K> mask = valid.mask32(); @@ -144,24 +120,19 @@ namespace embree } template<int K> - __forceinline vbool<K> runOcclusionFilterHelper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, IntersectContext* context) + __forceinline vbool<K> runOcclusionFilterHelper(RTCFilterFunctionNArguments* args, const Geometry* const geometry, RayQueryContext* context) { vint<K>* mask = (vint<K>*) args->valid; if (geometry->occlusionFilterN) - { - assert(context->scene->hasGeometryFilterFunction()); geometry->occlusionFilterN(args); - } - - vbool<K> valid_o = *mask != vint<K>(zero); + vbool<K> valid_o = *mask != vint<K>(zero); if (none(valid_o)) return valid_o; - if (context->user->filter) { - assert(context->scene->hasContextFilterFunction()); - context->user->filter(args); + if (context->getFilter()) { + if (context->enforceArgumentFilterFunction() || geometry->hasArgumentFilterFunctions()) + context->getFilter()(args); } - valid_o = *mask != vint<K>(zero); RayK<K>* ray = (RayK<K>*) args->ray; @@ -170,7 +141,7 @@ namespace embree } template<int K> - __forceinline vbool<K> runOcclusionFilter(const vbool<K>& valid, const Geometry* const geometry, RayK<K>& ray, IntersectContext* context, HitK<K>& hit) + __forceinline vbool<K> runOcclusionFilter(const vbool<K>& valid, const Geometry* const geometry, RayK<K>& ray, RayQueryContext* context, HitK<K>& hit) { RTCFilterFunctionNArguments args; vint<K> mask = valid.mask32(); diff --git a/thirdparty/embree/kernels/geometry/filter_sycl.h b/thirdparty/embree/kernels/geometry/filter_sycl.h new file mode 100644 index 0000000000..00f333134b --- /dev/null +++ b/thirdparty/embree/kernels/geometry/filter_sycl.h @@ -0,0 +1,109 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../common/geometry.h" +#include "../common/ray.h" +#include "../common/hit.h" +#include "../common/context.h" + +namespace embree +{ + __forceinline bool runIntersectionFilter1Helper(RTCFilterFunctionNArguments* args, int& mask, const Geometry* const geometry, RayQueryContext* context) + { + typedef void (*RTCFilterFunctionSYCL)(const void* args); + const RTCFeatureFlags feature_mask MAYBE_UNUSED = context->args->feature_mask; + +#if EMBREE_SYCL_GEOMETRY_CALLBACK + if (feature_mask & RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_GEOMETRY) + { + RTCFilterFunctionSYCL gfilter = (RTCFilterFunctionSYCL) geometry->intersectionFilterN; + if (gfilter) + { + gfilter(args); + + if (mask == 0) + return false; + } + } +#endif + + if (feature_mask & RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS) + { + RTCFilterFunctionSYCL cfilter = (RTCFilterFunctionSYCL) context->args->filter; + if (cfilter) + { + if (context->enforceArgumentFilterFunction() || geometry->hasArgumentFilterFunctions()) + cfilter(args); + + if (mask == 0) + return false; + } + } + + return true; + } + + __forceinline bool runOcclusionFilter1Helper(RTCFilterFunctionNArguments* args, int& mask, const Geometry* const geometry, RayQueryContext* context) + { + typedef void (*RTCFilterFunctionSYCL)(const void* args); + const RTCFeatureFlags feature_mask MAYBE_UNUSED = context->args->feature_mask; + +#if EMBREE_SYCL_GEOMETRY_CALLBACK + if (feature_mask & RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_GEOMETRY) + { + RTCFilterFunctionSYCL gfilter = (RTCFilterFunctionSYCL) geometry->occlusionFilterN; + if (gfilter) + { + gfilter(args); + + if (mask == 0) + return false; + } + } +#endif + + if (feature_mask & RTC_FEATURE_FLAG_FILTER_FUNCTION_IN_ARGUMENTS) + { + RTCFilterFunctionSYCL cfilter = (RTCFilterFunctionSYCL) context->args->filter; + if (cfilter) + { + if (context->enforceArgumentFilterFunction() || geometry->hasArgumentFilterFunctions()) + cfilter(args); + + if (mask == 0) + return false; + } + } + + return true; + } + + __forceinline bool runIntersectionFilter1SYCL(Geometry* geometry, RayHit& ray, sycl::private_ptr<RayQueryContext> context, Hit& hit) + { + RTCFilterFunctionNArguments args; + int mask = -1; + args.valid = &mask; + args.geometryUserPtr = geometry->userPtr; + args.context = context->user; + args.ray = (RTCRayN*) &ray; + args.hit = (RTCHitN*) &hit; + args.N = 1; + return runIntersectionFilter1Helper(&args,mask,geometry,context); + } + + + __forceinline bool runIntersectionFilter1SYCL(Geometry* geometry, Ray& ray, sycl::private_ptr<RayQueryContext> context, Hit& hit) + { + RTCFilterFunctionNArguments args; + int mask = -1; + args.valid = &mask; + args.geometryUserPtr = geometry->userPtr; + args.context = context->user; + args.ray = (RTCRayN*) &ray; + args.hit = (RTCHitN*) &hit; + args.N = 1; + return runOcclusionFilter1Helper(&args,mask,geometry,context); + } +} diff --git a/thirdparty/embree/kernels/geometry/grid_intersector.h b/thirdparty/embree/kernels/geometry/grid_intersector.h index 9c59cef119..9837205445 100644 --- a/thirdparty/embree/kernels/geometry/grid_intersector.h +++ b/thirdparty/embree/kernels/geometry/grid_intersector.h @@ -35,20 +35,20 @@ namespace embree typedef Grid1Precalculations<GridSOAIntersector1::Precalculations> Precalculations; /*! Intersect a ray with the primitive. */ - static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) + static __forceinline void intersect(Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) { GridSOAIntersector1::intersect(pre,ray,context,prim,lazy_node); } - static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) { + static __forceinline void intersect(Precalculations& pre, RayHit& ray, RayQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) { intersect(pre,ray,context,prim,ty,lazy_node); } /*! Test if the ray is occluded by the primitive */ - static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) + static __forceinline bool occluded(Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) { GridSOAIntersector1::occluded(pre,ray,context,prim,lazy_node); } - static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) { + static __forceinline bool occluded(Precalculations& pre, Ray& ray, RayQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, size_t& lazy_node) { return occluded(pre,ray,context,prim,ty,lazy_node); } @@ -70,22 +70,22 @@ namespace embree typedef SubdivPatch1PrecalculationsK<K,typename GridSOAIntersectorK<K>::Precalculations> Precalculations; - static __forceinline void intersect(const vbool<K>& valid, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) { GridSOAIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node); } - static __forceinline vbool<K> occluded(const vbool<K>& valid, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) { GridSOAIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node); } - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) { GridSOAIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t ty, size_t& lazy_node) { GridSOAIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node); } diff --git a/thirdparty/embree/kernels/geometry/grid_soa_intersector1.h b/thirdparty/embree/kernels/geometry/grid_soa_intersector1.h index 8fbf0d4bdf..6d56bd0404 100644 --- a/thirdparty/embree/kernels/geometry/grid_soa_intersector1.h +++ b/thirdparty/embree/kernels/geometry/grid_soa_intersector1.h @@ -30,7 +30,7 @@ namespace embree template<typename Loader> static __forceinline void intersect(RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const float* const grid_x, const size_t line_offset, const size_t lines, @@ -50,7 +50,7 @@ namespace embree template<typename Loader> static __forceinline bool occluded(Ray& ray, - IntersectContext* context, + RayQueryContext* context, const float* const grid_x, const size_t line_offset, const size_t lines, @@ -71,7 +71,7 @@ namespace embree } /*! Intersect a ray with the primitive. */ - static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline void intersect(Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t line_offset = pre.grid->width; const size_t lines = pre.grid->height; @@ -87,7 +87,7 @@ namespace embree } /*! Test if the ray is occluded by the primitive */ - static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline bool occluded(Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t line_offset = pre.grid->width; const size_t lines = pre.grid->height; @@ -112,7 +112,7 @@ namespace embree template<typename Loader> static __forceinline void intersect(RayHit& ray, const float ftime, - IntersectContext* context, + RayQueryContext* context, const float* const grid_x, const size_t line_offset, const size_t lines, @@ -142,7 +142,7 @@ namespace embree template<typename Loader> static __forceinline bool occluded(Ray& ray, const float ftime, - IntersectContext* context, + RayQueryContext* context, const float* const grid_x, const size_t line_offset, const size_t lines, @@ -171,7 +171,7 @@ namespace embree } /*! Intersect a ray with the primitive. */ - static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline void intersect(Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t line_offset = pre.grid->width; const size_t lines = pre.grid->height; @@ -187,7 +187,7 @@ namespace embree } /*! Test if the ray is occluded by the primitive */ - static __forceinline bool occluded(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline bool occluded(Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t line_offset = pre.grid->width; const size_t lines = pre.grid->height; diff --git a/thirdparty/embree/kernels/geometry/grid_soa_intersector_packet.h b/thirdparty/embree/kernels/geometry/grid_soa_intersector_packet.h index 14cacab5fe..5e5a24b7dd 100644 --- a/thirdparty/embree/kernels/geometry/grid_soa_intersector_packet.h +++ b/thirdparty/embree/kernels/geometry/grid_soa_intersector_packet.h @@ -79,7 +79,7 @@ namespace embree }; /*! Intersect a ray with the primitive. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t dim_offset = pre.grid->dim_offset; const size_t line_offset = pre.grid->width; @@ -110,7 +110,7 @@ namespace embree } /*! Test if the ray is occluded by the primitive */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t dim_offset = pre.grid->dim_offset; const size_t line_offset = pre.grid->width; @@ -146,7 +146,7 @@ namespace embree template<typename Loader> static __forceinline void intersect(RayHitK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const float* const grid_x, const size_t line_offset, const size_t lines, @@ -163,7 +163,7 @@ namespace embree template<typename Loader> static __forceinline bool occluded(RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const float* const grid_x, const size_t line_offset, const size_t lines, @@ -179,7 +179,7 @@ namespace embree } /*! Intersect a ray with the primitive. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t line_offset = pre.grid->width; const size_t lines = pre.grid->height; @@ -194,7 +194,7 @@ namespace embree } /*! Test if the ray is occluded by the primitive */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t line_offset = pre.grid->width; const size_t lines = pre.grid->height; @@ -219,7 +219,7 @@ namespace embree typedef typename GridSOAIntersectorK<K>::Precalculations Precalculations; /*! Intersect a ray with the primitive. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { vfloat<K> vftime; vint<K> vitime = getTimeSegment<K>(ray.time(), vfloat<K>((float)(pre.grid->time_steps-1)), vftime); @@ -235,7 +235,7 @@ namespace embree } /*! Intersect a ray with the primitive. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, const vfloat<K>& ftime, int itime, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, const vfloat<K>& ftime, int itime, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t grid_offset = pre.grid->gridBytes >> 2; const size_t dim_offset = pre.grid->dim_offset; @@ -279,7 +279,7 @@ namespace embree } /*! Test if the ray is occluded by the primitive */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { vfloat<K> vftime; vint<K> vitime = getTimeSegment<K>(ray.time(), vfloat<K>((float)(pre.grid->time_steps-1)), vftime); @@ -297,7 +297,7 @@ namespace embree } /*! Test if the ray is occluded by the primitive */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, const vfloat<K>& ftime, int itime, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, const vfloat<K>& ftime, int itime, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { const size_t grid_offset = pre.grid->gridBytes >> 2; const size_t dim_offset = pre.grid->dim_offset; @@ -347,7 +347,7 @@ namespace embree template<typename Loader> static __forceinline void intersect(RayHitK<K>& ray, size_t k, const float ftime, - IntersectContext* context, + RayQueryContext* context, const float* const grid_x, const size_t line_offset, const size_t lines, @@ -376,7 +376,7 @@ namespace embree template<typename Loader> static __forceinline bool occluded(RayK<K>& ray, size_t k, const float ftime, - IntersectContext* context, + RayQueryContext* context, const float* const grid_x, const size_t line_offset, const size_t lines, @@ -403,7 +403,7 @@ namespace embree } /*! Intersect a ray with the primitive. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { float ftime; int itime = getTimeSegment(ray.time()[k], float(pre.grid->time_steps-1), ftime); @@ -422,7 +422,7 @@ namespace embree } /*! Test if the ray is occluded by the primitive */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { float ftime; int itime = getTimeSegment(ray.time()[k], float(pre.grid->time_steps-1), ftime); diff --git a/thirdparty/embree/kernels/geometry/instance_array.h b/thirdparty/embree/kernels/geometry/instance_array.h new file mode 100644 index 0000000000..fdbe79b3a8 --- /dev/null +++ b/thirdparty/embree/kernels/geometry/instance_array.h @@ -0,0 +1,85 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "primitive.h" +#include "../common/scene_instance_array.h" + +namespace embree +{ + //template<int M> + struct InstanceArrayPrimitive + { + struct Type : public PrimitiveType + { + const char* name() const; + size_t sizeActive(const char* This) const; + size_t sizeTotal(const char* This) const; + size_t getBytes(const char* This) const; + }; + static Type type; + + public: + + /* primitive supports multiple time segments */ + static const bool singleTimeSegment = false; + + /* Returns maximum number of stored primitives */ + static __forceinline size_t max_size() { return 1; } + + /* Returns required number of primitive blocks for N primitives */ + static __forceinline size_t blocks(size_t N) { return N; } + + public: + + InstanceArrayPrimitive (const uint32_t geomID, const uint32_t primID) + : primID_(primID) + , instID_(geomID) + {} + + __forceinline bool valid() const { + return primID_ != -1; + } + + void fill(const PrimRef* prims, size_t& i, size_t end, Scene* scene) + { + assert(end-i == 1); + const PrimRef& prim = prims[i]; i++; + const unsigned int geomID = prim.geomID(); + const unsigned int primID = prim.primID(); + new (this) InstanceArrayPrimitive(geomID, primID); + } + + __forceinline LBBox3fa fillMB(const PrimRef* prims, size_t& i, size_t end, Scene* scene, size_t itime) + { + assert(end-i == 1); + const PrimRef& prim = prims[i]; i++; + const unsigned int geomID = prim.geomID(); + const size_t primID = prim.primID(); + new (this) InstanceArrayPrimitive(geomID, primID); + const InstanceArray* instanceArray = scene->get<InstanceArray>(geomID); + return instanceArray->linearBounds(primID,itime); + } + + __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& i, size_t end, Scene* scene, const BBox1f time_range) + { + assert(end-i == 1); + const PrimRefMB& prim = prims[i]; i++; + const unsigned int geomID = prim.geomID(); + const size_t primID = prim.primID(); + new (this) InstanceArrayPrimitive(geomID, primID); + const InstanceArray* instanceArray = scene->get<InstanceArray>(geomID); + return instanceArray->linearBounds(primID,time_range); + } + + /* Updates the primitive */ + __forceinline BBox3fa update(InstanceArray* instanceArray) { + return instanceArray->bounds(0); + } + + public: + unsigned int primID_; + unsigned int instID_; + }; +} diff --git a/thirdparty/embree/kernels/geometry/instance_array_intersector.h b/thirdparty/embree/kernels/geometry/instance_array_intersector.h new file mode 100644 index 0000000000..c32c8b4cde --- /dev/null +++ b/thirdparty/embree/kernels/geometry/instance_array_intersector.h @@ -0,0 +1,85 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "instance_array.h" +#include "../common/ray.h" +#include "../common/point_query.h" +#include "../common/scene.h" + +namespace embree +{ + namespace isa + { + struct InstanceArrayIntersector1 + { + typedef InstanceArrayPrimitive Primitive; + + struct Precalculations { + __forceinline Precalculations (const Ray& ray, const void *ptr) {} + }; + + static void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim); + static bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim); + static bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim); + }; + + struct InstanceArrayIntersector1MB + { + typedef InstanceArrayPrimitive Primitive; + + struct Precalculations { + __forceinline Precalculations (const Ray& ray, const void *ptr) {} + }; + + static void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim); + static bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim); + static bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim); + }; + + template<int K> + struct InstanceArrayIntersectorK + { + typedef InstanceArrayPrimitive Primitive; + + struct Precalculations { + __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {} + }; + + static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& prim); + static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& prim); + + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { + intersect(vbool<K>(1<<int(k)),pre,ray,context,prim); + } + + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { + occluded(vbool<K>(1<<int(k)),pre,ray,context,prim); + return ray.tfar[k] < 0.0f; + } + }; + + template<int K> + struct InstanceArrayIntersectorKMB + { + typedef InstanceArrayPrimitive Primitive; + + struct Precalculations { + __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {} + }; + + static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& prim); + static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& prim); + + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { + intersect(vbool<K>(1<<int(k)),pre,ray,context,prim); + } + + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { + occluded(vbool<K>(1<<int(k)),pre,ray,context,prim); + return ray.tfar[k] < 0.0f; + } + }; + } +} diff --git a/thirdparty/embree/kernels/geometry/instance_intersector.h b/thirdparty/embree/kernels/geometry/instance_intersector.h index 28a7b728e5..45c3d36c2d 100644 --- a/thirdparty/embree/kernels/geometry/instance_intersector.h +++ b/thirdparty/embree/kernels/geometry/instance_intersector.h @@ -19,8 +19,8 @@ namespace embree __forceinline Precalculations (const Ray& ray, const void *ptr) {} }; - static void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim); - static bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim); + static void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim); + static bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim); static bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim); }; @@ -32,8 +32,8 @@ namespace embree __forceinline Precalculations (const Ray& ray, const void *ptr) {} }; - static void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim); - static bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim); + static void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim); + static bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim); static bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim); }; @@ -46,14 +46,14 @@ namespace embree __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {} }; - static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim); - static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim); + static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& prim); + static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& prim); - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) { + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { intersect(vbool<K>(1<<int(k)),pre,ray,context,prim); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) { + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { occluded(vbool<K>(1<<int(k)),pre,ray,context,prim); return ray.tfar[k] < 0.0f; } @@ -68,14 +68,14 @@ namespace embree __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {} }; - static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim); - static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim); + static void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& prim); + static vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& prim); - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) { + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { intersect(vbool<K>(1<<int(k)),pre,ray,context,prim); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) { + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { occluded(vbool<K>(1<<int(k)),pre,ray,context,prim); return ray.tfar[k] < 0.0f; } diff --git a/thirdparty/embree/kernels/geometry/intersector_epilog.h b/thirdparty/embree/kernels/geometry/intersector_epilog.h index 7bf134cc54..af85b0e57d 100644 --- a/thirdparty/embree/kernels/geometry/intersector_epilog.h +++ b/thirdparty/embree/kernels/geometry/intersector_epilog.h @@ -21,12 +21,12 @@ namespace embree struct Intersect1Epilog1 { RayHit& ray; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1Epilog1(RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} @@ -64,6 +64,9 @@ namespace embree ray.primID = primID; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UU(context->user->instPrimID, ray.instPrimID); +#endif return true; } }; @@ -72,12 +75,12 @@ namespace embree struct Occluded1Epilog1 { Ray& ray; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1Epilog1(Ray& ray, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} @@ -117,12 +120,12 @@ namespace embree { RayHitK<K>& ray; size_t k; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1KEpilog1(RayHitK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} @@ -163,6 +166,9 @@ namespace embree ray.primID[k] = primID; ray.geomID[k] = geomID; instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, k); +#endif return true; } }; @@ -172,12 +178,12 @@ namespace embree { RayK<K>& ray; size_t k; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1KEpilog1(RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} @@ -215,12 +221,12 @@ namespace embree struct Intersect1EpilogM { RayHit& ray; - IntersectContext* context; + RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; __forceinline Intersect1EpilogM(RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs) : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {} @@ -287,6 +293,9 @@ namespace embree ray.primID = primIDs[i]; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UU(context->user->instPrimID, ray.instPrimID); +#endif return true; } @@ -296,12 +305,12 @@ namespace embree struct Occluded1EpilogM { Ray& ray; - IntersectContext* context; + RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; __forceinline Occluded1EpilogM(Ray& ray, - IntersectContext* context, + RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs) : ray(ray), context(context), geomIDs(geomIDs), primIDs(primIDs) {} @@ -363,12 +372,12 @@ namespace embree struct Intersect1EpilogMU { RayHit& ray; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1EpilogMU(RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} @@ -424,6 +433,9 @@ namespace embree ray.primID = primID; ray.geomID = geomID; instance_id_stack::copy_UU(context->user->instID, ray.instID); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UU(context->user->instPrimID, ray.instPrimID); +#endif return true; } }; @@ -432,12 +444,12 @@ namespace embree struct Occluded1EpilogMU { Ray& ray; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1EpilogMU(Ray& ray, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} @@ -477,13 +489,13 @@ namespace embree struct IntersectKEpilogM { RayHitK<K>& ray; - IntersectContext* context; + RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; const size_t i; __forceinline IntersectKEpilogM(RayHitK<K>& ray, - IntersectContext* context, + RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs, size_t i) @@ -534,6 +546,9 @@ namespace embree vuint<K>::store(valid,&ray.primID,primID); vuint<K>::store(valid,&ray.geomID,geomID); instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, valid); +#endif return valid; } }; @@ -543,14 +558,14 @@ namespace embree { vbool<K>& valid0; RayK<K>& ray; - IntersectContext* context; + RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; const size_t i; __forceinline OccludedKEpilogM(vbool<K>& valid0, RayK<K>& ray, - IntersectContext* context, + RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs, size_t i) @@ -598,12 +613,12 @@ namespace embree struct IntersectKEpilogMU { RayHitK<K>& ray; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline IntersectKEpilogMU(RayHitK<K>& ray, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), context(context), geomID(geomID), primID(primID) {} @@ -649,6 +664,9 @@ namespace embree vuint<K>::store(valid,&ray.primID,primID); vuint<K>::store(valid,&ray.geomID,geomID); instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, valid); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, valid); +#endif return valid; } }; @@ -658,13 +676,13 @@ namespace embree { vbool<K>& valid0; RayK<K>& ray; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline OccludedKEpilogMU(vbool<K>& valid0, RayK<K>& ray, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : valid0(valid0), ray(ray), context(context), geomID(geomID), primID(primID) {} @@ -709,12 +727,12 @@ namespace embree { RayHitK<K>& ray; size_t k; - IntersectContext* context; + RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; __forceinline Intersect1KEpilogM(RayHitK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs) : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {} @@ -783,6 +801,9 @@ namespace embree ray.primID[k] = primIDs[i]; ray.geomID[k] = geomID; instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, k); +#endif return true; } }; @@ -792,12 +813,12 @@ namespace embree { RayK<K>& ray; size_t k; - IntersectContext* context; + RayQueryContext* context; const vuint<M>& geomIDs; const vuint<M>& primIDs; __forceinline Occluded1KEpilogM(RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const vuint<M>& geomIDs, const vuint<M>& primIDs) : ray(ray), k(k), context(context), geomIDs(geomIDs), primIDs(primIDs) {} @@ -860,12 +881,12 @@ namespace embree { RayHitK<K>& ray; size_t k; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Intersect1KEpilogMU(RayHitK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} @@ -923,6 +944,9 @@ namespace embree ray.primID[k] = primID; ray.geomID[k] = geomID; instance_id_stack::copy_UV<K>(context->user->instID, ray.instID, k); +#if defined(RTC_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UV<K>(context->user->instPrimID, ray.instPrimID, k); +#endif return true; } }; @@ -932,12 +956,12 @@ namespace embree { RayK<K>& ray; size_t k; - IntersectContext* context; + RayQueryContext* context; const unsigned int geomID; const unsigned int primID; __forceinline Occluded1KEpilogMU(RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const unsigned int geomID, const unsigned int primID) : ray(ray), k(k), context(context), geomID(geomID), primID(primID) {} diff --git a/thirdparty/embree/kernels/geometry/intersector_epilog_sycl.h b/thirdparty/embree/kernels/geometry/intersector_epilog_sycl.h new file mode 100644 index 0000000000..9565006738 --- /dev/null +++ b/thirdparty/embree/kernels/geometry/intersector_epilog_sycl.h @@ -0,0 +1,207 @@ +// Copyright 2009-2021 Intel Corporation +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "../common/ray.h" +#include "../common/context.h" +#include "filter_sycl.h" + +namespace embree +{ + template<typename Ray> + struct Intersect1Epilog1_HWIF; + + template<> + struct Intersect1Epilog1_HWIF<RayHit> + { + RayHit& ray; + sycl::private_ptr<RayQueryContext> context; + const unsigned int geomID; + const unsigned int primID; + const bool filter; + + __forceinline Intersect1Epilog1_HWIF(RayHit& ray, + sycl::private_ptr<RayQueryContext> context, + const unsigned int geomID, + const unsigned int primID, + const bool filter) + : ray(ray), context(context), geomID(geomID), primID(primID), filter(filter) {} + + template<typename Hit_i> + __forceinline bool operator() (Hit_i& hit_i) const + { + hit_i.finalize(); + + Scene* scene MAYBE_UNUSED = context->scene; + Geometry* geometry MAYBE_UNUSED = scene->get(geomID); + + /* ray mask test */ +#if defined(EMBREE_RAY_MASK) + if ((geometry->mask & ray.mask) == 0) + return false; +#endif + + /* call intersection filter function */ +#if defined(EMBREE_FILTER_FUNCTION) + if (filter && (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter()))) + { + Hit h(context->user,geomID,primID,Vec2f(hit_i.u,hit_i.v),hit_i.Ng); + float old_t = ray.tfar; + ray.tfar = hit_i.t; + bool found = runIntersectionFilter1SYCL(geometry,ray,context,h); + if (!found) { + ray.tfar = old_t; + return false; + } + } +#endif + + ray.tfar = hit_i.t; + ray.u = hit_i.u; + ray.v = hit_i.v; + ray.Ng.x = hit_i.Ng.x; + ray.Ng.y = hit_i.Ng.y; + ray.Ng.z = hit_i.Ng.z; + ray.geomID = geomID; + ray.primID = primID; + instance_id_stack::copy_UU(context->user, context->user->instID, ray.instID); +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UU(context->user, context->user->instPrimID, ray.instPrimID); +#endif + return true; + } + + template<typename Hit_i> + __forceinline bool operator() (bool, Hit_i& hit_i) const + { + hit_i.finalize(); + + Scene* scene MAYBE_UNUSED = context->scene; + Geometry* geometry MAYBE_UNUSED = scene->get(geomID); + + /* ray mask test */ +#if defined(EMBREE_RAY_MASK) + if ((geometry->mask & ray.mask) == 0) + return false; +#endif + + const Vec3fa Ng = hit_i.Ng(); + const Vec2f uv = hit_i.uv(); + + /* call intersection filter function */ +#if defined(EMBREE_FILTER_FUNCTION) + if (filter && (unlikely(context->hasContextFilter() || geometry->hasIntersectionFilter()))) + { + Hit h(context->user,geomID,primID,uv,Ng); + float old_t = ray.tfar; + ray.tfar = hit_i.t(); + bool found = runIntersectionFilter1SYCL(geometry,ray,context,h); + if (!found) { + ray.tfar = old_t; + return false; + } + } +#endif + + ray.tfar = hit_i.t(); + ray.u = uv.x; + ray.v = uv.y; + ray.Ng.x = Ng.x; + ray.Ng.y = Ng.y; + ray.Ng.z = Ng.z; + ray.geomID = geomID; + ray.primID = primID; + instance_id_stack::copy_UU(context->user, context->user->instID, ray.instID); +#if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + instance_id_stack::copy_UU(context->user, context->user->instPrimID, ray.instPrimID); +#endif + return true; + } + }; + + template<> + struct Intersect1Epilog1_HWIF<Ray> + { + Ray& ray; + sycl::private_ptr<RayQueryContext> context; + const unsigned int geomID; + const unsigned int primID; + const bool filter; + + __forceinline Intersect1Epilog1_HWIF(Ray& ray, + sycl::private_ptr<RayQueryContext> context, + const unsigned int geomID, + const unsigned int primID, + const bool filter) + : ray(ray), context(context), geomID(geomID), primID(primID), filter(filter) {} + + template<typename Hit_i> + __forceinline bool operator() (Hit_i& hit_i) const + { + hit_i.finalize(); + + Scene* scene MAYBE_UNUSED = context->scene; + Geometry* geometry MAYBE_UNUSED = scene->get(geomID); + + /* ray mask test */ +#if defined(EMBREE_RAY_MASK) + if ((geometry->mask & ray.mask) == 0) + return false; +#endif + + /* call intersection filter function */ +#if defined(EMBREE_FILTER_FUNCTION) + if (filter && (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))) + { + Hit h(context->user,geomID,primID,Vec2f(hit_i.u,hit_i.v),hit_i.Ng); + float old_t = ray.tfar; + ray.tfar = hit_i.t; + bool found = runIntersectionFilter1SYCL(geometry,ray,context,h); + if (!found) { + ray.tfar = old_t; + return false; + } + } +#endif + + ray.tfar = neg_inf; + return true; + } + + template<typename Hit_i> + __forceinline bool operator() (bool, Hit_i& hit_i) const + { + hit_i.finalize(); + + Scene* scene MAYBE_UNUSED = context->scene; + Geometry* geometry MAYBE_UNUSED = scene->get(geomID); + + /* ray mask test */ +#if defined(EMBREE_RAY_MASK) + if ((geometry->mask & ray.mask) == 0) + return false; +#endif + + /* call intersection filter function */ +#if defined(EMBREE_FILTER_FUNCTION) + if (filter && (unlikely(context->hasContextFilter() || geometry->hasOcclusionFilter()))) + { + const Vec3fa Ng = hit_i.Ng(); + const Vec2f uv = hit_i.uv(); + Hit h(context->user,geomID,primID,uv,Ng); + float old_t = ray.tfar; + ray.tfar = hit_i.t(); + bool found = runIntersectionFilter1SYCL(geometry,ray,context,h); + if (!found) { + ray.tfar = old_t; + return false; + } + } +#endif + + ray.tfar = neg_inf; + return true; + } + }; +} diff --git a/thirdparty/embree/kernels/geometry/intersector_iterators.h b/thirdparty/embree/kernels/geometry/intersector_iterators.h index 9cac1cd25c..5c6a6a7bb0 100644 --- a/thirdparty/embree/kernels/geometry/intersector_iterators.h +++ b/thirdparty/embree/kernels/geometry/intersector_iterators.h @@ -20,14 +20,15 @@ namespace embree typedef typename Intersector::Precalculations Precalculations; template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { - for (size_t i=0; i<num; i++) + for (size_t i=0; i<num; i++) { Intersector::intersect(pre,ray,context,prim[i]); + } } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { for (size_t i=0; i<num; i++) { if (Intersector::occluded(pre,ray,context,prim[i])) @@ -35,7 +36,7 @@ namespace embree } return false; } - + template<int N> static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context, const Primitive* prim, size_t num, const TravPointQuery<N> &tquery, size_t& lazy_node) { @@ -46,12 +47,12 @@ namespace embree } template<int K> - static __forceinline void intersectK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node) + static __forceinline void intersectK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, size_t& lazy_node) { } template<int K> - static __forceinline vbool<K> occludedK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node) + static __forceinline vbool<K> occludedK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, size_t& lazy_node) { return valid; } @@ -64,7 +65,7 @@ namespace embree typedef typename Intersector::Precalculations Precalculations; template<bool robust> - static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { for (size_t i=0; i<num; i++) { Intersector::intersect(valid,pre,ray,context,prim[i]); @@ -72,7 +73,7 @@ namespace embree } template<bool robust> - static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { vbool<K> valid0 = valid; for (size_t i=0; i<num; i++) { @@ -83,7 +84,7 @@ namespace embree } template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { for (size_t i=0; i<num; i++) { Intersector::intersect(pre,ray,k,context,prim[i]); @@ -91,7 +92,7 @@ namespace embree } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { for (size_t i=0; i<num; i++) { if (Intersector::occluded(pre,ray,k,context,prim[i])) @@ -109,7 +110,7 @@ namespace embree typedef typename IntersectorK::Primitive PrimitiveK; typedef typename IntersectorK::Precalculations PrecalculationsK; - static __forceinline void intersectK(const vbool<K>& valid, const Accel::Intersectors* This, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) + static __forceinline void intersectK(const vbool<K>& valid, const Accel::Intersectors* This, /* PrecalculationsK& pre, */ RayHitK<K>& ray, RayQueryContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) { PrecalculationsK pre(valid,ray); // FIXME: might cause trouble @@ -118,7 +119,7 @@ namespace embree } } - static __forceinline vbool<K> occludedK(const vbool<K>& valid, const Accel::Intersectors* This, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) + static __forceinline vbool<K> occludedK(const vbool<K>& valid, const Accel::Intersectors* This, /* PrecalculationsK& pre, */ RayK<K>& ray, RayQueryContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) { PrecalculationsK pre(valid,ray); // FIXME: might cause trouble vbool<K> valid0 = valid; @@ -129,7 +130,7 @@ namespace embree return !valid0; } - static __forceinline void intersect(const Accel::Intersectors* This, RayHitK<K>& ray, size_t k, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, RayHitK<K>& ray, size_t k, RayQueryContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) { PrecalculationsK pre(ray.tnear() <= ray.tfar,ray); // FIXME: might cause trouble for (size_t i=0; i<num; i++) { @@ -137,7 +138,7 @@ namespace embree } } - static __forceinline bool occluded(const Accel::Intersectors* This, RayK<K>& ray, size_t k, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, RayK<K>& ray, size_t k, RayQueryContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) { PrecalculationsK pre(ray.tnear() <= ray.tfar,ray); // FIXME: might cause trouble for (size_t i=0; i<num; i++) { @@ -147,7 +148,7 @@ namespace embree return false; } - static __forceinline size_t occluded(const Accel::Intersectors* This, size_t cur_mask, RayK<K>** __restrict__ inputPackets, IntersectContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) + static __forceinline size_t occluded(const Accel::Intersectors* This, size_t cur_mask, RayK<K>** __restrict__ inputPackets, RayQueryContext* context, const PrimitiveK* prim, size_t num, size_t& lazy_node) { size_t m_occluded = 0; for (size_t i=0; i<num; i++) { diff --git a/thirdparty/embree/kernels/geometry/line_intersector.h b/thirdparty/embree/kernels/geometry/line_intersector.h index 41096d8794..e3bad0a3d5 100644 --- a/thirdparty/embree/kernels/geometry/line_intersector.h +++ b/thirdparty/embree/kernels/geometry/line_intersector.h @@ -43,7 +43,7 @@ namespace embree template<typename Ray, typename Epilog> static __forceinline bool intersect(const vbool<M>& valid_i, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const LineSegments* geom, const Precalculations& pre, const Vec4vf<M>& v0i, const Vec4vf<M>& v1i, @@ -96,7 +96,7 @@ namespace embree template<typename Epilog> static __forceinline bool intersect(const vbool<M>& valid_i, RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const LineSegments* geom, const Precalculations& pre, const Vec4vf<M>& v0i, const Vec4vf<M>& v1i, diff --git a/thirdparty/embree/kernels/geometry/linei.h b/thirdparty/embree/kernels/geometry/linei.h index 3ee70ac012..3305025fc9 100644 --- a/thirdparty/embree/kernels/geometry/linei.h +++ b/thirdparty/embree/kernels/geometry/linei.h @@ -457,6 +457,9 @@ namespace embree p1 = lerp(a1,b1,vfloat4(ftime)); pL = lerp(aL,bL,vfloat4(ftime)); pR = lerp(aR,bR,vfloat4(ftime)); + + pL = select(vboolf4(leftExists), pL, Vec4vf4(inf)); + pR = select(vboolf4(rightExists), pR, Vec4vf4(inf)); } #if defined(__AVX__) @@ -647,6 +650,9 @@ namespace embree p1 = lerp(a1,b1,vfloat8(ftime)); pL = lerp(aL,bL,vfloat8(ftime)); pR = lerp(aR,bR,vfloat8(ftime)); + + pL = select(vboolf4(leftExists), pL, Vec4vf8(inf)); + pR = select(vboolf4(rightExists), pR, Vec4vf8(inf)); } template<> diff --git a/thirdparty/embree/kernels/geometry/linei_intersector.h b/thirdparty/embree/kernels/geometry/linei_intersector.h index 5992827f5b..d754cc1269 100644 --- a/thirdparty/embree/kernels/geometry/linei_intersector.h +++ b/thirdparty/embree/kernels/geometry/linei_intersector.h @@ -17,7 +17,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculations1 Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -26,7 +26,7 @@ namespace embree FlatLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -47,7 +47,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculations1 Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -56,7 +56,7 @@ namespace embree FlatLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -77,7 +77,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculationsK<K> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -86,7 +86,7 @@ namespace embree FlatLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -102,7 +102,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculationsK<K> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -111,7 +111,7 @@ namespace embree FlatLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); diff --git a/thirdparty/embree/kernels/geometry/object.h b/thirdparty/embree/kernels/geometry/object.h index 2a61829ffd..9525b97880 100644 --- a/thirdparty/embree/kernels/geometry/object.h +++ b/thirdparty/embree/kernels/geometry/object.h @@ -62,6 +62,17 @@ namespace embree } /*! fill triangle from triangle list */ + __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t i, Scene* scene, const BBox1f time_range) + { + const PrimRefMB& prim = prims[i]; i++; + const unsigned geomID = prim.geomID(); + const unsigned primID = prim.primID(); + new (this) Object(geomID, primID); + AccelSet* accel = (AccelSet*) scene->get(geomID); + return accel->linearBounds(primID,time_range); + } + + /*! fill triangle from triangle list */ __forceinline LBBox3fa fillMB(const PrimRefMB* prims, size_t& i, size_t end, Scene* scene, const BBox1f time_range) { const PrimRefMB& prim = prims[i]; i++; diff --git a/thirdparty/embree/kernels/geometry/object_intersector.h b/thirdparty/embree/kernels/geometry/object_intersector.h index e4ad01852f..b89bc1837d 100644 --- a/thirdparty/embree/kernels/geometry/object_intersector.h +++ b/thirdparty/embree/kernels/geometry/object_intersector.h @@ -22,7 +22,7 @@ namespace embree __forceinline Precalculations (const Ray& ray, const void *ptr) {} }; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) { AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID()); @@ -35,7 +35,7 @@ namespace embree accel->intersect(ray,prim.geomID(),prim.primID(),context); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& prim) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID()); /* perform ray mask test */ @@ -47,6 +47,40 @@ namespace embree accel->occluded(ray,prim.geomID(),prim.primID(),context); return ray.tfar < 0.0f; } + + static __forceinline bool intersect(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { + return occluded(pre,ray,context,prim); + } + + static __forceinline void intersect(unsigned int k, const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& prim) + { + AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID()); + + /* perform ray mask test */ +#if defined(EMBREE_RAY_MASK) + if ((ray.mask & accel->mask) == 0) + return; +#endif + + accel->intersect(k,ray,prim.geomID(),prim.primID(),context); + } + + static __forceinline bool occluded(unsigned int k, const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) + { + AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID()); + /* perform ray mask test */ +#if defined(EMBREE_RAY_MASK) + if ((ray.mask & accel->mask) == 0) + return false; +#endif + + accel->occluded(k, ray,prim.geomID(),prim.primID(),context); + return ray.tfar < 0.0f; + } + + static __forceinline bool intersect(unsigned int k, const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& prim) { + return occluded(k,pre,ray,context,prim); + } static __forceinline bool pointQuery(PointQuery* query, PointQueryContext* context, const Primitive& prim) { @@ -57,13 +91,13 @@ namespace embree } template<int K> - static __forceinline void intersectK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node) + static __forceinline void intersectK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, size_t& lazy_node) { assert(false); } template<int K> - static __forceinline vbool<K> occludedK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, size_t& lazy_node) + static __forceinline vbool<K> occludedK(const vbool<K>& valid, /* PrecalculationsK& pre, */ RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, size_t& lazy_node) { assert(false); return valid; @@ -79,7 +113,7 @@ namespace embree __forceinline Precalculations (const vbool<K>& valid, const RayK<K>& ray) {} }; - static __forceinline void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& prim) + static __forceinline void intersect(const vbool<K>& valid_i, const Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& prim) { vbool<K> valid = valid_i; AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID()); @@ -92,7 +126,7 @@ namespace embree accel->intersect(valid,ray,prim.geomID(),prim.primID(),context); } - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& prim) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, const Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& prim) { vbool<K> valid = valid_i; AccelSet* accel = (AccelSet*) context->scene->get(prim.geomID()); @@ -106,11 +140,11 @@ namespace embree return ray.tfar < 0.0f; } - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) { + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { intersect(vbool<K>(1<<int(k)),pre,ray,context,prim); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& prim) { + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& prim) { occluded(vbool<K>(1<<int(k)),pre,ray,context,prim); return ray.tfar[k] < 0.0f; } diff --git a/thirdparty/embree/kernels/geometry/pointi.h b/thirdparty/embree/kernels/geometry/pointi.h index bed04116b0..f81edb9035 100644 --- a/thirdparty/embree/kernels/geometry/pointi.h +++ b/thirdparty/embree/kernels/geometry/pointi.h @@ -267,10 +267,10 @@ namespace embree const vfloat4 a2 = vfloat4::loadu(geom->vertexPtr(primID(2), itime)); const vfloat4 a3 = vfloat4::loadu(geom->vertexPtr(primID(3), itime)); transpose(a0, a1, a2, a3, p0.x, p0.y, p0.z, p0.w); - const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime)); - const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime)); - const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime)); - const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime)); + const vfloat4 b0 = vfloat4(geom->normal((size_t)primID(0), (size_t)itime)); + const vfloat4 b1 = vfloat4(geom->normal((size_t)primID(1), (size_t)itime)); + const vfloat4 b2 = vfloat4(geom->normal((size_t)primID(2), (size_t)itime)); + const vfloat4 b3 = vfloat4(geom->normal((size_t)primID(3), (size_t)itime)); transpose(b0, b1, b2, b3, n0.x, n0.y, n0.z); } @@ -364,14 +364,14 @@ namespace embree const vfloat4 a6 = vfloat4::loadu(geom->vertexPtr(primID(6), itime)); const vfloat4 a7 = vfloat4::loadu(geom->vertexPtr(primID(7), itime)); transpose(a0, a1, a2, a3, a4, a5, a6, a7, p0.x, p0.y, p0.z, p0.w); - const vfloat4 b0 = vfloat4(geom->normal(primID(0), itime)); - const vfloat4 b1 = vfloat4(geom->normal(primID(1), itime)); - const vfloat4 b2 = vfloat4(geom->normal(primID(2), itime)); - const vfloat4 b3 = vfloat4(geom->normal(primID(3), itime)); - const vfloat4 b4 = vfloat4(geom->normal(primID(4), itime)); - const vfloat4 b5 = vfloat4(geom->normal(primID(5), itime)); - const vfloat4 b6 = vfloat4(geom->normal(primID(6), itime)); - const vfloat4 b7 = vfloat4(geom->normal(primID(7), itime)); + const vfloat4 b0 = vfloat4(geom->normal((size_t)primID(0), (size_t)itime)); + const vfloat4 b1 = vfloat4(geom->normal((size_t)primID(1), (size_t)itime)); + const vfloat4 b2 = vfloat4(geom->normal((size_t)primID(2), (size_t)itime)); + const vfloat4 b3 = vfloat4(geom->normal((size_t)primID(3), (size_t)itime)); + const vfloat4 b4 = vfloat4(geom->normal((size_t)primID(4), (size_t)itime)); + const vfloat4 b5 = vfloat4(geom->normal((size_t)primID(5), (size_t)itime)); + const vfloat4 b6 = vfloat4(geom->normal((size_t)primID(6), (size_t)itime)); + const vfloat4 b7 = vfloat4(geom->normal((size_t)primID(7), (size_t)itime)); transpose(b0, b1, b2, b3, b4, b5, b6, b7, n0.x, n0.y, n0.z); } diff --git a/thirdparty/embree/kernels/geometry/primitive.h b/thirdparty/embree/kernels/geometry/primitive.h index 608d981dd7..de25ab87ef 100644 --- a/thirdparty/embree/kernels/geometry/primitive.h +++ b/thirdparty/embree/kernels/geometry/primitive.h @@ -6,8 +6,8 @@ #include "../common/default.h" #include "../common/scene.h" #include "../../common/simd/simd.h" -#include "../common/primref.h" -#include "../common/primref_mb.h" +#include "../builders/primref.h" +#include "../builders/primref_mb.h" namespace embree { diff --git a/thirdparty/embree/kernels/geometry/primitive4.cpp b/thirdparty/embree/kernels/geometry/primitive4.cpp index 9c953c5d35..924e78bbf1 100644 --- a/thirdparty/embree/kernels/geometry/primitive4.cpp +++ b/thirdparty/embree/kernels/geometry/primitive4.cpp @@ -15,6 +15,7 @@ #include "subdivpatch1.h" #include "object.h" #include "instance.h" +#include "instance_array.h" #include "subgrid.h" namespace embree @@ -335,6 +336,26 @@ namespace embree InstancePrimitive::Type InstancePrimitive::type; + /********************** InstanceArray4 **************************/ + + const char* InstanceArrayPrimitive::Type::name () const { + return "instance_array"; + } + + size_t InstanceArrayPrimitive::Type::sizeActive(const char* This) const { + return 1; + } + + size_t InstanceArrayPrimitive::Type::sizeTotal(const char* This) const { + return 1; + } + + size_t InstanceArrayPrimitive::Type::getBytes(const char* This) const { + return sizeof(InstanceArrayPrimitive); + } + + InstanceArrayPrimitive::Type InstanceArrayPrimitive::type; + /********************** SubGrid **************************/ const char* SubGrid::Type::name () const { diff --git a/thirdparty/embree/kernels/geometry/quad_intersector_moeller.h b/thirdparty/embree/kernels/geometry/quad_intersector_moeller.h index 3abc9d6f70..2c574e4e47 100644 --- a/thirdparty/embree/kernels/geometry/quad_intersector_moeller.h +++ b/thirdparty/embree/kernels/geometry/quad_intersector_moeller.h @@ -122,7 +122,7 @@ namespace embree __forceinline QuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {} - __forceinline void intersect(RayHit& ray, IntersectContext* context, + __forceinline void intersect(RayHit& ray, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomID, const vuint<M>& primID) const { @@ -144,7 +144,7 @@ namespace embree } } - __forceinline bool occluded(Ray& ray, IntersectContext* context, + __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomID, const vuint<M>& primID) const { @@ -215,14 +215,14 @@ namespace embree return false; } - __forceinline bool intersect(RayHit& ray, IntersectContext* context, + __forceinline bool intersect(RayHit& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const vuint4& geomID, const vuint4& primID) const { return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID))); } - __forceinline bool occluded(Ray& ray, IntersectContext* context, + __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const vuint4& geomID, const vuint4& primID) const { @@ -394,7 +394,7 @@ namespace embree __forceinline QuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray) : QuadMIntersectorKMoellerTrumboreBase<M,K,filter>(valid,ray) {} - __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context, + __forceinline void intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomID, const vuint<M>& primID) const { @@ -403,7 +403,7 @@ namespace embree MoellerTrumboreIntersector1KTriangleM::intersect1<M,K>(ray,k,v2,v3,v1,vbool<M>(true ),epilog); } - __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomID, const vuint<M>& primID) const { @@ -440,14 +440,14 @@ namespace embree return MoellerTrumboreIntersector1KTriangleM::intersect1<8,K>(ray,k,vtx0,vtx1,vtx2,flags,epilog); } - __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const vuint4& geomID, const vuint4& primID) const { return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID))); } - __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const vuint4& geomID, const vuint4& primID) const { diff --git a/thirdparty/embree/kernels/geometry/quad_intersector_pluecker.h b/thirdparty/embree/kernels/geometry/quad_intersector_pluecker.h index 9873ff76ac..69d6881080 100644 --- a/thirdparty/embree/kernels/geometry/quad_intersector_pluecker.h +++ b/thirdparty/embree/kernels/geometry/quad_intersector_pluecker.h @@ -171,7 +171,7 @@ namespace embree __forceinline QuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {} - __forceinline void intersect(RayHit& ray, IntersectContext* context, + __forceinline void intersect(RayHit& ray, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomID, const vuint<M>& primID) const { @@ -180,7 +180,7 @@ namespace embree PlueckerIntersectorTriangle1::intersect<M>(ray,v2,v3,v1,vbool<M>(true),epilog); } - __forceinline bool occluded(Ray& ray, IntersectContext* context, + __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomID, const vuint<M>& primID) const { @@ -216,13 +216,13 @@ namespace embree return PlueckerIntersectorTriangle1::intersect<8>(ray,vtx0,vtx1,vtx2,flags,epilog); } - __forceinline bool intersect(RayHit& ray, IntersectContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, + __forceinline bool intersect(RayHit& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const vuint4& geomID, const vuint4& primID) const { return intersect(ray,v0,v1,v2,v3,Intersect1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID))); } - __forceinline bool occluded(Ray& ray, IntersectContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, + __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const vuint4& geomID, const vuint4& primID) const { return intersect(ray,v0,v1,v2,v3,Occluded1EpilogM<8,filter>(ray,context,vuint8(geomID),vuint8(primID))); @@ -374,7 +374,7 @@ namespace embree __forceinline QuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray) : QuadMIntersectorKPlueckerBase<M,K,filter>(valid,ray) {} - __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context, + __forceinline void intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomID, const vuint<M>& primID) const { @@ -383,7 +383,7 @@ namespace embree PlueckerIntersector1KTriangleM::intersect1<M,K>(ray,k,v2,v3,v1,vbool<M>(true ),epilog); } - __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const vuint<M>& geomID, const vuint<M>& primID) const { @@ -418,14 +418,14 @@ namespace embree return PlueckerIntersector1KTriangleM::intersect1<8,K>(ray,k,vtx0,vtx1,vtx2,flags,epilog); } - __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const vuint4& geomID, const vuint4& primID) const { return intersect1(ray,k,v0,v1,v2,v3,Intersect1KEpilogM<8,K,filter>(ray,k,context,vuint8(geomID),vuint8(primID))); } - __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const vuint4& geomID, const vuint4& primID) const { diff --git a/thirdparty/embree/kernels/geometry/quadi_intersector.h b/thirdparty/embree/kernels/geometry/quadi_intersector.h index 20a98c3406..96fc77b42d 100644 --- a/thirdparty/embree/kernels/geometry/quadi_intersector.h +++ b/thirdparty/embree/kernels/geometry/quadi_intersector.h @@ -19,7 +19,7 @@ namespace embree typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations; /*! Intersect a ray with the M quads and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& quad) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene); @@ -27,7 +27,7 @@ namespace embree } /*! Test if the ray is occluded by one of M quads. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& quad) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene); @@ -48,7 +48,7 @@ namespace embree typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const QuadMi<M>& quad) { Scene* scene = context->scene; for (size_t i=0; i<QuadMi<M>::max_size(); i++) @@ -64,7 +64,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const QuadMi<M>& quad) { Scene* scene = context->scene; vbool<K> valid0 = valid_i; @@ -83,7 +83,7 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const QuadMi<M>& quad) { STAT3(normal.trav_prims,1,1,1); Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene); @@ -91,7 +91,7 @@ namespace embree } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const QuadMi<M>& quad) { STAT3(shadow.trav_prims,1,1,1); Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene); @@ -107,7 +107,7 @@ namespace embree typedef QuadMIntersector1Pluecker<M,filter> Precalculations; /*! Intersect a ray with the M quads and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& quad) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene); @@ -115,7 +115,7 @@ namespace embree } /*! Test if the ray is occluded by one of M quads. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& quad) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene); @@ -136,7 +136,7 @@ namespace embree typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const QuadMi<M>& quad) { Scene* scene = context->scene; for (size_t i=0; i<QuadMi<M>::max_size(); i++) @@ -152,7 +152,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const QuadMi<M>& quad) { Scene* scene = context->scene; vbool<K> valid0 = valid_i; @@ -171,7 +171,7 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const QuadMi<M>& quad) { STAT3(normal.trav_prims,1,1,1); Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene); @@ -179,7 +179,7 @@ namespace embree } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const QuadMi<M>& quad) { STAT3(shadow.trav_prims,1,1,1); Vec3vf4 v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene); @@ -195,7 +195,7 @@ namespace embree typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations; /*! Intersect a ray with the M quads and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& quad) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()); @@ -203,7 +203,7 @@ namespace embree } /*! Test if the ray is occluded by one of M quads. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& quad) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()); @@ -224,7 +224,7 @@ namespace embree typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations; /*! Intersects K rays with M quads. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const QuadMi<M>& quad) { for (size_t i=0; i<QuadMi<M>::max_size(); i++) { @@ -236,7 +236,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M quads. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const QuadMi<M>& quad) { vbool<K> valid0 = valid_i; for (size_t i=0; i<QuadMi<M>::max_size(); i++) @@ -251,7 +251,7 @@ namespace embree } /*! Intersect a ray with M quads and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const QuadMi<M>& quad) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]); @@ -259,7 +259,7 @@ namespace embree } /*! Test if the ray is occluded by one of the M quads. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const QuadMi<M>& quad) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]); @@ -275,7 +275,7 @@ namespace embree typedef QuadMIntersector1Pluecker<M,filter> Precalculations; /*! Intersect a ray with the M quads and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& quad) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()); @@ -283,7 +283,7 @@ namespace embree } /*! Test if the ray is occluded by one of M quads. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& quad) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()); @@ -304,7 +304,7 @@ namespace embree typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations; /*! Intersects K rays with M quads. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const QuadMi<M>& quad) { for (size_t i=0; i<QuadMi<M>::max_size(); i++) { @@ -316,7 +316,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M quads. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const QuadMi<M>& quad) { vbool<K> valid0 = valid_i; for (size_t i=0; i<QuadMi<M>::max_size(); i++) @@ -331,7 +331,7 @@ namespace embree } /*! Intersect a ray with M quads and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const QuadMi<M>& quad) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]); @@ -339,7 +339,7 @@ namespace embree } /*! Test if the ray is occluded by one of the M quads. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMi<M>& quad) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const QuadMi<M>& quad) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2,v3; quad.gather(v0,v1,v2,v3,context->scene,ray.time()[k]); diff --git a/thirdparty/embree/kernels/geometry/quadv_intersector.h b/thirdparty/embree/kernels/geometry/quadv_intersector.h index 9b28e05614..9eea8275f7 100644 --- a/thirdparty/embree/kernels/geometry/quadv_intersector.h +++ b/thirdparty/embree/kernels/geometry/quadv_intersector.h @@ -19,14 +19,14 @@ namespace embree typedef QuadMIntersector1MoellerTrumbore<M,filter> Precalculations; /*! Intersect a ray with the M quads and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& quad) { STAT3(normal.trav_prims,1,1,1); pre.intersect(ray,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID()); } /*! Test if the ray is occluded by one of M quads. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& quad) { STAT3(shadow.trav_prims,1,1,1); return pre.occluded(ray,context, quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID()); @@ -46,7 +46,7 @@ namespace embree typedef QuadMIntersectorKMoellerTrumbore<M,K,filter> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMv<M>& quad) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const QuadMv<M>& quad) { for (size_t i=0; i<QuadMv<M>::max_size(); i++) { @@ -61,7 +61,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMv<M>& quad) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const QuadMv<M>& quad) { vbool<K> valid0 = valid_i; @@ -80,14 +80,14 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const QuadMv<M>& quad) { STAT3(normal.trav_prims,1,1,1); pre.intersect1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID()); } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const QuadMv<M>& quad) { STAT3(shadow.trav_prims,1,1,1); return pre.occluded1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID()); @@ -102,14 +102,14 @@ namespace embree typedef QuadMIntersector1Pluecker<M,filter> Precalculations; /*! Intersect a ray with the M quads and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& quad) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& quad) { STAT3(normal.trav_prims,1,1,1); pre.intersect(ray,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID()); } /*! Test if the ray is occluded by one of M quads. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& quad) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& quad) { STAT3(shadow.trav_prims,1,1,1); return pre.occluded(ray,context, quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID()); @@ -129,7 +129,7 @@ namespace embree typedef QuadMIntersectorKPluecker<M,K,filter> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const QuadMv<M>& quad) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const QuadMv<M>& quad) { for (size_t i=0; i<QuadMv<M>::max_size(); i++) { @@ -144,7 +144,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const QuadMv<M>& quad) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const QuadMv<M>& quad) { vbool<K> valid0 = valid_i; @@ -163,14 +163,14 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const QuadMv<M>& quad) { STAT3(normal.trav_prims,1,1,1); pre.intersect1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID()); } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const QuadMv<M>& quad) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const QuadMv<M>& quad) { STAT3(shadow.trav_prims,1,1,1); return pre.occluded1(ray,k,context,quad.v0,quad.v1,quad.v2,quad.v3,quad.geomID(),quad.primID()); diff --git a/thirdparty/embree/kernels/geometry/roundline_intersector.h b/thirdparty/embree/kernels/geometry/roundline_intersector.h index 764ff93fec..a83dd72a7f 100644 --- a/thirdparty/embree/kernels/geometry/roundline_intersector.h +++ b/thirdparty/embree/kernels/geometry/roundline_intersector.h @@ -661,7 +661,7 @@ namespace embree template<typename Ray, typename Epilog> static __forceinline bool intersect(const vbool<M>& valid_i, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const LineSegments* geom, const Precalculations& pre, const Vec4vf<M>& v0i, const Vec4vf<M>& v1i, @@ -694,7 +694,7 @@ namespace embree template<typename Epilog> static __forceinline bool intersect(const vbool<M>& valid_i, RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const LineSegments* geom, const Precalculations& pre, const Vec4vf<M>& v0i, const Vec4vf<M>& v1i, diff --git a/thirdparty/embree/kernels/geometry/roundlinei_intersector.h b/thirdparty/embree/kernels/geometry/roundlinei_intersector.h index 29061d6475..02a5d63a3d 100644 --- a/thirdparty/embree/kernels/geometry/roundlinei_intersector.h +++ b/thirdparty/embree/kernels/geometry/roundlinei_intersector.h @@ -16,7 +16,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculations1 Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -25,7 +25,7 @@ namespace embree RoundLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -46,7 +46,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculations1 Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -55,7 +55,7 @@ namespace embree RoundLinearCurveIntersector1<M>::intersect(valid,ray,context,geom,pre,v0,v1,vL,vR,Intersect1EpilogM<M,filter>(ray,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -76,7 +76,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculationsK<K> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -85,7 +85,7 @@ namespace embree RoundLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -101,7 +101,7 @@ namespace embree typedef LineMi<M> Primitive; typedef CurvePrecalculationsK<K> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline void intersect(const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(normal.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); @@ -110,7 +110,7 @@ namespace embree RoundLinearCurveIntersectorK<M,K>::intersect(valid,ray,k,context,geom,pre,v0,v1,vL,vR,Intersect1KEpilogM<M,K,filter>(ray,k,context,line.geomID(),line.primID())); } - static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& line) + static __forceinline bool occluded(const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& line) { STAT3(shadow.trav_prims,1,1,1); const LineSegments* geom = context->scene->get<LineSegments>(line.geomID()); diff --git a/thirdparty/embree/kernels/geometry/sphere_intersector.h b/thirdparty/embree/kernels/geometry/sphere_intersector.h index 2670f9762d..ba242a88b6 100644 --- a/thirdparty/embree/kernels/geometry/sphere_intersector.h +++ b/thirdparty/embree/kernels/geometry/sphere_intersector.h @@ -24,24 +24,60 @@ namespace embree __forceinline Vec2f uv(const size_t i) const { return Vec2f(0.0f, 0.0f); } + __forceinline Vec2vf<M> uv() const { + return Vec2vf<M>(0.0f, 0.0f); + } __forceinline float t(const size_t i) const { return vt[i]; } + __forceinline vfloat<M> t() const { + return vt; + } __forceinline Vec3fa Ng(const size_t i) const { return Vec3fa(vNg.x[i], vNg.y[i], vNg.z[i]); } + __forceinline Vec3vf<M> Ng() const { + return vNg; + } public: vfloat<M> vt; Vec3vf<M> vNg; }; + template<> + struct SphereIntersectorHitM<1> + { + __forceinline SphereIntersectorHitM() {} + + __forceinline SphereIntersectorHitM(const float& t, const Vec3f& Ng) + : vt(t), vNg(Ng) {} + + __forceinline void finalize() {} + + __forceinline Vec2f uv() const { + return Vec2f(0.0f, 0.0f); + } + + __forceinline float t() const { + return vt; + } + + __forceinline Vec3f Ng() const { + return vNg; + } + + public: + float vt; + Vec3f vNg; + }; + template<int M> struct SphereIntersector1 { typedef CurvePrecalculations1 Precalculations; - template<typename Epilog> + template<typename Ray, typename Epilog> static __forceinline bool intersect( const vbool<M>& valid_i, Ray& ray, const Precalculations& pre, const Vec4vf<M>& v0, const Epilog& epilog) @@ -68,10 +104,15 @@ namespace embree const vfloat<M> t_back = projC0 + td; const vbool<M> valid_front = valid & (ray.tnear() <= t_front) & (t_front <= ray.tfar); - const vbool<M> valid_back = valid & (ray.tnear() <= t_back ) & (t_back <= ray.tfar); /* check if there is a first hit */ +#if defined (EMBREE_BACKFACE_CULLING_SPHERES) + /* check if there is a first hit */ + const vbool<M> valid_first = valid_front; +#else + const vbool<M> valid_back = valid & (ray.tnear() <= t_back ) & (t_back <= ray.tfar); const vbool<M> valid_first = valid_front | valid_back; +#endif if (unlikely(none(valid_first))) return false; @@ -84,7 +125,10 @@ namespace embree /* invoke intersection filter for first hit */ const bool is_hit_first = epilog(valid_first, hit); - + +#if defined (EMBREE_BACKFACE_CULLING_SPHERES) + return is_hit_first; +#else /* check for possible second hits before potentially accepted hit */ const vfloat<M> t_second = t_back; const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar); @@ -95,13 +139,13 @@ namespace embree const Vec3vf<M> Ng_second = td_back * ray_dir - perp; hit = SphereIntersectorHitM<M> (t_second, Ng_second); const bool is_hit_second = epilog(valid_second, hit); - return is_hit_first | is_hit_second; +#endif } template<typename Epilog> static __forceinline bool intersect( - const vbool<M>& valid_i, Ray& ray, IntersectContext* context, const Points* geom, + const vbool<M>& valid_i, Ray& ray, RayQueryContext* context, const Points* geom, const Precalculations& pre, const Vec4vf<M>& v0i, const Epilog& epilog) { const Vec3vf<M> ray_org(ray.org.x, ray.org.y, ray.org.z); @@ -118,7 +162,7 @@ namespace embree template<typename Epilog> static __forceinline bool intersect(const vbool<M>& valid_i, RayK<K>& ray, size_t k, - IntersectContext* context, + RayQueryContext* context, const Points* geom, const Precalculations& pre, const Vec4vf<M>& v0i, @@ -148,10 +192,14 @@ namespace embree const vfloat<M> t_back = projC0 + td; const vbool<M> valid_front = valid & (ray.tnear()[k] <= t_front) & (t_front <= ray.tfar[k]); - const vbool<M> valid_back = valid & (ray.tnear()[k] <= t_back ) & (t_back <= ray.tfar[k]); /* check if there is a first hit */ +#if defined (EMBREE_BACKFACE_CULLING_SPHERES) + const vbool<M> valid_first = valid_front; +#else + const vbool<M> valid_back = valid & (ray.tnear()[k] <= t_back ) & (t_back <= ray.tfar[k]); const vbool<M> valid_first = valid_front | valid_back; +#endif if (unlikely(none(valid_first))) return false; @@ -164,7 +212,10 @@ namespace embree /* invoke intersection filter for first hit */ const bool is_hit_first = epilog(valid_first, hit); - + +#if defined (EMBREE_BACKFACE_CULLING_SPHERES) + return is_hit_first; +#else /* check for possible second hits before potentially accepted hit */ const vfloat<M> t_second = t_back; const vbool<M> valid_second = valid_front & valid_back & (t_second <= ray.tfar[k]); @@ -177,6 +228,7 @@ namespace embree const bool is_hit_second = epilog(valid_second, hit); return is_hit_first | is_hit_second; +#endif } }; } // namespace isa diff --git a/thirdparty/embree/kernels/geometry/spherei_intersector.h b/thirdparty/embree/kernels/geometry/spherei_intersector.h index 7a0b428117..7072ea81e8 100644 --- a/thirdparty/embree/kernels/geometry/spherei_intersector.h +++ b/thirdparty/embree/kernels/geometry/spherei_intersector.h @@ -19,7 +19,7 @@ namespace embree static __forceinline void intersect(const Precalculations& pre, RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& sphere) { STAT3(normal.trav_prims, 1, 1, 1); @@ -32,7 +32,7 @@ namespace embree static __forceinline bool occluded(const Precalculations& pre, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& sphere) { STAT3(shadow.trav_prims, 1, 1, 1); @@ -59,7 +59,7 @@ namespace embree static __forceinline void intersect(const Precalculations& pre, RayHit& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& sphere) { STAT3(normal.trav_prims, 1, 1, 1); @@ -72,7 +72,7 @@ namespace embree static __forceinline bool occluded(const Precalculations& pre, Ray& ray, - IntersectContext* context, + RayQueryContext* context, const Primitive& sphere) { STAT3(shadow.trav_prims, 1, 1, 1); @@ -98,7 +98,7 @@ namespace embree typedef CurvePrecalculationsK<K> Precalculations; static __forceinline void intersect( - const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere) + const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& sphere) { STAT3(normal.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(sphere.geomID()); @@ -110,7 +110,7 @@ namespace embree } static __forceinline bool occluded( - const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere) + const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& sphere) { STAT3(shadow.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(sphere.geomID()); @@ -129,7 +129,7 @@ namespace embree typedef CurvePrecalculationsK<K> Precalculations; static __forceinline void intersect( - const Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere) + const Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& sphere) { STAT3(normal.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(sphere.geomID()); @@ -141,7 +141,7 @@ namespace embree } static __forceinline bool occluded( - const Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& sphere) + const Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& sphere) { STAT3(shadow.trav_prims, 1, 1, 1); const Points* geom = context->scene->get<Points>(sphere.geomID()); diff --git a/thirdparty/embree/kernels/geometry/subdivpatch1_intersector.h b/thirdparty/embree/kernels/geometry/subdivpatch1_intersector.h index b4b15a1210..cf17127169 100644 --- a/thirdparty/embree/kernels/geometry/subdivpatch1_intersector.h +++ b/thirdparty/embree/kernels/geometry/subdivpatch1_intersector.h @@ -35,7 +35,7 @@ namespace embree typedef GridSOA Primitive; typedef SubdivPatch1Precalculations<GridSOAIntersector1::Precalculations> Precalculations; - static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline bool processLazyNode(Precalculations& pre, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { lazy_node = prim->root(0); pre.grid = (Primitive*)prim; @@ -44,27 +44,27 @@ namespace embree /*! Intersect a ray with the primitive. */ template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) GridSOAIntersector1::intersect(pre,ray,context,prim,lazy_node); else processLazyNode(pre,context,prim,lazy_node); } template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { intersect(This,pre,ray,context,prim,ty,tray,lazy_node); } /*! Test if the ray is occluded by the primitive */ template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) return GridSOAIntersector1::occluded(pre,ray,context,prim,lazy_node); else return processLazyNode(pre,context,prim,lazy_node); } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { return occluded(This,pre,ray,context,prim,ty,tray,lazy_node); } @@ -88,7 +88,7 @@ namespace embree typedef SubdivPatch1 Primitive; typedef GridSOAMBIntersector1::Precalculations Precalculations; - static __forceinline bool processLazyNode(Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim_i, size_t& lazy_node) + static __forceinline bool processLazyNode(Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim_i, size_t& lazy_node) { Primitive* prim = (Primitive*) prim_i; GridSOA* grid = nullptr; @@ -101,27 +101,27 @@ namespace embree /*! Intersect a ray with the primitive. */ template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) GridSOAMBIntersector1::intersect(pre,ray,context,prim,lazy_node); else processLazyNode(pre,ray,context,prim,lazy_node); } template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { intersect(This,pre,ray,context,prim,ty,tray,lazy_node); } /*! Test if the ray is occluded by the primitive */ template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) return GridSOAMBIntersector1::occluded(pre,ray,context,prim,lazy_node); else return processLazyNode(pre,ray,context,prim,lazy_node); } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, size_t ty0, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { return occluded(This,pre,ray,context,prim,ty,tray,lazy_node); } @@ -145,7 +145,7 @@ namespace embree typedef GridSOA Primitive; typedef SubdivPatch1PrecalculationsK<K,typename GridSOAIntersectorK<K>::Precalculations> Precalculations; - static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim, size_t& lazy_node) + static __forceinline bool processLazyNode(Precalculations& pre, RayQueryContext* context, const Primitive* prim, size_t& lazy_node) { lazy_node = prim->root(0); pre.grid = (Primitive*)prim; @@ -153,28 +153,28 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) GridSOAIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node); else processLazyNode(pre,context,prim,lazy_node); } template<bool robust> - static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) return GridSOAIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node); else return processLazyNode(pre,context,prim,lazy_node); } template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) GridSOAIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node); else processLazyNode(pre,context,prim,lazy_node); } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) return GridSOAIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node); else return processLazyNode(pre,context,prim,lazy_node); @@ -192,7 +192,7 @@ namespace embree //typedef GridSOAMBIntersectorK<K>::Precalculations Precalculations; typedef SubdivPatch1PrecalculationsK<K,typename GridSOAMBIntersectorK<K>::Precalculations> Precalculations; - static __forceinline bool processLazyNode(Precalculations& pre, IntersectContext* context, const Primitive* prim_i, size_t& lazy_node) + static __forceinline bool processLazyNode(Precalculations& pre, RayQueryContext* context, const Primitive* prim_i, size_t& lazy_node) { Primitive* prim = (Primitive*) prim_i; GridSOA* grid = (GridSOA*) prim->root_ref.get(); @@ -202,28 +202,28 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) GridSOAMBIntersectorK<K>::intersect(valid,pre,ray,context,prim,lazy_node); else processLazyNode(pre,context,prim,lazy_node); } template<bool robust> - static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRayK<K, robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) return GridSOAMBIntersectorK<K>::occluded(valid,pre,ray,context,prim,lazy_node); else return processLazyNode(pre,context,prim,lazy_node); } template<int N, bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) GridSOAMBIntersectorK<K>::intersect(pre,ray,k,context,prim,lazy_node); else processLazyNode(pre,context,prim,lazy_node); } template<int N, bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t ty, const TravRay<N,robust> &tray, size_t& lazy_node) { if (likely(ty == 0)) return GridSOAMBIntersectorK<K>::occluded(pre,ray,k,context,prim,lazy_node); else return processLazyNode(pre,context,prim,lazy_node); diff --git a/thirdparty/embree/kernels/geometry/subgrid.h b/thirdparty/embree/kernels/geometry/subgrid.h index ce54421cab..f57e55db78 100644 --- a/thirdparty/embree/kernels/geometry/subgrid.h +++ b/thirdparty/embree/kernels/geometry/subgrid.h @@ -283,7 +283,7 @@ namespace embree friend embree_ostream operator<<(embree_ostream cout, const SubGrid& sg) { - return cout << "SubGrid " << " ( x " << sg.x() << ", y = " << sg.y() << ", geomID = " << sg.geomID() << ", primID = " << sg.primID() << " )"; + return cout << "SubGrid " << " ( x = " << sg.x() << ", y = " << sg.y() << ", geomID = " << sg.geomID() << ", primID = " << sg.primID() << ", invalid3x3X() " << (int)sg.invalid3x3X() << ", invalid3x3Y() " << (int)sg.invalid3x3Y(); } __forceinline unsigned int geomID() const { return _geomID; } @@ -305,9 +305,10 @@ namespace embree __forceinline SubGridID() {} __forceinline SubGridID(const unsigned int x, const unsigned int y, const unsigned int primID) : - x(x), y(y), primID(primID) {} + x(x), y(y), primID(primID) {} + }; - + /* QuantizedBaseNode as large subgrid leaf */ template<int N> struct SubGridQBVHN @@ -403,6 +404,9 @@ namespace embree typedef SubGridQBVHN<8> SubGridQBVH8; + + + /* QuantizedBaseNode as large subgrid leaf */ template<int N> struct SubGridMBQBVHN @@ -513,5 +517,4 @@ namespace embree } }; - } diff --git a/thirdparty/embree/kernels/geometry/subgrid_intersector.h b/thirdparty/embree/kernels/geometry/subgrid_intersector.h index e241073812..561d3d43f2 100644 --- a/thirdparty/embree/kernels/geometry/subgrid_intersector.h +++ b/thirdparty/embree/kernels/geometry/subgrid_intersector.h @@ -23,7 +23,7 @@ namespace embree typedef SubGridQBVHN<N> Primitive; typedef SubGridQuadMIntersector1MoellerTrumbore<4,filter> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const SubGrid& subgrid) { STAT3(normal.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -33,7 +33,7 @@ namespace embree pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const SubGrid& subgrid) { STAT3(shadow.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -54,7 +54,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; @@ -76,7 +76,7 @@ namespace embree } } template<bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; @@ -126,7 +126,7 @@ namespace embree typedef SubGridQBVHN<N> Primitive; typedef SubGridQuadMIntersector1Pluecker<4,filter> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const SubGrid& subgrid) { STAT3(normal.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -136,7 +136,7 @@ namespace embree pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const SubGrid& subgrid) { STAT3(shadow.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -156,7 +156,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; @@ -179,7 +179,7 @@ namespace embree } template<bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; @@ -231,7 +231,7 @@ namespace embree typedef SubGridQBVHN<N> Primitive; typedef SubGridQuadMIntersectorKMoellerTrumbore<4,K,filter> Precalculations; - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const SubGrid& subgrid) { Vec3fa vtx[16]; const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -249,7 +249,7 @@ namespace embree } } - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const SubGrid& subgrid) { vbool<K> valid0 = valid_i; Vec3fa vtx[16]; @@ -270,7 +270,7 @@ namespace embree return !valid0; } - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const SubGrid& subgrid) { STAT3(normal.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -280,7 +280,7 @@ namespace embree pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const SubGrid& subgrid) { STAT3(shadow.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -290,7 +290,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK; for (size_t j=0;j<num;j++) @@ -307,7 +307,7 @@ namespace embree } template<bool robust> - static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK; vbool<K> valid0 = valid; @@ -327,7 +327,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; @@ -347,7 +347,7 @@ namespace embree } template<bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; @@ -375,7 +375,7 @@ namespace embree typedef SubGridQBVHN<N> Primitive; typedef SubGridQuadMIntersectorKPluecker<4,K,filter> Precalculations; - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const SubGrid& subgrid) { Vec3fa vtx[16]; const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -393,7 +393,7 @@ namespace embree } } - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const SubGrid& subgrid) { vbool<K> valid0 = valid_i; Vec3fa vtx[16]; @@ -414,7 +414,7 @@ namespace embree return !valid0; } - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const SubGrid& subgrid) { STAT3(normal.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -424,7 +424,7 @@ namespace embree pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const SubGrid& subgrid) { STAT3(shadow.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -434,7 +434,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK; for (size_t j=0;j<num;j++) @@ -451,7 +451,7 @@ namespace embree } template<bool robust> - static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK; vbool<K> valid0 = valid; @@ -471,7 +471,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; @@ -491,7 +491,7 @@ namespace embree } template<bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; diff --git a/thirdparty/embree/kernels/geometry/subgrid_intersector_moeller.h b/thirdparty/embree/kernels/geometry/subgrid_intersector_moeller.h index 64937d34fe..2666847333 100644 --- a/thirdparty/embree/kernels/geometry/subgrid_intersector_moeller.h +++ b/thirdparty/embree/kernels/geometry/subgrid_intersector_moeller.h @@ -39,7 +39,7 @@ namespace embree __forceinline SubGridQuadMIntersector1MoellerTrumbore(const Ray& ray, const void* ptr) {} - __forceinline void intersect(RayHit& ray, IntersectContext* context, + __forceinline void intersect(RayHit& ray, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid& subgrid) const { @@ -65,7 +65,7 @@ namespace embree } } - __forceinline bool occluded(Ray& ray, IntersectContext* context, + __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid& subgrid) const { @@ -135,14 +135,14 @@ namespace embree return false; } - __forceinline bool intersect(RayHit& ray, IntersectContext* context, + __forceinline bool intersect(RayHit& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid) const { return intersect(ray,v0,v1,v2,v3,g,subgrid,Intersect1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID())); } - __forceinline bool occluded(Ray& ray, IntersectContext* context, + __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid) const { @@ -270,7 +270,7 @@ namespace embree __forceinline SubGridQuadMIntersectorKMoellerTrumbore(const vbool<K>& valid, const RayK<K>& ray) : SubGridQuadMIntersectorKMoellerTrumboreBase<M,K,filter>(valid,ray) {} - __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context, + __forceinline void intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const { UVIdentity<M> mapUV; @@ -294,7 +294,7 @@ namespace embree } } - __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const { UVIdentity<M> mapUV; @@ -361,13 +361,13 @@ namespace embree return false; } - __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const { return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Intersect1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID())); } - __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const { return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Occluded1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID())); diff --git a/thirdparty/embree/kernels/geometry/subgrid_intersector_pluecker.h b/thirdparty/embree/kernels/geometry/subgrid_intersector_pluecker.h index 5ded56e1f7..4919f927ae 100644 --- a/thirdparty/embree/kernels/geometry/subgrid_intersector_pluecker.h +++ b/thirdparty/embree/kernels/geometry/subgrid_intersector_pluecker.h @@ -36,7 +36,7 @@ namespace embree __forceinline SubGridQuadMIntersector1Pluecker(const Ray& ray, const void* ptr) {} - __forceinline void intersect(RayHit& ray, IntersectContext* context, + __forceinline void intersect(RayHit& ray, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid& subgrid) const { @@ -63,7 +63,7 @@ namespace embree } } - __forceinline bool occluded(Ray& ray, IntersectContext* context, + __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid& subgrid) const { @@ -134,14 +134,14 @@ namespace embree return false; } - __forceinline bool intersect(RayHit& ray, IntersectContext* context, + __forceinline bool intersect(RayHit& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid) const { return intersect(ray,v0,v1,v2,v3,g,subgrid,Intersect1EpilogMU<8,filter>(ray,context,subgrid.geomID(),subgrid.primID())); } - __forceinline bool occluded(Ray& ray, IntersectContext* context, + __forceinline bool occluded(Ray& ray, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid& subgrid) const { @@ -255,7 +255,7 @@ namespace embree __forceinline SubGridQuadMIntersectorKPluecker(const vbool<K>& valid, const RayK<K>& ray) : SubGridQuadMIntersectorKPlueckerBase<M,K,filter>(valid,ray) {} - __forceinline void intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context, + __forceinline void intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const { UVIdentity<M> mapUV; @@ -280,7 +280,7 @@ namespace embree } } - __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf<M>& v0, const Vec3vf<M>& v1, const Vec3vf<M>& v2, const Vec3vf<M>& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const { UVIdentity<M> mapUV; @@ -348,13 +348,13 @@ namespace embree return false; } - __forceinline bool intersect1(RayHitK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool intersect1(RayHitK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const { return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Intersect1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID())); } - __forceinline bool occluded1(RayK<K>& ray, size_t k, IntersectContext* context, + __forceinline bool occluded1(RayK<K>& ray, size_t k, RayQueryContext* context, const Vec3vf4& v0, const Vec3vf4& v1, const Vec3vf4& v2, const Vec3vf4& v3, const GridMesh::Grid &g, const SubGrid &subgrid) const { return intersect1(ray,k,v0,v1,v2,v3,g,subgrid,Occluded1KEpilogMU<8,K,filter>(ray,k,context,subgrid.geomID(),subgrid.primID())); diff --git a/thirdparty/embree/kernels/geometry/subgrid_mb_intersector.h b/thirdparty/embree/kernels/geometry/subgrid_mb_intersector.h index 473d656e24..0986eea134 100644 --- a/thirdparty/embree/kernels/geometry/subgrid_mb_intersector.h +++ b/thirdparty/embree/kernels/geometry/subgrid_mb_intersector.h @@ -15,7 +15,7 @@ namespace embree typedef SubGridMBQBVHN<N> Primitive; typedef SubGridQuadMIntersector1Pluecker<4,filter> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const SubGrid& subgrid) { STAT3(normal.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -27,7 +27,7 @@ namespace embree pre.intersect(ray,context,v0,v1,v2,v3,g,subgrid); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const SubGrid& subgrid) { STAT3(shadow.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -46,7 +46,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; for (size_t i=0;i<num;i++) @@ -69,7 +69,7 @@ namespace embree } template<bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; for (size_t i=0;i<num;i++) @@ -102,7 +102,7 @@ namespace embree typedef SubGridMBQBVHN<N> Primitive; typedef SubGridQuadMIntersectorKPluecker<4,K,filter> Precalculations; - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const SubGrid& subgrid) { size_t m_valid = movemask(valid_i); while(m_valid) @@ -112,7 +112,7 @@ namespace embree } } - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const SubGrid& subgrid) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const SubGrid& subgrid) { vbool<K> valid0 = valid_i; size_t m_valid = movemask(valid_i); @@ -125,7 +125,7 @@ namespace embree return !valid0; } - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const SubGrid& subgrid) { STAT3(normal.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -137,7 +137,7 @@ namespace embree pre.intersect1(ray,k,context,v0,v1,v2,v3,g,subgrid); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const SubGrid& subgrid) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const SubGrid& subgrid) { STAT3(shadow.trav_prims,1,1,1); const GridMesh* mesh = context->scene->get<GridMesh>(subgrid.geomID()); @@ -150,7 +150,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK; for (size_t j=0;j<num;j++) @@ -169,7 +169,7 @@ namespace embree } template<bool robust> - static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) + static __forceinline vbool<K> occluded(const vbool<K>& valid, const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive* prim, size_t num, const TravRayK<K, robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersectorK<N,K,robust> isecK; @@ -191,7 +191,7 @@ namespace embree } template<bool robust> - static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline void intersect(const Accel::Intersectors* This, Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; for (size_t i=0;i<num;i++) @@ -211,7 +211,7 @@ namespace embree } template<bool robust> - static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) + static __forceinline bool occluded(const Accel::Intersectors* This, Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive* prim, size_t num, const TravRay<N,robust> &tray, size_t& lazy_node) { BVHNQuantizedBaseNodeIntersector1<N,robust> isec1; diff --git a/thirdparty/embree/kernels/geometry/triangle_intersector.h b/thirdparty/embree/kernels/geometry/triangle_intersector.h index 2cdff78ec8..9d9ddc7cad 100644 --- a/thirdparty/embree/kernels/geometry/triangle_intersector.h +++ b/thirdparty/embree/kernels/geometry/triangle_intersector.h @@ -18,14 +18,14 @@ namespace embree typedef MoellerTrumboreIntersector1<M> Precalculations; /*! Intersect a ray with the M triangles and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleM<M>& tri) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const TriangleM<M>& tri) { STAT3(normal.trav_prims,1,1,1); pre.intersectEdge(ray,tri.v0,tri.e1,tri.e2,UVIdentity<M>(),Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); } /*! Test if the ray is occluded by one of M triangles. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleM<M>& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const TriangleM<M>& tri) { STAT3(shadow.trav_prims,1,1,1); return pre.intersectEdge(ray,tri.v0,tri.e1,tri.e2,UVIdentity<M>(),Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); @@ -46,7 +46,7 @@ namespace embree typedef MoellerTrumboreIntersectorK<M,K> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleM<M>& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const TriangleM<M>& tri) { STAT_USER(0,TriangleM<M>::max_size()); for (size_t i=0; i<TriangleM<M>::max_size(); i++) @@ -61,7 +61,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleM<M>& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const TriangleM<M>& tri) { vbool<K> valid0 = valid_i; @@ -79,14 +79,14 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleM<M>& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const TriangleM<M>& tri) { STAT3(normal.trav_prims,1,1,1); pre.intersectEdge(ray,k,tri.v0,tri.e1,tri.e2,UVIdentity<M>(),Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleM<M>& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const TriangleM<M>& tri) { STAT3(shadow.trav_prims,1,1,1); return pre.intersectEdge(ray,k,tri.v0,tri.e1,tri.e2,UVIdentity<M>(),Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); diff --git a/thirdparty/embree/kernels/geometry/triangle_intersector_moeller.h b/thirdparty/embree/kernels/geometry/triangle_intersector_moeller.h index 0a42d8f08b..87bf0cd069 100644 --- a/thirdparty/embree/kernels/geometry/triangle_intersector_moeller.h +++ b/thirdparty/embree/kernels/geometry/triangle_intersector_moeller.h @@ -77,18 +77,18 @@ namespace embree { /* calculate denominator */ vbool<M> valid = valid0; + const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org); const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir); const Vec3vf<M> C = Vec3vf<M>(tri_v0) - O; const Vec3vf<M> R = cross(C,D); const vfloat<M> den = dot(Vec3vf<M>(tri_Ng),D); - const vfloat<M> absDen = abs(den); const vfloat<M> sgnDen = signmsk(den); - + /* perform edge tests */ - const vfloat<M> U = dot(R,Vec3vf<M>(tri_e2)) ^ sgnDen; - const vfloat<M> V = dot(R,Vec3vf<M>(tri_e1)) ^ sgnDen; + const vfloat<M> U = asFloat(asInt(dot(R,Vec3vf<M>(tri_e2))) ^ asInt(sgnDen)); + const vfloat<M> V = asFloat(asInt(dot(R,Vec3vf<M>(tri_e1))) ^ asInt(sgnDen)); /* perform backface culling */ #if defined(EMBREE_BACKFACE_CULLING) @@ -99,14 +99,15 @@ namespace embree if (likely(early_out && none(valid))) return false; /* perform depth test */ - const vfloat<M> T = dot(Vec3vf<M>(tri_Ng),C) ^ sgnDen; + const vfloat<M> T = asFloat(asInt(dot(Vec3vf<M>(tri_Ng),C)) ^ asInt(sgnDen)); + valid &= (absDen*vfloat<M>(ray.tnear()) < T) & (T <= absDen*vfloat<M>(ray.tfar)); if (likely(early_out && none(valid))) return false; /* update hit information */ new (&hit) MoellerTrumboreHitM<M,UVMapper>(valid,U,V,T,absDen,tri_Ng,mapUV); - return true; + return early_out || any(valid); } template<typename UVMapper> @@ -320,8 +321,7 @@ namespace embree const Vec3vf<K> Ng = cross(e2,e1); return intersectK(valid0,ray.org,ray.dir,ray.tnear(),ray.tfar,tri_v0,e1,e2,Ng,mapUV,hit); } - - + /*! Intersects K rays with one of M triangles. */ template<typename UVMapper, typename Epilog> __forceinline vbool<K> intersectK(const vbool<K>& valid0, diff --git a/thirdparty/embree/kernels/geometry/triangle_intersector_pluecker.h b/thirdparty/embree/kernels/geometry/triangle_intersector_pluecker.h index 8fbefcea88..e21f1fa4c8 100644 --- a/thirdparty/embree/kernels/geometry/triangle_intersector_pluecker.h +++ b/thirdparty/embree/kernels/geometry/triangle_intersector_pluecker.h @@ -78,7 +78,7 @@ namespace embree /* calculate vertices relative to ray origin */ const Vec3vf<M> O = Vec3vf<M>((Vec3fa)ray.org); - const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir); + const Vec3vf<M> D = Vec3vf<M>((Vec3fa)ray.dir); const Vec3vf<M> v0 = tri_v0-O; const Vec3vf<M> v1 = tri_v1-O; const Vec3vf<M> v2 = tri_v2-O; @@ -114,7 +114,7 @@ namespace embree /* update hit information */ new (&hit) PlueckerHitM<M,UVMapper>(valid,U,V,UVW,t,Ng,mapUV); - return true; + return early_out || any(valid); } template<typename UVMapper> diff --git a/thirdparty/embree/kernels/geometry/triangle_intersector_woop.h b/thirdparty/embree/kernels/geometry/triangle_intersector_woop.h index f05dcc4537..03d23adc3d 100644 --- a/thirdparty/embree/kernels/geometry/triangle_intersector_woop.h +++ b/thirdparty/embree/kernels/geometry/triangle_intersector_woop.h @@ -64,7 +64,7 @@ namespace embree kx = (kz+1) % 3; ky = (kx+1) % 3; const float inv_dir_kz = rcp(ray.dir[kz]); - if (ray.dir[kz]) std::swap(kx,ky); + if (ray.dir[kz] < 0.0f) std::swap(kx,ky); S.x = ray.dir[kx] * inv_dir_kz; S.y = ray.dir[ky] * inv_dir_kz; S.z = inv_dir_kz; diff --git a/thirdparty/embree/kernels/geometry/trianglei_intersector.h b/thirdparty/embree/kernels/geometry/trianglei_intersector.h index f7deb9e72d..fa7f3ae43d 100644 --- a/thirdparty/embree/kernels/geometry/trianglei_intersector.h +++ b/thirdparty/embree/kernels/geometry/trianglei_intersector.h @@ -18,14 +18,14 @@ namespace embree typedef TriangleMi<M> Primitive; typedef MoellerTrumboreIntersector1<M> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene); pre.intersect(ray,v0,v1,v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene); @@ -45,7 +45,7 @@ namespace embree typedef TriangleMi<M> Primitive; typedef MoellerTrumboreIntersectorK<M,K> Precalculations; - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& tri) { const Scene* scene = context->scene; for (size_t i=0; i<Primitive::max_size(); i++) @@ -59,7 +59,7 @@ namespace embree } } - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& tri) { vbool<K> valid0 = valid_i; const Scene* scene = context->scene; @@ -77,14 +77,14 @@ namespace embree return !valid0; } - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene); pre.intersect(ray,k,v0,v1,v2,Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene); @@ -99,14 +99,14 @@ namespace embree typedef TriangleMi<M> Primitive; typedef PlueckerIntersector1<M> Precalculations; - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene); pre.intersect(ray,v0,v1,v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); } - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene); @@ -126,7 +126,7 @@ namespace embree typedef TriangleMi<M> Primitive; typedef PlueckerIntersectorK<M,K> Precalculations; - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& tri) { const Scene* scene = context->scene; for (size_t i=0; i<Primitive::max_size(); i++) @@ -140,7 +140,7 @@ namespace embree } } - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& tri) { vbool<K> valid0 = valid_i; const Scene* scene = context->scene; @@ -158,14 +158,14 @@ namespace embree return !valid0; } - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene); pre.intersect(ray,k,v0,v1,v2,Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); } - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0, v1, v2; tri.gather(v0,v1,v2,context->scene); @@ -181,7 +181,7 @@ namespace embree typedef MoellerTrumboreIntersector1<M> Precalculations; /*! Intersect a ray with the M triangles and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()); @@ -189,7 +189,7 @@ namespace embree } /*! Test if the ray is occluded by one of M triangles. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()); @@ -210,7 +210,7 @@ namespace embree typedef MoellerTrumboreIntersectorK<M,K> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const TriangleMi<M>& tri) { for (size_t i=0; i<TriangleMi<M>::max_size(); i++) { @@ -222,7 +222,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const TriangleMi<M>& tri) { vbool<K> valid0 = valid_i; for (size_t i=0; i<TriangleMi<M>::max_size(); i++) @@ -237,7 +237,7 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const TriangleMi<M>& tri) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]); @@ -245,7 +245,7 @@ namespace embree } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const TriangleMi<M>& tri) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]); @@ -261,7 +261,7 @@ namespace embree typedef PlueckerIntersector1<M> Precalculations; /*! Intersect a ray with the M triangles and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()); @@ -269,7 +269,7 @@ namespace embree } /*! Test if the ray is occluded by one of M triangles. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()); @@ -290,7 +290,7 @@ namespace embree typedef PlueckerIntersectorK<M,K> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const TriangleMi<M>& tri) { for (size_t i=0; i<TriangleMi<M>::max_size(); i++) { @@ -302,7 +302,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMi<M>& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const TriangleMi<M>& tri) { vbool<K> valid0 = valid_i; for (size_t i=0; i<TriangleMi<M>::max_size(); i++) @@ -317,7 +317,7 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const TriangleMi<M>& tri) { STAT3(normal.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]); @@ -325,7 +325,7 @@ namespace embree } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMi<M>& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const TriangleMi<M>& tri) { STAT3(shadow.trav_prims,1,1,1); Vec3vf<M> v0,v1,v2; tri.gather(v0,v1,v2,context->scene,ray.time()[k]); diff --git a/thirdparty/embree/kernels/geometry/trianglev_intersector.h b/thirdparty/embree/kernels/geometry/trianglev_intersector.h index 3abb7f8e32..0575bad388 100644 --- a/thirdparty/embree/kernels/geometry/trianglev_intersector.h +++ b/thirdparty/embree/kernels/geometry/trianglev_intersector.h @@ -20,14 +20,14 @@ namespace embree typedef MoellerTrumboreIntersector1<M> Precalculations; /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); pre.intersect(ray,tri.v0,tri.v1,tri.v2,/*UVIdentity<M>(),*/Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); return pre.intersect(ray,tri.v0,tri.v1,tri.v2,/*UVIdentity<M>(),*/Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); @@ -48,14 +48,14 @@ namespace embree typedef WoopPrecalculations1<M> Precalculations; /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); intersec::intersect(ray,pre,tri.v0,tri.v1,tri.v2,Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); return intersec::intersect(ray,pre,tri.v0,tri.v1,tri.v2,Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); @@ -76,7 +76,7 @@ namespace embree typedef MoellerTrumboreIntersectorK<M,K> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& tri) { for (size_t i=0; i<M; i++) { @@ -90,7 +90,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& tri) { vbool<K> valid0 = valid_i; @@ -108,14 +108,14 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,/*UVIdentity<M>(),*/Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); //FIXME: M } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); return pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,/*UVIdentity<M>(),*/Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); //FIXME: M @@ -130,14 +130,14 @@ namespace embree typedef PlueckerIntersector1<M> Precalculations; /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHit& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(Precalculations& pre, RayHit& ray, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); pre.intersect(ray,tri.v0,tri.v1,tri.v2,UVIdentity<M>(),Intersect1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); return pre.intersect(ray,tri.v0,tri.v1,tri.v2,UVIdentity<M>(),Occluded1EpilogM<M,filter>(ray,context,tri.geomID(),tri.primID())); @@ -157,7 +157,7 @@ namespace embree typedef PlueckerIntersectorK<M,K> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const Primitive& tri) { for (size_t i=0; i<M; i++) { @@ -171,7 +171,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const Primitive& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const Primitive& tri) { vbool<K> valid0 = valid_i; @@ -189,14 +189,14 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const Primitive& tri) { STAT3(normal.trav_prims,1,1,1); pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,UVIdentity<M>(),Intersect1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const Primitive& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const Primitive& tri) { STAT3(shadow.trav_prims,1,1,1); return pre.intersect(ray,k,tri.v0,tri.v1,tri.v2,UVIdentity<M>(),Occluded1KEpilogM<M,K,filter>(ray,k,context,tri.geomID(),tri.primID())); diff --git a/thirdparty/embree/kernels/geometry/trianglev_mb.h b/thirdparty/embree/kernels/geometry/trianglev_mb.h index b550a29fd5..c15313f209 100644 --- a/thirdparty/embree/kernels/geometry/trianglev_mb.h +++ b/thirdparty/embree/kernels/geometry/trianglev_mb.h @@ -113,7 +113,6 @@ namespace embree BBox3fa bounds0 = empty; BBox3fa bounds1 = empty; - for (size_t i=0; i<M && begin<end; i++, begin++) { const PrimRef& prim = prims[begin]; @@ -121,12 +120,12 @@ namespace embree const unsigned primID = prim.primID(); const TriangleMesh* __restrict__ const mesh = scene->get<TriangleMesh>(geomID); const TriangleMesh::Triangle& tri = mesh->triangle(primID); - const Vec3fa& a0 = mesh->vertex(tri.v[0],itime+0); bounds0.extend(a0); - const Vec3fa& a1 = mesh->vertex(tri.v[0],itime+1); bounds1.extend(a1); - const Vec3fa& b0 = mesh->vertex(tri.v[1],itime+0); bounds0.extend(b0); - const Vec3fa& b1 = mesh->vertex(tri.v[1],itime+1); bounds1.extend(b1); - const Vec3fa& c0 = mesh->vertex(tri.v[2],itime+0); bounds0.extend(c0); - const Vec3fa& c1 = mesh->vertex(tri.v[2],itime+1); bounds1.extend(c1); + const Vec3fa& a0 = mesh->vertex(tri.v[0],size_t(itime+0)); bounds0.extend(a0); + const Vec3fa& a1 = mesh->vertex(tri.v[0],size_t(itime+1)); bounds1.extend(a1); + const Vec3fa& b0 = mesh->vertex(tri.v[1],size_t(itime+0)); bounds0.extend(b0); + const Vec3fa& b1 = mesh->vertex(tri.v[1],size_t(itime+1)); bounds1.extend(b1); + const Vec3fa& c0 = mesh->vertex(tri.v[2],size_t(itime+0)); bounds0.extend(c0); + const Vec3fa& c1 = mesh->vertex(tri.v[2],size_t(itime+1)); bounds1.extend(c1); vgeomID [i] = geomID; vprimID [i] = primID; va0.x[i] = a0.x; va0.y[i] = a0.y; va0.z[i] = a0.z; @@ -159,12 +158,12 @@ namespace embree const int ilower = itime_range.begin(); const TriangleMesh::Triangle& tri = mesh->triangle(primID); allBounds.extend(mesh->linearBounds(primID, time_range)); - const Vec3fa& a0 = mesh->vertex(tri.v[0],ilower+0); - const Vec3fa& a1 = mesh->vertex(tri.v[0],ilower+1); - const Vec3fa& b0 = mesh->vertex(tri.v[1],ilower+0); - const Vec3fa& b1 = mesh->vertex(tri.v[1],ilower+1); - const Vec3fa& c0 = mesh->vertex(tri.v[2],ilower+0); - const Vec3fa& c1 = mesh->vertex(tri.v[2],ilower+1); + const Vec3fa& a0 = mesh->vertex(tri.v[0],size_t(ilower+0)); + const Vec3fa& a1 = mesh->vertex(tri.v[0],size_t(ilower+1)); + const Vec3fa& b0 = mesh->vertex(tri.v[1],size_t(ilower+0)); + const Vec3fa& b1 = mesh->vertex(tri.v[1],size_t(ilower+1)); + const Vec3fa& c0 = mesh->vertex(tri.v[2],size_t(ilower+0)); + const Vec3fa& c1 = mesh->vertex(tri.v[2],size_t(ilower+1)); const BBox1f time_range_v(mesh->timeStep(ilower+0),mesh->timeStep(ilower+1)); auto a01 = globalLinear(std::make_pair(a0,a1),time_range_v); auto b01 = globalLinear(std::make_pair(b0,b1),time_range_v); diff --git a/thirdparty/embree/kernels/geometry/trianglev_mb_intersector.h b/thirdparty/embree/kernels/geometry/trianglev_mb_intersector.h index 38cd52e85d..c9042ba323 100644 --- a/thirdparty/embree/kernels/geometry/trianglev_mb_intersector.h +++ b/thirdparty/embree/kernels/geometry/trianglev_mb_intersector.h @@ -18,7 +18,7 @@ namespace embree typedef MoellerTrumboreIntersector1<M> Precalculations; /*! Intersect a ray with the M triangles and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const TriangleMvMB<M>& tri) { STAT3(normal.trav_prims,1,1,1); const Vec3vf<M> time(ray.time()); @@ -29,7 +29,7 @@ namespace embree } /*! Test if the ray is occluded by one of M triangles. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const TriangleMvMB<M>& tri) { STAT3(shadow.trav_prims,1,1,1); const Vec3vf<M> time(ray.time()); @@ -53,7 +53,7 @@ namespace embree typedef MoellerTrumboreIntersectorK<M,K> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const TriangleMvMB<M>& tri) { for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++) { @@ -68,7 +68,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const TriangleMvMB<M>& tri) { vbool<K> valid0 = valid_i; @@ -87,7 +87,7 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const TriangleMvMB<M>& tri) { STAT3(normal.trav_prims,1,1,1); const Vec3vf<M> time(ray.time()[k]); @@ -98,7 +98,7 @@ namespace embree } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const TriangleMvMB<M>& tri) { STAT3(shadow.trav_prims,1,1,1); const Vec3vf<M> time(ray.time()[k]); @@ -117,7 +117,7 @@ namespace embree typedef PlueckerIntersector1<M> Precalculations; /*! Intersect a ray with the M triangles and updates the hit. */ - static __forceinline void intersect(const Precalculations& pre, RayHit& ray, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline void intersect(const Precalculations& pre, RayHit& ray, RayQueryContext* context, const TriangleMvMB<M>& tri) { STAT3(normal.trav_prims,1,1,1); const Vec3vf<M> time(ray.time()); @@ -128,7 +128,7 @@ namespace embree } /*! Test if the ray is occluded by one of M triangles. */ - static __forceinline bool occluded(const Precalculations& pre, Ray& ray, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline bool occluded(const Precalculations& pre, Ray& ray, RayQueryContext* context, const TriangleMvMB<M>& tri) { STAT3(shadow.trav_prims,1,1,1); const Vec3vf<M> time(ray.time()); @@ -152,7 +152,7 @@ namespace embree typedef PlueckerIntersectorK<M,K> Precalculations; /*! Intersects K rays with M triangles. */ - static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline void intersect(const vbool<K>& valid_i, Precalculations& pre, RayHitK<K>& ray, RayQueryContext* context, const TriangleMvMB<M>& tri) { for (size_t i=0; i<TriangleMvMB<M>::max_size(); i++) { @@ -167,7 +167,7 @@ namespace embree } /*! Test for K rays if they are occluded by any of the M triangles. */ - static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline vbool<K> occluded(const vbool<K>& valid_i, Precalculations& pre, RayK<K>& ray, RayQueryContext* context, const TriangleMvMB<M>& tri) { vbool<K> valid0 = valid_i; @@ -186,7 +186,7 @@ namespace embree } /*! Intersect a ray with M triangles and updates the hit. */ - static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline void intersect(Precalculations& pre, RayHitK<K>& ray, size_t k, RayQueryContext* context, const TriangleMvMB<M>& tri) { STAT3(normal.trav_prims,1,1,1); const Vec3vf<M> time(ray.time()[k]); @@ -197,7 +197,7 @@ namespace embree } /*! Test if the ray is occluded by one of the M triangles. */ - static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, IntersectContext* context, const TriangleMvMB<M>& tri) + static __forceinline bool occluded(Precalculations& pre, RayK<K>& ray, size_t k, RayQueryContext* context, const TriangleMvMB<M>& tri) { STAT3(shadow.trav_prims,1,1,1); const Vec3vf<M> time(ray.time()[k]); diff --git a/thirdparty/embree/kernels/hash.h b/thirdparty/embree/kernels/hash.h index 39d50e2354..ec9759ee35 100644 --- a/thirdparty/embree/kernels/hash.h +++ b/thirdparty/embree/kernels/hash.h @@ -1,4 +1,4 @@ // Copyright 2009-2021 Intel Corporation // SPDX-License-Identifier: Apache-2.0 -#define RTC_HASH "698442324ccddd11725fb8875275dc1384f7fb40" +#define RTC_HASH "daa8de0e714e18ad5e5c9841b67c1950d9c91c51" diff --git a/thirdparty/embree/kernels/subdiv/bezier_curve.h b/thirdparty/embree/kernels/subdiv/bezier_curve.h index a5adad5cc9..257e0afd40 100644 --- a/thirdparty/embree/kernels/subdiv/bezier_curve.h +++ b/thirdparty/embree/kernels/subdiv/bezier_curve.h @@ -185,9 +185,10 @@ namespace embree __forceinline CubicBezierCurve<float> xfm(const Vertex& dx) const { return CubicBezierCurve<float>(dot(v0,dx),dot(v1,dx),dot(v2,dx),dot(v3,dx)); } - - __forceinline CubicBezierCurve<vfloatx> vxfm(const Vertex& dx) const { - return CubicBezierCurve<vfloatx>(dot(v0,dx),dot(v1,dx),dot(v2,dx),dot(v3,dx)); + + template<int W> + __forceinline CubicBezierCurve<vfloat<W>> vxfm(const Vertex& dx) const { + return CubicBezierCurve<vfloat<W>>(dot(v0,dx),dot(v1,dx),dot(v2,dx),dot(v3,dx)); } __forceinline CubicBezierCurve<float> xfm(const Vertex& dx, const Vertex& p) const { @@ -286,7 +287,7 @@ namespace embree { const float u0 = 0.0f, u1 = 1.0f; const float dscale = (u1-u0)*(1.0f/(3.0f*(VSIZEX-1))); - const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(VSIZEX-1))); + const vfloatx vu0 = lerp(u0,u1,vfloatx(StepTy())*(1.0f/(VSIZEX-1))); Vec2vfx P0, dP0du; evalN(vu0,P0,dP0du); dP0du = dP0du * Vec2vfx(dscale); const Vec2vfx P3 = shift_right_1(P0); const Vec2vfx dP3du = shift_right_1(dP0du); @@ -299,7 +300,7 @@ namespace embree { const float u0 = u.lower, u1 = u.upper; const float dscale = (u1-u0)*(1.0f/(3.0f*(VSIZEX-1))); - const vfloatx vu0 = lerp(u0,u1,vfloatx(step)*(1.0f/(VSIZEX-1))); + const vfloatx vu0 = lerp(u0,u1,vfloatx(StepTy())*(1.0f/(VSIZEX-1))); Vec2vfx P0, dP0du; evalN(vu0,P0,dP0du); dP0du = dP0du * Vec2vfx(dscale); const Vec2vfx P3 = shift_right_1(P0); const Vec2vfx dP3du = shift_right_1(dP0du); @@ -307,6 +308,33 @@ namespace embree const Vec2vfx P2 = P3 - dP3du; return CubicBezierCurve<Vec2vfx>(P0,P1,P2,P3); } + + template<int W> + __forceinline CubicBezierCurve<Vec2vf<W>> split(const BBox1f& u, int i, int N) const + { + const float u0 = u.lower, u1 = u.upper; + const float dscale = (u1-u0)*(1.0f/(3.0f*N)); + const vfloat<W> vu0 = lerp(u0,u1,(vfloat<W>(i)+vfloat<W>(StepTy()))*(1.0f/N)); + Vec2vf<W> P0, dP0du; evalN(vu0,P0,dP0du); dP0du = dP0du * Vec2vf<W>(dscale); + const Vec2vf<W> P3 = shift_right_1(P0); + const Vec2vf<W> dP3du = shift_right_1(dP0du); + const Vec2vf<W> P1 = P0 + dP0du; + const Vec2vf<W> P2 = P3 - dP3du; + return CubicBezierCurve<Vec2vf<W>>(P0,P1,P2,P3); + } + + __forceinline CubicBezierCurve<Vec2f> split1(const BBox1f& u, int i, int N) const + { + const float u0 = u.lower, u1 = u.upper; + const float dscale = (u1-u0)*(1.0f/(3.0f*N)); + const float vu0 = lerp(u0,u1,(float(i)+0)*(1.0f/N)); + const float vu1 = lerp(u0,u1,(float(i)+1)*(1.0f/N)); + Vec2fa P0, dP0du; eval(vu0,P0,dP0du); dP0du = dP0du * Vec2fa(dscale); + Vec2fa P3, dP3du; eval(vu1,P3,dP3du); dP3du = dP3du * Vec2fa(dscale); + const Vec2fa P1 = P0 + dP0du; + const Vec2fa P2 = P3 - dP3du; + return CubicBezierCurve<Vec2f>(P0,P1,P2,P3); + } __forceinline void eval(float t, Vertex& p, Vertex& dp) const { @@ -461,20 +489,20 @@ namespace embree return madd(b.x, Vec4vf<M>(v0), madd(b.y, Vec4vf<M>(v1), madd(b.z, Vec4vf<M>(v2), b.w * Vec4vf<M>(v3)))); } - template<int M> - __forceinline void veval(const vfloat<M>& t, Vec4vf<M>& p, Vec4vf<M>& dp) const + template<int M, typename Vec> + __forceinline void veval(const vfloat<M>& t, Vec& p, Vec& dp) const { - const Vec4vf<M> p00 = v0; - const Vec4vf<M> p01 = v1; - const Vec4vf<M> p02 = v2; - const Vec4vf<M> p03 = v3; + const Vec p00 = v0; + const Vec p01 = v1; + const Vec p02 = v2; + const Vec p03 = v3; - const Vec4vf<M> p10 = lerp(p00,p01,t); - const Vec4vf<M> p11 = lerp(p01,p02,t); - const Vec4vf<M> p12 = lerp(p02,p03,t); - const Vec4vf<M> p20 = lerp(p10,p11,t); - const Vec4vf<M> p21 = lerp(p11,p12,t); - const Vec4vf<M> p30 = lerp(p20,p21,t); + const Vec p10 = lerp(p00,p01,t); + const Vec p11 = lerp(p01,p02,t); + const Vec p12 = lerp(p02,p03,t); + const Vec p20 = lerp(p10,p11,t); + const Vec p21 = lerp(p11,p12,t); + const Vec p30 = lerp(p20,p21,t); p = p30; dp = vfloat<M>(3.0f)*(p21-p20); @@ -485,10 +513,17 @@ namespace embree { assert(size <= PrecomputedBezierBasis::N); assert(ofs <= size); +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + assert(size > 0); + const vfloat<M> t = (vfloat<M>(step) + vfloat<M>(ofs+0))*rcp(float(size)); + Vec p,dp; veval<M>(t,p,dp); + return p; +#else return madd(vfloat<M>::loadu(&bezier_basis0.c0[size][ofs]), Vec(v0), madd(vfloat<M>::loadu(&bezier_basis0.c1[size][ofs]), Vec(v1), madd(vfloat<M>::loadu(&bezier_basis0.c2[size][ofs]), Vec(v2), vfloat<M>::loadu(&bezier_basis0.c3[size][ofs]) * Vec(v3)))); +#endif } template<int M, typename Vec = Vec4vf<M>> @@ -496,10 +531,17 @@ namespace embree { assert(size <= PrecomputedBezierBasis::N); assert(ofs <= size); +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + assert(size > 0); + const vfloat<M> t = (vfloat<M>(step) + vfloat<M>(ofs+1))*rcp(float(size)); + Vec p,dp; veval<M>(t,p,dp); + return p; +#else return madd(vfloat<M>::loadu(&bezier_basis1.c0[size][ofs]), Vec(v0), madd(vfloat<M>::loadu(&bezier_basis1.c1[size][ofs]), Vec(v1), madd(vfloat<M>::loadu(&bezier_basis1.c2[size][ofs]), Vec(v2), vfloat<M>::loadu(&bezier_basis1.c3[size][ofs]) * Vec(v3)))); +#endif } template<int M, typename Vec = Vec4vf<M>> @@ -507,10 +549,17 @@ namespace embree { assert(size <= PrecomputedBezierBasis::N); assert(ofs <= size); +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + assert(size > 0); + const vfloat<M> t = (vfloat<M>(step) + vfloat<M>(ofs+0))*rcp(float(size)); + Vec p,dp; veval<M>(t,p,dp); + return dp; +#else return madd(vfloat<M>::loadu(&bezier_basis0.d0[size][ofs]), Vec(v0), madd(vfloat<M>::loadu(&bezier_basis0.d1[size][ofs]), Vec(v1), madd(vfloat<M>::loadu(&bezier_basis0.d2[size][ofs]), Vec(v2), vfloat<M>::loadu(&bezier_basis0.d3[size][ofs]) * Vec(v3)))); +#endif } template<int M, typename Vec = Vec4vf<M>> @@ -518,10 +567,17 @@ namespace embree { assert(size <= PrecomputedBezierBasis::N); assert(ofs <= size); +#if defined(EMBREE_SYCL_SUPPORT) && defined(__SYCL_DEVICE_ONLY__) + assert(size > 0); + const vfloat<M> t = (vfloat<M>(step) + vfloat<M>(ofs+1))*rcp(float(size)); + Vec p,dp; veval<M>(t,p,dp); + return dp; +#else return madd(vfloat<M>::loadu(&bezier_basis1.d0[size][ofs]), Vec(v0), madd(vfloat<M>::loadu(&bezier_basis1.d1[size][ofs]), Vec(v1), madd(vfloat<M>::loadu(&bezier_basis1.d2[size][ofs]), Vec(v2), vfloat<M>::loadu(&bezier_basis1.d3[size][ofs]) * Vec(v3)))); +#endif } /* calculates bounds of bezier curve geometry */ @@ -532,7 +588,7 @@ namespace embree Vec3vfx pl(pos_inf), pu(neg_inf); for (int i=0; i<=N; i+=VSIZEX) { - vintx vi = vintx(i)+vintx(step); + vintx vi = vintx(i)+vintx(StepTy()); vboolx valid = vi <= vintx(N); const Vec3vfx p = eval0<VSIZEX,Vec3vf<VSIZEX>>(i,N); const Vec3vfx dp = derivative0<VSIZEX,Vec3vf<VSIZEX>>(i,N); @@ -554,7 +610,7 @@ namespace embree Vec4vfx pl(pos_inf), pu(neg_inf); for (int i=0; i<=N; i+=VSIZEX) { - vintx vi = vintx(i)+vintx(step); + vintx vi = vintx(i)+vintx(StepTy()); vboolx valid = vi <= vintx(N); const Vec4vfx p = eval0<VSIZEX>(i,N); const Vec4vfx dp = derivative0<VSIZEX>(i,N); @@ -587,7 +643,7 @@ namespace embree Vec3vfx pl(pos_inf), pu(neg_inf); vfloatx ru(0.0f); for (int i=0; i<N; i+=VSIZEX) { - vboolx valid = vintx(i)+vintx(step) < vintx(N); + vboolx valid = vintx(i)+vintx(StepTy()) < vintx(N); const Vec4vfx pi = eval0<VSIZEX>(i,N); pl.x = select(valid,min(pl.x,pi.x),pl.x); // FIXME: use masked min @@ -645,6 +701,7 @@ namespace embree typedef CubicBezierCurve<Vec2fa> CubicBezierCurve2fa; typedef CubicBezierCurve<Vec3fa> CubicBezierCurve3fa; typedef CubicBezierCurve<Vec3fa> BezierCurve3fa; + typedef CubicBezierCurve<Vec3ff> BezierCurve3ff; template<> __forceinline int CubicBezierCurve<float>::maxRoots() const { @@ -660,8 +717,9 @@ namespace embree return numRoots(v0,v1) + numRoots(v1,v2) + numRoots(v2,v3); } + struct CurveGeometry; // FIXME: this code should move ! template<typename CurveGeometry> - __forceinline CubicBezierCurve<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const CubicBezierCurve<Vec3ff>& curve) + __forceinline CubicBezierCurve<Vec3ff> enlargeRadiusToMinWidth(const RayQueryContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const CubicBezierCurve<Vec3ff>& curve) { return CubicBezierCurve<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0), enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1), diff --git a/thirdparty/embree/kernels/subdiv/bspline_curve.h b/thirdparty/embree/kernels/subdiv/bspline_curve.h index 51489ef37c..5d25ebb8e4 100644 --- a/thirdparty/embree/kernels/subdiv/bspline_curve.h +++ b/thirdparty/embree/kernels/subdiv/bspline_curve.h @@ -129,6 +129,12 @@ namespace embree const Vec4<float> b = BSplineBasis::derivative2(t); return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3))); } + + __forceinline void eval(const float t, Vertex& p, Vertex& dp) const + { + p = eval(t); + dp = eval_du(t); + } __forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const { @@ -307,7 +313,7 @@ namespace embree } template<typename CurveGeometry> - __forceinline BSplineCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const BSplineCurveT<Vec3ff>& curve) + __forceinline BSplineCurveT<Vec3ff> enlargeRadiusToMinWidth(const RayQueryContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const BSplineCurveT<Vec3ff>& curve) { return BSplineCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0), enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1), diff --git a/thirdparty/embree/kernels/subdiv/catmullrom_curve.h b/thirdparty/embree/kernels/subdiv/catmullrom_curve.h index 9532287d98..c42435b9d7 100644 --- a/thirdparty/embree/kernels/subdiv/catmullrom_curve.h +++ b/thirdparty/embree/kernels/subdiv/catmullrom_curve.h @@ -4,12 +4,13 @@ #pragma once #include "../common/default.h" +#include "bezier_curve.h" #include "../common/scene_curves.h" /* - Implements Catmull-Rom curves with control points p0, p1, p2, p3. At - t=0 the curve goes through p1, with tangent (p2-p0)/3, and for t=1 + Implements Catmul Rom curves with control points p0, p1, p2, p3. At + t=0 the curve goes through p1, with tangent (p2-p0)/2, and for t=1 the curve goes through p2 with tangent (p3-p2)/2. */ @@ -99,7 +100,7 @@ namespace embree } __forceinline Vertex center() const { - return 0.25f*(v0+v1+v2+v3); + return 0.5f*(v0+v1); } __forceinline BBox<Vertex> bounds() const { @@ -136,6 +137,12 @@ namespace embree const Vec4<float> b = CatmullRomBasis::derivative2(t); return madd(b.x,v0,madd(b.y,v1,madd(b.z,v2,b.w*v3))); } + + __forceinline void eval(const float t, Vertex& p, Vertex& dp) const + { + p = eval(t); + dp = eval_du(t); + } __forceinline void eval(const float t, Vertex& p, Vertex& dp, Vertex& ddp) const { @@ -283,8 +290,18 @@ namespace embree } }; + template<typename Vertex> + __forceinline void convert(const CatmullRomCurveT<Vertex>& icurve, BezierCurveT<Vertex>& ocurve) + { + const Vertex v0 = icurve.v1; + const Vertex v1 = icurve.v1+(icurve.v2-icurve.v0)*(1.0f/6.0f); + const Vertex v2 = icurve.v2+(icurve.v1-icurve.v3)*(1.0f/6.0f); + const Vertex v3 = icurve.v2; + ocurve = BezierCurveT<Vertex>(v0,v1,v2,v3); + } + template<typename CurveGeometry> - __forceinline CatmullRomCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const CatmullRomCurveT<Vec3ff>& curve) + __forceinline CatmullRomCurveT<Vec3ff> enlargeRadiusToMinWidth(const RayQueryContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const CatmullRomCurveT<Vec3ff>& curve) { return CatmullRomCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,curve.v0), enlargeRadiusToMinWidth(context,geom,ray_org,curve.v1), diff --git a/thirdparty/embree/kernels/subdiv/hermite_curve.h b/thirdparty/embree/kernels/subdiv/hermite_curve.h index ffef5a4315..09ad4cd8b4 100644 --- a/thirdparty/embree/kernels/subdiv/hermite_curve.h +++ b/thirdparty/embree/kernels/subdiv/hermite_curve.h @@ -29,8 +29,14 @@ namespace embree } }; + template<typename Vertex> + __forceinline void convert(const HermiteCurveT<Vertex>& icurve, BezierCurveT<Vertex>& ocurve) + { + ocurve = BezierCurveT<Vertex>(icurve.v0,icurve.v1,icurve.v2,icurve.v3); + } + template<typename CurveGeometry> - __forceinline HermiteCurveT<Vec3ff> enlargeRadiusToMinWidth(const IntersectContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const HermiteCurveT<Vec3ff>& curve) { + __forceinline HermiteCurveT<Vec3ff> enlargeRadiusToMinWidth(const RayQueryContext* context, const CurveGeometry* geom, const Vec3fa& ray_org, const HermiteCurveT<Vec3ff>& curve) { return HermiteCurveT<Vec3ff>(enlargeRadiusToMinWidth(context,geom,ray_org,BezierCurveT<Vec3ff>(curve))); } diff --git a/thirdparty/embree/kernels/subdiv/linear_bezier_patch.h b/thirdparty/embree/kernels/subdiv/linear_bezier_patch.h index dcdb101d7c..e93a86d7a3 100644 --- a/thirdparty/embree/kernels/subdiv/linear_bezier_patch.h +++ b/thirdparty/embree/kernels/subdiv/linear_bezier_patch.h @@ -31,7 +31,8 @@ namespace embree return merge(L.bounds(),R.bounds()); } }; - + +#if !defined(__SYCL_DEVICE_ONLY__) template<> struct TensorLinearQuadraticBezierSurface<Vec2fa> { @@ -57,6 +58,7 @@ namespace embree return merge(bl,br); } }; +#endif template<typename V> struct TensorLinearCubicBezierSurface @@ -148,9 +150,10 @@ namespace embree __forceinline TensorLinearCubicBezierSurface<float> xfm(const V& dx) const { return TensorLinearCubicBezierSurface<float>(L.xfm(dx),R.xfm(dx)); } - - __forceinline TensorLinearCubicBezierSurface<vfloatx> vxfm(const V& dx) const { - return TensorLinearCubicBezierSurface<vfloatx>(L.vxfm(dx),R.vxfm(dx)); + + template<int W> + __forceinline TensorLinearCubicBezierSurface<vfloat<W>> vxfm(const V& dx) const { + return TensorLinearCubicBezierSurface<vfloat<W>>(L.template vxfm<W>(dx),R.template vxfm<W>(dx)); } __forceinline TensorLinearCubicBezierSurface<float> xfm(const V& dx, const V& p) const { @@ -188,11 +191,20 @@ namespace embree new (&left ) TensorLinearCubicBezierSurface(L0,R0); new (&right) TensorLinearCubicBezierSurface(L1,R1); } - + __forceinline TensorLinearCubicBezierSurface<Vec2vfx> vsplit_u(vboolx& valid, const BBox1f& u) const { valid = true; clear(valid,VSIZEX-1); return TensorLinearCubicBezierSurface<Vec2vfx>(L.split(u),R.split(u)); } + + template<int W> + __forceinline TensorLinearCubicBezierSurface<Vec2vf<W>> vsplit_u(vbool<W>& valid, const BBox1f& u, int& i, int N) const + { + valid = true; clear(valid,W-1); + auto r = TensorLinearCubicBezierSurface<Vec2vf<W>>(L.template split<W>(u,i,N),R.template split<W>(u,i,N)); + i += W-1; + return r; + } __forceinline V eval(const float u, const float v) const { return clerp(L,R,V(v)).eval(u); @@ -244,6 +256,8 @@ namespace embree return TensorLinearCubicBezierSurface(clerp(a.L,b.L,V(t)), clerp(a.R,b.R,V(t))); } }; + +#if !defined(__SYCL_DEVICE_ONLY__) template<> struct TensorLinearCubicBezierSurface<Vec2fa> @@ -332,12 +346,20 @@ namespace embree new (&left ) TensorLinearCubicBezierSurface(LR0); new (&right) TensorLinearCubicBezierSurface(LR1); } - + __forceinline TensorLinearCubicBezierSurface<Vec2vfx> vsplit_u(vboolx& valid, const BBox1f& u) const { valid = true; clear(valid,VSIZEX-1); return TensorLinearCubicBezierSurface<Vec2vfx>(getL().split(u),getR().split(u)); } + template<int W> + __forceinline TensorLinearCubicBezierSurface<Vec2vf<W>> vsplit_u(vbool<W>& valid, const BBox1f& u, int& i, int N) const { + valid = true; clear(valid,W-1); + auto r = TensorLinearCubicBezierSurface<Vec2vf<W>>(getL().split<W>(u,i,N),getR().split<W>(u,i,N)); + i += W-1; + return r; + } + __forceinline Vec2fa eval(const float u, const float v) const { const vfloat4 p = LR.eval(u); @@ -396,6 +418,24 @@ namespace embree } }; + template<> + __forceinline TensorLinearCubicBezierSurface<Vec2f> TensorLinearCubicBezierSurface<Vec2fa>::vsplit_u<1>(bool& valid, const BBox1f& u, int& i, int N) const { + auto r = TensorLinearCubicBezierSurface<Vec2f>(getL().split1(u,i,N),getR().split1(u,i,N)); + valid = true; i += 1; + return r; + } + +#else + + template<> template<> + __forceinline TensorLinearCubicBezierSurface<Vec2f> TensorLinearCubicBezierSurface<Vec2fa>::vsplit_u<1>(bool& valid, const BBox1f& u, int& i, int N) const { + auto r = TensorLinearCubicBezierSurface<Vec2f>(L.split1(u,i,N),R.split1(u,i,N)); + valid = true; i += 1; + return r; + } + +#endif + typedef TensorLinearCubicBezierSurface<float> TensorLinearCubicBezierSurface1f; typedef TensorLinearCubicBezierSurface<Vec2fa> TensorLinearCubicBezierSurface2fa; typedef TensorLinearCubicBezierSurface<Vec3fa> TensorLinearCubicBezierSurface3fa; diff --git a/thirdparty/embree/patches/godot-changes-noexcept.patch b/thirdparty/embree/patches/godot-changes-noexcept.patch index 84169c36e4..bf9973a764 100644 --- a/thirdparty/embree/patches/godot-changes-noexcept.patch +++ b/thirdparty/embree/patches/godot-changes-noexcept.patch @@ -1,121 +1,5 @@ -diff --git a/thirdparty/embree/common/algorithms/parallel_for.h b/thirdparty/embree/common/algorithms/parallel_for.h -index f2969a88f1..6d411e4852 100644 ---- a/thirdparty/embree/common/algorithms/parallel_for.h -+++ b/thirdparty/embree/common/algorithms/parallel_for.h -@@ -21,7 +21,10 @@ namespace embree - func(r.begin()); - }); - if (!TaskScheduler::wait()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - } - #elif defined(TASKING_TBB) - #if TBB_INTERFACE_VERSION >= 12002 -@@ -30,13 +33,19 @@ namespace embree - func(i); - },context); - if (context.is_group_execution_cancelled()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - #else - tbb::parallel_for(Index(0),N,Index(1),[&](Index i) { - func(i); - }); - if (tbb::task::self().is_cancelled()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - #endif - - #elif defined(TASKING_PPL) -@@ -56,7 +65,10 @@ namespace embree - #if defined(TASKING_INTERNAL) - TaskScheduler::spawn(first,last,minStepSize,func); - if (!TaskScheduler::wait()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - - #elif defined(TASKING_TBB) - #if TBB_INTERFACE_VERSION >= 12002 -@@ -65,13 +77,19 @@ namespace embree - func(range<Index>(r.begin(),r.end())); - },context); - if (context.is_group_execution_cancelled()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - #else - tbb::parallel_for(tbb::blocked_range<Index>(first,last,minStepSize),[&](const tbb::blocked_range<Index>& r) { - func(range<Index>(r.begin(),r.end())); - }); - if (tbb::task::self().is_cancelled()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - #endif - - #elif defined(TASKING_PPL) -@@ -103,13 +121,19 @@ namespace embree - func(i); - },tbb::simple_partitioner(),context); - if (context.is_group_execution_cancelled()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - #else - tbb::parallel_for(Index(0),N,Index(1),[&](Index i) { - func(i); - },tbb::simple_partitioner()); - if (tbb::task::self().is_cancelled()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - #endif - } - -@@ -124,13 +148,19 @@ namespace embree - func(i); - },ap,context); - if (context.is_group_execution_cancelled()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - #else - tbb::parallel_for(Index(0),N,Index(1),[&](Index i) { - func(i); - },ap); - if (tbb::task::self().is_cancelled()) -- throw std::runtime_error("task cancelled"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task cancelled"); -+ abort(); -+ // -- GODOT end -- - #endif - } - diff --git a/thirdparty/embree/common/algorithms/parallel_reduce.h b/thirdparty/embree/common/algorithms/parallel_reduce.h -index 1a94aad8c4..cd0078f2e6 100644 +index b52b1e2e13..51ec0a6405 100644 --- a/thirdparty/embree/common/algorithms/parallel_reduce.h +++ b/thirdparty/embree/common/algorithms/parallel_reduce.h @@ -58,15 +58,19 @@ namespace embree @@ -143,119 +27,233 @@ index 1a94aad8c4..cd0078f2e6 100644 #endif #else // TASKING_PPL diff --git a/thirdparty/embree/common/lexers/stringstream.cpp b/thirdparty/embree/common/lexers/stringstream.cpp -index 42ffb10176..a037869506 100644 +index 42ffb10176..c93da0b420 100644 --- a/thirdparty/embree/common/lexers/stringstream.cpp +++ b/thirdparty/embree/common/lexers/stringstream.cpp -@@ -39,7 +39,10 @@ namespace embree +@@ -39,7 +39,12 @@ namespace embree std::vector<char> str; str.reserve(64); while (cin->peek() != EOF && !isSeparator(cin->peek())) { int c = cin->get(); - if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input"); + // -- GODOT start -- + // if (!isValidChar(c)) throw std::runtime_error("invalid character "+std::string(1,c)+" in input"); -+ if (!isValidChar(c)) abort(); ++ if (!isValidChar(c)) { ++ abort(); ++ } + // -- GODOT end -- str.push_back((char)c); } str.push_back(0); diff --git a/thirdparty/embree/common/sys/alloc.cpp b/thirdparty/embree/common/sys/alloc.cpp -index 1bc30fe9a5..abdd269069 100644 +index de225fafc6..71616a3982 100644 --- a/thirdparty/embree/common/sys/alloc.cpp +++ b/thirdparty/embree/common/sys/alloc.cpp -@@ -21,7 +21,10 @@ namespace embree +@@ -24,16 +24,32 @@ namespace embree + + void enableUSMAllocEmbree(sycl::context* context, sycl::device* device) + { +- if (tls_context_embree != nullptr) throw std::runtime_error("USM allocation already enabled"); +- if (tls_device_embree != nullptr) throw std::runtime_error("USM allocation already enabled"); ++ // -- GODOT start -- ++ // if (tls_context_embree != nullptr) throw std::runtime_error("USM allocation already enabled"); ++ // if (tls_device_embree != nullptr) throw std::runtime_error("USM allocation already enabled"); ++ if (tls_context_embree != nullptr) { ++ abort(); ++ } ++ if (tls_device_embree != nullptr) { ++ abort(); ++ } ++ // -- GODOT end -- + tls_context_embree = context; + tls_device_embree = device; + } + + void disableUSMAllocEmbree() + { +- if (tls_context_embree == nullptr) throw std::runtime_error("USM allocation not enabled"); +- if (tls_device_embree == nullptr) throw std::runtime_error("USM allocation not enabled"); ++ // -- GODOT start -- ++ // if (tls_context_embree == nullptr) throw std::runtime_error("USM allocation not enabled"); ++ // if (tls_device_embree == nullptr) throw std::runtime_error("USM allocation not enabled"); ++ if (tls_context_embree == nullptr) { ++ abort(); ++ } ++ if (tls_device_embree == nullptr) { ++ abort(); ++ } ++ // -- GODOT end -- + tls_context_embree = nullptr; + tls_device_embree = nullptr; + } +@@ -48,8 +64,16 @@ namespace embree + + void disableUSMAllocTutorial() + { +- if (tls_context_tutorial == nullptr) throw std::runtime_error("USM allocation not enabled"); +- if (tls_device_tutorial == nullptr) throw std::runtime_error("USM allocation not enabled"); ++ // -- GODOT start -- ++ // if (tls_context_tutorial == nullptr) throw std::runtime_error("USM allocation not enabled"); ++ // if (tls_device_tutorial == nullptr) throw std::runtime_error("USM allocation not enabled"); ++ if (tls_context_tutorial == nullptr) { ++ abort(); ++ } ++ if (tls_device_tutorial == nullptr) { ++ abort(); ++ } ++ // -- GODOT end -- + + tls_context_tutorial = nullptr; + tls_device_tutorial = nullptr; +@@ -64,8 +88,13 @@ namespace embree + + assert((align & (align-1)) == 0); void* ptr = _mm_malloc(size,align); +- if (size != 0 && ptr == nullptr) +- throw std::bad_alloc(); ++ // -- GODOT start -- ++ // if (size != 0 && ptr == nullptr) ++ // throw std::bad_alloc(); ++ if (size != 0 && ptr == nullptr) { ++ abort(); ++ } ++ // -- GODOT end -- + return ptr; + } - if (size != 0 && ptr == nullptr) +@@ -94,8 +123,13 @@ namespace embree + else + ptr = sycl::aligned_alloc_shared(align,size,*device,*context); + +- if (size != 0 && ptr == nullptr) - throw std::bad_alloc(); -+ // -- GODOT start -- -+ // throw std::bad_alloc(); ++ // -- GODOT start -- ++ // if (size != 0 && ptr == nullptr) ++ // throw std::bad_alloc(); ++ if (size != 0 && ptr == nullptr) { + abort(); -+ // -- GODOT end -- - ++ } ++ // -- GODOT end -- + return ptr; } -@@ -128,7 +131,10 @@ namespace embree +@@ -241,7 +275,12 @@ namespace embree /* fall back to 4k pages */ int flags = MEM_COMMIT | MEM_RESERVE; char* ptr = (char*) VirtualAlloc(nullptr,bytes,flags,PAGE_READWRITE); - if (ptr == nullptr) throw std::bad_alloc(); + // -- GODOT start -- + // if (ptr == nullptr) throw std::bad_alloc(); -+ if (ptr == nullptr) abort(); ++ if (ptr == nullptr) { ++ abort(); ++ } + // -- GODOT end -- hugepages = false; return ptr; } -@@ -145,7 +151,10 @@ namespace embree +@@ -257,8 +296,13 @@ namespace embree + if (bytesNew >= bytesOld) return bytesOld; - if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT)) +- if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT)) - throw std::bad_alloc(); -+ // -- GODOT start -- -+ // throw std::bad_alloc(); ++ // -- GODOT start -- ++ // if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT)) ++ // throw std::bad_alloc(); ++ if (!VirtualFree((char*)ptr+bytesNew,bytesOld-bytesNew,MEM_DECOMMIT)) { + abort(); -+ // -- GODOT end -- ++ } ++ // -- GODOT end -- return bytesNew; } -@@ -156,7 +165,10 @@ namespace embree +@@ -268,8 +312,13 @@ namespace embree + if (bytes == 0) return; - if (!VirtualFree(ptr,0,MEM_RELEASE)) +- if (!VirtualFree(ptr,0,MEM_RELEASE)) - throw std::bad_alloc(); -+ // -- GODOT start -- -+ // throw std::bad_alloc(); ++ // -- GODOT start -- ++ // if (!VirtualFree(ptr,0,MEM_RELEASE)) ++ // throw std::bad_alloc(); ++ if (!VirtualFree(ptr,0,MEM_RELEASE)) { + abort(); -+ // -- GODOT end -- ++ } ++ // -- GODOT end -- } void os_advise(void *ptr, size_t bytes) -@@ -260,7 +272,10 @@ namespace embree +@@ -373,7 +422,12 @@ namespace embree /* fallback to 4k pages */ void* ptr = (char*) mmap(0, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - if (ptr == MAP_FAILED) throw std::bad_alloc(); + // -- GODOT start -- + // if (ptr == MAP_FAILED) throw std::bad_alloc(); -+ if (ptr == MAP_FAILED) abort(); ++ if (ptr == MAP_FAILED) { ++ abort(); ++ } + // -- GODOT end -- hugepages = false; /* advise huge page hint for THP */ -@@ -277,7 +292,10 @@ namespace embree +@@ -389,8 +443,13 @@ namespace embree + if (bytesNew >= bytesOld) return bytesOld; - if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1) +- if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1) - throw std::bad_alloc(); -+ // -- GODOT start -- -+ // throw std::bad_alloc(); ++ // -- GODOT start -- ++ // if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1) ++ // throw std::bad_alloc(); ++ if (munmap((char*)ptr+bytesNew,bytesOld-bytesNew) == -1) { + abort(); -+ // -- GODOT end -- ++ } ++ // -- GODOT end -- return bytesNew; } -@@ -291,7 +309,10 @@ namespace embree +@@ -403,8 +462,13 @@ namespace embree + /* for hugepages we need to also align the size */ const size_t pageSize = hugepages ? PAGE_SIZE_2M : PAGE_SIZE_4K; bytes = (bytes+pageSize-1) & ~(pageSize-1); - if (munmap(ptr,bytes) == -1) +- if (munmap(ptr,bytes) == -1) - throw std::bad_alloc(); -+ // -- GODOT start -- -+ // throw std::bad_alloc(); ++ // -- GODOT start -- ++ // if (munmap(ptr,bytes) == -1) ++ // throw std::bad_alloc(); ++ if (munmap(ptr,bytes) == -1) { + abort(); -+ // -- GODOT end -- ++ } ++ // -- GODOT end -- } /* hint for transparent huge pages (THP) */ +diff --git a/thirdparty/embree/common/sys/alloc.h b/thirdparty/embree/common/sys/alloc.h +index e19c2c221a..28b17f988d 100644 +--- a/thirdparty/embree/common/sys/alloc.h ++++ b/thirdparty/embree/common/sys/alloc.h +@@ -160,7 +160,10 @@ namespace embree + typedef std::ptrdiff_t difference_type; + + __forceinline pointer allocate( size_type n ) { +- throw std::runtime_error("no allocation supported"); ++ // -- GODOT start -- ++ // throw std::runtime_error("no allocation supported"); ++ abort(); ++ // -- GODOT end -- + } + + __forceinline void deallocate( pointer p, size_type n ) { diff --git a/thirdparty/embree/common/sys/platform.h b/thirdparty/embree/common/sys/platform.h -index be3ec36436..728bf6ed7d 100644 +index 6dc0cf3318..d4a9b9e119 100644 --- a/thirdparty/embree/common/sys/platform.h +++ b/thirdparty/embree/common/sys/platform.h -@@ -178,11 +178,19 @@ - #define PRINT4(x,y,z,w) embree_cout << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << embree_endl +@@ -213,11 +213,19 @@ + #define UPRINT4(x,y,z,w) embree_cout_uniform << STRING(x) << " = " << (x) << ", " << STRING(y) << " = " << (y) << ", " << STRING(z) << " = " << (z) << ", " << STRING(w) << " = " << (w) << embree_endl #if defined(DEBUG) // only report file and line in debug mode + // -- GODOT start -- -+ // #define THROW_RUNTIME_ERROR(str) ++ // #define THROW_RUNTIME_ERROR(str) \ + // throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)); #define THROW_RUNTIME_ERROR(str) \ - throw std::runtime_error(std::string(__FILE__) + " (" + toString(__LINE__) + "): " + std::string(str)); @@ -263,7 +261,7 @@ index be3ec36436..728bf6ed7d 100644 + // -- GODOT end -- #else + // -- GODOT start -- -+ // #define THROW_RUNTIME_ERROR(str) ++ // #define THROW_RUNTIME_ERROR(str) \ + // throw std::runtime_error(str); #define THROW_RUNTIME_ERROR(str) \ - throw std::runtime_error(str); @@ -273,7 +271,7 @@ index be3ec36436..728bf6ed7d 100644 #define FATAL(x) THROW_RUNTIME_ERROR(x) diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.cpp b/thirdparty/embree/common/tasking/taskschedulerinternal.cpp -index dca835a716..ad438588a3 100644 +index 83ead95122..88b88a30ec 100644 --- a/thirdparty/embree/common/tasking/taskschedulerinternal.cpp +++ b/thirdparty/embree/common/tasking/taskschedulerinternal.cpp @@ -48,13 +48,15 @@ namespace embree @@ -281,115 +279,59 @@ index dca835a716..ad438588a3 100644 Task* prevTask = thread.task; thread.task = this; - try { -- if (thread.scheduler->cancellingException == nullptr) +- if (context->cancellingException == nullptr) + // -- GODOT start -- + // try { -+ // if (thread.scheduler->cancellingException == nullptr) ++ // if (context->cancellingException == nullptr) closure->execute(); - } catch (...) { -- if (thread.scheduler->cancellingException == nullptr) -- thread.scheduler->cancellingException = std::current_exception(); +- if (context->cancellingException == nullptr) +- context->cancellingException = std::current_exception(); - } + // } catch (...) { -+ // if (thread.scheduler->cancellingException == nullptr) -+ // thread.scheduler->cancellingException = std::current_exception(); ++ // if (context->cancellingException == nullptr) ++ // context->cancellingException = std::current_exception(); + // } + // -- GODOT end -- thread.task = prevTask; add_dependencies(-1); } -@@ -291,8 +293,11 @@ namespace embree - size_t threadIndex = allocThreadIndex(); - condition.wait(mutex, [&] () { return hasRootTask.load(); }); - mutex.unlock(); -- std::exception_ptr except = thread_loop(threadIndex); -- if (except != nullptr) std::rethrow_exception(except); -+ // -- GODOT start -- -+ // std::exception_ptr except = thread_loop(threadIndex); -+ // if (except != nullptr) std::rethrow_exception(except); -+ thread_loop(threadIndex); -+ // -- GODOT end -- - } - - void TaskScheduler::reset() { -@@ -324,7 +329,10 @@ namespace embree - return thread->scheduler->cancellingException == nullptr; - } - -- std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex) -+// -- GODOT start -- -+// std::exception_ptr TaskScheduler::thread_loop(size_t threadIndex) -+ void TaskScheduler::thread_loop(size_t threadIndex) -+// -- GODOT end -- - { - /* allocate thread structure */ - std::unique_ptr<Thread> mthread(new Thread(threadIndex,this)); // too large for stack allocation -@@ -347,9 +355,10 @@ namespace embree - swapThread(oldThread); - - /* remember exception to throw */ -- std::exception_ptr except = nullptr; -- if (cancellingException != nullptr) except = cancellingException; -- -+ // -- GODOT start -- -+ // std::exception_ptr except = nullptr; -+ // if (cancellingException != nullptr) except = cancellingException; -+ // -- GODOT end -- - /* wait for all threads to terminate */ - threadCounter--; - #if defined(__WIN32__) -@@ -367,7 +376,10 @@ namespace embree - yield(); - #endif - } -- return except; -+ // -- GODOT start -- -+ // return except; -+ return; -+ // -- GODOT end -- - } - - bool TaskScheduler::steal_from_other_threads(Thread& thread) diff --git a/thirdparty/embree/common/tasking/taskschedulerinternal.h b/thirdparty/embree/common/tasking/taskschedulerinternal.h -index 61a0e57c5b..6cc2495195 100644 +index 355648b3f8..e72d3b72ba 100644 --- a/thirdparty/embree/common/tasking/taskschedulerinternal.h +++ b/thirdparty/embree/common/tasking/taskschedulerinternal.h -@@ -123,7 +123,10 @@ namespace embree +@@ -130,8 +130,13 @@ namespace embree + __forceinline void* alloc(size_t bytes, size_t align = 64) { size_t ofs = bytes + ((align - stackPtr) & (align-1)); - if (stackPtr + ofs > CLOSURE_STACK_SIZE) +- if (stackPtr + ofs > CLOSURE_STACK_SIZE) - throw std::runtime_error("closure stack overflow"); -+ // -- GODOT start -- -+ // throw std::runtime_error("closure stack overflow"); ++ // -- GODOT start -- ++ // if (stackPtr + ofs > CLOSURE_STACK_SIZE) ++ // throw std::runtime_error("closure stack overflow"); ++ if (stackPtr + ofs > CLOSURE_STACK_SIZE) { + abort(); -+ // -- GODOT end -- ++ } ++ // -- GODOT end -- stackPtr += ofs; return &stack[stackPtr-bytes]; } -@@ -132,7 +135,10 @@ namespace embree - __forceinline void push_right(Thread& thread, const size_t size, const Closure& closure) +@@ -139,8 +144,13 @@ namespace embree + template<typename Closure> + __forceinline void push_right(Thread& thread, const size_t size, const Closure& closure, TaskGroupContext* context) { - if (right >= TASK_STACK_SIZE) +- if (right >= TASK_STACK_SIZE) - throw std::runtime_error("task stack overflow"); -+ // -- GODOT start -- -+ // throw std::runtime_error("task stack overflow"); -+ abort(); -+ // -- GODOT end -- ++ // -- GODOT start -- ++ // if (right >= TASK_STACK_SIZE) ++ // throw std::runtime_error("task stack overflow"); ++ if (right >= TASK_STACK_SIZE) { ++ abort(); ++ } ++ // -- GODOT end -- /* allocate new task on right side of stack */ size_t oldStackPtr = stackPtr; -@@ -238,7 +244,10 @@ namespace embree - void wait_for_threads(size_t threadCount); - - /*! thread loop for all worker threads */ -- std::exception_ptr thread_loop(size_t threadIndex); -+ // -- GODOT start -- -+ // std::exception_ptr thread_loop(size_t threadIndex); -+ void thread_loop(size_t threadIndex); -+ // -- GODOT end -- - - /*! steals a task from a different thread */ - bool steal_from_other_threads(Thread& thread); diff --git a/thirdparty/embree/kernels/bvh/bvh_statistics.cpp b/thirdparty/embree/kernels/bvh/bvh_statistics.cpp index 40f9043736..57f75bfd7e 100644 --- a/thirdparty/embree/kernels/bvh/bvh_statistics.cpp @@ -406,40 +348,94 @@ index 40f9043736..57f75bfd7e 100644 } return s; } +diff --git a/thirdparty/embree/kernels/common/alloc.h b/thirdparty/embree/kernels/common/alloc.h +index 2bd292de4d..840d48c327 100644 +--- a/thirdparty/embree/kernels/common/alloc.h ++++ b/thirdparty/embree/kernels/common/alloc.h +@@ -189,8 +189,13 @@ namespace embree + , atype(osAllocation ? EMBREE_OS_MALLOC : ALIGNED_MALLOC) + , primrefarray(device,0) + { +- if (osAllocation && useUSM) +- throw std::runtime_error("USM allocation cannot be combined with OS allocation."); ++ // -- GODOT start -- ++ // if (osAllocation && useUSM) ++ // throw std::runtime_error("USM allocation cannot be combined with OS allocation."); ++ if (osAllocation && useUSM) { ++ abort(); ++ } ++ // -- GODOT end -- + + for (size_t i=0; i<MAX_THREAD_USED_BLOCK_SLOTS; i++) + { +@@ -502,8 +507,13 @@ namespace embree + Block* myUsedBlocks = threadUsedBlocks[slot]; + if (myUsedBlocks) { + void* ptr = myUsedBlocks->malloc(device,bytes,align,partial); +- if (ptr == nullptr && !blockAllocation) +- throw std::bad_alloc(); ++ // -- GODOT start -- ++ // if (ptr == nullptr && !blockAllocation) ++ // throw std::bad_alloc(); ++ if (ptr == nullptr && !blockAllocation) { ++ abort(); ++ } ++ // -- GODOT end -- + if (ptr) return ptr; + } + diff --git a/thirdparty/embree/kernels/common/rtcore.cpp b/thirdparty/embree/kernels/common/rtcore.cpp -index 95a94319ec..a6ea55bfc4 100644 +index 8dc5d7045b..eb8d2c0a58 100644 --- a/thirdparty/embree/kernels/common/rtcore.cpp +++ b/thirdparty/embree/kernels/common/rtcore.cpp -@@ -198,7 +198,10 @@ RTC_NAMESPACE_BEGIN; +@@ -257,10 +257,17 @@ RTC_NAMESPACE_BEGIN; + RTC_TRACE(rtcSetSceneBuildQuality); + RTC_VERIFY_HANDLE(hscene); + RTC_ENTER_DEVICE(hscene); ++ // -- GODOT start -- ++ // if (quality != RTC_BUILD_QUALITY_LOW && ++ // quality != RTC_BUILD_QUALITY_MEDIUM && ++ // quality != RTC_BUILD_QUALITY_HIGH) ++ // throw std::runtime_error("invalid build quality"); if (quality != RTC_BUILD_QUALITY_LOW && quality != RTC_BUILD_QUALITY_MEDIUM && - quality != RTC_BUILD_QUALITY_HIGH) +- quality != RTC_BUILD_QUALITY_HIGH) - throw std::runtime_error("invalid build quality"); -+ // -- GODOT start -- -+ // throw std::runtime_error("invalid build quality"); ++ quality != RTC_BUILD_QUALITY_HIGH) { + abort(); -+ // -- GODOT end -- ++ } ++ // -- GODOT end -- scene->setBuildQuality(quality); RTC_CATCH_END2(scene); } -@@ -1351,7 +1354,10 @@ RTC_NAMESPACE_BEGIN; +@@ -1563,11 +1570,19 @@ RTC_API void rtcSetGeometryTransform(RTCGeometry hgeometry, unsigned int timeSte + RTC_TRACE(rtcSetGeometryBuildQuality); + RTC_VERIFY_HANDLE(hgeometry); + RTC_ENTER_DEVICE(hgeometry); ++ // -- GODOT start -- ++ // if (quality != RTC_BUILD_QUALITY_LOW && ++ // quality != RTC_BUILD_QUALITY_MEDIUM && ++ // quality != RTC_BUILD_QUALITY_HIGH && ++ // quality != RTC_BUILD_QUALITY_REFIT) ++ // throw std::runtime_error("invalid build quality"); + if (quality != RTC_BUILD_QUALITY_LOW && quality != RTC_BUILD_QUALITY_MEDIUM && quality != RTC_BUILD_QUALITY_HIGH && - quality != RTC_BUILD_QUALITY_REFIT) +- quality != RTC_BUILD_QUALITY_REFIT) - throw std::runtime_error("invalid build quality"); -+ // -- GODOT start -- -+ // throw std::runtime_error("invalid build quality"); ++ quality != RTC_BUILD_QUALITY_REFIT) { + abort(); -+ // -- GODOT end -- ++ } ++ // -- GODOT end -- geometry->setBuildQuality(quality); RTC_CATCH_END2(geometry); } diff --git a/thirdparty/embree/kernels/common/rtcore.h b/thirdparty/embree/kernels/common/rtcore.h -index 4e4b24e9c2..ac58a84d6f 100644 +index 73a061de11..47526482c1 100644 --- a/thirdparty/embree/kernels/common/rtcore.h +++ b/thirdparty/embree/kernels/common/rtcore.h -@@ -25,6 +25,13 @@ namespace embree - #endif +@@ -13,13 +13,13 @@ namespace embree + __forceinline bool isIncoherent(RTCRayQueryFlags flags) { return (flags & RTC_RAY_QUERY_FLAG_COHERENT) == RTC_RAY_QUERY_FLAG_INCOHERENT; } /*! Macros used in the rtcore API implementation */ +// -- GODOT start -- @@ -447,21 +443,18 @@ index 4e4b24e9c2..ac58a84d6f 100644 +#define RTC_CATCH_END(device) +#define RTC_CATCH_END2(scene) +#define RTC_CATCH_END2_FALSE(scene) return false; -+ -+#if 0 + #if 0 +-# define RTC_CATCH_BEGIN +-# define RTC_CATCH_END(device) +-# define RTC_CATCH_END2(scene) +-# define RTC_CATCH_END2_FALSE(scene) return false; +-#else +- ++// -- GODOT end -- #define RTC_CATCH_BEGIN try { #define RTC_CATCH_END(device) \ -@@ -71,6 +78,8 @@ namespace embree - Device::process_error(device,RTC_ERROR_UNKNOWN,"unknown exception caught"); \ - return false; \ - } -+#endif -+// -- GODOT end -- - - #define RTC_VERIFY_HANDLE(handle) \ - if (handle == nullptr) { \ -@@ -97,6 +106,8 @@ namespace embree +@@ -94,6 +94,8 @@ namespace embree #define RTC_TRACE(x) #endif @@ -470,7 +463,7 @@ index 4e4b24e9c2..ac58a84d6f 100644 /*! used to throw embree API errors */ struct rtcore_error : public std::exception { -@@ -112,14 +123,18 @@ namespace embree +@@ -109,14 +111,18 @@ namespace embree RTCError error; std::string str; }; @@ -490,36 +483,61 @@ index 4e4b24e9c2..ac58a84d6f 100644 +// -- GODOT end -- #define RTC_BUILD_ARGUMENTS_HAS(settings,member) \ - (settings.byteSize > (offsetof(RTCBuildArguments,member)+sizeof(settings.member))) + (settings.byteSize > (offsetof(RTCBuildArguments,member)+sizeof(settings.member))) diff --git a/thirdparty/embree/kernels/common/scene.cpp b/thirdparty/embree/kernels/common/scene.cpp -index ad1916c54e..65d31d0f81 100644 +index fda8dd938a..10cb3c4bec 100644 --- a/thirdparty/embree/kernels/common/scene.cpp +++ b/thirdparty/embree/kernels/common/scene.cpp -@@ -790,16 +790,18 @@ namespace embree +@@ -894,16 +894,18 @@ namespace embree } /* initiate build */ - try { + // -- GODOT start -- + // try { - scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(schedulerMutex); this->scheduler = nullptr; }, 1, !join); + TaskScheduler::TaskGroupContext context; + scheduler->spawn_root([&]() { commit_task(); Lock<MutexSys> lock(taskGroup->schedulerMutex); taskGroup->scheduler = nullptr; }, &context, 1, !join); - } - catch (...) { - accels_clear(); -- updateInterface(); -- Lock<MutexSys> lock(schedulerMutex); -- this->scheduler = nullptr; +- Lock<MutexSys> lock(taskGroup->schedulerMutex); +- taskGroup->scheduler = nullptr; - throw; - } + // } + // catch (...) { + // accels_clear(); -+ // updateInterface(); -+ // Lock<MutexSys> lock(schedulerMutex); -+ // this->scheduler = nullptr; ++ // Lock<MutexSys> lock(taskGroup->schedulerMutex); ++ // taskGroup->scheduler = nullptr; + // throw; + // } + // -- GODOT end -- } #endif +diff --git a/thirdparty/embree/kernels/common/state.cpp b/thirdparty/embree/kernels/common/state.cpp +index 4e3ab6ddfb..1d73ae9629 100644 +--- a/thirdparty/embree/kernels/common/state.cpp ++++ b/thirdparty/embree/kernels/common/state.cpp +@@ -194,13 +194,15 @@ namespace embree + bool State::parseFile(const FileName& fileName) + { + Ref<Stream<int> > file; +- try { ++ // -- GODOT start -- ++ // try { + file = new FileStream(fileName); +- } +- catch (std::runtime_error& e) { +- (void) e; +- return false; +- } ++ // } ++ // catch (std::runtime_error& e) { ++ // (void) e; ++ // return false; ++ // } ++ // -- GODOT end -- + + std::vector<std::string> syms; + for (size_t i=0; i<sizeof(symbols)/sizeof(void*); i++) diff --git a/thirdparty/embree/patches/godot-config-changes.patch b/thirdparty/embree/patches/godot-config-changes.patch new file mode 100644 index 0000000000..88e15c282c --- /dev/null +++ b/thirdparty/embree/patches/godot-config-changes.patch @@ -0,0 +1,102 @@ +diff --git a/thirdparty/embree/include/embree4/rtcore_config.h b/thirdparty/embree/include/embree4/rtcore_config.h +index 8abd6954c3..cb3a8678a7 100644 +--- a/thirdparty/embree/include/embree4/rtcore_config.h ++++ b/thirdparty/embree/include/embree4/rtcore_config.h +@@ -4,7 +4,7 @@ + #pragma once + + #if !defined(EMBREE_SYCL_SUPPORT) +-#cmakedefine EMBREE_SYCL_SUPPORT ++// #cmakedefine EMBREE_SYCL_SUPPORT + #endif + + #define RTC_VERSION_MAJOR 4 +@@ -13,28 +13,28 @@ + #define RTC_VERSION 40301 + #define RTC_VERSION_STRING "4.3.1" + +-#define RTC_MAX_INSTANCE_LEVEL_COUNT @EMBREE_MAX_INSTANCE_LEVEL_COUNT@ ++#define RTC_MAX_INSTANCE_LEVEL_COUNT 1 + +-#cmakedefine EMBREE_GEOMETRY_INSTANCE_ARRAY ++// #cmakedefine EMBREE_GEOMETRY_INSTANCE_ARRAY + #if defined(EMBREE_GEOMETRY_INSTANCE_ARRAY) + #define RTC_GEOMETRY_INSTANCE_ARRAY + #endif + +-#cmakedefine01 EMBREE_SYCL_GEOMETRY_CALLBACK ++// #cmakedefine01 EMBREE_SYCL_GEOMETRY_CALLBACK + +-#cmakedefine01 EMBREE_MIN_WIDTH ++#define EMBREE_MIN_WIDTH 0 + #define RTC_MIN_WIDTH EMBREE_MIN_WIDTH + + #if !defined(EMBREE_STATIC_LIB) +-#cmakedefine EMBREE_STATIC_LIB ++#define EMBREE_STATIC_LIB + #endif +-#cmakedefine EMBREE_API_NAMESPACE ++// #cmakedefine EMBREE_API_NAMESPACE + + #if defined(EMBREE_API_NAMESPACE) +-# define RTC_NAMESPACE @EMBREE_API_NAMESPACE@ +-# define RTC_NAMESPACE_BEGIN namespace @EMBREE_API_NAMESPACE@ { ++# define RTC_NAMESPACE ++# define RTC_NAMESPACE_BEGIN namespace { + # define RTC_NAMESPACE_END } +-# define RTC_NAMESPACE_USE using namespace @EMBREE_API_NAMESPACE@; ++# define RTC_NAMESPACE_USE using namespace; + # define RTC_API_EXTERN_C + # undef EMBREE_API_NAMESPACE + #else +diff --git a/thirdparty/embree/kernels/config.h b/thirdparty/embree/kernels/config.h +index 1669c4af72..5979b543c9 100644 +--- a/thirdparty/embree/kernels/config.h ++++ b/thirdparty/embree/kernels/config.h +@@ -3,27 +3,27 @@ + + #include "../include/embree4/rtcore_config.h" + +-#cmakedefine EMBREE_RAY_MASK +-#cmakedefine EMBREE_STAT_COUNTERS +-#cmakedefine EMBREE_BACKFACE_CULLING +-#cmakedefine EMBREE_BACKFACE_CULLING_CURVES +-#cmakedefine EMBREE_BACKFACE_CULLING_SPHERES +-#cmakedefine EMBREE_FILTER_FUNCTION +-#cmakedefine EMBREE_IGNORE_INVALID_RAYS +-#cmakedefine EMBREE_GEOMETRY_TRIANGLE +-#cmakedefine EMBREE_GEOMETRY_QUAD +-#cmakedefine EMBREE_GEOMETRY_CURVE +-#cmakedefine EMBREE_GEOMETRY_SUBDIVISION +-#cmakedefine EMBREE_GEOMETRY_USER +-#cmakedefine EMBREE_GEOMETRY_INSTANCE ++// #cmakedefine EMBREE_RAY_MASK ++// #cmakedefine EMBREE_STAT_COUNTERS ++// #cmakedefine EMBREE_BACKFACE_CULLING ++// #cmakedefine EMBREE_BACKFACE_CULLING_CURVES ++// #cmakedefine EMBREE_BACKFACE_CULLING_SPHERES ++#define EMBREE_FILTER_FUNCTION ++// #cmakedefine EMBREE_IGNORE_INVALID_RAYS ++#define EMBREE_GEOMETRY_TRIANGLE ++// #cmakedefine EMBREE_GEOMETRY_QUAD ++// #cmakedefine EMBREE_GEOMETRY_CURVE ++// #cmakedefine EMBREE_GEOMETRY_SUBDIVISION ++// #cmakedefine EMBREE_GEOMETRY_USER ++// #cmakedefine EMBREE_GEOMETRY_INSTANCE + // EMBREE_GEOMETRY_INSTANCE_ARRAY is defined in rtcore_config.h +-#cmakedefine EMBREE_GEOMETRY_GRID +-#cmakedefine EMBREE_GEOMETRY_POINT +-#cmakedefine EMBREE_RAY_PACKETS +-#cmakedefine EMBREE_COMPACT_POLYS ++// #cmakedefine EMBREE_GEOMETRY_GRID ++// #cmakedefine EMBREE_GEOMETRY_POINT ++#define EMBREE_RAY_PACKETS ++// #cmakedefine EMBREE_COMPACT_POLYS + +-#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR @EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR@ +-#cmakedefine EMBREE_DISC_POINT_SELF_INTERSECTION_AVOIDANCE ++#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0 ++#define EMBREE_DISC_POINT_SELF_INTERSECTION_AVOIDANCE + + #if defined(EMBREE_GEOMETRY_TRIANGLE) + #define IF_ENABLED_TRIS(x) x diff --git a/thirdparty/thorvg/inc/config.h b/thirdparty/thorvg/inc/config.h index 1133b99e64..67716b66cc 100644 --- a/thirdparty/thorvg/inc/config.h +++ b/thirdparty/thorvg/inc/config.h @@ -10,5 +10,5 @@ // For internal debugging: //#define THORVG_LOG_ENABLED -#define THORVG_VERSION_STRING "0.12.7" +#define THORVG_VERSION_STRING "0.12.9" #endif diff --git a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp index 67c87ba149..f9780749a9 100644 --- a/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp +++ b/thirdparty/thorvg/src/loaders/svg/tvgSvgPath.cpp @@ -122,9 +122,6 @@ void _pathAppendArcTo(Array<PathCommand>* cmds, Array<Point>* pts, Point* cur, P sx = cur->x; sy = cur->y; - //If start and end points are identical, then no arc is drawn - if ((fabsf(x - sx) < (1.0f / 256.0f)) && (fabsf(y - sy) < (1.0f / 256.0f))) return; - //Correction of out-of-range radii, see F6.6.1 (step 2) rx = fabsf(rx); ry = fabsf(ry); diff --git a/thirdparty/thorvg/src/renderer/tvgScene.h b/thirdparty/thorvg/src/renderer/tvgScene.h index 5fb6e45cab..8b1981edfa 100644 --- a/thirdparty/thorvg/src/renderer/tvgScene.h +++ b/thirdparty/thorvg/src/renderer/tvgScene.h @@ -133,7 +133,6 @@ struct Scene::Impl if (needComp) { cmp = renderer->target(bounds(renderer), renderer->colorSpace()); renderer->beginComposite(cmp, CompositeMethod::None, opacity); - needComp = false; } for (auto paint : paints) { diff --git a/thirdparty/thorvg/src/renderer/tvgShape.h b/thirdparty/thorvg/src/renderer/tvgShape.h index 740da55847..e438a61c16 100644 --- a/thirdparty/thorvg/src/renderer/tvgShape.h +++ b/thirdparty/thorvg/src/renderer/tvgShape.h @@ -56,7 +56,6 @@ struct Shape::Impl if (needComp) { cmp = renderer->target(bounds(renderer), renderer->colorSpace()); renderer->beginComposite(cmp, CompositeMethod::None, opacity); - needComp = false; } ret = renderer->renderShape(rd); if (cmp) renderer->endComposite(cmp); diff --git a/thirdparty/thorvg/update-thorvg.sh b/thirdparty/thorvg/update-thorvg.sh index 3ef2c25878..7a754c09b9 100755 --- a/thirdparty/thorvg/update-thorvg.sh +++ b/thirdparty/thorvg/update-thorvg.sh @@ -1,6 +1,6 @@ #!/bin/bash -e -VERSION=0.12.7 +VERSION=0.12.9 cd thirdparty/thorvg/ || true rm -rf AUTHORS LICENSE inc/ src/ *.zip *.tar.gz tmp/ |