diff --git a/.gitignore b/.gitignore index 92be3345706..19da8b9205c 100644 --- a/.gitignore +++ b/.gitignore @@ -65,3 +65,10 @@ waveletNoiseTile.bin /release/datafiles/locale/ /release/scripts/addons_contrib/ /source/tools/ + +# Build files for VS and VS Code. +/build/ +/out/ +CMakeSettings.json +CMakePresets.json +CMakeUserPresets.json diff --git a/CMakeLists.txt b/CMakeLists.txt index f351fe1cd82..86785737b11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1555,6 +1555,9 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") # add_check_c_compiler_flag(C_WARNINGS C_WARN_UNUSED_MACROS -Wunused-macros) # add_check_cxx_compiler_flag(CXX_WARNINGS CXX_WARN_UNUSED_MACROS -Wunused-macros) + add_check_c_compiler_flag(C_WARNINGS C_WARN_ERROR_UNGUARDED_AVAILABILITY_NEW -Werror=unguarded-availability-new) + add_check_c_compiler_flag(CXX_WARNINGS CXX_WARN_ERROR_UNGUARDED_AVAILABILITY_NEW -Werror=unguarded-availability-new) + # --------------------- # Suppress Strict Flags @@ -1607,6 +1610,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "MSVC") # warning level: "/W3" "/w34062" # switch statement contains 'default' but no 'case' labels + "/w34100" # 'identifier' : unreferenced formal parameter "/w34115" # 'type' : named type definition in parentheses "/w34189" # local variable is initialized but not referenced # see https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/c5038?view=vs-2017 @@ -1933,7 +1937,7 @@ if(FIRST_RUN) info_cfg_option(WITH_IMAGE_OPENEXR) info_cfg_option(WITH_IMAGE_OPENJPEG) info_cfg_option(WITH_IMAGE_TIFF) - + info_cfg_text("Audio:") info_cfg_option(WITH_CODEC_AVI) info_cfg_option(WITH_CODEC_FFMPEG) diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 958c8205bfd..92e36767cad 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -702,6 +702,7 @@ macro(remove_strict_flags) endif() if(MSVC) + remove_cc_flag(/w34100) # Restore warn C4100 (unreferenced formal parameter) back to w4 remove_cc_flag(/w34189) # Restore warn C4189 (unused variable) back to w4 endif() @@ -721,7 +722,7 @@ macro(remove_extra_strict_flags) endif() if(MSVC) - # TODO + remove_cc_flag(/w34100) # Restore warn C4100 (unreferenced formal parameter) back to w4 endif() endmacro() diff --git a/build_files/cmake/platform/platform_win32.cmake b/build_files/cmake/platform/platform_win32.cmake index e52d2be3b34..fc1dcfc6803 100644 --- a/build_files/cmake/platform/platform_win32.cmake +++ b/build_files/cmake/platform/platform_win32.cmake @@ -993,6 +993,23 @@ if(WITH_VULKAN_BACKEND) endif() endif() +if(WITH_VULKAN_BACKEND) + if(EXISTS ${LIBDIR}/shaderc) + set(SHADERC_FOUND On) + set(SHADERC_ROOT_DIR ${LIBDIR}/shaderc) + set(SHADERC_INCLUDE_DIR ${SHADERC_ROOT_DIR}/include) + set(SHADERC_INCLUDE_DIRS ${SHADERC_INCLUDE_DIR}) + set(SHADERC_LIBRARY + DEBUG ${SHADERC_ROOT_DIR}/lib/shaderc_shared_d.lib + OPTIMIZED ${SHADERC_ROOT_DIR}/lib/shaderc_shared.lib + ) + set(SHADERC_LIBRARIES ${SHADERC_LIBRARY}) + else() + message(WARNING "Shaderc was not found, disabling WITH_VULKAN_BACKEND") + set(WITH_VULKAN_BACKEND OFF) + endif() +endif() + if(WITH_CYCLES AND WITH_CYCLES_PATH_GUIDING) find_package(openpgl QUIET) if(openpgl_FOUND) diff --git a/build_files/windows/check_submodules.cmd b/build_files/windows/check_submodules.cmd deleted file mode 100644 index 9138870f838..00000000000 --- a/build_files/windows/check_submodules.cmd +++ /dev/null @@ -1,20 +0,0 @@ -if NOT exist "%BLENDER_DIR%\source\tools\.git" ( - echo Checking out sub-modules - if not "%GIT%" == "" ( - "%GIT%" submodule update --init --recursive --progress - if errorlevel 1 goto FAIL - "%GIT%" submodule foreach git checkout main - if errorlevel 1 goto FAIL - "%GIT%" submodule foreach git pull --rebase origin main - if errorlevel 1 goto FAIL - goto EOF - ) else ( - echo Blender submodules not found, and git not found in path to retrieve them. - goto FAIL - ) -) -goto EOF - -:FAIL -exit /b 1 -:EOF \ No newline at end of file diff --git a/build_files/windows/format.cmd b/build_files/windows/format.cmd index 95440cb1818..c68286738ab 100644 --- a/build_files/windows/format.cmd +++ b/build_files/windows/format.cmd @@ -14,7 +14,7 @@ if NOT EXIST %PYTHON% ( exit /b 1 ) -set FORMAT_PATHS=%BLENDER_DIR%\source\tools\utils_maintenance\clang_format_paths.py +set FORMAT_PATHS=%BLENDER_DIR%\tools\utils_maintenance\clang_format_paths.py REM The formatting script expects clang-format to be in the current PATH. set PATH=%CF_PATH%;%PATH% diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index f43f91bcc9f..876a8307dcb 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1865,7 +1865,7 @@ def pyrna2sphinx(basepath): else: url_base = API_BASEURL - fw(" :file: `%s\\:%d <%s/%s$%d>`_\n\n" % + fw(" :file:`%s\\:%d <%s/%s#L%d>`_\n\n" % (location[0], location[1], url_base, location[0], location[1])) file.close() diff --git a/extern/tinygltf/README.blender b/extern/tinygltf/README.blender index 2aba84dea80..3dcd6d15f03 100644 --- a/extern/tinygltf/README.blender +++ b/extern/tinygltf/README.blender @@ -1,6 +1,5 @@ Project: TinyGLTF URL: https://github.com/syoyo/tinygltf License: MIT -Upstream version: 2.5.0, 19a41d20ec0 -Local modifications: -* Silence "enum value not handled in switch" warnings due to JSON dependency. +Upstream version: 2.8.3, 84a83d39f55d +Local modifications: None diff --git a/extern/tinygltf/patches/TinyGLTF.diff b/extern/tinygltf/patches/TinyGLTF.diff deleted file mode 100644 index 411bd5621f3..00000000000 Binary files a/extern/tinygltf/patches/TinyGLTF.diff and /dev/null differ diff --git a/extern/tinygltf/tiny_gltf.h b/extern/tinygltf/tiny_gltf.h index 099e0c76d92..c935b89df9a 100644 --- a/extern/tinygltf/tiny_gltf.h +++ b/extern/tinygltf/tiny_gltf.h @@ -26,8 +26,16 @@ // THE SOFTWARE. // Version: +// - v2.8.1 Missed serialization texture sampler name fixed. PR#399. +// - v2.8.0 Add URICallbacks for custom URI handling in Buffer and Image. PR#397. +// - v2.7.0 Change WriteImageDataFunction user callback function signature. PR#393. +// - v2.6.3 Fix GLB file with empty BIN chunk was not handled. PR#382 and PR#383. +// - v2.6.2 Fix out-of-bounds access of accessors. PR#379. +// - v2.6.1 Better GLB validation check when loading. +// - v2.6.0 Support serializing sparse accessor(Thanks to @fynv). +// Disable expanding file path for security(no use of awkward `wordexp` anymore). // - v2.5.0 Add SetPreserveImageChannels() option to load image data as is. -// - v2.4.3 Fix null object output when when material has all default +// - v2.4.3 Fix null object output when material has all default // parameters. // - v2.4.2 Decode percent-encoded URI. // - v2.4.1 Fix some glTF object class does not have `extensions` and/or @@ -41,7 +49,7 @@ // - v2.2.0 Add loading 16bit PNG support. Add Sparse accessor support(Thanks // to @Ybalrid) // - v2.1.0 Add draco compression. -// - v2.0.1 Add comparsion feature(Thanks to @Selmar). +// - v2.0.1 Add comparison feature(Thanks to @Selmar). // - v2.0.0 glTF 2.0!. // // Tiny glTF loader is using following third party libraries: @@ -64,6 +72,11 @@ #include #include +//Auto-detect C++14 standard version +#if !defined(TINYGLTF_USE_CPP14) && defined(__cplusplus) && (__cplusplus >= 201402L) +#define TINYGLTF_USE_CPP14 +#endif + #ifndef TINYGLTF_USE_CPP14 #include #endif @@ -108,7 +121,11 @@ namespace tinygltf { #define TINYGLTF_COMPONENT_TYPE_INT (5124) #define TINYGLTF_COMPONENT_TYPE_UNSIGNED_INT (5125) #define TINYGLTF_COMPONENT_TYPE_FLOAT (5126) -#define TINYGLTF_COMPONENT_TYPE_DOUBLE (5130) +#define TINYGLTF_COMPONENT_TYPE_DOUBLE \ + (5130) // OpenGL double type. Note that some of glTF 2.0 validator does not + // support double type even the schema seems allow any value of + // integer: + // https://github.com/KhronosGroup/glTF/blob/b9884a2fd45130b4d673dd6c8a706ee21ee5c5f7/specification/2.0/schema/accessor.schema.json#L22 #define TINYGLTF_TEXTURE_FILTER_NEAREST (9728) #define TINYGLTF_TEXTURE_FILTER_LINEAR (9729) @@ -186,7 +203,11 @@ namespace tinygltf { #ifdef __ANDROID__ #ifdef TINYGLTF_ANDROID_LOAD_FROM_ASSETS +#ifdef TINYGLTF_IMPLEMENTATION AAssetManager *asset_manager = nullptr; +#else +extern AAssetManager *asset_manager; +#endif #endif #endif @@ -219,7 +240,7 @@ static inline int32_t GetComponentSizeInBytes(uint32_t componentType) { } else if (componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) { return 8; } else { - // Unknown componenty type + // Unknown component type return -1; } } @@ -240,7 +261,7 @@ static inline int32_t GetNumComponentsInType(uint32_t ty) { } else if (ty == TINYGLTF_TYPE_MAT4) { return 16; } else { - // Unknown componenty type + // Unknown component type return -1; } } @@ -253,7 +274,6 @@ bool DecodeDataURI(std::vector *out, std::string &mime_type, #ifdef __clang__ #pragma clang diagnostic push // Suppress warning for : static Value null_value -// https://stackoverflow.com/questions/15708411/how-to-deal-with-global-constructor-warning-in-clang #pragma clang diagnostic ignored "-Wexit-time-destructors" #pragma clang diagnostic ignored "-Wpadded" #endif @@ -428,7 +448,7 @@ TINYGLTF_VALUE_GET(Value::Object, object_value_) #pragma clang diagnostic ignored "-Wpadded" #endif -/// Agregate object for representing a color +/// Aggregate object for representing a color using ColorValue = std::array; // === legacy interface ==== @@ -465,7 +485,7 @@ struct Parameter { if (it != std::end(json_double_value)) { return int(it->second); } - // As per the spec, if texCoord is ommited, this parameter is 0 + // As per the spec, if texCoord is omitted, this parameter is 0 return 0; } @@ -477,7 +497,7 @@ struct Parameter { if (it != std::end(json_double_value)) { return it->second; } - // As per the spec, if scale is ommited, this paramter is 1 + // As per the spec, if scale is omitted, this parameter is 1 return 1; } @@ -489,7 +509,7 @@ struct Parameter { if (it != std::end(json_double_value)) { return it->second; } - // As per the spec, if strenghth is ommited, this parameter is 1 + // As per the spec, if strength is omitted, this parameter is 1 return 1; } @@ -503,7 +523,7 @@ struct Parameter { /// material ColorValue ColorFactor() const { return { - {// this agregate intialize the std::array object, and uses C++11 RVO. + {// this aggregate initialize the std::array object, and uses C++11 RVO. number_array[0], number_array[1], number_array[2], (number_array.size() > 3 ? number_array[3] : 1.0)}}; } @@ -527,9 +547,10 @@ typedef std::map ExtensionMap; struct AnimationChannel { int sampler; // required - int target_node; // required (index of the node to target) - std::string target_path; // required in ["translation", "rotation", "scale", - // "weights"] + int target_node; // optional index of the node to target (alternative + // target should be provided by extension) + std::string target_path; // required with standard values of ["translation", + // "rotation", "scale", "weights"] Value extras; ExtensionMap extensions; ExtensionMap target_extensions; @@ -614,7 +635,8 @@ struct Sampler { int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT; // ["CLAMP_TO_EDGE", "MIRRORED_REPEAT", // "REPEAT"], default "REPEAT" - //int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently not used. + // int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; // TinyGLTF extension. currently + // not used. Value extras; ExtensionMap extensions; @@ -813,7 +835,7 @@ struct BufferView { size_t byteStride{0}; // minimum 4, maximum 252 (multiple of 4), default 0 = // understood to be tightly packed int target{0}; // ["ARRAY_BUFFER", "ELEMENT_ARRAY_BUFFER"] for vertex indices - // or atttribs. Could be 0 for other data + // or attribs. Could be 0 for other data Value extras; ExtensionMap extensions; @@ -889,7 +911,7 @@ struct Accessor { return componentSizeInBytes * numComponents; } else { - // Check if byteStride is a mulple of the size of the accessor's component + // Check if byteStride is a multiple of the size of the accessor's component // type. int componentSizeInBytes = GetComponentSizeInBytes(static_cast(componentType)); @@ -928,7 +950,7 @@ struct PerspectiveCamera { PerspectiveCamera() : aspectRatio(0.0), yfov(0.0), - zfar(0.0) // 0 = use infinite projecton matrix + zfar(0.0) // 0 = use infinite projection matrix , znear(0.0) {} DEFAULT_METHODS(PerspectiveCamera) @@ -989,7 +1011,7 @@ struct Primitive { int indices; // The index of the accessor that contains the indices. int mode; // one of TINYGLTF_MODE_*** std::vector > targets; // array of morph targets, - // where each target is a dict with attribues in ["POSITION, "NORMAL", + // where each target is a dict with attributes in ["POSITION, "NORMAL", // "TANGENT"] pointing // to their corresponding accessors ExtensionMap extensions; @@ -1124,7 +1146,7 @@ struct Light { std::vector color; double intensity{1.0}; std::string type; - double range{0.0}; // 0.0 = inifinite + double range{0.0}; // 0.0 = infinite SpotLight spot; Light() : intensity(1.0), range(0.0) {} @@ -1188,6 +1210,39 @@ enum SectionCheck { REQUIRE_ALL = 0x7f }; +/// +/// URIEncodeFunction type. Signature for custom URI encoding of external +/// resources such as .bin and image files. Used by tinygltf to re-encode the +/// final location of saved files. object_type may be used to encode buffer and +/// image URIs differently, for example. See +/// https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#uris +/// +typedef bool (*URIEncodeFunction)(const std::string &in_uri, + const std::string &object_type, + std::string *out_uri, void *user_data); + +/// +/// URIDecodeFunction type. Signature for custom URI decoding of external +/// resources such as .bin and image files. Used by tinygltf when computing +/// filenames to write resources. +/// +typedef bool (*URIDecodeFunction)(const std::string &in_uri, + std::string *out_uri, void *user_data); + +// Declaration of default uri decode function +bool URIDecode(const std::string &in_uri, std::string *out_uri, + void *user_data); + +/// +/// A structure containing URI callbacks and a pointer to their user data. +/// +struct URICallbacks { + URIEncodeFunction encode; // Optional encode method + URIDecodeFunction decode; // Required decode method + + void *user_data; // An argument that is passed to all uri callbacks +}; + /// /// LoadImageDataFunction type. Signature for custom image loading callbacks. /// @@ -1198,9 +1253,15 @@ typedef bool (*LoadImageDataFunction)(Image *, const int, std::string *, /// /// WriteImageDataFunction type. Signature for custom image writing callbacks. +/// The out_uri parameter becomes the URI written to the gltf and may reference +/// a file or contain a data URI. /// -typedef bool (*WriteImageDataFunction)(const std::string *, const std::string *, - Image *, bool, void *); +typedef bool (*WriteImageDataFunction)(const std::string *basepath, + const std::string *filename, + const Image *image, bool embedImages, + const URICallbacks *uri_cb, + std::string *out_uri, + void *user_pointer); #ifndef TINYGLTF_NO_STB_IMAGE // Declaration of default image loader callback @@ -1212,7 +1273,8 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, #ifndef TINYGLTF_NO_STB_IMAGE_WRITE // Declaration of default image writer callback bool WriteImageData(const std::string *basepath, const std::string *filename, - Image *image, bool embedImages, void *); + const Image *image, bool embedImages, + const URICallbacks *uri_cb, std::string *out_uri, void *); #endif /// @@ -1274,7 +1336,7 @@ bool WriteWholeFile(std::string *err, const std::string &filepath, #endif /// -/// glTF Parser/Serialier context. +/// glTF Parser/Serializer context. /// class TinyGLTF { public: @@ -1303,8 +1365,10 @@ class TinyGLTF { /// /// Loads glTF ASCII asset from string(memory). /// `length` = strlen(str); - /// Set warning message to `warn` for example it fails to load asserts. - /// Returns false and set error string to `err` if there's an error. + /// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an + /// expanded path (e.g. no tilde(`~`), no environment variables). Set warning + /// message to `warn` for example it fails to load asserts. Returns false and + /// set error string to `err` if there's an error. /// bool LoadASCIIFromString(Model *model, std::string *err, std::string *warn, const char *str, const unsigned int length, @@ -1323,6 +1387,8 @@ class TinyGLTF { /// /// Loads glTF binary asset from memory. /// `length` = strlen(str); + /// `base_dir` is a search path of glTF asset(e.g. images). Path Must be an + /// expanded path (e.g. no tilde(`~`), no environment variables). /// Set warning message to `warn` for example it fails to load asserts. /// Returns false and set error string to `err` if there's an error. /// @@ -1333,15 +1399,15 @@ class TinyGLTF { unsigned int check_sections = REQUIRE_VERSION); /// - /// Write glTF to stream, buffers and images will be embeded + /// Write glTF to stream, buffers and images will be embedded /// - bool WriteGltfSceneToStream(Model *model, std::ostream &stream, + bool WriteGltfSceneToStream(const Model *model, std::ostream &stream, bool prettyPrint, bool writeBinary); /// /// Write glTF to file. /// - bool WriteGltfSceneToFile(Model *model, const std::string &filename, + bool WriteGltfSceneToFile(const Model *model, const std::string &filename, bool embedImages, bool embedBuffers, bool prettyPrint, bool writeBinary); @@ -1360,6 +1426,11 @@ class TinyGLTF { /// void SetImageWriter(WriteImageDataFunction WriteImageData, void *user_data); + /// + /// Set callbacks to use for URI encoding and decoding and their user data + /// + void SetURICallbacks(URICallbacks callbacks); + /// /// Set callbacks to use for filesystem (fs) access and their user data /// @@ -1368,7 +1439,7 @@ class TinyGLTF { /// /// Set serializing default values(default = false). /// When true, default values are force serialized to .glTF. - /// This may be helpfull if you want to serialize a full description of glTF + /// This may be helpful if you want to serialize a full description of glTF /// data. /// /// TODO(LTE): Supply parsing option as function arguments to @@ -1394,8 +1465,8 @@ class TinyGLTF { } /// - /// Specify whether preserve image channales when loading images or not. - /// (Not effective when the user suppy their own LoadImageData callbacks) + /// Specify whether preserve image channels when loading images or not. + /// (Not effective when the user supplies their own LoadImageData callbacks) /// void SetPreserveImageChannels(bool onoff) { preserve_image_channels_ = onoff; @@ -1425,6 +1496,10 @@ class TinyGLTF { bool preserve_image_channels_ = false; /// Default false(expand channels to /// RGBA) for backward compatibility. + // Warning & error messages + std::string warn_; + std::string err_; + FsCallbacks fs = { #ifndef TINYGLTF_NO_FS &tinygltf::FileExists, &tinygltf::ExpandFilePath, @@ -1438,6 +1513,15 @@ class TinyGLTF { #endif }; + URICallbacks uri_cb = { + // Use paths as-is by default. This will use JSON string escaping. + nullptr, + // Decode all URIs before using them as paths as the application may have + // percent encoded them. + &tinygltf::URIDecode, + // URI callback user data + nullptr}; + LoadImageDataFunction LoadImageData = #ifndef TINYGLTF_NO_STB_IMAGE &tinygltf::LoadImageData; @@ -1528,7 +1612,7 @@ class TinyGLTF { #endif #endif -// Disable GCC warnigs +// Disable GCC warnings #ifdef __GNUC__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wtype-limits" @@ -1577,7 +1661,7 @@ class TinyGLTF { // issue 143. // Define NOMINMAX to avoid min/max defines, -// but undef it after included windows.h +// but undef it after included Windows.h #ifndef NOMINMAX #define TINYGLTF_INTERNAL_NOMINMAX #define NOMINMAX @@ -1587,7 +1671,11 @@ class TinyGLTF { #define WIN32_LEAN_AND_MEAN #define TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN #endif -#include // include API for expanding a file path +#ifndef __MINGW32__ +#include // include API for expanding a file path +#else +#include +#endif #ifdef TINYGLTF_INTERNAL_WIN32_LEAN_AND_MEAN #undef WIN32_LEAN_AND_MEAN @@ -1606,10 +1694,10 @@ class TinyGLTF { #endif #elif !defined(__ANDROID__) && !defined(__OpenBSD__) -#include +//#include #endif -#if defined(__sparcv9) +#if defined(__sparcv9) || defined(__powerpc__) // Big endian #else #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU @@ -1617,7 +1705,8 @@ class TinyGLTF { #endif #endif -namespace { +namespace tinygltf { +namespace detail { #ifdef TINYGLTF_USE_RAPIDJSON #ifdef TINYGLTF_USE_RAPIDJSON_CRTALLOCATOR @@ -1693,10 +1782,11 @@ void JsonParse(JsonDocument &doc, const char *str, size_t length, (void)throwExc; doc.Parse(str, length); #else - doc = json::parse(str, str + length, nullptr, throwExc); + doc = detail::json::parse(str, str + length, nullptr, throwExc); #endif } } // namespace +} #ifdef __APPLE__ #include "TargetConditionals.h" @@ -1718,7 +1808,7 @@ namespace tinygltf { struct LoadImageDataOption { // true: preserve image channels(e.g. load as RGB image if the image has RGB // channels) default `false`(channels are expanded to RGBA for backward - // compatiblity). + // compatibility). bool preserve_channels{false}; }; @@ -1934,9 +2024,9 @@ bool Sampler::operator==(const Sampler &other) const { return this->extensions == other.extensions && this->extras == other.extras && this->magFilter == other.magFilter && this->minFilter == other.minFilter && this->name == other.name && - this->wrapT == other.wrapT; + this->wrapS == other.wrapS && this->wrapT == other.wrapT; - //this->wrapR == other.wrapR && this->wrapS == other.wrapS && + // this->wrapR == other.wrapR } bool Scene::operator==(const Scene &other) const { return this->extensions == other.extensions && this->extras == other.extras && @@ -2040,9 +2130,10 @@ static std::string GetBaseDir(const std::string &filepath) { return ""; } -// https://stackoverflow.com/questions/8520560/get-a-file-name-from-a-path static std::string GetBaseFilename(const std::string &filepath) { - return filepath.substr(filepath.find_last_of("/\\") + 1); + auto idx = filepath.find_last_of("/\\"); + if (idx != std::string::npos) return filepath.substr(idx + 1); + return filepath; } std::string base64_encode(unsigned char const *, unsigned int len); @@ -2188,47 +2279,35 @@ std::string base64_decode(std::string const &encoded_string) { // TODO(syoyo): Use uriparser https://uriparser.github.io/ for stricter Uri // decoding? // -// https://stackoverflow.com/questions/18307429/encode-decode-url-in-c +// Uri Decoding from DLIB // http://dlib.net/dlib/server/server_http.cpp.html - -// --- dlib beign ------------------------------------------------------------ +// --- dlib begin ------------------------------------------------------------ // Copyright (C) 2003 Davis E. King (davis@dlib.net) -// License: Boost Software License See LICENSE.txt for the full license. +// License: Boost Software License +// Boost Software License - Version 1.0 - August 17th, 2003 +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// namespace dlib { -#if 0 - inline unsigned char to_hex( unsigned char x ) - { - return x + (x > 9 ? ('A'-10) : '0'); - } - - const std::string urlencode( const std::string& s ) - { - std::ostringstream os; - - for ( std::string::const_iterator ci = s.begin(); ci != s.end(); ++ci ) - { - if ( (*ci >= 'a' && *ci <= 'z') || - (*ci >= 'A' && *ci <= 'Z') || - (*ci >= '0' && *ci <= '9') ) - { // allowed - os << *ci; - } - else if ( *ci == ' ') - { - os << '+'; - } - else - { - os << '%' << to_hex(static_cast(*ci >> 4)) << to_hex(static_cast(*ci % 16)); - } - } - - return os.str(); - } -#endif - inline unsigned char from_hex(unsigned char ch) { if (ch <= '9' && ch >= '0') ch -= '0'; @@ -2266,6 +2345,13 @@ static const std::string urldecode(const std::string &str) { } // namespace dlib // --- dlib end -------------------------------------------------------------- +bool URIDecode(const std::string &in_uri, std::string *out_uri, + void *user_data) { + (void)user_data; + *out_uri = dlib::urldecode(in_uri); + return true; +} + static bool LoadExternalFile(std::vector *out, std::string *err, std::string *warn, const std::string &filename, const std::string &basedir, bool required, @@ -2376,7 +2462,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, // It is possible that the image we want to load is a 16bit per channel image // We are going to attempt to load it as 16bit per channel, and if it worked, - // set the image data accodingly. We are casting the returned pointer into + // set the image data accordingly. We are casting the returned pointer into // unsigned char, because we are representing "bytes". But we are updating // the Image metadata to signal that this image uses 2 bytes (16bits) per // channel: @@ -2391,7 +2477,7 @@ bool LoadImageData(Image *image, const int image_idx, std::string *err, // at this point, if data is still NULL, it means that the image wasn't // 16bit per channel, we are going to load it as a normal 8bit per channel - // mage as we used to do: + // image as we used to do: // if image cannot be decoded, ignore parsing and keep it by its path // don't break in this case // FIXME we should only enter this function if the image is embedded. If @@ -2476,7 +2562,9 @@ static void WriteToMemory_stbi(void *context, void *data, int size) { } bool WriteImageData(const std::string *basepath, const std::string *filename, - Image *image, bool embedImages, void *fsPtr) { + const Image *image, bool embedImages, + const URICallbacks *uri_cb, std::string *out_uri, + void *fsPtr) { const std::string ext = GetFilePathExtension(*filename); // Write image to temporary buffer @@ -2518,9 +2606,8 @@ bool WriteImageData(const std::string *basepath, const std::string *filename, if (embedImages) { // Embed base64-encoded image into URI if (data.size()) { - image->uri = - header + - base64_encode(&data[0], static_cast(data.size())); + *out_uri = header + + base64_encode(&data[0], static_cast(data.size())); } else { // Throw error? } @@ -2538,20 +2625,33 @@ bool WriteImageData(const std::string *basepath, const std::string *filename, } else { // Throw error? } - image->uri = *filename; + if (uri_cb->encode) { + if (!uri_cb->encode(*filename, "image", out_uri, uri_cb->user_data)) { + return false; + } + } else { + *out_uri = *filename; + } } return true; } #endif +void TinyGLTF::SetURICallbacks(URICallbacks callbacks) { + assert(callbacks.decode); + if (callbacks.decode) { + uri_cb = callbacks; + } +} + void TinyGLTF::SetFsCallbacks(FsCallbacks callbacks) { fs = callbacks; } #ifdef _WIN32 static inline std::wstring UTF8ToWchar(const std::string &str) { int wstr_size = MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), nullptr, 0); - std::wstring wstr(wstr_size, 0); + std::wstring wstr((size_t)wstr_size, 0); MultiByteToWideChar(CP_UTF8, 0, str.data(), (int)str.size(), &wstr[0], (int)wstr.size()); return wstr; @@ -2559,10 +2659,10 @@ static inline std::wstring UTF8ToWchar(const std::string &str) { static inline std::string WcharToUTF8(const std::wstring &wstr) { int str_size = WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), - nullptr, 0, NULL, NULL); - std::string str(str_size, 0); + nullptr, 0, nullptr, nullptr); + std::string str((size_t)str_size, 0); WideCharToMultiByte(CP_UTF8, 0, wstr.data(), (int)wstr.size(), &str[0], - (int)str.size(), NULL, NULL); + (int)str.size(), nullptr, nullptr); return str; } #endif @@ -2586,7 +2686,7 @@ bool FileExists(const std::string &abs_filename, void *) { } #else #ifdef _WIN32 -#if defined(_MSC_VER) || defined(__GLIBCXX__) +#if defined(_MSC_VER) || defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) FILE *fp = nullptr; errno_t err = _wfopen_s(&fp, UTF8ToWchar(abs_filename).c_str(), L"rb"); if (err != 0) { @@ -2615,6 +2715,18 @@ bool FileExists(const std::string &abs_filename, void *) { } std::string ExpandFilePath(const std::string &filepath, void *) { + // https://github.com/syoyo/tinygltf/issues/368 + // + // No file path expansion in built-in FS function anymore, since glTF URI + // should not contain tilde('~') and environment variables, and for security + // reason(`wordexp`). + // + // Users need to supply `base_dir`(in `LoadASCIIFromString`, + // `LoadBinaryFromMemory`) in expanded absolute path. + + return filepath; + +#if 0 #ifdef _WIN32 // Assume input `filepath` is encoded in UTF-8 std::wstring wfilepath = UTF8ToWchar(filepath); @@ -2662,6 +2774,7 @@ std::string ExpandFilePath(const std::string &filepath, void *) { return s; #endif +#endif } bool ReadWholeFile(std::vector *out, std::string *err, @@ -2796,15 +2909,21 @@ static std::string MimeToExt(const std::string &mimeType) { return ""; } -static void UpdateImageObject(Image &image, std::string &baseDir, int index, - bool embedImages, - WriteImageDataFunction *WriteImageData = nullptr, - void *user_data = nullptr) { +static bool UpdateImageObject(const Image &image, std::string &baseDir, + int index, bool embedImages, + const URICallbacks *uri_cb, + WriteImageDataFunction *WriteImageData, + void *user_data, std::string *out_uri) { std::string filename; std::string ext; - // If image has uri, use it it as a filename + // If image has uri, use it as a filename if (image.uri.size()) { - filename = GetBaseFilename(image.uri); + std::string decoded_uri; + if (!uri_cb->decode(image.uri, &decoded_uri, uri_cb->user_data)) { + // A decode failure results in a failure to write the gltf. + return false; + } + filename = GetBaseFilename(decoded_uri); ext = GetFilePathExtension(filename); } else if (image.bufferView != -1) { // If there's no URI and the data exists in a buffer, @@ -2819,11 +2938,24 @@ static void UpdateImageObject(Image &image, std::string &baseDir, int index, filename = std::to_string(index) + "." + ext; } - // If callback is set, modify image data object - if (*WriteImageData != nullptr && !filename.empty()) { - std::string uri; - (*WriteImageData)(&baseDir, &filename, &image, embedImages, user_data); + // If callback is set and image data exists, modify image data object. If + // image data does not exist, this is not considered a failure and the + // original uri should be maintained. + bool imageWritten = false; + if (*WriteImageData != nullptr && !filename.empty() && !image.image.empty()) { + imageWritten = (*WriteImageData)(&baseDir, &filename, &image, embedImages, + uri_cb, out_uri, user_data); + if (!imageWritten) { + return false; + } } + + // Use the original uri if the image was not written. + if (!imageWritten) { + *out_uri = image.uri; + } + + return true; } bool IsDataURI(const std::string &in) { @@ -2937,8 +3069,8 @@ bool DecodeDataURI(std::vector *out, std::string &mime_type, return true; } -namespace { -bool GetInt(const json &o, int &val) { +namespace detail { +bool GetInt(const detail::json &o, int &val) { #ifdef TINYGLTF_USE_RAPIDJSON if (!o.IsDouble()) { if (o.IsInt()) { @@ -2960,8 +3092,8 @@ bool GetInt(const json &o, int &val) { #else auto type = o.type(); - if ((type == json::value_t::number_integer) || - (type == json::value_t::number_unsigned)) { + if ((type == detail::json::value_t::number_integer) || + (type == detail::json::value_t::number_unsigned)) { val = static_cast(o.get()); return true; } @@ -2971,7 +3103,7 @@ bool GetInt(const json &o, int &val) { } #ifdef TINYGLTF_USE_RAPIDJSON -bool GetDouble(const json &o, double &val) { +bool GetDouble(const detail::json &o, double &val) { if (o.IsDouble()) { val = o.GetDouble(); return true; @@ -2981,7 +3113,7 @@ bool GetDouble(const json &o, double &val) { } #endif -bool GetNumber(const json &o, double &val) { +bool GetNumber(const detail::json &o, double &val) { #ifdef TINYGLTF_USE_RAPIDJSON if (o.IsNumber()) { val = o.GetDouble(); @@ -2999,7 +3131,7 @@ bool GetNumber(const json &o, double &val) { #endif } -bool GetString(const json &o, std::string &val) { +bool GetString(const detail::json &o, std::string &val) { #ifdef TINYGLTF_USE_RAPIDJSON if (o.IsString()) { val = o.GetString(); @@ -3008,7 +3140,7 @@ bool GetString(const json &o, std::string &val) { return false; #else - if (o.type() == json::value_t::string) { + if (o.type() == detail::json::value_t::string) { val = o.get(); return true; } @@ -3017,7 +3149,7 @@ bool GetString(const json &o, std::string &val) { #endif } -bool IsArray(const json &o) { +bool IsArray(const detail::json &o) { #ifdef TINYGLTF_USE_RAPIDJSON return o.IsArray(); #else @@ -3025,7 +3157,7 @@ bool IsArray(const json &o) { #endif } -json_const_array_iterator ArrayBegin(const json &o) { +detail::json_const_array_iterator ArrayBegin(const detail::json &o) { #ifdef TINYGLTF_USE_RAPIDJSON return o.Begin(); #else @@ -3033,7 +3165,7 @@ json_const_array_iterator ArrayBegin(const json &o) { #endif } -json_const_array_iterator ArrayEnd(const json &o) { +detail::json_const_array_iterator ArrayEnd(const detail::json &o) { #ifdef TINYGLTF_USE_RAPIDJSON return o.End(); #else @@ -3041,7 +3173,7 @@ json_const_array_iterator ArrayEnd(const json &o) { #endif } -bool IsObject(const json &o) { +bool IsObject(const detail::json &o) { #ifdef TINYGLTF_USE_RAPIDJSON return o.IsObject(); #else @@ -3049,7 +3181,7 @@ bool IsObject(const json &o) { #endif } -json_const_iterator ObjectBegin(const json &o) { +detail::json_const_iterator ObjectBegin(const detail::json &o) { #ifdef TINYGLTF_USE_RAPIDJSON return o.MemberBegin(); #else @@ -3057,7 +3189,7 @@ json_const_iterator ObjectBegin(const json &o) { #endif } -json_const_iterator ObjectEnd(const json &o) { +detail::json_const_iterator ObjectEnd(const detail::json &o) { #ifdef TINYGLTF_USE_RAPIDJSON return o.MemberEnd(); #else @@ -3067,7 +3199,7 @@ json_const_iterator ObjectEnd(const json &o) { // Making this a const char* results in a pointer to a temporary when // TINYGLTF_USE_RAPIDJSON is off. -std::string GetKey(json_const_iterator &it) { +std::string GetKey(detail::json_const_iterator &it) { #ifdef TINYGLTF_USE_RAPIDJSON return it->name.GetString(); #else @@ -3075,7 +3207,7 @@ std::string GetKey(json_const_iterator &it) { #endif } -bool FindMember(const json &o, const char *member, json_const_iterator &it) { +bool FindMember(const detail::json &o, const char *member, detail::json_const_iterator &it) { #ifdef TINYGLTF_USE_RAPIDJSON if (!o.IsObject()) { return false; @@ -3088,7 +3220,7 @@ bool FindMember(const json &o, const char *member, json_const_iterator &it) { #endif } -const json &GetValue(json_const_iterator &it) { +const detail::json &GetValue(detail::json_const_iterator &it) { #ifdef TINYGLTF_USE_RAPIDJSON return it->value; #else @@ -3096,17 +3228,23 @@ const json &GetValue(json_const_iterator &it) { #endif } -std::string JsonToString(const json &o, int spacing = -1) { +std::string JsonToString(const detail::json &o, int spacing = -1) { #ifdef TINYGLTF_USE_RAPIDJSON using namespace rapidjson; StringBuffer buffer; if (spacing == -1) { Writer writer(buffer); - o.Accept(writer); + // TODO: Better error handling. + // https://github.com/syoyo/tinygltf/issues/332 + if (!o.Accept(writer)) { + return "tiny_gltf::JsonToString() failed rapidjson conversion"; + } } else { PrettyWriter writer(buffer); writer.SetIndent(' ', uint32_t(spacing)); - o.Accept(writer); + if (!o.Accept(writer)) { + return "tiny_gltf::JsonToString() failed rapidjson conversion"; + } } return buffer.GetString(); #else @@ -3116,7 +3254,7 @@ std::string JsonToString(const json &o, int spacing = -1) { } // namespace -static bool ParseJsonAsValue(Value *ret, const json &o) { +static bool ParseJsonAsValue(Value *ret, const detail::json &o) { Value val{}; #ifdef TINYGLTF_USE_RAPIDJSON using rapidjson::Type; @@ -3127,7 +3265,7 @@ static bool ParseJsonAsValue(Value *ret, const json &o) { Value entry; ParseJsonAsValue(&entry, it->value); if (entry.Type() != NULL_TYPE) - value_object.emplace(GetKey(it), std::move(entry)); + value_object.emplace(detail::GetKey(it), std::move(entry)); } if (value_object.size() > 0) val = Value(std::move(value_object)); } break; @@ -3152,11 +3290,11 @@ static bool ParseJsonAsValue(Value *ret, const json &o) { case Type::kNumberType: if (!o.IsDouble()) { int i = 0; - GetInt(o, i); + detail::GetInt(o, i); val = Value(i); } else { double d = 0.0; - GetDouble(o, d); + detail::GetDouble(o, d); val = Value(d); } break; @@ -3166,7 +3304,7 @@ static bool ParseJsonAsValue(Value *ret, const json &o) { } #else switch (o.type()) { - case json::value_t::object: { + case detail::json::value_t::object: { Value::Object value_object; for (auto it = o.begin(); it != o.end(); it++) { Value entry; @@ -3176,7 +3314,7 @@ static bool ParseJsonAsValue(Value *ret, const json &o) { } if (value_object.size() > 0) val = Value(std::move(value_object)); } break; - case json::value_t::array: { + case detail::json::value_t::array: { Value::Array value_array; value_array.reserve(o.size()); for (auto it = o.begin(); it != o.end(); it++) { @@ -3187,46 +3325,48 @@ static bool ParseJsonAsValue(Value *ret, const json &o) { } if (value_array.size() > 0) val = Value(std::move(value_array)); } break; - case json::value_t::string: + case detail::json::value_t::string: val = Value(o.get()); break; - case json::value_t::boolean: + case detail::json::value_t::boolean: val = Value(o.get()); break; - case json::value_t::number_integer: - case json::value_t::number_unsigned: + case detail::json::value_t::number_integer: + case detail::json::value_t::number_unsigned: val = Value(static_cast(o.get())); break; - case json::value_t::number_float: + case detail::json::value_t::number_float: val = Value(o.get()); break; - case json::value_t::null: - case json::value_t::binary: - case json::value_t::discarded: + case detail::json::value_t::null: + case detail::json::value_t::discarded: + case detail::json::value_t::binary: // default: break; } #endif + const bool isNotNull = val.Type() != NULL_TYPE; + if (ret) *ret = std::move(val); - return val.Type() != NULL_TYPE; + return isNotNull; } -static bool ParseExtrasProperty(Value *ret, const json &o) { - json_const_iterator it; - if (!FindMember(o, "extras", it)) { +static bool ParseExtrasProperty(Value *ret, const detail::json &o) { + detail::json_const_iterator it; + if (!detail::FindMember(o, "extras", it)) { return false; } - return ParseJsonAsValue(ret, GetValue(it)); + return ParseJsonAsValue(ret, detail::GetValue(it)); } -static bool ParseBooleanProperty(bool *ret, std::string *err, const json &o, +static bool ParseBooleanProperty(bool *ret, std::string *err, const detail::json &o, const std::string &property, const bool required, const std::string &parent_node = "") { - json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { (*err) += "'" + property + "' property is missing"; @@ -3239,7 +3379,7 @@ static bool ParseBooleanProperty(bool *ret, std::string *err, const json &o, return false; } - auto &value = GetValue(it); + auto &value = detail::GetValue(it); bool isBoolean; bool boolValue = false; @@ -3270,12 +3410,12 @@ static bool ParseBooleanProperty(bool *ret, std::string *err, const json &o, return true; } -static bool ParseIntegerProperty(int *ret, std::string *err, const json &o, +static bool ParseIntegerProperty(int *ret, std::string *err, const detail::json &o, const std::string &property, const bool required, const std::string &parent_node = "") { - json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { (*err) += "'" + property + "' property is missing"; @@ -3289,7 +3429,7 @@ static bool ParseIntegerProperty(int *ret, std::string *err, const json &o, } int intValue; - bool isInt = GetInt(GetValue(it), intValue); + bool isInt = detail::GetInt(detail::GetValue(it), intValue); if (!isInt) { if (required) { if (err) { @@ -3306,12 +3446,12 @@ static bool ParseIntegerProperty(int *ret, std::string *err, const json &o, return true; } -static bool ParseUnsignedProperty(size_t *ret, std::string *err, const json &o, +static bool ParseUnsignedProperty(size_t *ret, std::string *err, const detail::json &o, const std::string &property, const bool required, const std::string &parent_node = "") { - json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { (*err) += "'" + property + "' property is missing"; @@ -3324,7 +3464,7 @@ static bool ParseUnsignedProperty(size_t *ret, std::string *err, const json &o, return false; } - auto &value = GetValue(it); + auto &value = detail::GetValue(it); size_t uValue = 0; bool isUValue; @@ -3359,13 +3499,13 @@ static bool ParseUnsignedProperty(size_t *ret, std::string *err, const json &o, return true; } -static bool ParseNumberProperty(double *ret, std::string *err, const json &o, +static bool ParseNumberProperty(double *ret, std::string *err, const detail::json &o, const std::string &property, const bool required, const std::string &parent_node = "") { - json_const_iterator it; + detail::json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { (*err) += "'" + property + "' property is missing"; @@ -3379,7 +3519,7 @@ static bool ParseNumberProperty(double *ret, std::string *err, const json &o, } double numberValue; - bool isNumber = GetNumber(GetValue(it), numberValue); + bool isNumber = detail::GetNumber(detail::GetValue(it), numberValue); if (!isNumber) { if (required) { @@ -3398,11 +3538,11 @@ static bool ParseNumberProperty(double *ret, std::string *err, const json &o, } static bool ParseNumberArrayProperty(std::vector *ret, std::string *err, - const json &o, const std::string &property, + const detail::json &o, const std::string &property, bool required, const std::string &parent_node = "") { - json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { (*err) += "'" + property + "' property is missing"; @@ -3415,7 +3555,7 @@ static bool ParseNumberArrayProperty(std::vector *ret, std::string *err, return false; } - if (!IsArray(GetValue(it))) { + if (!detail::IsArray(detail::GetValue(it))) { if (required) { if (err) { (*err) += "'" + property + "' property is not an array"; @@ -3429,10 +3569,10 @@ static bool ParseNumberArrayProperty(std::vector *ret, std::string *err, } ret->clear(); - auto end = ArrayEnd(GetValue(it)); - for (auto i = ArrayBegin(GetValue(it)); i != end; ++i) { + auto end = detail::ArrayEnd(detail::GetValue(it)); + for (auto i = detail::ArrayBegin(detail::GetValue(it)); i != end; ++i) { double numberValue; - const bool isNumber = GetNumber(*i, numberValue); + const bool isNumber = detail::GetNumber(*i, numberValue); if (!isNumber) { if (required) { if (err) { @@ -3452,12 +3592,12 @@ static bool ParseNumberArrayProperty(std::vector *ret, std::string *err, } static bool ParseIntegerArrayProperty(std::vector *ret, std::string *err, - const json &o, + const detail::json &o, const std::string &property, bool required, const std::string &parent_node = "") { - json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { (*err) += "'" + property + "' property is missing"; @@ -3470,7 +3610,7 @@ static bool ParseIntegerArrayProperty(std::vector *ret, std::string *err, return false; } - if (!IsArray(GetValue(it))) { + if (!detail::IsArray(detail::GetValue(it))) { if (required) { if (err) { (*err) += "'" + property + "' property is not an array"; @@ -3484,10 +3624,10 @@ static bool ParseIntegerArrayProperty(std::vector *ret, std::string *err, } ret->clear(); - auto end = ArrayEnd(GetValue(it)); - for (auto i = ArrayBegin(GetValue(it)); i != end; ++i) { + auto end = detail::ArrayEnd(detail::GetValue(it)); + for (auto i = detail::ArrayBegin(detail::GetValue(it)); i != end; ++i) { int numberValue; - bool isNumber = GetInt(*i, numberValue); + bool isNumber = detail::GetInt(*i, numberValue); if (!isNumber) { if (required) { if (err) { @@ -3507,11 +3647,11 @@ static bool ParseIntegerArrayProperty(std::vector *ret, std::string *err, } static bool ParseStringProperty( - std::string *ret, std::string *err, const json &o, + std::string *ret, std::string *err, const detail::json &o, const std::string &property, bool required, const std::string &parent_node = std::string()) { - json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { (*err) += "'" + property + "' property is missing"; @@ -3526,7 +3666,7 @@ static bool ParseStringProperty( } std::string strValue; - if (!GetString(GetValue(it), strValue)) { + if (!detail::GetString(detail::GetValue(it), strValue)) { if (required) { if (err) { (*err) += "'" + property + "' property is not a string type.\n"; @@ -3543,12 +3683,12 @@ static bool ParseStringProperty( } static bool ParseStringIntegerProperty(std::map *ret, - std::string *err, const json &o, + std::string *err, const detail::json &o, const std::string &property, bool required, const std::string &parent = "") { - json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { if (!parent.empty()) { @@ -3562,10 +3702,10 @@ static bool ParseStringIntegerProperty(std::map *ret, return false; } - const json &dict = GetValue(it); + const detail::json &dict = detail::GetValue(it); // Make sure we are dealing with an object / dictionary. - if (!IsObject(dict)) { + if (!detail::IsObject(dict)) { if (required) { if (err) { (*err) += "'" + property + "' property is not an object.\n"; @@ -3576,12 +3716,12 @@ static bool ParseStringIntegerProperty(std::map *ret, ret->clear(); - json_const_iterator dictIt(ObjectBegin(dict)); - json_const_iterator dictItEnd(ObjectEnd(dict)); + detail::json_const_iterator dictIt(detail::ObjectBegin(dict)); + detail::json_const_iterator dictItEnd(detail::ObjectEnd(dict)); for (; dictIt != dictItEnd; ++dictIt) { int intVal; - if (!GetInt(GetValue(dictIt), intVal)) { + if (!detail::GetInt(detail::GetValue(dictIt), intVal)) { if (required) { if (err) { (*err) += "'" + property + "' value is not an integer type.\n"; @@ -3591,16 +3731,16 @@ static bool ParseStringIntegerProperty(std::map *ret, } // Insert into the list. - (*ret)[GetKey(dictIt)] = intVal; + (*ret)[detail::GetKey(dictIt)] = intVal; } return true; } static bool ParseJSONProperty(std::map *ret, - std::string *err, const json &o, + std::string *err, const detail::json &o, const std::string &property, bool required) { - json_const_iterator it; - if (!FindMember(o, property.c_str(), it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, property.c_str(), it)) { if (required) { if (err) { (*err) += "'" + property + "' property is missing. \n'"; @@ -3609,9 +3749,9 @@ static bool ParseJSONProperty(std::map *ret, return false; } - const json &obj = GetValue(it); + const detail::json &obj = detail::GetValue(it); - if (!IsObject(obj)) { + if (!detail::IsObject(obj)) { if (required) { if (err) { (*err) += "'" + property + "' property is not a JSON object.\n"; @@ -3622,19 +3762,19 @@ static bool ParseJSONProperty(std::map *ret, ret->clear(); - json_const_iterator it2(ObjectBegin(obj)); - json_const_iterator itEnd(ObjectEnd(obj)); + detail::json_const_iterator it2(detail::ObjectBegin(obj)); + detail::json_const_iterator itEnd(detail::ObjectEnd(obj)); for (; it2 != itEnd; ++it2) { double numVal; - if (GetNumber(GetValue(it2), numVal)) - ret->emplace(std::string(GetKey(it2)), numVal); + if (detail::GetNumber(detail::GetValue(it2), numVal)) + ret->emplace(std::string(detail::GetKey(it2)), numVal); } return true; } static bool ParseParameterProperty(Parameter *param, std::string *err, - const json &o, const std::string &prop, + const detail::json &o, const std::string &prop, bool required) { // A parameter value can either be a string or an array of either a boolean or // a number. Booleans of any kind aren't supported here. Granted, it @@ -3649,7 +3789,8 @@ static bool ParseParameterProperty(Parameter *param, std::string *err, // Found a number array. return true; } else if (ParseNumberProperty(¶m->number_value, err, o, prop, false)) { - return param->has_number_value = true; + param->has_number_value = true; + return true; } else if (ParseJSONProperty(¶m->json_double_value, err, o, prop, false)) { return true; @@ -3666,25 +3807,25 @@ static bool ParseParameterProperty(Parameter *param, std::string *err, } static bool ParseExtensionsProperty(ExtensionMap *ret, std::string *err, - const json &o) { + const detail::json &o) { (void)err; - json_const_iterator it; - if (!FindMember(o, "extensions", it)) { + detail::json_const_iterator it; + if (!detail::FindMember(o, "extensions", it)) { return false; } - auto &obj = GetValue(it); - if (!IsObject(obj)) { + auto &obj = detail::GetValue(it); + if (!detail::IsObject(obj)) { return false; } ExtensionMap extensions; - json_const_iterator extIt = ObjectBegin(obj); // it.value().begin(); - json_const_iterator extEnd = ObjectEnd(obj); + detail::json_const_iterator extIt = detail::ObjectBegin(obj); // it.value().begin(); + detail::json_const_iterator extEnd = detail::ObjectEnd(obj); for (; extIt != extEnd; ++extIt) { - auto &itObj = GetValue(extIt); - if (!IsObject(itObj)) continue; - std::string key(GetKey(extIt)); + auto &itObj = detail::GetValue(extIt); + if (!detail::IsObject(itObj)) continue; + std::string key(detail::GetKey(extIt)); if (!ParseJsonAsValue(&extensions[key], itObj)) { if (!key.empty()) { // create empty object so that an extension object is still of type @@ -3699,7 +3840,7 @@ static bool ParseExtensionsProperty(ExtensionMap *ret, std::string *err, return true; } -static bool ParseAsset(Asset *asset, std::string *err, const json &o, +static bool ParseAsset(Asset *asset, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&asset->version, err, o, "version", true, "Asset"); ParseStringProperty(&asset->generator, err, o, "generator", false, "Asset"); @@ -3713,15 +3854,15 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - asset->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + asset->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - asset->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + asset->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -3730,18 +3871,19 @@ static bool ParseAsset(Asset *asset, std::string *err, const json &o, } static bool ParseImage(Image *image, const int image_idx, std::string *err, - std::string *warn, const json &o, + std::string *warn, const detail::json &o, bool store_original_json_for_extras_and_extensions, const std::string &basedir, FsCallbacks *fs, + const URICallbacks *uri_cb, LoadImageDataFunction *LoadImageData = nullptr, void *load_image_user_data = nullptr) { // A glTF image must either reference a bufferView or an image uri // schema says oneOf [`bufferView`, `uri`] // TODO(syoyo): Check the type of each parameters. - json_const_iterator it; - bool hasBufferView = FindMember(o, "bufferView", it); - bool hasURI = FindMember(o, "uri", it); + detail::json_const_iterator it; + bool hasBufferView = detail::FindMember(o, "bufferView", it); + bool hasURI = detail::FindMember(o, "uri", it); ParseStringProperty(&image->name, err, o, "name", false); @@ -3770,15 +3912,15 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator eit; - if (FindMember(o, "extensions", eit)) { - image->extensions_json_string = JsonToString(GetValue(eit)); + detail::json_const_iterator eit; + if (detail::FindMember(o, "extensions", eit)) { + image->extensions_json_string = detail::JsonToString(detail::GetValue(eit)); } } { - json_const_iterator eit; - if (FindMember(o, "extras", eit)) { - image->extras_json_string = JsonToString(GetValue(eit)); + detail::json_const_iterator eit; + if (detail::FindMember(o, "extras", eit)) { + image->extras_json_string = detail::JsonToString(detail::GetValue(eit)); } } } @@ -3842,8 +3984,19 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, image->uri = uri; #ifdef TINYGLTF_NO_EXTERNAL_IMAGE return true; -#endif - std::string decoded_uri = dlib::urldecode(uri); +#else + std::string decoded_uri; + if (!uri_cb->decode(uri, &decoded_uri, uri_cb->user_data)) { + if (warn) { + (*warn) += "Failed to decode 'uri' for image[" + + std::to_string(image_idx) + "] name = [" + image->name + + "]\n"; + } + + // Image loading failure is not critical to overall gltf loading. + return true; + } + if (!LoadExternalFile(&img, err, warn, decoded_uri, basedir, /* required */ false, /* required bytes */ 0, /* checksize */ false, fs)) { @@ -3864,6 +4017,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, } return false; } +#endif } if (*LoadImageData == nullptr) { @@ -3876,7 +4030,7 @@ static bool ParseImage(Image *image, const int image_idx, std::string *err, static_cast(img.size()), load_image_user_data); } -static bool ParseTexture(Texture *texture, std::string *err, const json &o, +static bool ParseTexture(Texture *texture, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions, const std::string &basedir) { (void)basedir; @@ -3894,15 +4048,15 @@ static bool ParseTexture(Texture *texture, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - texture->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + texture->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - texture->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + texture->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -3913,7 +4067,7 @@ static bool ParseTexture(Texture *texture, std::string *err, const json &o, } static bool ParseTextureInfo( - TextureInfo *texinfo, std::string *err, const json &o, + TextureInfo *texinfo, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { if (texinfo == nullptr) { return false; @@ -3931,15 +4085,15 @@ static bool ParseTextureInfo( if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - texinfo->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + texinfo->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - texinfo->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + texinfo->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -3948,7 +4102,7 @@ static bool ParseTextureInfo( } static bool ParseNormalTextureInfo( - NormalTextureInfo *texinfo, std::string *err, const json &o, + NormalTextureInfo *texinfo, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { if (texinfo == nullptr) { return false; @@ -3967,15 +4121,15 @@ static bool ParseNormalTextureInfo( if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - texinfo->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + texinfo->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - texinfo->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + texinfo->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -3984,7 +4138,7 @@ static bool ParseNormalTextureInfo( } static bool ParseOcclusionTextureInfo( - OcclusionTextureInfo *texinfo, std::string *err, const json &o, + OcclusionTextureInfo *texinfo, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { if (texinfo == nullptr) { return false; @@ -4003,15 +4157,15 @@ static bool ParseOcclusionTextureInfo( if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - texinfo->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + texinfo->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - texinfo->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + texinfo->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4019,10 +4173,10 @@ static bool ParseOcclusionTextureInfo( return true; } -static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, +static bool ParseBuffer(Buffer *buffer, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions, - FsCallbacks *fs, const std::string &basedir, - bool is_binary = false, + FsCallbacks *fs, const URICallbacks *uri_cb, + const std::string &basedir, bool is_binary = false, const unsigned char *bin_data = nullptr, size_t bin_size = 0) { size_t byteLength; @@ -4042,10 +4196,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, } } - json_const_iterator type; - if (FindMember(o, "type", type)) { + detail::json_const_iterator type; + if (detail::FindMember(o, "type", type)) { std::string typeStr; - if (GetString(GetValue(type), typeStr)) { + if (detail::GetString(detail::GetValue(type), typeStr)) { if (typeStr.compare("arraybuffer") == 0) { // buffer.type = "arraybuffer"; } @@ -4068,7 +4222,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, } } else { // External .bin file. - std::string decoded_uri = dlib::urldecode(buffer->uri); + std::string decoded_uri; + if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) { + return false; + } if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, decoded_uri, basedir, /* required */ true, byteLength, /* checkSize */ true, fs)) { @@ -4080,7 +4237,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, if ((bin_size == 0) || (bin_data == nullptr)) { if (err) { - (*err) += "Invalid binary data in `Buffer'.\n"; + (*err) += "Invalid binary data in `Buffer', or GLB with empty BIN chunk.\n"; } return false; } @@ -4113,7 +4270,10 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, } } else { // Assume external .bin file. - std::string decoded_uri = dlib::urldecode(buffer->uri); + std::string decoded_uri; + if (!uri_cb->decode(buffer->uri, &decoded_uri, uri_cb->user_data)) { + return false; + } if (!LoadExternalFile(&buffer->data, err, /* warn */ nullptr, decoded_uri, basedir, /* required */ true, byteLength, /* checkSize */ true, fs)) { @@ -4129,15 +4289,15 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - buffer->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + buffer->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - buffer->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + buffer->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4146,7 +4306,7 @@ static bool ParseBuffer(Buffer *buffer, std::string *err, const json &o, } static bool ParseBufferView( - BufferView *bufferView, std::string *err, const json &o, + BufferView *bufferView, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { int buffer = -1; if (!ParseIntegerProperty(&buffer, err, o, "buffer", true, "BufferView")) { @@ -4201,15 +4361,15 @@ static bool ParseBufferView( if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - bufferView->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + bufferView->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - bufferView->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + bufferView->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4222,40 +4382,48 @@ static bool ParseBufferView( } static bool ParseSparseAccessor(Accessor *accessor, std::string *err, - const json &o) { + const detail::json &o) { accessor->sparse.isSparse = true; int count = 0; - ParseIntegerProperty(&count, err, o, "count", true); + if (!ParseIntegerProperty(&count, err, o, "count", true, "SparseAccessor")) { + return false; + } - json_const_iterator indices_iterator; - json_const_iterator values_iterator; - if (!FindMember(o, "indices", indices_iterator)) { + detail::json_const_iterator indices_iterator; + detail::json_const_iterator values_iterator; + if (!detail::FindMember(o, "indices", indices_iterator)) { (*err) = "the sparse object of this accessor doesn't have indices"; return false; } - if (!FindMember(o, "values", values_iterator)) { - (*err) = "the sparse object ob ths accessor doesn't have values"; + if (!detail::FindMember(o, "values", values_iterator)) { + (*err) = "the sparse object of this accessor doesn't have values"; return false; } - const json &indices_obj = GetValue(indices_iterator); - const json &values_obj = GetValue(values_iterator); + const detail::json &indices_obj = detail::GetValue(indices_iterator); + const detail::json &values_obj = detail::GetValue(values_iterator); int indices_buffer_view = 0, indices_byte_offset = 0, component_type = 0; - ParseIntegerProperty(&indices_buffer_view, err, indices_obj, "bufferView", - true); + if (!ParseIntegerProperty(&indices_buffer_view, err, indices_obj, + "bufferView", true, "SparseAccessor")) { + return false; + } ParseIntegerProperty(&indices_byte_offset, err, indices_obj, "byteOffset", - true); - ParseIntegerProperty(&component_type, err, indices_obj, "componentType", - true); + false); + if (!ParseIntegerProperty(&component_type, err, indices_obj, "componentType", + true, "SparseAccessor")) { + return false; + } int values_buffer_view = 0, values_byte_offset = 0; - ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView", - true); + if (!ParseIntegerProperty(&values_buffer_view, err, values_obj, "bufferView", + true, "SparseAccessor")) { + return false; + } ParseIntegerProperty(&values_byte_offset, err, values_obj, "byteOffset", - true); + false); accessor->sparse.count = count; accessor->sparse.indices.bufferView = indices_buffer_view; @@ -4264,12 +4432,10 @@ static bool ParseSparseAccessor(Accessor *accessor, std::string *err, accessor->sparse.values.bufferView = values_buffer_view; accessor->sparse.values.byteOffset = values_byte_offset; - // todo check theses values - return true; } -static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o, +static bool ParseAccessor(Accessor *accessor, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { int bufferView = -1; ParseIntegerProperty(&bufferView, err, o, "bufferView", false, "Accessor"); @@ -4354,24 +4520,24 @@ static bool ParseAccessor(Accessor *accessor, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - accessor->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + accessor->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - accessor->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + accessor->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } // check if accessor has a "sparse" object: - json_const_iterator iterator; - if (FindMember(o, "sparse", iterator)) { + detail::json_const_iterator iterator; + if (detail::FindMember(o, "sparse", iterator)) { // here this accessor has a "sparse" subobject - return ParseSparseAccessor(accessor, err, GetValue(iterator)); + return ParseSparseAccessor(accessor, err, detail::GetValue(iterator)); } return true; @@ -4570,7 +4736,7 @@ static bool ParseDracoExtension(Primitive *primitive, Model *model, #endif static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, - const json &o, + const detail::json &o, bool store_original_json_for_extras_and_extensions) { int material = -1; ParseIntegerProperty(&material, err, o, "material", false); @@ -4578,7 +4744,7 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, int mode = TINYGLTF_MODE_TRIANGLES; ParseIntegerProperty(&mode, err, o, "mode", false); - primitive->mode = mode; // Why only triangled were supported ? + primitive->mode = mode; // Why only triangles were supported ? int indices = -1; ParseIntegerProperty(&indices, err, o, "indices", false); @@ -4589,23 +4755,23 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, } // Look for morph targets - json_const_iterator targetsObject; - if (FindMember(o, "targets", targetsObject) && - IsArray(GetValue(targetsObject))) { - auto targetsObjectEnd = ArrayEnd(GetValue(targetsObject)); - for (json_const_array_iterator i = ArrayBegin(GetValue(targetsObject)); + detail::json_const_iterator targetsObject; + if (detail::FindMember(o, "targets", targetsObject) && + detail::IsArray(detail::GetValue(targetsObject))) { + auto targetsObjectEnd = detail::ArrayEnd(detail::GetValue(targetsObject)); + for (detail::json_const_array_iterator i = detail::ArrayBegin(detail::GetValue(targetsObject)); i != targetsObjectEnd; ++i) { std::map targetAttribues; - const json &dict = *i; - if (IsObject(dict)) { - json_const_iterator dictIt(ObjectBegin(dict)); - json_const_iterator dictItEnd(ObjectEnd(dict)); + const detail::json &dict = *i; + if (detail::IsObject(dict)) { + detail::json_const_iterator dictIt(detail::ObjectBegin(dict)); + detail::json_const_iterator dictItEnd(detail::ObjectEnd(dict)); for (; dictIt != dictItEnd; ++dictIt) { int iVal; - if (GetInt(GetValue(dictIt), iVal)) - targetAttribues[GetKey(dictIt)] = iVal; + if (detail::GetInt(detail::GetValue(dictIt), iVal)) + targetAttribues[detail::GetKey(dictIt)] = iVal; } primitive->targets.emplace_back(std::move(targetAttribues)); } @@ -4617,15 +4783,15 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - primitive->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + primitive->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - primitive->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + primitive->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4643,16 +4809,16 @@ static bool ParsePrimitive(Primitive *primitive, Model *model, std::string *err, return true; } -static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o, +static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&mesh->name, err, o, "name", false); mesh->primitives.clear(); - json_const_iterator primObject; - if (FindMember(o, "primitives", primObject) && - IsArray(GetValue(primObject))) { - json_const_array_iterator primEnd = ArrayEnd(GetValue(primObject)); - for (json_const_array_iterator i = ArrayBegin(GetValue(primObject)); + detail::json_const_iterator primObject; + if (detail::FindMember(o, "primitives", primObject) && + detail::IsArray(detail::GetValue(primObject))) { + detail::json_const_array_iterator primEnd = detail::ArrayEnd(detail::GetValue(primObject)); + for (detail::json_const_array_iterator i = detail::ArrayBegin(detail::GetValue(primObject)); i != primEnd; ++i) { Primitive primitive; if (ParsePrimitive(&primitive, model, err, *i, @@ -4671,15 +4837,15 @@ static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - mesh->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + mesh->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - mesh->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + mesh->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4687,7 +4853,7 @@ static bool ParseMesh(Mesh *mesh, Model *model, std::string *err, const json &o, return true; } -static bool ParseNode(Node *node, std::string *err, const json &o, +static bool ParseNode(Node *node, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&node->name, err, o, "name", false); @@ -4720,15 +4886,15 @@ static bool ParseNode(Node *node, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - node->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + node->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - node->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + node->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4737,7 +4903,7 @@ static bool ParseNode(Node *node, std::string *err, const json &o, } static bool ParsePbrMetallicRoughness( - PbrMetallicRoughness *pbr, std::string *err, const json &o, + PbrMetallicRoughness *pbr, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { if (pbr == nullptr) { return false; @@ -4759,17 +4925,17 @@ static bool ParsePbrMetallicRoughness( } { - json_const_iterator it; - if (FindMember(o, "baseColorTexture", it)) { - ParseTextureInfo(&pbr->baseColorTexture, err, GetValue(it), + detail::json_const_iterator it; + if (detail::FindMember(o, "baseColorTexture", it)) { + ParseTextureInfo(&pbr->baseColorTexture, err, detail::GetValue(it), store_original_json_for_extras_and_extensions); } } { - json_const_iterator it; - if (FindMember(o, "metallicRoughnessTexture", it)) { - ParseTextureInfo(&pbr->metallicRoughnessTexture, err, GetValue(it), + detail::json_const_iterator it; + if (detail::FindMember(o, "metallicRoughnessTexture", it)) { + ParseTextureInfo(&pbr->metallicRoughnessTexture, err, detail::GetValue(it), store_original_json_for_extras_and_extensions); } } @@ -4782,15 +4948,15 @@ static bool ParsePbrMetallicRoughness( if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - pbr->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + pbr->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - pbr->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + pbr->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4798,7 +4964,7 @@ static bool ParsePbrMetallicRoughness( return true; } -static bool ParseMaterial(Material *material, std::string *err, const json &o, +static bool ParseMaterial(Material *material, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&material->name, err, o, "name", /* required */ false); @@ -4827,63 +4993,63 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o, /* required */ false); { - json_const_iterator it; - if (FindMember(o, "pbrMetallicRoughness", it)) { + detail::json_const_iterator it; + if (detail::FindMember(o, "pbrMetallicRoughness", it)) { ParsePbrMetallicRoughness(&material->pbrMetallicRoughness, err, - GetValue(it), + detail::GetValue(it), store_original_json_for_extras_and_extensions); } } { - json_const_iterator it; - if (FindMember(o, "normalTexture", it)) { - ParseNormalTextureInfo(&material->normalTexture, err, GetValue(it), + detail::json_const_iterator it; + if (detail::FindMember(o, "normalTexture", it)) { + ParseNormalTextureInfo(&material->normalTexture, err, detail::GetValue(it), store_original_json_for_extras_and_extensions); } } { - json_const_iterator it; - if (FindMember(o, "occlusionTexture", it)) { - ParseOcclusionTextureInfo(&material->occlusionTexture, err, GetValue(it), + detail::json_const_iterator it; + if (detail::FindMember(o, "occlusionTexture", it)) { + ParseOcclusionTextureInfo(&material->occlusionTexture, err, detail::GetValue(it), store_original_json_for_extras_and_extensions); } } { - json_const_iterator it; - if (FindMember(o, "emissiveTexture", it)) { - ParseTextureInfo(&material->emissiveTexture, err, GetValue(it), + detail::json_const_iterator it; + if (detail::FindMember(o, "emissiveTexture", it)) { + ParseTextureInfo(&material->emissiveTexture, err, detail::GetValue(it), store_original_json_for_extras_and_extensions); } } // Old code path. For backward compatibility, we still store material values // as Parameter. This will create duplicated information for - // example(pbrMetallicRoughness), but should be neglible in terms of memory + // example(pbrMetallicRoughness), but should be negligible in terms of memory // consumption. // TODO(syoyo): Remove in the next major release. material->values.clear(); material->additionalValues.clear(); - json_const_iterator it(ObjectBegin(o)); - json_const_iterator itEnd(ObjectEnd(o)); + detail::json_const_iterator it(detail::ObjectBegin(o)); + detail::json_const_iterator itEnd(detail::ObjectEnd(o)); for (; it != itEnd; ++it) { - std::string key(GetKey(it)); + std::string key(detail::GetKey(it)); if (key == "pbrMetallicRoughness") { - if (IsObject(GetValue(it))) { - const json &values_object = GetValue(it); + if (detail::IsObject(detail::GetValue(it))) { + const detail::json &values_object = detail::GetValue(it); - json_const_iterator itVal(ObjectBegin(values_object)); - json_const_iterator itValEnd(ObjectEnd(values_object)); + detail::json_const_iterator itVal(detail::ObjectBegin(values_object)); + detail::json_const_iterator itValEnd(detail::ObjectEnd(values_object)); for (; itVal != itValEnd; ++itVal) { Parameter param; - if (ParseParameterProperty(¶m, err, values_object, GetKey(itVal), + if (ParseParameterProperty(¶m, err, values_object, detail::GetKey(itVal), false)) { - material->values.emplace(GetKey(itVal), std::move(param)); + material->values.emplace(detail::GetKey(itVal), std::move(param)); } } } @@ -4894,7 +5060,7 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o, Parameter param; if (ParseParameterProperty(¶m, err, o, key, false)) { // names of materials have already been parsed. Putting it in this map - // doesn't correctly reflext the glTF specification + // doesn't correctly reflect the glTF specification if (key != "name") material->additionalValues.emplace(std::move(key), std::move(param)); } @@ -4907,15 +5073,15 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator eit; - if (FindMember(o, "extensions", eit)) { - material->extensions_json_string = JsonToString(GetValue(eit)); + detail::json_const_iterator eit; + if (detail::FindMember(o, "extensions", eit)) { + material->extensions_json_string = detail::JsonToString(detail::GetValue(eit)); } } { - json_const_iterator eit; - if (FindMember(o, "extras", eit)) { - material->extras_json_string = JsonToString(GetValue(eit)); + detail::json_const_iterator eit; + if (detail::FindMember(o, "extras", eit)) { + material->extras_json_string = detail::JsonToString(detail::GetValue(eit)); } } } @@ -4924,7 +5090,7 @@ static bool ParseMaterial(Material *material, std::string *err, const json &o, } static bool ParseAnimationChannel( - AnimationChannel *channel, std::string *err, const json &o, + AnimationChannel *channel, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { int samplerIndex = -1; int targetIndex = -1; @@ -4936,16 +5102,11 @@ static bool ParseAnimationChannel( return false; } - json_const_iterator targetIt; - if (FindMember(o, "target", targetIt) && IsObject(GetValue(targetIt))) { - const json &target_object = GetValue(targetIt); + detail::json_const_iterator targetIt; + if (detail::FindMember(o, "target", targetIt) && detail::IsObject(detail::GetValue(targetIt))) { + const detail::json &target_object = detail::GetValue(targetIt); - if (!ParseIntegerProperty(&targetIndex, err, target_object, "node", true)) { - if (err) { - (*err) += "`node` field is missing in animation.channels.target\n"; - } - return false; - } + ParseIntegerProperty(&targetIndex, err, target_object, "node", false); if (!ParseStringProperty(&channel->target_path, err, target_object, "path", true)) { @@ -4956,9 +5117,9 @@ static bool ParseAnimationChannel( } ParseExtensionsProperty(&channel->target_extensions, err, target_object); if (store_original_json_for_extras_and_extensions) { - json_const_iterator it; - if (FindMember(target_object, "extensions", it)) { - channel->target_extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(target_object, "extensions", it)) { + channel->target_extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4971,15 +5132,15 @@ static bool ParseAnimationChannel( if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - channel->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + channel->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - channel->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + channel->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -4988,14 +5149,14 @@ static bool ParseAnimationChannel( } static bool ParseAnimation(Animation *animation, std::string *err, - const json &o, + const detail::json &o, bool store_original_json_for_extras_and_extensions) { { - json_const_iterator channelsIt; - if (FindMember(o, "channels", channelsIt) && - IsArray(GetValue(channelsIt))) { - json_const_array_iterator channelEnd = ArrayEnd(GetValue(channelsIt)); - for (json_const_array_iterator i = ArrayBegin(GetValue(channelsIt)); + detail::json_const_iterator channelsIt; + if (detail::FindMember(o, "channels", channelsIt) && + detail::IsArray(detail::GetValue(channelsIt))) { + detail::json_const_array_iterator channelEnd = detail::ArrayEnd(detail::GetValue(channelsIt)); + for (detail::json_const_array_iterator i = detail::ArrayBegin(detail::GetValue(channelsIt)); i != channelEnd; ++i) { AnimationChannel channel; if (ParseAnimationChannel( @@ -5009,15 +5170,15 @@ static bool ParseAnimation(Animation *animation, std::string *err, } { - json_const_iterator samplerIt; - if (FindMember(o, "samplers", samplerIt) && IsArray(GetValue(samplerIt))) { - const json &sampler_array = GetValue(samplerIt); + detail::json_const_iterator samplerIt; + if (detail::FindMember(o, "samplers", samplerIt) && detail::IsArray(detail::GetValue(samplerIt))) { + const detail::json &sampler_array = detail::GetValue(samplerIt); - json_const_array_iterator it = ArrayBegin(sampler_array); - json_const_array_iterator itEnd = ArrayEnd(sampler_array); + detail::json_const_array_iterator it = detail::ArrayBegin(sampler_array); + detail::json_const_array_iterator itEnd = detail::ArrayEnd(sampler_array); for (; it != itEnd; ++it) { - const json &s = *it; + const detail::json &s = *it; AnimationSampler sampler; int inputIndex = -1; @@ -5043,15 +5204,15 @@ static bool ParseAnimation(Animation *animation, std::string *err, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator eit; - if (FindMember(o, "extensions", eit)) { - sampler.extensions_json_string = JsonToString(GetValue(eit)); + detail::json_const_iterator eit; + if (detail::FindMember(o, "extensions", eit)) { + sampler.extensions_json_string = detail::JsonToString(detail::GetValue(eit)); } } { - json_const_iterator eit; - if (FindMember(o, "extras", eit)) { - sampler.extras_json_string = JsonToString(GetValue(eit)); + detail::json_const_iterator eit; + if (detail::FindMember(o, "extras", eit)) { + sampler.extras_json_string = detail::JsonToString(detail::GetValue(eit)); } } } @@ -5068,15 +5229,15 @@ static bool ParseAnimation(Animation *animation, std::string *err, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - animation->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + animation->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - animation->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + animation->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5084,7 +5245,7 @@ static bool ParseAnimation(Animation *animation, std::string *err, return true; } -static bool ParseSampler(Sampler *sampler, std::string *err, const json &o, +static bool ParseSampler(Sampler *sampler, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&sampler->name, err, o, "name", false); @@ -5092,36 +5253,37 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o, int magFilter = -1; int wrapS = TINYGLTF_TEXTURE_WRAP_REPEAT; int wrapT = TINYGLTF_TEXTURE_WRAP_REPEAT; - //int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; + // int wrapR = TINYGLTF_TEXTURE_WRAP_REPEAT; ParseIntegerProperty(&minFilter, err, o, "minFilter", false); ParseIntegerProperty(&magFilter, err, o, "magFilter", false); ParseIntegerProperty(&wrapS, err, o, "wrapS", false); ParseIntegerProperty(&wrapT, err, o, "wrapT", false); - //ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf extension + // ParseIntegerProperty(&wrapR, err, o, "wrapR", false); // tinygltf + // extension - // TODO(syoyo): Check the value is alloed one. + // TODO(syoyo): Check the value is allowed one. // (e.g. we allow 9728(NEAREST), but don't allow 9727) sampler->minFilter = minFilter; sampler->magFilter = magFilter; sampler->wrapS = wrapS; sampler->wrapT = wrapT; - //sampler->wrapR = wrapR; + // sampler->wrapR = wrapR; ParseExtensionsProperty(&(sampler->extensions), err, o); ParseExtrasProperty(&(sampler->extras), o); if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - sampler->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + sampler->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - sampler->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + sampler->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5129,7 +5291,7 @@ static bool ParseSampler(Sampler *sampler, std::string *err, const json &o, return true; } -static bool ParseSkin(Skin *skin, std::string *err, const json &o, +static bool ParseSkin(Skin *skin, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { ParseStringProperty(&skin->name, err, o, "name", false, "Skin"); @@ -5152,15 +5314,15 @@ static bool ParseSkin(Skin *skin, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - skin->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + skin->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - skin->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + skin->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5169,7 +5331,7 @@ static bool ParseSkin(Skin *skin, std::string *err, const json &o, } static bool ParsePerspectiveCamera( - PerspectiveCamera *camera, std::string *err, const json &o, + PerspectiveCamera *camera, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { double yfov = 0.0; if (!ParseNumberProperty(&yfov, err, o, "yfov", true, "OrthographicCamera")) { @@ -5199,15 +5361,15 @@ static bool ParsePerspectiveCamera( if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - camera->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + camera->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - camera->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + camera->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5217,7 +5379,7 @@ static bool ParsePerspectiveCamera( return true; } -static bool ParseSpotLight(SpotLight *light, std::string *err, const json &o, +static bool ParseSpotLight(SpotLight *light, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { ParseNumberProperty(&light->innerConeAngle, err, o, "innerConeAngle", false); ParseNumberProperty(&light->outerConeAngle, err, o, "outerConeAngle", false); @@ -5227,15 +5389,15 @@ static bool ParseSpotLight(SpotLight *light, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - light->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + light->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - light->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + light->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5246,7 +5408,7 @@ static bool ParseSpotLight(SpotLight *light, std::string *err, const json &o, } static bool ParseOrthographicCamera( - OrthographicCamera *camera, std::string *err, const json &o, + OrthographicCamera *camera, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { double xmag = 0.0; if (!ParseNumberProperty(&xmag, err, o, "xmag", true, "OrthographicCamera")) { @@ -5274,15 +5436,15 @@ static bool ParseOrthographicCamera( if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - camera->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + camera->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - camera->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + camera->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5297,25 +5459,25 @@ static bool ParseOrthographicCamera( return true; } -static bool ParseCamera(Camera *camera, std::string *err, const json &o, +static bool ParseCamera(Camera *camera, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { if (!ParseStringProperty(&camera->type, err, o, "type", true, "Camera")) { return false; } if (camera->type.compare("orthographic") == 0) { - json_const_iterator orthoIt; - if (!FindMember(o, "orthographic", orthoIt)) { + detail::json_const_iterator orthoIt; + if (!detail::FindMember(o, "orthographic", orthoIt)) { if (err) { std::stringstream ss; - ss << "Orhographic camera description not found." << std::endl; + ss << "Orthographic camera description not found." << std::endl; (*err) += ss.str(); } return false; } - const json &v = GetValue(orthoIt); - if (!IsObject(v)) { + const detail::json &v = detail::GetValue(orthoIt); + if (!detail::IsObject(v)) { if (err) { std::stringstream ss; ss << "\"orthographic\" is not a JSON object." << std::endl; @@ -5330,8 +5492,8 @@ static bool ParseCamera(Camera *camera, std::string *err, const json &o, return false; } } else if (camera->type.compare("perspective") == 0) { - json_const_iterator perspIt; - if (!FindMember(o, "perspective", perspIt)) { + detail::json_const_iterator perspIt; + if (!detail::FindMember(o, "perspective", perspIt)) { if (err) { std::stringstream ss; ss << "Perspective camera description not found." << std::endl; @@ -5340,8 +5502,8 @@ static bool ParseCamera(Camera *camera, std::string *err, const json &o, return false; } - const json &v = GetValue(perspIt); - if (!IsObject(v)) { + const detail::json &v = detail::GetValue(perspIt); + if (!detail::IsObject(v)) { if (err) { std::stringstream ss; ss << "\"perspective\" is not a JSON object." << std::endl; @@ -5372,15 +5534,15 @@ static bool ParseCamera(Camera *camera, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - camera->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + camera->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - camera->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + camera->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5388,15 +5550,15 @@ static bool ParseCamera(Camera *camera, std::string *err, const json &o, return true; } -static bool ParseLight(Light *light, std::string *err, const json &o, +static bool ParseLight(Light *light, std::string *err, const detail::json &o, bool store_original_json_for_extras_and_extensions) { if (!ParseStringProperty(&light->type, err, o, "type", true)) { return false; } if (light->type == "spot") { - json_const_iterator spotIt; - if (!FindMember(o, "spot", spotIt)) { + detail::json_const_iterator spotIt; + if (!detail::FindMember(o, "spot", spotIt)) { if (err) { std::stringstream ss; ss << "Spot light description not found." << std::endl; @@ -5405,8 +5567,8 @@ static bool ParseLight(Light *light, std::string *err, const json &o, return false; } - const json &v = GetValue(spotIt); - if (!IsObject(v)) { + const detail::json &v = detail::GetValue(spotIt); + if (!detail::IsObject(v)) { if (err) { std::stringstream ss; ss << "\"spot\" is not a JSON object." << std::endl; @@ -5430,15 +5592,15 @@ static bool ParseLight(Light *light, std::string *err, const json &o, if (store_original_json_for_extras_and_extensions) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - light->extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + light->extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - light->extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + light->extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5458,13 +5620,13 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, return false; } - JsonDocument v; + detail::JsonDocument v; #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || \ defined(_CPPUNWIND)) && \ !defined(TINYGLTF_NOEXCEPTION) try { - JsonParse(v, json_str, json_str_length, true); + detail::JsonParse(v, json_str, json_str_length, true); } catch (const std::exception &e) { if (err) { @@ -5474,9 +5636,9 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, } #else { - JsonParse(v, json_str, json_str_length); + detail::JsonParse(v, json_str, json_str_length); - if (!IsObject(v)) { + if (!detail::IsObject(v)) { // Assume parsing was failed. if (err) { (*err) = "Failed to parse JSON object\n"; @@ -5486,7 +5648,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, } #endif - if (!IsObject(v)) { + if (!detail::IsObject(v)) { // root is not an object. if (err) { (*err) = "Root element is not a JSON object\n"; @@ -5496,13 +5658,13 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, { bool version_found = false; - json_const_iterator it; - if (FindMember(v, "asset", it) && IsObject(GetValue(it))) { - auto &itObj = GetValue(it); - json_const_iterator version_it; + detail::json_const_iterator it; + if (detail::FindMember(v, "asset", it) && detail::IsObject(detail::GetValue(it))) { + auto &itObj = detail::GetValue(it); + detail::json_const_iterator version_it; std::string versionStr; - if (FindMember(itObj, "version", version_it) && - GetString(GetValue(version_it), versionStr)) { + if (detail::FindMember(itObj, "version", version_it) && + detail::GetString(detail::GetValue(version_it), versionStr)) { version_found = true; } } @@ -5519,9 +5681,9 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // scene is not mandatory. // FIXME Maybe a better way to handle it than removing the code - auto IsArrayMemberPresent = [](const json &_v, const char *name) -> bool { - json_const_iterator it; - return FindMember(_v, name, it) && IsArray(GetValue(it)); + auto IsArrayMemberPresent = [](const detail::json &_v, const char *name) -> bool { + detail::json_const_iterator it; + return detail::FindMember(_v, name, it) && detail::IsArray(detail::GetValue(it)); }; { @@ -5586,9 +5748,9 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 1. Parse Asset { - json_const_iterator it; - if (FindMember(v, "asset", it) && IsObject(GetValue(it))) { - const json &root = GetValue(it); + detail::json_const_iterator it; + if (detail::FindMember(v, "asset", it) && detail::IsObject(detail::GetValue(it))) { + const detail::json &root = detail::GetValue(it); ParseAsset(&model->asset, err, root, store_original_json_for_extras_and_extensions_); @@ -5596,21 +5758,21 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, } #ifdef TINYGLTF_USE_CPP14 - auto ForEachInArray = [](const json &_v, const char *member, + auto ForEachInArray = [](const detail::json &_v, const char *member, const auto &cb) -> bool #else // The std::function<> implementation can be less efficient because it will // allocate heap when the size of the captured lambda is above 16 bytes with // clang and gcc, but it does not require C++14. - auto ForEachInArray = [](const json &_v, const char *member, - const std::function &cb) -> bool + auto ForEachInArray = [](const detail::json &_v, const char *member, + const std::function &cb) -> bool #endif { - json_const_iterator itm; - if (FindMember(_v, member, itm) && IsArray(GetValue(itm))) { - const json &root = GetValue(itm); - auto it = ArrayBegin(root); - auto end = ArrayEnd(root); + detail::json_const_iterator itm; + if (detail::FindMember(_v, member, itm) && detail::IsArray(detail::GetValue(itm))) { + const detail::json &root = detail::GetValue(itm); + auto it = detail::ArrayBegin(root); + auto end = detail::ArrayEnd(root); for (; it != end; ++it) { if (!cb(*it)) return false; } @@ -5620,18 +5782,18 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 2. Parse extensionUsed { - ForEachInArray(v, "extensionsUsed", [&](const json &o) { + ForEachInArray(v, "extensionsUsed", [&](const detail::json &o) { std::string str; - GetString(o, str); + detail::GetString(o, str); model->extensionsUsed.emplace_back(std::move(str)); return true; }); } { - ForEachInArray(v, "extensionsRequired", [&](const json &o) { + ForEachInArray(v, "extensionsRequired", [&](const detail::json &o) { std::string str; - GetString(o, str); + detail::GetString(o, str); model->extensionsRequired.emplace_back(std::move(str)); return true; }); @@ -5639,8 +5801,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 3. Parse Buffer { - bool success = ForEachInArray(v, "buffers", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "buffers", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`buffers' does not contain an JSON object."; } @@ -5649,7 +5811,7 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, Buffer buffer; if (!ParseBuffer(&buffer, err, o, store_original_json_for_extras_and_extensions_, &fs, - base_dir, is_binary_, bin_data_, bin_size_)) { + &uri_cb, base_dir, is_binary_, bin_data_, bin_size_)) { return false; } @@ -5663,8 +5825,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, } // 4. Parse BufferView { - bool success = ForEachInArray(v, "bufferViews", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "bufferViews", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`bufferViews' does not contain an JSON object."; } @@ -5687,8 +5849,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 5. Parse Accessor { - bool success = ForEachInArray(v, "accessors", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "accessors", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`accessors' does not contain an JSON object."; } @@ -5711,8 +5873,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 6. Parse Mesh { - bool success = ForEachInArray(v, "meshes", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "meshes", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`meshes' does not contain an JSON object."; } @@ -5760,25 +5922,32 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, model->bufferViews[size_t(bufferView)].target = TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER; - // we could optionally check if acessors' bufferView type is Scalar, as + // we could optionally check if accessors' bufferView type is Scalar, as // it should be } for (auto &attribute : primitive.attributes) { - model - ->bufferViews[size_t( - model->accessors[size_t(attribute.second)].bufferView)] - .target = TINYGLTF_TARGET_ARRAY_BUFFER; + const auto accessorsIndex = size_t(attribute.second); + if (accessorsIndex < model->accessors.size()) { + const auto bufferView = model->accessors[accessorsIndex].bufferView; + // bufferView could be null(-1) for sparse morph target + if (bufferView >= 0 && bufferView < (int)model->bufferViews.size()) { + model->bufferViews[size_t(bufferView)].target = + TINYGLTF_TARGET_ARRAY_BUFFER; + } + } } for (auto &target : primitive.targets) { for (auto &attribute : target) { - auto bufferView = - model->accessors[size_t(attribute.second)].bufferView; - // bufferView could be null(-1) for sparse morph target - if (bufferView >= 0) { - model->bufferViews[size_t(bufferView)].target = - TINYGLTF_TARGET_ARRAY_BUFFER; + const auto accessorsIndex = size_t(attribute.second); + if (accessorsIndex < model->accessors.size()) { + const auto bufferView = model->accessors[accessorsIndex].bufferView; + // bufferView could be null(-1) for sparse morph target + if (bufferView >= 0 && bufferView < (int)model->bufferViews.size()) { + model->bufferViews[size_t(bufferView)].target = + TINYGLTF_TARGET_ARRAY_BUFFER; + } } } } @@ -5787,8 +5956,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 7. Parse Node { - bool success = ForEachInArray(v, "nodes", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "nodes", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`nodes' does not contain an JSON object."; } @@ -5811,8 +5980,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 8. Parse scenes. { - bool success = ForEachInArray(v, "scenes", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "scenes", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`scenes' does not contain an JSON object."; } @@ -5831,15 +6000,15 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, if (store_original_json_for_extras_and_extensions_) { { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - scene.extensions_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + scene.extensions_json_string = detail::JsonToString(detail::GetValue(it)); } } { - json_const_iterator it; - if (FindMember(o, "extras", it)) { - scene.extras_json_string = JsonToString(GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extras", it)) { + scene.extras_json_string = detail::JsonToString(detail::GetValue(it)); } } } @@ -5855,17 +6024,17 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 9. Parse default scenes. { - json_const_iterator rootIt; + detail::json_const_iterator rootIt; int iVal; - if (FindMember(v, "scene", rootIt) && GetInt(GetValue(rootIt), iVal)) { + if (detail::FindMember(v, "scene", rootIt) && detail::GetInt(detail::GetValue(rootIt), iVal)) { model->defaultScene = iVal; } } // 10. Parse Material { - bool success = ForEachInArray(v, "materials", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "materials", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`materials' does not contain an JSON object."; } @@ -5903,8 +6072,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, { int idx = 0; - bool success = ForEachInArray(v, "images", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "images", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "image[" + std::to_string(idx) + "] is not a JSON object."; } @@ -5913,7 +6082,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, Image image; if (!ParseImage(&image, idx, err, warn, o, store_original_json_for_extras_and_extensions_, base_dir, - &fs, &this->LoadImageData, load_image_user_data)) { + &fs, &uri_cb, &this->LoadImageData, + load_image_user_data)) { return false; } @@ -5969,8 +6139,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 12. Parse Texture { - bool success = ForEachInArray(v, "textures", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "textures", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`textures' does not contain an JSON object."; } @@ -5994,8 +6164,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 13. Parse Animation { - bool success = ForEachInArray(v, "animations", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "animations", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`animations' does not contain an JSON object."; } @@ -6018,8 +6188,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 14. Parse Skin { - bool success = ForEachInArray(v, "skins", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "skins", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`skins' does not contain an JSON object."; } @@ -6042,8 +6212,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 15. Parse Sampler { - bool success = ForEachInArray(v, "samplers", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "samplers", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`samplers' does not contain an JSON object."; } @@ -6066,8 +6236,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 16. Parse Camera { - bool success = ForEachInArray(v, "cameras", [&](const json &o) { - if (!IsObject(o)) { + bool success = ForEachInArray(v, "cameras", [&](const detail::json &o) { + if (!detail::IsObject(o)) { if (err) { (*err) += "`cameras' does not contain an JSON object."; } @@ -6093,26 +6263,26 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, // 18. Specific extension implementations { - json_const_iterator rootIt; - if (FindMember(v, "extensions", rootIt) && IsObject(GetValue(rootIt))) { - const json &root = GetValue(rootIt); + detail::json_const_iterator rootIt; + if (detail::FindMember(v, "extensions", rootIt) && detail::IsObject(detail::GetValue(rootIt))) { + const detail::json &root = detail::GetValue(rootIt); - json_const_iterator it(ObjectBegin(root)); - json_const_iterator itEnd(ObjectEnd(root)); + detail::json_const_iterator it(detail::ObjectBegin(root)); + detail::json_const_iterator itEnd(detail::ObjectEnd(root)); for (; it != itEnd; ++it) { // parse KHR_lights_punctual extension - std::string key(GetKey(it)); - if ((key == "KHR_lights_punctual") && IsObject(GetValue(it))) { - const json &object = GetValue(it); - json_const_iterator itLight; - if (FindMember(object, "lights", itLight)) { - const json &lights = GetValue(itLight); - if (!IsArray(lights)) { + std::string key(detail::GetKey(it)); + if ((key == "KHR_lights_punctual") && detail::IsObject(detail::GetValue(it))) { + const detail::json &object = detail::GetValue(it); + detail::json_const_iterator itLight; + if (detail::FindMember(object, "lights", itLight)) { + const detail::json &lights = detail::GetValue(itLight); + if (!detail::IsArray(lights)) { continue; } - auto arrayIt(ArrayBegin(lights)); - auto arrayItEnd(ArrayEnd(lights)); + auto arrayIt(detail::ArrayBegin(lights)); + auto arrayItEnd(detail::ArrayEnd(lights)); for (; arrayIt != arrayItEnd; ++arrayIt) { Light light; if (!ParseLight(&light, err, *arrayIt, @@ -6131,8 +6301,8 @@ bool TinyGLTF::LoadFromString(Model *model, std::string *err, std::string *warn, ParseExtrasProperty(&model->extras, v); if (store_original_json_for_extras_and_extensions_) { - model->extras_json_string = JsonToString(v["extras"]); - model->extensions_json_string = JsonToString(v["extensions"]); + model->extras_json_string = detail::JsonToString(v["extras"]); + model->extensions_json_string = detail::JsonToString(v["extensions"]); } return true; @@ -6219,44 +6389,125 @@ bool TinyGLTF::LoadBinaryFromMemory(Model *model, std::string *err, unsigned int version; // 4 bytes unsigned int length; // 4 bytes - unsigned int model_length; // 4 bytes - unsigned int model_format; // 4 bytes; + unsigned int chunk0_length; // 4 bytes + unsigned int chunk0_format; // 4 bytes; - // @todo { Endian swap for big endian machine. } memcpy(&version, bytes + 4, 4); swap4(&version); memcpy(&length, bytes + 8, 4); swap4(&length); - memcpy(&model_length, bytes + 12, 4); - swap4(&model_length); - memcpy(&model_format, bytes + 16, 4); - swap4(&model_format); + memcpy(&chunk0_length, bytes + 12, 4); // JSON data length + swap4(&chunk0_length); + memcpy(&chunk0_format, bytes + 16, 4); + swap4(&chunk0_format); + // https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#binary-gltf-layout + // // In case the Bin buffer is not present, the size is exactly 20 + size of // JSON contents, // so use "greater than" operator. - if ((20 + model_length > size) || (model_length < 1) || (length > size) || - (20 + model_length > length) || - (model_format != 0x4E4F534A)) { // 0x4E4F534A = JSON format. + // + // https://github.com/syoyo/tinygltf/issues/372 + // Use 64bit uint to avoid integer overflow. + uint64_t header_and_json_size = 20ull + uint64_t(chunk0_length); + + if (header_and_json_size > std::numeric_limits::max()) { + // Do not allow 4GB or more GLB data. + (*err) = "Invalid glTF binary. GLB data exceeds 4GB."; + } + + if ((header_and_json_size > uint64_t(size)) || (chunk0_length < 1) || (length > size) || + (header_and_json_size > uint64_t(length)) || + (chunk0_format != 0x4E4F534A)) { // 0x4E4F534A = JSON format. if (err) { (*err) = "Invalid glTF binary."; } return false; } + // Padding check + // The start and the end of each chunk must be aligned to a 4-byte boundary. + // No padding check for chunk0 start since its 4byte-boundary is ensured. + if ((header_and_json_size % 4) != 0) { + if (err) { + (*err) = "JSON Chunk end does not aligned to a 4-byte boundary."; + } + } + + //std::cout << "header_and_json_size = " << header_and_json_size << "\n"; + //std::cout << "length = " << length << "\n"; + + // Chunk1(BIN) data + // The spec says: When the binary buffer is empty or when it is stored by other means, this chunk SHOULD be omitted. + // So when header + JSON data == binary size, Chunk1 is omitted. + if (header_and_json_size == uint64_t(length)) { + + bin_data_ = nullptr; + bin_size_ = 0; + } else { + // Read Chunk1 info(BIN data) + // At least Chunk1 should have 12 bytes(8 bytes(header) + 4 bytes(bin payload could be 1~3 bytes, but need to be aligned to 4 bytes) + if ((header_and_json_size + 12ull) > uint64_t(length)) { + if (err) { + (*err) = "Insufficient storage space for Chunk1(BIN data). At least Chunk1 Must have 4 bytes or more bytes, but got " + std::to_string((header_and_json_size + 12ull) - uint64_t(length)) + ".\n"; + } + return false; + } + + unsigned int chunk1_length; // 4 bytes + unsigned int chunk1_format; // 4 bytes; + memcpy(&chunk1_length, bytes + header_and_json_size, 4); // JSON data length + swap4(&chunk1_length); + memcpy(&chunk1_format, bytes + header_and_json_size + 4, 4); + swap4(&chunk1_format); + + //std::cout << "chunk1_length = " << chunk1_length << "\n"; + + if (chunk1_length < 4) { + if (err) { + (*err) = "Insufficient Chunk1(BIN) data size."; + } + return false; + } + + if ((chunk1_length % 4) != 0) { + if (err) { + (*err) = "BIN Chunk end does not aligned to a 4-byte boundary."; + } + return false; + } + + if (uint64_t(chunk1_length) + header_and_json_size > uint64_t(length)) { + if (err) { + (*err) = "BIN Chunk data length exceeds the GLB size."; + } + return false; + } + + if (chunk1_format != 0x004e4942) { + if (err) { + (*err) = "Invalid type for chunk1 data."; + } + return false; + } + + //std::cout << "chunk1_length = " << chunk1_length << "\n"; + + bin_data_ = bytes + header_and_json_size + + 8; // 4 bytes (bin_buffer_length) + 4 bytes(bin_buffer_format) + + bin_size_ = size_t(chunk1_length); + } + // Extract JSON string. std::string jsonString(reinterpret_cast(&bytes[20]), - model_length); + chunk0_length); is_binary_ = true; - bin_data_ = bytes + 20 + model_length + - 8; // 4 bytes (buffer_length) + 4 bytes(buffer_format) - bin_size_ = - length - (20 + model_length); // extract header + JSON scene data. bool ret = LoadFromString(model, err, warn, reinterpret_cast(&bytes[20]), - model_length, base_dir, check_sections); + chunk0_length, base_dir, check_sections); if (!ret) { return ret; } @@ -6303,43 +6554,43 @@ bool TinyGLTF::LoadBinaryFromFile(Model *model, std::string *err, /////////////////////// // GLTF Serialization /////////////////////// -namespace { -json JsonFromString(const char *s) { +namespace detail { +detail::json JsonFromString(const char *s) { #ifdef TINYGLTF_USE_RAPIDJSON - return json(s, GetAllocator()); + return detail::json(s, detail::GetAllocator()); #else - return json(s); + return detail::json(s); #endif } -void JsonAssign(json &dest, const json &src) { +void JsonAssign(detail::json &dest, const detail::json &src) { #ifdef TINYGLTF_USE_RAPIDJSON - dest.CopyFrom(src, GetAllocator()); + dest.CopyFrom(src, detail::GetAllocator()); #else dest = src; #endif } -void JsonAddMember(json &o, const char *key, json &&value) { +void JsonAddMember(detail::json &o, const char *key, detail::json &&value) { #ifdef TINYGLTF_USE_RAPIDJSON if (!o.IsObject()) { o.SetObject(); } - o.AddMember(json(key, GetAllocator()), std::move(value), GetAllocator()); + o.AddMember(detail::json(key, detail::GetAllocator()), std::move(value), detail::GetAllocator()); #else o[key] = std::move(value); #endif } -void JsonPushBack(json &o, json &&value) { +void JsonPushBack(detail::json &o, detail::json &&value) { #ifdef TINYGLTF_USE_RAPIDJSON - o.PushBack(std::move(value), GetAllocator()); + o.PushBack(std::move(value), detail::GetAllocator()); #else o.push_back(std::move(value)); #endif } -bool JsonIsNull(const json &o) { +bool JsonIsNull(const detail::json &o) { #ifdef TINYGLTF_USE_RAPIDJSON return o.IsNull(); #else @@ -6347,7 +6598,7 @@ bool JsonIsNull(const json &o) { #endif } -void JsonSetObject(json &o) { +void JsonSetObject(detail::json &o) { #ifdef TINYGLTF_USE_RAPIDJSON o.SetObject(); #else @@ -6355,66 +6606,66 @@ void JsonSetObject(json &o) { #endif } -void JsonReserveArray(json &o, size_t s) { +void JsonReserveArray(detail::json &o, size_t s) { #ifdef TINYGLTF_USE_RAPIDJSON o.SetArray(); - o.Reserve(static_cast(s), GetAllocator()); + o.Reserve(static_cast(s), detail::GetAllocator()); #endif (void)(o); (void)(s); } } // namespace -// typedef std::pair json_object_pair; +// typedef std::pair json_object_pair; template static void SerializeNumberProperty(const std::string &key, T number, - json &obj) { + detail::json &obj) { // obj.insert( - // json_object_pair(key, json(static_cast(number)))); + // json_object_pair(key, detail::json(static_cast(number)))); // obj[key] = static_cast(number); - JsonAddMember(obj, key.c_str(), json(number)); + detail::JsonAddMember(obj, key.c_str(), detail::json(number)); } #ifdef TINYGLTF_USE_RAPIDJSON template <> -void SerializeNumberProperty(const std::string &key, size_t number, json &obj) { - JsonAddMember(obj, key.c_str(), json(static_cast(number))); +void SerializeNumberProperty(const std::string &key, size_t number, detail::json &obj) { + detail::JsonAddMember(obj, key.c_str(), detail::json(static_cast(number))); } #endif template static void SerializeNumberArrayProperty(const std::string &key, const std::vector &value, - json &obj) { + detail::json &obj) { if (value.empty()) return; - json ary; - JsonReserveArray(ary, value.size()); + detail::json ary; + detail::JsonReserveArray(ary, value.size()); for (const auto &s : value) { - JsonPushBack(ary, json(s)); + detail::JsonPushBack(ary, detail::json(s)); } - JsonAddMember(obj, key.c_str(), std::move(ary)); + detail::JsonAddMember(obj, key.c_str(), std::move(ary)); } static void SerializeStringProperty(const std::string &key, - const std::string &value, json &obj) { - JsonAddMember(obj, key.c_str(), JsonFromString(value.c_str())); + const std::string &value, detail::json &obj) { + detail::JsonAddMember(obj, key.c_str(), detail::JsonFromString(value.c_str())); } static void SerializeStringArrayProperty(const std::string &key, const std::vector &value, - json &obj) { - json ary; - JsonReserveArray(ary, value.size()); + detail::json &obj) { + detail::json ary; + detail::JsonReserveArray(ary, value.size()); for (auto &s : value) { - JsonPushBack(ary, JsonFromString(s.c_str())); + detail::JsonPushBack(ary, detail::JsonFromString(s.c_str())); } - JsonAddMember(obj, key.c_str(), std::move(ary)); + detail::JsonAddMember(obj, key.c_str(), std::move(ary)); } -static bool ValueToJson(const Value &value, json *ret) { - json obj; +static bool ValueToJson(const Value &value, detail::json *ret) { + detail::json obj; #ifdef TINYGLTF_USE_RAPIDJSON switch (value.Type()) { case REAL_TYPE: @@ -6427,33 +6678,33 @@ static bool ValueToJson(const Value &value, json *ret) { obj.SetBool(value.Get()); break; case STRING_TYPE: - obj.SetString(value.Get().c_str(), GetAllocator()); + obj.SetString(value.Get().c_str(), detail::GetAllocator()); break; case ARRAY_TYPE: { obj.SetArray(); obj.Reserve(static_cast(value.ArrayLen()), - GetAllocator()); + detail::GetAllocator()); for (unsigned int i = 0; i < value.ArrayLen(); ++i) { Value elementValue = value.Get(int(i)); - json elementJson; + detail::json elementJson; if (ValueToJson(value.Get(int(i)), &elementJson)) - obj.PushBack(std::move(elementJson), GetAllocator()); + obj.PushBack(std::move(elementJson), detail::GetAllocator()); } break; } case BINARY_TYPE: // TODO - // obj = json(value.Get>()); + // obj = detail::json(value.Get>()); return false; break; case OBJECT_TYPE: { obj.SetObject(); Value::Object objMap = value.Get(); for (auto &it : objMap) { - json elementJson; + detail::json elementJson; if (ValueToJson(it.second, &elementJson)) { - obj.AddMember(json(it.first.c_str(), GetAllocator()), - std::move(elementJson), GetAllocator()); + obj.AddMember(detail::json(it.first.c_str(), detail::GetAllocator()), + std::move(elementJson), detail::GetAllocator()); } } break; @@ -6465,21 +6716,21 @@ static bool ValueToJson(const Value &value, json *ret) { #else switch (value.Type()) { case REAL_TYPE: - obj = json(value.Get()); + obj = detail::json(value.Get()); break; case INT_TYPE: - obj = json(value.Get()); + obj = detail::json(value.Get()); break; case BOOL_TYPE: - obj = json(value.Get()); + obj = detail::json(value.Get()); break; case STRING_TYPE: - obj = json(value.Get()); + obj = detail::json(value.Get()); break; case ARRAY_TYPE: { for (unsigned int i = 0; i < value.ArrayLen(); ++i) { Value elementValue = value.Get(int(i)); - json elementJson; + detail::json elementJson; if (ValueToJson(value.Get(int(i)), &elementJson)) obj.push_back(elementJson); } @@ -6493,7 +6744,7 @@ static bool ValueToJson(const Value &value, json *ret) { case OBJECT_TYPE: { Value::Object objMap = value.Get(); for (auto &it : objMap) { - json elementJson; + detail::json elementJson; if (ValueToJson(it.second, &elementJson)) obj[it.first] = elementJson; } break; @@ -6508,15 +6759,15 @@ static bool ValueToJson(const Value &value, json *ret) { } static void SerializeValue(const std::string &key, const Value &value, - json &obj) { - json ret; + detail::json &obj) { + detail::json ret; if (ValueToJson(value, &ret)) { - JsonAddMember(obj, key.c_str(), std::move(ret)); + detail::JsonAddMember(obj, key.c_str(), std::move(ret)); } } static void SerializeGltfBufferData(const std::vector &data, - json &o) { + detail::json &o) { std::string header = "data:application/octet-stream;base64,"; if (data.size() > 0) { std::string encodedData = @@ -6524,7 +6775,7 @@ static void SerializeGltfBufferData(const std::vector &data, SerializeStringProperty("uri", header + encodedData, o); } else { // Issue #229 - // size 0 is allowd. Just emit mime header. + // size 0 is allowed. Just emit mime header. SerializeStringProperty("uri", header, o); } } @@ -6562,14 +6813,14 @@ static bool SerializeGltfBufferData(const std::vector &data, } #if 0 // FIXME(syoyo): not used. will be removed in the future release. -static void SerializeParameterMap(ParameterMap ¶m, json &o) { +static void SerializeParameterMap(ParameterMap ¶m, detail::json &o) { for (ParameterMap::iterator paramIt = param.begin(); paramIt != param.end(); ++paramIt) { if (paramIt->second.number_array.size()) { SerializeNumberArrayProperty(paramIt->first, paramIt->second.number_array, o); } else if (paramIt->second.json_double_value.size()) { - json json_double_value; + detail::json json_double_value; for (std::map::iterator it = paramIt->second.json_double_value.begin(); it != paramIt->second.json_double_value.end(); ++it) { @@ -6592,33 +6843,33 @@ static void SerializeParameterMap(ParameterMap ¶m, json &o) { } #endif -static void SerializeExtensionMap(const ExtensionMap &extensions, json &o) { +static void SerializeExtensionMap(const ExtensionMap &extensions, detail::json &o) { if (!extensions.size()) return; - json extMap; + detail::json extMap; for (ExtensionMap::const_iterator extIt = extensions.begin(); extIt != extensions.end(); ++extIt) { // Allow an empty object for extension(#97) - json ret; + detail::json ret; bool isNull = true; if (ValueToJson(extIt->second, &ret)) { - isNull = JsonIsNull(ret); - JsonAddMember(extMap, extIt->first.c_str(), std::move(ret)); + isNull = detail::JsonIsNull(ret); + detail::JsonAddMember(extMap, extIt->first.c_str(), std::move(ret)); } if (isNull) { if (!(extIt->first.empty())) { // name should not be empty, but for sure // create empty object so that an extension name is still included in // json. - json empty; - JsonSetObject(empty); - JsonAddMember(extMap, extIt->first.c_str(), std::move(empty)); + detail::json empty; + detail::JsonSetObject(empty); + detail::JsonAddMember(extMap, extIt->first.c_str(), std::move(empty)); } } } - JsonAddMember(o, "extensions", std::move(extMap)); + detail::JsonAddMember(o, "extensions", std::move(extMap)); } -static void SerializeGltfAccessor(Accessor &accessor, json &o) { +static void SerializeGltfAccessor(const Accessor &accessor, detail::json &o) { if (accessor.bufferView >= 0) SerializeNumberProperty("bufferView", accessor.bufferView, o); @@ -6687,18 +6938,44 @@ static void SerializeGltfAccessor(Accessor &accessor, json &o) { if (accessor.extras.Type() != NULL_TYPE) { SerializeValue("extras", accessor.extras, o); } + + // sparse + if (accessor.sparse.isSparse) + { + detail::json sparse; + SerializeNumberProperty("count", accessor.sparse.count, sparse); + { + detail::json indices; + SerializeNumberProperty("bufferView", accessor.sparse.indices.bufferView, indices); + SerializeNumberProperty("byteOffset", accessor.sparse.indices.byteOffset, indices); + SerializeNumberProperty("componentType", accessor.sparse.indices.componentType, indices); + detail::JsonAddMember(sparse, "indices", std::move(indices)); + } + { + detail::json values; + SerializeNumberProperty("bufferView", accessor.sparse.values.bufferView, values); + SerializeNumberProperty("byteOffset", accessor.sparse.values.byteOffset, values); + detail::JsonAddMember(sparse, "values", std::move(values)); + } + detail::JsonAddMember(o, "sparse", std::move(sparse)); + } } -static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) { +static void SerializeGltfAnimationChannel(const AnimationChannel &channel, + detail::json &o) { SerializeNumberProperty("sampler", channel.sampler, o); { - json target; - SerializeNumberProperty("node", channel.target_node, target); + detail::json target; + + if (channel.target_node > 0) { + SerializeNumberProperty("node", channel.target_node, target); + } + SerializeStringProperty("path", channel.target_path, target); SerializeExtensionMap(channel.target_extensions, target); - JsonAddMember(o, "target", std::move(target)); + detail::JsonAddMember(o, "target", std::move(target)); } if (channel.extras.Type() != NULL_TYPE) { @@ -6708,7 +6985,8 @@ static void SerializeGltfAnimationChannel(AnimationChannel &channel, json &o) { SerializeExtensionMap(channel.extensions, o); } -static void SerializeGltfAnimationSampler(AnimationSampler &sampler, json &o) { +static void SerializeGltfAnimationSampler(const AnimationSampler &sampler, + detail::json &o) { SerializeNumberProperty("input", sampler.input, o); SerializeNumberProperty("output", sampler.output, o); SerializeStringProperty("interpolation", sampler.interpolation, o); @@ -6718,33 +6996,33 @@ static void SerializeGltfAnimationSampler(AnimationSampler &sampler, json &o) { } } -static void SerializeGltfAnimation(Animation &animation, json &o) { +static void SerializeGltfAnimation(const Animation &animation, detail::json &o) { if (!animation.name.empty()) SerializeStringProperty("name", animation.name, o); { - json channels; - JsonReserveArray(channels, animation.channels.size()); + detail::json channels; + detail::JsonReserveArray(channels, animation.channels.size()); for (unsigned int i = 0; i < animation.channels.size(); ++i) { - json channel; + detail::json channel; AnimationChannel gltfChannel = animation.channels[i]; SerializeGltfAnimationChannel(gltfChannel, channel); - JsonPushBack(channels, std::move(channel)); + detail::JsonPushBack(channels, std::move(channel)); } - JsonAddMember(o, "channels", std::move(channels)); + detail::JsonAddMember(o, "channels", std::move(channels)); } { - json samplers; - JsonReserveArray(samplers, animation.samplers.size()); + detail::json samplers; + detail::JsonReserveArray(samplers, animation.samplers.size()); for (unsigned int i = 0; i < animation.samplers.size(); ++i) { - json sampler; + detail::json sampler; AnimationSampler gltfSampler = animation.samplers[i]; SerializeGltfAnimationSampler(gltfSampler, sampler); - JsonPushBack(samplers, std::move(sampler)); + detail::JsonPushBack(samplers, std::move(sampler)); } - JsonAddMember(o, "samplers", std::move(samplers)); + detail::JsonAddMember(o, "samplers", std::move(samplers)); } if (animation.extras.Type() != NULL_TYPE) { @@ -6754,7 +7032,7 @@ static void SerializeGltfAnimation(Animation &animation, json &o) { SerializeExtensionMap(animation.extensions, o); } -static void SerializeGltfAsset(Asset &asset, json &o) { +static void SerializeGltfAsset(const Asset &asset, detail::json &o) { if (!asset.generator.empty()) { SerializeStringProperty("generator", asset.generator, o); } @@ -6763,14 +7041,15 @@ static void SerializeGltfAsset(Asset &asset, json &o) { SerializeStringProperty("copyright", asset.copyright, o); } - if (asset.version.empty()) { + auto version = asset.version; + if (version.empty()) { // Just in case // `version` must be defined - asset.version = "2.0"; + version = "2.0"; } // TODO(syoyo): Do we need to check if `version` is greater or equal to 2.0? - SerializeStringProperty("version", asset.version, o); + SerializeStringProperty("version", version, o); if (asset.extras.Keys().size()) { SerializeValue("extras", asset.extras, o); @@ -6779,7 +7058,7 @@ static void SerializeGltfAsset(Asset &asset, json &o) { SerializeExtensionMap(asset.extensions, o); } -static void SerializeGltfBufferBin(Buffer &buffer, json &o, +static void SerializeGltfBufferBin(const Buffer &buffer, detail::json &o, std::vector &binBuffer) { SerializeNumberProperty("byteLength", buffer.data.size(), o); binBuffer = buffer.data; @@ -6791,7 +7070,7 @@ static void SerializeGltfBufferBin(Buffer &buffer, json &o, } } -static void SerializeGltfBuffer(Buffer &buffer, json &o) { +static void SerializeGltfBuffer(const Buffer &buffer, detail::json &o) { SerializeNumberProperty("byteLength", buffer.data.size(), o); SerializeGltfBufferData(buffer.data, o); @@ -6802,12 +7081,12 @@ static void SerializeGltfBuffer(Buffer &buffer, json &o) { } } -static bool SerializeGltfBuffer(Buffer &buffer, json &o, +static bool SerializeGltfBuffer(const Buffer &buffer, detail::json &o, const std::string &binFilename, - const std::string &binBaseFilename) { + const std::string &binUri) { if (!SerializeGltfBufferData(buffer.data, binFilename)) return false; SerializeNumberProperty("byteLength", buffer.data.size(), o); - SerializeStringProperty("uri", binBaseFilename, o); + SerializeStringProperty("uri", binUri, o); if (buffer.name.size()) SerializeStringProperty("name", buffer.name, o); @@ -6817,7 +7096,7 @@ static bool SerializeGltfBuffer(Buffer &buffer, json &o, return true; } -static void SerializeGltfBufferView(BufferView &bufferView, json &o) { +static void SerializeGltfBufferView(const BufferView &bufferView, detail::json &o) { SerializeNumberProperty("buffer", bufferView.buffer, o); SerializeNumberProperty("byteLength", bufferView.byteLength, o); @@ -6843,14 +7122,15 @@ static void SerializeGltfBufferView(BufferView &bufferView, json &o) { } } -static void SerializeGltfImage(Image &image, json &o) { - // if uri empty, the mimeType and bufferview should be set - if (image.uri.empty()) { +static void SerializeGltfImage(const Image &image, const std::string &uri, + detail::json &o) { + // From 2.7.0, we look for `uri` parameter, not `Image.uri` + // if uri is empty, the mimeType and bufferview should be set + if (uri.empty()) { SerializeStringProperty("mimeType", image.mimeType, o); SerializeNumberProperty("bufferView", image.bufferView, o); } else { - // TODO(syoyo): dlib::urilencode? - SerializeStringProperty("uri", image.uri, o); + SerializeStringProperty("uri", uri, o); } if (image.name.size()) { @@ -6864,7 +7144,7 @@ static void SerializeGltfImage(Image &image, json &o) { SerializeExtensionMap(image.extensions, o); } -static void SerializeGltfTextureInfo(TextureInfo &texinfo, json &o) { +static void SerializeGltfTextureInfo(const TextureInfo &texinfo, detail::json &o) { SerializeNumberProperty("index", texinfo.index, o); if (texinfo.texCoord != 0) { @@ -6878,8 +7158,8 @@ static void SerializeGltfTextureInfo(TextureInfo &texinfo, json &o) { SerializeExtensionMap(texinfo.extensions, o); } -static void SerializeGltfNormalTextureInfo(NormalTextureInfo &texinfo, - json &o) { +static void SerializeGltfNormalTextureInfo(const NormalTextureInfo &texinfo, + detail::json &o) { SerializeNumberProperty("index", texinfo.index, o); if (texinfo.texCoord != 0) { @@ -6897,8 +7177,8 @@ static void SerializeGltfNormalTextureInfo(NormalTextureInfo &texinfo, SerializeExtensionMap(texinfo.extensions, o); } -static void SerializeGltfOcclusionTextureInfo(OcclusionTextureInfo &texinfo, - json &o) { +static void SerializeGltfOcclusionTextureInfo( + const OcclusionTextureInfo &texinfo, detail::json &o) { SerializeNumberProperty("index", texinfo.index, o); if (texinfo.texCoord != 0) { @@ -6916,8 +7196,8 @@ static void SerializeGltfOcclusionTextureInfo(OcclusionTextureInfo &texinfo, SerializeExtensionMap(texinfo.extensions, o); } -static void SerializeGltfPbrMetallicRoughness(PbrMetallicRoughness &pbr, - json &o) { +static void SerializeGltfPbrMetallicRoughness(const PbrMetallicRoughness &pbr, + detail::json &o) { std::vector default_baseColorFactor = {1.0, 1.0, 1.0, 1.0}; if (!Equals(pbr.baseColorFactor, default_baseColorFactor)) { SerializeNumberArrayProperty("baseColorFactor", pbr.baseColorFactor, @@ -6933,15 +7213,15 @@ static void SerializeGltfPbrMetallicRoughness(PbrMetallicRoughness &pbr, } if (pbr.baseColorTexture.index > -1) { - json texinfo; + detail::json texinfo; SerializeGltfTextureInfo(pbr.baseColorTexture, texinfo); - JsonAddMember(o, "baseColorTexture", std::move(texinfo)); + detail::JsonAddMember(o, "baseColorTexture", std::move(texinfo)); } if (pbr.metallicRoughnessTexture.index > -1) { - json texinfo; + detail::json texinfo; SerializeGltfTextureInfo(pbr.metallicRoughnessTexture, texinfo); - JsonAddMember(o, "metallicRoughnessTexture", std::move(texinfo)); + detail::JsonAddMember(o, "metallicRoughnessTexture", std::move(texinfo)); } SerializeExtensionMap(pbr.extensions, o); @@ -6951,7 +7231,7 @@ static void SerializeGltfPbrMetallicRoughness(PbrMetallicRoughness &pbr, } } -static void SerializeGltfMaterial(Material &material, json &o) { +static void SerializeGltfMaterial(const Material &material, detail::json &o) { if (material.name.size()) { SerializeStringProperty("name", material.name, o); } @@ -6967,24 +7247,24 @@ static void SerializeGltfMaterial(Material &material, json &o) { } if (material.doubleSided != false) - JsonAddMember(o, "doubleSided", json(material.doubleSided)); + detail::JsonAddMember(o, "doubleSided", detail::json(material.doubleSided)); if (material.normalTexture.index > -1) { - json texinfo; + detail::json texinfo; SerializeGltfNormalTextureInfo(material.normalTexture, texinfo); - JsonAddMember(o, "normalTexture", std::move(texinfo)); + detail::JsonAddMember(o, "normalTexture", std::move(texinfo)); } if (material.occlusionTexture.index > -1) { - json texinfo; + detail::json texinfo; SerializeGltfOcclusionTextureInfo(material.occlusionTexture, texinfo); - JsonAddMember(o, "occlusionTexture", std::move(texinfo)); + detail::JsonAddMember(o, "occlusionTexture", std::move(texinfo)); } if (material.emissiveTexture.index > -1) { - json texinfo; + detail::json texinfo; SerializeGltfTextureInfo(material.emissiveTexture, texinfo); - JsonAddMember(o, "emissiveTexture", std::move(texinfo)); + detail::JsonAddMember(o, "emissiveTexture", std::move(texinfo)); } std::vector default_emissiveFactor = {0.0, 0.0, 0.0}; @@ -6994,25 +7274,25 @@ static void SerializeGltfMaterial(Material &material, json &o) { } { - json pbrMetallicRoughness; + detail::json pbrMetallicRoughness; SerializeGltfPbrMetallicRoughness(material.pbrMetallicRoughness, pbrMetallicRoughness); // Issue 204 // Do not serialize `pbrMetallicRoughness` if pbrMetallicRoughness has all // default values(json is null). Otherwise it will serialize to // `pbrMetallicRoughness : null`, which cannot be read by other glTF - // importers(and validators). + // importers (and validators). // - if (!JsonIsNull(pbrMetallicRoughness)) { - JsonAddMember(o, "pbrMetallicRoughness", std::move(pbrMetallicRoughness)); + if (!detail::JsonIsNull(pbrMetallicRoughness)) { + detail::JsonAddMember(o, "pbrMetallicRoughness", std::move(pbrMetallicRoughness)); } } #if 0 // legacy way. just for the record. if (material.values.size()) { - json pbrMetallicRoughness; + detail::json pbrMetallicRoughness; SerializeParameterMap(material.values, pbrMetallicRoughness); - JsonAddMember(o, "pbrMetallicRoughness", std::move(pbrMetallicRoughness)); + detail::JsonAddMember(o, "pbrMetallicRoughness", std::move(pbrMetallicRoughness)); } SerializeParameterMap(material.additionalValues, o); @@ -7027,23 +7307,23 @@ static void SerializeGltfMaterial(Material &material, json &o) { } } -static void SerializeGltfMesh(Mesh &mesh, json &o) { - json primitives; - JsonReserveArray(primitives, mesh.primitives.size()); +static void SerializeGltfMesh(const Mesh &mesh, detail::json &o) { + detail::json primitives; + detail::JsonReserveArray(primitives, mesh.primitives.size()); for (unsigned int i = 0; i < mesh.primitives.size(); ++i) { - json primitive; + detail::json primitive; const Primitive &gltfPrimitive = mesh.primitives[i]; // don't make a copy { - json attributes; + detail::json attributes; for (auto attrIt = gltfPrimitive.attributes.begin(); attrIt != gltfPrimitive.attributes.end(); ++attrIt) { SerializeNumberProperty(attrIt->first, attrIt->second, attributes); } - JsonAddMember(primitive, "attributes", std::move(attributes)); + detail::JsonAddMember(primitive, "attributes", std::move(attributes)); } - // Indicies is optional + // Indices is optional if (gltfPrimitive.indices > -1) { SerializeNumberProperty("indices", gltfPrimitive.indices, primitive); } @@ -7056,19 +7336,19 @@ static void SerializeGltfMesh(Mesh &mesh, json &o) { // Morph targets if (gltfPrimitive.targets.size()) { - json targets; - JsonReserveArray(targets, gltfPrimitive.targets.size()); + detail::json targets; + detail::JsonReserveArray(targets, gltfPrimitive.targets.size()); for (unsigned int k = 0; k < gltfPrimitive.targets.size(); ++k) { - json targetAttributes; + detail::json targetAttributes; std::map targetData = gltfPrimitive.targets[k]; for (std::map::iterator attrIt = targetData.begin(); attrIt != targetData.end(); ++attrIt) { SerializeNumberProperty(attrIt->first, attrIt->second, targetAttributes); } - JsonPushBack(targets, std::move(targetAttributes)); + detail::JsonPushBack(targets, std::move(targetAttributes)); } - JsonAddMember(primitive, "targets", std::move(targets)); + detail::JsonAddMember(primitive, "targets", std::move(targets)); } SerializeExtensionMap(gltfPrimitive.extensions, primitive); @@ -7077,10 +7357,10 @@ static void SerializeGltfMesh(Mesh &mesh, json &o) { SerializeValue("extras", gltfPrimitive.extras, primitive); } - JsonPushBack(primitives, std::move(primitive)); + detail::JsonPushBack(primitives, std::move(primitive)); } - JsonAddMember(o, "primitives", std::move(primitives)); + detail::JsonAddMember(o, "primitives", std::move(primitives)); if (mesh.weights.size()) { SerializeNumberArrayProperty("weights", mesh.weights, o); @@ -7096,7 +7376,7 @@ static void SerializeGltfMesh(Mesh &mesh, json &o) { } } -static void SerializeSpotLight(SpotLight &spot, json &o) { +static void SerializeSpotLight(const SpotLight &spot, detail::json &o) { SerializeNumberProperty("innerConeAngle", spot.innerConeAngle, o); SerializeNumberProperty("outerConeAngle", spot.outerConeAngle, o); SerializeExtensionMap(spot.extensions, o); @@ -7105,7 +7385,7 @@ static void SerializeSpotLight(SpotLight &spot, json &o) { } } -static void SerializeGltfLight(Light &light, json &o) { +static void SerializeGltfLight(const Light &light, detail::json &o) { if (!light.name.empty()) SerializeStringProperty("name", light.name, o); SerializeNumberProperty("intensity", light.intensity, o); if (light.range > 0.0) { @@ -7114,9 +7394,9 @@ static void SerializeGltfLight(Light &light, json &o) { SerializeNumberArrayProperty("color", light.color, o); SerializeStringProperty("type", light.type, o); if (light.type == "spot") { - json spot; + detail::json spot; SerializeSpotLight(light.spot, spot); - JsonAddMember(o, "spot", std::move(spot)); + detail::JsonAddMember(o, "spot", std::move(spot)); } SerializeExtensionMap(light.extensions, o); if (light.extras.Type() != NULL_TYPE) { @@ -7124,7 +7404,7 @@ static void SerializeGltfLight(Light &light, json &o) { } } -static void SerializeGltfNode(Node &node, json &o) { +static void SerializeGltfNode(const Node &node, detail::json &o) { if (node.translation.size() > 0) { SerializeNumberArrayProperty("translation", node.translation, o); } @@ -7162,14 +7442,17 @@ static void SerializeGltfNode(Node &node, json &o) { SerializeNumberArrayProperty("children", node.children, o); } -static void SerializeGltfSampler(Sampler &sampler, json &o) { +static void SerializeGltfSampler(const Sampler &sampler, detail::json &o) { + if (!sampler.name.empty()) { + SerializeStringProperty("name", sampler.name, o); + } if (sampler.magFilter != -1) { SerializeNumberProperty("magFilter", sampler.magFilter, o); } if (sampler.minFilter != -1) { SerializeNumberProperty("minFilter", sampler.minFilter, o); } - //SerializeNumberProperty("wrapR", sampler.wrapR, o); + // SerializeNumberProperty("wrapR", sampler.wrapR, o); SerializeNumberProperty("wrapS", sampler.wrapS, o); SerializeNumberProperty("wrapT", sampler.wrapT, o); @@ -7179,7 +7462,7 @@ static void SerializeGltfSampler(Sampler &sampler, json &o) { } static void SerializeGltfOrthographicCamera(const OrthographicCamera &camera, - json &o) { + detail::json &o) { SerializeNumberProperty("zfar", camera.zfar, o); SerializeNumberProperty("znear", camera.znear, o); SerializeNumberProperty("xmag", camera.xmag, o); @@ -7191,7 +7474,7 @@ static void SerializeGltfOrthographicCamera(const OrthographicCamera &camera, } static void SerializeGltfPerspectiveCamera(const PerspectiveCamera &camera, - json &o) { + detail::json &o) { SerializeNumberProperty("zfar", camera.zfar, o); SerializeNumberProperty("znear", camera.znear, o); if (camera.aspectRatio > 0) { @@ -7207,20 +7490,20 @@ static void SerializeGltfPerspectiveCamera(const PerspectiveCamera &camera, } } -static void SerializeGltfCamera(const Camera &camera, json &o) { +static void SerializeGltfCamera(const Camera &camera, detail::json &o) { SerializeStringProperty("type", camera.type, o); if (!camera.name.empty()) { SerializeStringProperty("name", camera.name, o); } if (camera.type.compare("orthographic") == 0) { - json orthographic; + detail::json orthographic; SerializeGltfOrthographicCamera(camera.orthographic, orthographic); - JsonAddMember(o, "orthographic", std::move(orthographic)); + detail::JsonAddMember(o, "orthographic", std::move(orthographic)); } else if (camera.type.compare("perspective") == 0) { - json perspective; + detail::json perspective; SerializeGltfPerspectiveCamera(camera.perspective, perspective); - JsonAddMember(o, "perspective", std::move(perspective)); + detail::JsonAddMember(o, "perspective", std::move(perspective)); } else { // ??? } @@ -7231,7 +7514,7 @@ static void SerializeGltfCamera(const Camera &camera, json &o) { SerializeExtensionMap(camera.extensions, o); } -static void SerializeGltfScene(Scene &scene, json &o) { +static void SerializeGltfScene(const Scene &scene, detail::json &o) { SerializeNumberArrayProperty("nodes", scene.nodes, o); if (scene.name.size()) { @@ -7243,7 +7526,7 @@ static void SerializeGltfScene(Scene &scene, json &o) { SerializeExtensionMap(scene.extensions, o); } -static void SerializeGltfSkin(Skin &skin, json &o) { +static void SerializeGltfSkin(const Skin &skin, detail::json &o) { // required SerializeNumberArrayProperty("joints", skin.joints, o); @@ -7260,7 +7543,7 @@ static void SerializeGltfSkin(Skin &skin, json &o) { } } -static void SerializeGltfTexture(Texture &texture, json &o) { +static void SerializeGltfTexture(const Texture &texture, detail::json &o) { if (texture.sampler > -1) { SerializeNumberProperty("sampler", texture.sampler, o); } @@ -7279,49 +7562,49 @@ static void SerializeGltfTexture(Texture &texture, json &o) { /// /// Serialize all properties except buffers and images. /// -static void SerializeGltfModel(Model *model, json &o) { +static void SerializeGltfModel(const Model *model, detail::json &o) { // ACCESSORS if (model->accessors.size()) { - json accessors; - JsonReserveArray(accessors, model->accessors.size()); + detail::json accessors; + detail::JsonReserveArray(accessors, model->accessors.size()); for (unsigned int i = 0; i < model->accessors.size(); ++i) { - json accessor; + detail::json accessor; SerializeGltfAccessor(model->accessors[i], accessor); - JsonPushBack(accessors, std::move(accessor)); + detail::JsonPushBack(accessors, std::move(accessor)); } - JsonAddMember(o, "accessors", std::move(accessors)); + detail::JsonAddMember(o, "accessors", std::move(accessors)); } // ANIMATIONS if (model->animations.size()) { - json animations; - JsonReserveArray(animations, model->animations.size()); + detail::json animations; + detail::JsonReserveArray(animations, model->animations.size()); for (unsigned int i = 0; i < model->animations.size(); ++i) { if (model->animations[i].channels.size()) { - json animation; + detail::json animation; SerializeGltfAnimation(model->animations[i], animation); - JsonPushBack(animations, std::move(animation)); + detail::JsonPushBack(animations, std::move(animation)); } } - JsonAddMember(o, "animations", std::move(animations)); + detail::JsonAddMember(o, "animations", std::move(animations)); } // ASSET - json asset; + detail::json asset; SerializeGltfAsset(model->asset, asset); - JsonAddMember(o, "asset", std::move(asset)); + detail::JsonAddMember(o, "asset", std::move(asset)); // BUFFERVIEWS if (model->bufferViews.size()) { - json bufferViews; - JsonReserveArray(bufferViews, model->bufferViews.size()); + detail::json bufferViews; + detail::JsonReserveArray(bufferViews, model->bufferViews.size()); for (unsigned int i = 0; i < model->bufferViews.size(); ++i) { - json bufferView; + detail::json bufferView; SerializeGltfBufferView(model->bufferViews[i], bufferView); - JsonPushBack(bufferViews, std::move(bufferView)); + detail::JsonPushBack(bufferViews, std::move(bufferView)); } - JsonAddMember(o, "bufferViews", std::move(bufferViews)); + detail::JsonAddMember(o, "bufferViews", std::move(bufferViews)); } // Extensions required @@ -7332,48 +7615,48 @@ static void SerializeGltfModel(Model *model, json &o) { // MATERIALS if (model->materials.size()) { - json materials; - JsonReserveArray(materials, model->materials.size()); + detail::json materials; + detail::JsonReserveArray(materials, model->materials.size()); for (unsigned int i = 0; i < model->materials.size(); ++i) { - json material; + detail::json material; SerializeGltfMaterial(model->materials[i], material); - if (JsonIsNull(material)) { + if (detail::JsonIsNull(material)) { // Issue 294. // `material` does not have any required parameters // so the result may be null(unmodified) when all material parameters // have default value. // // null is not allowed thus we create an empty JSON object. - JsonSetObject(material); + detail::JsonSetObject(material); } - JsonPushBack(materials, std::move(material)); + detail::JsonPushBack(materials, std::move(material)); } - JsonAddMember(o, "materials", std::move(materials)); + detail::JsonAddMember(o, "materials", std::move(materials)); } // MESHES if (model->meshes.size()) { - json meshes; - JsonReserveArray(meshes, model->meshes.size()); + detail::json meshes; + detail::JsonReserveArray(meshes, model->meshes.size()); for (unsigned int i = 0; i < model->meshes.size(); ++i) { - json mesh; + detail::json mesh; SerializeGltfMesh(model->meshes[i], mesh); - JsonPushBack(meshes, std::move(mesh)); + detail::JsonPushBack(meshes, std::move(mesh)); } - JsonAddMember(o, "meshes", std::move(meshes)); + detail::JsonAddMember(o, "meshes", std::move(meshes)); } // NODES if (model->nodes.size()) { - json nodes; - JsonReserveArray(nodes, model->nodes.size()); + detail::json nodes; + detail::JsonReserveArray(nodes, model->nodes.size()); for (unsigned int i = 0; i < model->nodes.size(); ++i) { - json node; + detail::json node; SerializeGltfNode(model->nodes[i], node); - JsonPushBack(nodes, std::move(node)); + detail::JsonPushBack(nodes, std::move(node)); } - JsonAddMember(o, "nodes", std::move(nodes)); + detail::JsonAddMember(o, "nodes", std::move(nodes)); } // SCENE @@ -7383,62 +7666,62 @@ static void SerializeGltfModel(Model *model, json &o) { // SCENES if (model->scenes.size()) { - json scenes; - JsonReserveArray(scenes, model->scenes.size()); + detail::json scenes; + detail::JsonReserveArray(scenes, model->scenes.size()); for (unsigned int i = 0; i < model->scenes.size(); ++i) { - json currentScene; + detail::json currentScene; SerializeGltfScene(model->scenes[i], currentScene); - JsonPushBack(scenes, std::move(currentScene)); + detail::JsonPushBack(scenes, std::move(currentScene)); } - JsonAddMember(o, "scenes", std::move(scenes)); + detail::JsonAddMember(o, "scenes", std::move(scenes)); } // SKINS if (model->skins.size()) { - json skins; - JsonReserveArray(skins, model->skins.size()); + detail::json skins; + detail::JsonReserveArray(skins, model->skins.size()); for (unsigned int i = 0; i < model->skins.size(); ++i) { - json skin; + detail::json skin; SerializeGltfSkin(model->skins[i], skin); - JsonPushBack(skins, std::move(skin)); + detail::JsonPushBack(skins, std::move(skin)); } - JsonAddMember(o, "skins", std::move(skins)); + detail::JsonAddMember(o, "skins", std::move(skins)); } // TEXTURES if (model->textures.size()) { - json textures; - JsonReserveArray(textures, model->textures.size()); + detail::json textures; + detail::JsonReserveArray(textures, model->textures.size()); for (unsigned int i = 0; i < model->textures.size(); ++i) { - json texture; + detail::json texture; SerializeGltfTexture(model->textures[i], texture); - JsonPushBack(textures, std::move(texture)); + detail::JsonPushBack(textures, std::move(texture)); } - JsonAddMember(o, "textures", std::move(textures)); + detail::JsonAddMember(o, "textures", std::move(textures)); } // SAMPLERS if (model->samplers.size()) { - json samplers; - JsonReserveArray(samplers, model->samplers.size()); + detail::json samplers; + detail::JsonReserveArray(samplers, model->samplers.size()); for (unsigned int i = 0; i < model->samplers.size(); ++i) { - json sampler; + detail::json sampler; SerializeGltfSampler(model->samplers[i], sampler); - JsonPushBack(samplers, std::move(sampler)); + detail::JsonPushBack(samplers, std::move(sampler)); } - JsonAddMember(o, "samplers", std::move(samplers)); + detail::JsonAddMember(o, "samplers", std::move(samplers)); } // CAMERAS if (model->cameras.size()) { - json cameras; - JsonReserveArray(cameras, model->cameras.size()); + detail::json cameras; + detail::JsonReserveArray(cameras, model->cameras.size()); for (unsigned int i = 0; i < model->cameras.size(); ++i) { - json camera; + detail::json camera; SerializeGltfCamera(model->cameras[i], camera); - JsonPushBack(cameras, std::move(camera)); + detail::JsonPushBack(cameras, std::move(camera)); } - JsonAddMember(o, "cameras", std::move(cameras)); + detail::JsonAddMember(o, "cameras", std::move(cameras)); } // EXTENSIONS @@ -7448,27 +7731,27 @@ static void SerializeGltfModel(Model *model, json &o) { // LIGHTS as KHR_lights_punctual if (model->lights.size()) { - json lights; - JsonReserveArray(lights, model->lights.size()); + detail::json lights; + detail::JsonReserveArray(lights, model->lights.size()); for (unsigned int i = 0; i < model->lights.size(); ++i) { - json light; + detail::json light; SerializeGltfLight(model->lights[i], light); - JsonPushBack(lights, std::move(light)); + detail::JsonPushBack(lights, std::move(light)); } - json khr_lights_cmn; - JsonAddMember(khr_lights_cmn, "lights", std::move(lights)); - json ext_j; + detail::json khr_lights_cmn; + detail::JsonAddMember(khr_lights_cmn, "lights", std::move(lights)); + detail::json ext_j; { - json_const_iterator it; - if (FindMember(o, "extensions", it)) { - JsonAssign(ext_j, GetValue(it)); + detail::json_const_iterator it; + if (detail::FindMember(o, "extensions", it)) { + detail::JsonAssign(ext_j, detail::GetValue(it)); } } - JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn)); + detail::JsonAddMember(ext_j, "KHR_lights_punctual", std::move(khr_lights_cmn)); - JsonAddMember(o, "extensions", std::move(ext_j)); + detail::JsonAddMember(o, "extensions", std::move(ext_j)); // Also add "KHR_lights_punctual" to `extensionsUsed` { @@ -7523,37 +7806,32 @@ static bool WriteGltfFile(const std::string &output, return WriteGltfStream(gltfFile, content); } -static void WriteBinaryGltfStream(std::ostream &stream, +static bool WriteBinaryGltfStream(std::ostream &stream, const std::string &content, const std::vector &binBuffer) { const std::string header = "glTF"; const int version = 2; - // https://stackoverflow.com/questions/3407012/c-rounding-up-to-the-nearest-multiple-of-a-number - auto roundUp = [](uint32_t numToRound, uint32_t multiple) { - if (multiple == 0) return numToRound; - - uint32_t remainder = numToRound % multiple; - if (remainder == 0) return numToRound; - - return numToRound + multiple - remainder; - }; - - const uint32_t padding_size = - roundUp(uint32_t(content.size()), 4) - uint32_t(content.size()); + const uint32_t content_size = uint32_t(content.size()); + const uint32_t binBuffer_size = uint32_t(binBuffer.size()); + // determine number of padding bytes required to ensure 4 byte alignment + const uint32_t content_padding_size = + content_size % 4 == 0 ? 0 : 4 - content_size % 4; + const uint32_t bin_padding_size = + binBuffer_size % 4 == 0 ? 0 : 4 - binBuffer_size % 4; // 12 bytes for header, JSON content length, 8 bytes for JSON chunk info. - // Chunk data must be located at 4-byte boundary. + // Chunk data must be located at 4-byte boundary, which may require padding const uint32_t length = - 12 + 8 + roundUp(uint32_t(content.size()), 4) + - (binBuffer.size() ? (8 + roundUp(uint32_t(binBuffer.size()), 4)) : 0); + 12 + 8 + content_size + content_padding_size + + (binBuffer_size ? (8 + binBuffer_size + bin_padding_size) : 0); stream.write(header.c_str(), std::streamsize(header.size())); stream.write(reinterpret_cast(&version), sizeof(version)); stream.write(reinterpret_cast(&length), sizeof(length)); // JSON chunk info, then JSON data - const uint32_t model_length = uint32_t(content.size()) + padding_size; + const uint32_t model_length = uint32_t(content.size()) + content_padding_size; const uint32_t model_format = 0x4E4F534A; stream.write(reinterpret_cast(&model_length), sizeof(model_length)); @@ -7562,13 +7840,11 @@ static void WriteBinaryGltfStream(std::ostream &stream, stream.write(content.c_str(), std::streamsize(content.size())); // Chunk must be multiplies of 4, so pad with spaces - if (padding_size > 0) { - const std::string padding = std::string(size_t(padding_size), ' '); + if (content_padding_size > 0) { + const std::string padding = std::string(size_t(content_padding_size), ' '); stream.write(padding.c_str(), std::streamsize(padding.size())); } if (binBuffer.size() > 0) { - const uint32_t bin_padding_size = - roundUp(uint32_t(binBuffer.size()), 4) - uint32_t(binBuffer.size()); // BIN chunk info, then BIN data const uint32_t bin_length = uint32_t(binBuffer.size()) + bin_padding_size; const uint32_t bin_format = 0x004e4942; @@ -7586,9 +7862,12 @@ static void WriteBinaryGltfStream(std::ostream &stream, std::streamsize(padding.size())); } } + + // TODO: Check error on stream.write + return true; } -static void WriteBinaryGltfFile(const std::string &output, +static bool WriteBinaryGltfFile(const std::string &output, const std::string &content, const std::vector &binBuffer) { #ifdef _WIN32 @@ -7606,13 +7885,13 @@ static void WriteBinaryGltfFile(const std::string &output, #else std::ofstream gltfFile(output.c_str(), std::ios::binary); #endif - WriteBinaryGltfStream(gltfFile, content, binBuffer); + return WriteBinaryGltfStream(gltfFile, content, binBuffer); } -bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream, +bool TinyGLTF::WriteGltfSceneToStream(const Model *model, std::ostream &stream, bool prettyPrint = true, bool writeBinary = false) { - JsonDocument output; + detail::JsonDocument output; /// Serialize all properties except buffers and images. SerializeGltfModel(model, output); @@ -7620,54 +7899,57 @@ bool TinyGLTF::WriteGltfSceneToStream(Model *model, std::ostream &stream, // BUFFERS std::vector binBuffer; if (model->buffers.size()) { - json buffers; - JsonReserveArray(buffers, model->buffers.size()); + detail::json buffers; + detail::JsonReserveArray(buffers, model->buffers.size()); for (unsigned int i = 0; i < model->buffers.size(); ++i) { - json buffer; + detail::json buffer; if (writeBinary && i == 0 && model->buffers[i].uri.empty()) { SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer); } else { SerializeGltfBuffer(model->buffers[i], buffer); } - JsonPushBack(buffers, std::move(buffer)); + detail::JsonPushBack(buffers, std::move(buffer)); } - JsonAddMember(output, "buffers", std::move(buffers)); + detail::JsonAddMember(output, "buffers", std::move(buffers)); } // IMAGES if (model->images.size()) { - json images; - JsonReserveArray(images, model->images.size()); + detail::json images; + detail::JsonReserveArray(images, model->images.size()); for (unsigned int i = 0; i < model->images.size(); ++i) { - json image; + detail::json image; std::string dummystring = ""; // UpdateImageObject need baseDir but only uses it if embeddedImages is // enabled, since we won't write separate images when writing to a stream // we - UpdateImageObject(model->images[i], dummystring, int(i), false, - &this->WriteImageData, this->write_image_user_data_); - SerializeGltfImage(model->images[i], image); - JsonPushBack(images, std::move(image)); + std::string uri; + if (!UpdateImageObject(model->images[i], dummystring, int(i), true, + &uri_cb, &this->WriteImageData, + this->write_image_user_data_, &uri)) { + return false; + } + SerializeGltfImage(model->images[i], uri, image); + detail::JsonPushBack(images, std::move(image)); } - JsonAddMember(output, "images", std::move(images)); + detail::JsonAddMember(output, "images", std::move(images)); } if (writeBinary) { - WriteBinaryGltfStream(stream, JsonToString(output), binBuffer); + return WriteBinaryGltfStream(stream, detail::JsonToString(output), binBuffer); } else { - WriteGltfStream(stream, JsonToString(output, prettyPrint ? 2 : -1)); + return WriteGltfStream(stream, detail::JsonToString(output, prettyPrint ? 2 : -1)); } - - return true; } -bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename, +bool TinyGLTF::WriteGltfSceneToFile(const Model *model, + const std::string &filename, bool embedImages = false, bool embedBuffers = false, bool prettyPrint = true, bool writeBinary = false) { - JsonDocument output; + detail::JsonDocument output; std::string defaultBinFilename = GetBaseFilename(filename); std::string defaultBinFileExt = ".bin"; std::string::size_type pos = @@ -7684,72 +7966,87 @@ bool TinyGLTF::WriteGltfSceneToFile(Model *model, const std::string &filename, SerializeGltfModel(model, output); // BUFFERS - std::vector usedUris; + std::vector usedFilenames; std::vector binBuffer; if (model->buffers.size()) { - json buffers; - JsonReserveArray(buffers, model->buffers.size()); + detail::json buffers; + detail::JsonReserveArray(buffers, model->buffers.size()); for (unsigned int i = 0; i < model->buffers.size(); ++i) { - json buffer; + detail::json buffer; if (writeBinary && i == 0 && model->buffers[i].uri.empty()) { SerializeGltfBufferBin(model->buffers[i], buffer, binBuffer); } else if (embedBuffers) { SerializeGltfBuffer(model->buffers[i], buffer); } else { std::string binSavePath; + std::string binFilename; std::string binUri; if (!model->buffers[i].uri.empty() && !IsDataURI(model->buffers[i].uri)) { binUri = model->buffers[i].uri; + if (!uri_cb.decode(binUri, &binFilename, uri_cb.user_data)) { + return false; + } } else { - binUri = defaultBinFilename + defaultBinFileExt; + binFilename = defaultBinFilename + defaultBinFileExt; bool inUse = true; int numUsed = 0; while (inUse) { inUse = false; - for (const std::string &usedName : usedUris) { - if (binUri.compare(usedName) != 0) continue; + for (const std::string &usedName : usedFilenames) { + if (binFilename.compare(usedName) != 0) continue; inUse = true; - binUri = defaultBinFilename + std::to_string(numUsed++) + - defaultBinFileExt; + binFilename = defaultBinFilename + std::to_string(numUsed++) + + defaultBinFileExt; break; } } + + if (uri_cb.encode) { + if (!uri_cb.encode(binFilename, "buffer", &binUri, + uri_cb.user_data)) { + return false; + } + } else { + binUri = binFilename; + } } - usedUris.push_back(binUri); - binSavePath = JoinPath(baseDir, binUri); + usedFilenames.push_back(binFilename); + binSavePath = JoinPath(baseDir, binFilename); if (!SerializeGltfBuffer(model->buffers[i], buffer, binSavePath, binUri)) { return false; } } - JsonPushBack(buffers, std::move(buffer)); + detail::JsonPushBack(buffers, std::move(buffer)); } - JsonAddMember(output, "buffers", std::move(buffers)); + detail::JsonAddMember(output, "buffers", std::move(buffers)); } // IMAGES if (model->images.size()) { - json images; - JsonReserveArray(images, model->images.size()); + detail::json images; + detail::JsonReserveArray(images, model->images.size()); for (unsigned int i = 0; i < model->images.size(); ++i) { - json image; + detail::json image; - UpdateImageObject(model->images[i], baseDir, int(i), embedImages, - &this->WriteImageData, this->write_image_user_data_); - SerializeGltfImage(model->images[i], image); - JsonPushBack(images, std::move(image)); + std::string uri; + if (!UpdateImageObject(model->images[i], baseDir, int(i), embedImages, + &uri_cb, &this->WriteImageData, + this->write_image_user_data_, &uri)) { + return false; + } + SerializeGltfImage(model->images[i], uri, image); + detail::JsonPushBack(images, std::move(image)); } - JsonAddMember(output, "images", std::move(images)); + detail::JsonAddMember(output, "images", std::move(images)); } if (writeBinary) { - WriteBinaryGltfFile(filename, JsonToString(output), binBuffer); + return WriteBinaryGltfFile(filename, detail::JsonToString(output), binBuffer); } else { - WriteGltfFile(filename, JsonToString(output, (prettyPrint ? 2 : -1))); + return WriteGltfFile(filename, detail::JsonToString(output, (prettyPrint ? 2 : -1))); } - - return true; } } // namespace tinygltf diff --git a/intern/cycles/app/opengl/shader.cpp b/intern/cycles/app/opengl/shader.cpp index 4d22fc2b763..906e1979438 100644 --- a/intern/cycles/app/opengl/shader.cpp +++ b/intern/cycles/app/opengl/shader.cpp @@ -41,7 +41,7 @@ static const char *FRAGMENT_SHADER = "void main()\n" "{\n" " vec4 rgba = texture(image_texture, texCoord_interp);\n" - /* Harcoded Rec.709 gamma, should use OpenColorIO eventually. */ + /* Hard-coded Rec.709 gamma, should use OpenColorIO eventually. */ " fragColor = pow(rgba, vec4(0.45, 0.45, 0.45, 1.0));\n" "}\n\0"; diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp index b82ef9bbe78..847c7358f7a 100644 --- a/intern/cycles/blender/mesh.cpp +++ b/intern/cycles/blender/mesh.cpp @@ -893,6 +893,23 @@ static std::optional find_material_index_attribute(BL::Mesh b_ return std::nullopt; } +static std::optional find_sharp_face_attribute(BL::Mesh b_mesh) +{ + for (BL::Attribute &b_attribute : b_mesh.attributes) { + if (b_attribute.domain() != BL::Attribute::domain_FACE) { + continue; + } + if (b_attribute.data_type() != BL::Attribute::data_type_BOOLEAN) { + continue; + } + if (b_attribute.name() != "sharp_face") { + continue; + } + return BL::BoolAttribute{b_attribute}; + } + return std::nullopt; +} + static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, @@ -983,16 +1000,22 @@ static void create_mesh(Scene *scene, return 0; }; + std::optional sharp_faces = find_sharp_face_attribute(b_mesh); + auto get_face_sharp = [&](const int poly_index) -> bool { + if (sharp_faces) { + return sharp_faces->data[poly_index].value(); + } + return false; + }; + /* create faces */ - const MPoly *polys = static_cast(b_mesh.polygons[0].ptr.data); if (!subdivision) { for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) { const int poly_index = t.polygon_index(); - const MPoly &b_poly = polys[poly_index]; int3 vi = get_int3(t.vertices()); int shader = get_material_index(poly_index); - bool smooth = (b_poly.flag & ME_SMOOTH) || use_loop_normals; + bool smooth = !get_face_sharp(poly_index) || use_loop_normals; if (use_loop_normals) { BL::Array loop_normals = t.split_normals(); @@ -1012,13 +1035,14 @@ static void create_mesh(Scene *scene, else { vector vi; + const MPoly *polys = static_cast(b_mesh.polygons[0].ptr.data); const MLoop *loops = static_cast(b_mesh.loops[0].ptr.data); for (int i = 0; i < numfaces; i++) { const MPoly &b_poly = polys[i]; int n = b_poly.totloop; int shader = get_material_index(i); - bool smooth = (b_poly.flag & ME_SMOOTH) || use_loop_normals; + bool smooth = !get_face_sharp(i) || use_loop_normals; vi.resize(n); for (int i = 0; i < n; i++) { diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index f7c64de234f..f586adc34a9 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -81,7 +81,7 @@ class DeviceInfo { bool has_gpu_queue; /* Device supports GPU queue. */ bool use_metalrt; /* Use MetalRT to accelerate ray queries (Metal only). */ KernelOptimizationLevel kernel_optimization_level; /* Optimization level applied to path tracing - kernels (Metal only). */ + * kernels (Metal only). */ DenoiserTypeMask denoisers; /* Supported denoiser types. */ int cpu_threads; vector multi_devices; diff --git a/intern/cycles/device/metal/device_impl.mm b/intern/cycles/device/metal/device_impl.mm index 67c2fdeebf5..bec6a654f81 100644 --- a/intern/cycles/device/metal/device_impl.mm +++ b/intern/cycles/device/metal/device_impl.mm @@ -581,6 +581,11 @@ void MetalDevice::compile_and_load(int device_id, MetalPipelineType pso_type) thread_scoped_lock lock(existing_devices_mutex); if (MetalDevice *instance = get_device_by_ID(device_id, lock)) { if (mtlLibrary) { + if (error && [error localizedDescription]) { + VLOG_WARNING << "MSL compilation messages: " + << [[error localizedDescription] UTF8String]; + } + instance->mtlLibrary[pso_type] = mtlLibrary; starttime = time_dt(); diff --git a/intern/cycles/device/metal/kernel.mm b/intern/cycles/device/metal/kernel.mm index fea25172f21..8e092a3ebc5 100644 --- a/intern/cycles/device/metal/kernel.mm +++ b/intern/cycles/device/metal/kernel.mm @@ -161,25 +161,12 @@ ShaderCache::~ShaderCache() running = false; cond_var.notify_all(); - int num_incomplete = int(incomplete_requests); - if (num_incomplete) { - /* Shutting down the app with incomplete shader compilation requests. Give 1 second's grace for - * clean shutdown. */ - metal_printf("ShaderCache busy (incomplete_requests = %d)...\n", num_incomplete); - std::this_thread::sleep_for(std::chrono::seconds(1)); - num_incomplete = int(incomplete_requests); - } - - if (num_incomplete && !MetalDeviceKernels::is_benchmark_warmup()) { - metal_printf("ShaderCache still busy (incomplete_requests = %d). Terminating...\n", - num_incomplete); - std::terminate(); - } - - metal_printf("ShaderCache idle. Shutting down.\n"); + metal_printf("Waiting for ShaderCache threads... (incomplete_requests = %d)\n", + int(incomplete_requests)); for (auto &thread : compile_threads) { thread.join(); } + metal_printf("ShaderCache shut down.\n"); } void ShaderCache::wait_for_all() @@ -634,6 +621,8 @@ void MetalKernelPipeline::compile() MTLPipelineOption pipelineOptions = MTLPipelineOptionNone; bool use_binary_archive = should_use_binary_archive(); + bool loading_existing_archive = false; + bool creating_new_archive = false; id archive = nil; string metalbin_path; @@ -663,72 +652,136 @@ void MetalKernelPipeline::compile() metalbin_path = path_cache_get(path_join("kernels", metalbin_name)); path_create_directories(metalbin_path); - /* Retrieve shader binary from disk, and update the file timestamp for LRU purging to work as - * intended. */ - if (use_binary_archive && path_cache_kernel_exists_and_mark_used(metalbin_path)) { - if (@available(macOS 11.0, *)) { - MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init]; + /* Check if shader binary exists on disk, and if so, update the file timestamp for LRU purging + * to work as intended. */ + loading_existing_archive = path_cache_kernel_exists_and_mark_used(metalbin_path); + creating_new_archive = !loading_existing_archive; + + if (@available(macOS 11.0, *)) { + MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init]; + if (loading_existing_archive) { archiveDesc.url = [NSURL fileURLWithPath:@(metalbin_path.c_str())]; - archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil]; - [archiveDesc release]; + } + NSError *error = nil; + archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:&error]; + if (!archive) { + const char *err = error ? [[error localizedDescription] UTF8String] : nullptr; + metal_printf("newBinaryArchiveWithDescriptor failed: %s\n", err ? err : "nil"); + } + [archiveDesc release]; + + if (loading_existing_archive) { + pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss; + computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil]; } } } - __block bool creating_new_archive = false; - if (@available(macOS 11.0, *)) { - if (use_binary_archive) { - if (!archive) { - MTLBinaryArchiveDescriptor *archiveDesc = [[MTLBinaryArchiveDescriptor alloc] init]; - archiveDesc.url = nil; - archive = [mtlDevice newBinaryArchiveWithDescriptor:archiveDesc error:nil]; - creating_new_archive = true; - } - computePipelineStateDescriptor.binaryArchives = [NSArray arrayWithObjects:archive, nil]; - pipelineOptions = MTLPipelineOptionFailOnBinaryArchiveMiss; + bool recreate_archive = false; + + /* Lambda to do the actual pipeline compilation. */ + auto do_compilation = [&]() { + __block bool compilation_finished = false; + __block string error_str; + + if (loading_existing_archive) { + /* Use the blocking variant of newComputePipelineStateWithDescriptor if an archive exists on + * disk. It should load almost instantaneously, and will fail gracefully when loading a + * corrupt archive (unlike the async variant). */ + NSError *error = nil; + pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor + options:pipelineOptions + reflection:nullptr + error:&error]; + const char *err = error ? [[error localizedDescription] UTF8String] : nullptr; + error_str = err ? err : "nil"; } - } + else { + /* TODO / MetalRT workaround: + * Workaround for a crash when addComputePipelineFunctionsWithDescriptor is called *after* + * newComputePipelineStateWithDescriptor with linked functions (i.e. with MetalRT enabled). + * Ideally we would like to call newComputePipelineStateWithDescriptor (async) first so we + * can bail out if needed, but we can stop the crash by flipping the order when there are + * linked functions. However when addComputePipelineFunctionsWithDescriptor is called first + * it will block while it builds the pipeline, offering no way of bailing out. */ + auto addComputePipelineFunctionsWithDescriptor = [&]() { + if (creating_new_archive && ShaderCache::running) { + NSError *error; + if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor + error:&error]) { + NSString *errStr = [error localizedDescription]; + metal_printf("Failed to add PSO to archive:\n%s\n", + errStr ? [errStr UTF8String] : "nil"); + } + } + }; + if (linked_functions) { + addComputePipelineFunctionsWithDescriptor(); + } + + /* Use the async variant of newComputePipelineStateWithDescriptor if no archive exists on + * disk. This allows us to respond to app shutdown. */ + [mtlDevice + newComputePipelineStateWithDescriptor:computePipelineStateDescriptor + options:pipelineOptions + completionHandler:^(id computePipelineState, + MTLComputePipelineReflection *reflection, + NSError *error) { + pipeline = computePipelineState; + + /* Retain the pipeline so we can use it safely past the completion + * handler. */ + if (pipeline) { + [pipeline retain]; + } + const char *err = error ? + [[error localizedDescription] UTF8String] : + nullptr; + error_str = err ? err : "nil"; + + compilation_finished = true; + }]; + + /* Immediately wait for either the compilation to finish or for app shutdown. */ + while (ShaderCache::running && !compilation_finished) { + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + + /* Add pipeline into the new archive (unless we did it earlier). */ + if (pipeline && !linked_functions) { + addComputePipelineFunctionsWithDescriptor(); + } + } + + if (!pipeline) { + metal_printf( + "newComputePipelineStateWithDescriptor failed for \"%s\"%s. " + "Error:\n%s\n", + device_kernel_as_string((DeviceKernel)device_kernel), + (archive && !recreate_archive) ? " Archive may be incomplete or corrupt - attempting " + "recreation.." : + "", + error_str.c_str()); + } + }; double starttime = time_dt(); - /* Block on load to ensure we continue with a valid kernel function */ - if (creating_new_archive) { - starttime = time_dt(); - NSError *error; - if (![archive addComputePipelineFunctionsWithDescriptor:computePipelineStateDescriptor - error:&error]) { - NSString *errStr = [error localizedDescription]; - metal_printf("Failed to add PSO to archive:\n%s\n", errStr ? [errStr UTF8String] : "nil"); - } - } + do_compilation(); - pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor - options:pipelineOptions - reflection:nullptr - error:&error]; - - bool recreate_archive = false; + /* An archive might have a corrupt entry and fail to materialize the pipeline. This shouldn't + * happen, but if it does we recreate it. */ if (pipeline == nil && archive) { - NSString *errStr = [error localizedDescription]; - metal_printf( - "Failed to create compute pipeline state \"%s\" from archive - attempting recreation... " - "(error: %s)\n", - device_kernel_as_string((DeviceKernel)device_kernel), - errStr ? [errStr UTF8String] : "nil"); - pipeline = [mtlDevice newComputePipelineStateWithDescriptor:computePipelineStateDescriptor - options:MTLPipelineOptionNone - reflection:nullptr - error:&error]; recreate_archive = true; + pipelineOptions = MTLPipelineOptionNone; + path_remove(metalbin_path); + + do_compilation(); } double duration = time_dt() - starttime; if (pipeline == nil) { - NSString *errStr = [error localizedDescription]; - error_str = string_printf("Failed to create compute pipeline state \"%s\", error: \n", - device_kernel_as_string((DeviceKernel)device_kernel)); - error_str += (errStr ? [errStr UTF8String] : "nil"); metal_printf("%16s | %2d | %-55s | %7.2fs | FAILED!\n", kernel_type_as_string(pso_type), device_kernel, @@ -748,7 +801,8 @@ void MetalKernelPipeline::compile() if (creating_new_archive || recreate_archive) { if (![archive serializeToURL:[NSURL fileURLWithPath:@(metalbin_path.c_str())] error:&error]) { - metal_printf("Failed to save binary archive, error:\n%s\n", + metal_printf("Failed to save binary archive to %s, error:\n%s\n", + metalbin_path.c_str(), [[error localizedDescription] UTF8String]); } else { diff --git a/intern/cycles/device/metal/queue.mm b/intern/cycles/device/metal/queue.mm index a7c136669ed..0792e20296f 100644 --- a/intern/cycles/device/metal/queue.mm +++ b/intern/cycles/device/metal/queue.mm @@ -278,7 +278,7 @@ int MetalDeviceQueue::num_concurrent_states(const size_t state_size) const if (metal_device_->device_vendor == METAL_GPU_APPLE) { result *= 4; - /* Increasing the state count doesn't notably benefit M1-family systems. */ + /* Increasing the state count doesn't notably benefit M1-family systems. */ if (MetalInfo::get_apple_gpu_architecture(metal_device_->mtlDevice) != APPLE_M1) { size_t system_ram = system_physical_ram(); size_t allocated_so_far = [metal_device_->mtlDevice currentAllocatedSize]; diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp index 06589140ad9..23517d9e0f1 100644 --- a/intern/cycles/device/optix/device_impl.cpp +++ b/intern/cycles/device/optix/device_impl.cpp @@ -1437,6 +1437,9 @@ void OptiXDevice::build_bvh(BVH *bvh, Progress &progress, bool refit) BVHOptiX *const blas = static_cast(ob->get_geometry()->bvh); OptixTraversableHandle handle = blas->traversable_handle; + if (handle == 0) { + continue; + } OptixInstance &instance = instances[num_instances++]; memset(&instance, 0, sizeof(instance)); diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp index c17add4ed9b..fbea83b1236 100644 --- a/intern/cycles/integrator/path_trace.cpp +++ b/intern/cycles/integrator/path_trace.cpp @@ -1343,7 +1343,7 @@ void PathTrace::guiding_prepare_structures() * per update to be limited, for reproducible results and reasonable training size. * * Idea: we could stochastically discard samples with a probability of 1/num_samples_per_update - * we can then update only after the num_samples_per_update iterations are rendered. */ + * we can then update only after the num_samples_per_update iterations are rendered. */ render_scheduler_.set_limit_samples_per_update(4); } else { diff --git a/intern/cycles/integrator/path_trace.h b/intern/cycles/integrator/path_trace.h index d3a238696fd..edc7afaf551 100644 --- a/intern/cycles/integrator/path_trace.h +++ b/intern/cycles/integrator/path_trace.h @@ -94,7 +94,7 @@ class PathTrace { void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling); /* Set the parameters for guiding. - * Use to setup the guiding structures before each rendering iteration.*/ + * Use to setup the guiding structures before each rendering iteration. */ void set_guiding_params(const GuidingParams ¶ms, const bool reset); /* Sets output driver for render buffer output. */ @@ -119,7 +119,7 @@ class PathTrace { */ void cancel(); - /* Copy an entire render buffer to/from the path trace. */ + /* Copy an entire render buffer to/from the path trace. */ /* Copy happens via CPU side buffer: data will be copied from every device of the path trace, and * the data will be copied to the device of the given render buffers. */ @@ -294,7 +294,7 @@ class PathTrace { * rendering iteration. */ unique_ptr guiding_sample_data_storage_; - /* The number of already performed training iterations for the guiding field.*/ + /* The number of already performed training iterations for the guiding field. */ int guiding_update_count = 0; #endif diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp index 066d6c3bf24..dc9b3d358ea 100644 --- a/intern/cycles/integrator/render_scheduler.cpp +++ b/intern/cycles/integrator/render_scheduler.cpp @@ -128,9 +128,8 @@ void RenderScheduler::reset(const BufferParams &buffer_params, int num_samples, state_.resolution_divider = 1; } else { - /* NOTE: Divide by 2 because of the way how scheduling works: it advances resolution divider - * first and then initialized render work. */ - state_.resolution_divider = start_resolution_divider_ * 2; + state_.user_is_navigating = true; + state_.resolution_divider = start_resolution_divider_; } state_.num_rendered_samples = 0; @@ -312,7 +311,21 @@ RenderWork RenderScheduler::get_render_work() RenderWork render_work; if (state_.resolution_divider != pixel_size_) { - state_.resolution_divider = max(state_.resolution_divider / 2, pixel_size_); + if (state_.user_is_navigating) { + /* Don't progress the resolution divider as the user is currently navigating in the scene. */ + state_.user_is_navigating = false; + } + else { + /* If the resolution divider is greater than or equal to default_start_resolution_divider_, + * drop the resolution divider down to 4. This is so users with slow hardware and thus high + * resolution dividers (E.G. 16), get an update to let them know something is happening + * rather than having to wait for the full 1:1 render to show up. */ + state_.resolution_divider = state_.resolution_divider > default_start_resolution_divider_ ? + (4 * pixel_size_) : + 1; + } + + state_.resolution_divider = max(state_.resolution_divider, pixel_size_); state_.num_rendered_samples = 0; state_.last_display_update_sample = -1; } @@ -1058,10 +1071,16 @@ void RenderScheduler::update_start_resolution_divider() return; } + /* Calculate the maximum resolution divider possible while keeping the long axis of the viewport + * above our prefered minimum axis size (128) */ + const int long_viewport_axis = max(buffer_params_.width, buffer_params_.height); + const int max_res_divider_for_desired_size = long_viewport_axis / 128; + if (start_resolution_divider_ == 0) { - /* Resolution divider has never been calculated before: use default resolution, so that we have - * somewhat good initial behavior, giving a chance to collect real numbers. */ - start_resolution_divider_ = default_start_resolution_divider_; + /* Resolution divider has never been calculated before: start with a high resolution divider so + * that we have a somewhat good initial behavior, giving a chance to collect real numbers. */ + start_resolution_divider_ = min(default_start_resolution_divider_, + max_res_divider_for_desired_size); VLOG_WORK << "Initial resolution divider is " << start_resolution_divider_; return; } @@ -1089,8 +1108,7 @@ void RenderScheduler::update_start_resolution_divider() /* Don't let resolution drop below the desired one. It's better to be slow than provide an * unreadable viewport render. */ - start_resolution_divider_ = min(resolution_divider_for_update, - default_start_resolution_divider_); + start_resolution_divider_ = min(resolution_divider_for_update, max_res_divider_for_desired_size); VLOG_WORK << "Calculated resolution divider is " << start_resolution_divider_; } diff --git a/intern/cycles/integrator/render_scheduler.h b/intern/cycles/integrator/render_scheduler.h index a0ab17b3794..6fe5a49a55c 100644 --- a/intern/cycles/integrator/render_scheduler.h +++ b/intern/cycles/integrator/render_scheduler.h @@ -332,6 +332,8 @@ class RenderScheduler { }; struct { + bool user_is_navigating = false; + int resolution_divider = 1; /* Number of rendered samples on top of the start sample. */ diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 0b643994422..bfb1a0af97d 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -741,22 +741,21 @@ if(WITH_CYCLES_DEVICE_ONEAPI) endif() # SYCL_CPP_FLAGS is a variable that the user can set to pass extra compiler options set(sycl_compiler_flags - ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_KERNEL_DEVICE_ONEAPI} - -fsycl - -fsycl-unnamed-lambda - -fdelayed-template-parsing - -mllvm -inlinedefault-threshold=250 - -mllvm -inlinehint-threshold=350 - -fsycl-device-code-split=per_kernel - -fsycl-max-parallel-link-jobs=${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS} - -shared - -DWITH_ONEAPI - -ffast-math - -DNDEBUG - -O2 - -o ${cycles_kernel_oneapi_lib} - -I${CMAKE_CURRENT_SOURCE_DIR}/.. - ${SYCL_CPP_FLAGS} + ${CMAKE_CURRENT_SOURCE_DIR}/${SRC_KERNEL_DEVICE_ONEAPI} + -fsycl + -fsycl-unnamed-lambda + -fdelayed-template-parsing + -mllvm -inlinedefault-threshold=250 + -mllvm -inlinehint-threshold=350 + -fsycl-device-code-split=per_kernel + -fsycl-max-parallel-link-jobs=${SYCL_OFFLINE_COMPILER_PARALLEL_JOBS} + -shared + -DWITH_ONEAPI + -ffast-math + -O2 + -o"${cycles_kernel_oneapi_lib}" + -I"${CMAKE_CURRENT_SOURCE_DIR}/.." + ${SYCL_CPP_FLAGS} ) if(WITH_CYCLES_ONEAPI_HOST_TASK_EXECUTION) @@ -783,14 +782,14 @@ if(WITH_CYCLES_DEVICE_ONEAPI) list(APPEND sycl_compiler_flags -fsycl-targets=${targets_string}) foreach(target ${CYCLES_ONEAPI_SYCL_TARGETS}) if(DEFINED CYCLES_ONEAPI_SYCL_OPTIONS_${target}) - list(APPEND sycl_compiler_flags -Xsycl-target-backend=${target} "${CYCLES_ONEAPI_SYCL_OPTIONS_${target}}") + list(APPEND sycl_compiler_flags "-Xsycl-target-backend=${target} \"${CYCLES_ONEAPI_SYCL_OPTIONS_${target}}\"") endif() endforeach() else() # If AOT is disabled, build for spir64 list(APPEND sycl_compiler_flags -fsycl-targets=spir64 - -Xsycl-target-backend=spir64 "${CYCLES_ONEAPI_SYCL_OPTIONS_spir64}") + "-Xsycl-target-backend=spir64 \"${CYCLES_ONEAPI_SYCL_OPTIONS_spir64}\"") endif() if(WITH_NANOVDB) @@ -804,7 +803,6 @@ if(WITH_CYCLES_DEVICE_ONEAPI) endif() get_filename_component(sycl_compiler_root ${SYCL_COMPILER} DIRECTORY) - get_filename_component(sycl_compiler_compiler_name ${SYCL_COMPILER} NAME_WE) if(UNIX AND NOT APPLE) if(NOT WITH_CXX11_ABI) @@ -816,7 +814,7 @@ if(WITH_CYCLES_DEVICE_ONEAPI) endif() endif() - if(WIN32) + if(WIN32) # Add Windows specific compiler flags. list(APPEND sycl_compiler_flags -fuse-ld=link -fms-extensions @@ -843,54 +841,79 @@ if(WITH_CYCLES_DEVICE_ONEAPI) get_filename_component(WINDOWS_KIT_DIR "${WINDOWS_KIT_DIR}/../" ABSOLUTE) endif() list(APPEND sycl_compiler_flags - -L "${MSVC_TOOLS_DIR}/lib/x64" - -L "${WINDOWS_KIT_DIR}/um/x64" - -L "${WINDOWS_KIT_DIR}/ucrt/x64") + -L"${MSVC_TOOLS_DIR}/lib/x64" + -L"${WINDOWS_KIT_DIR}/um/x64" + -L"${WINDOWS_KIT_DIR}/ucrt/x64") + else() # Add Linux specific compiler flags. + list(APPEND sycl_compiler_flags -fPIC) - set(sycl_compiler_flags_Release ${sycl_compiler_flags}) - set(sycl_compiler_flags_Debug ${sycl_compiler_flags}) - set(sycl_compiler_flags_RelWithDebInfo ${sycl_compiler_flags}) - set(sycl_compiler_flags_MinSizeRel ${sycl_compiler_flags}) - list(APPEND sycl_compiler_flags_RelWithDebInfo -g) + # We avoid getting __FAST_MATH__ to be defined when building on CentOS-7 and Rocky-8 + # until the compilation issues it triggers at either AoT or JIT stages gets fixed. + list(APPEND sycl_compiler_flags -fhonor-nans) + + # add $ORIGIN to cycles_kernel_oneapi.so rpath so libsycl.so and + # libpi_level_zero.so can be placed next to it and get found. + list(APPEND sycl_compiler_flags -Wl,-rpath,'$$ORIGIN') + endif() + + # Create CONFIG specific compiler flags. + set(sycl_compiler_flags_Release ${sycl_compiler_flags}) + set(sycl_compiler_flags_Debug ${sycl_compiler_flags}) + set(sycl_compiler_flags_RelWithDebInfo ${sycl_compiler_flags}) + + list(APPEND sycl_compiler_flags_Release + -DNDEBUG + ) + list(APPEND sycl_compiler_flags_RelWithDebInfo + -DNDEBUG + -g + ) + list(APPEND sycl_compiler_flags_Debug + -g + ) + + if(WIN32) list(APPEND sycl_compiler_flags_Debug - -g -D_DEBUG - -nostdlib -Xclang --dependent-lib=msvcrtd) - + -nostdlib + -Xclang --dependent-lib=msvcrtd + ) add_custom_command( OUTPUT ${cycles_kernel_oneapi_lib} ${cycles_kernel_oneapi_linker_lib} COMMAND ${CMAKE_COMMAND} -E env - "LIB=${sycl_compiler_root}/../lib" # for compiler to find sycl.lib + "LIB=${sycl_compiler_root}/../lib\;${sycl_compiler_root}/../compiler/lib/intel64_win" # for compiler to find sycl.lib and in case of icpx, libircmt.lib "PATH=${OCLOC_INSTALL_DIR}\;${sycl_compiler_root}" ${SYCL_COMPILER} "$<$:${sycl_compiler_flags_Release}>" "$<$:${sycl_compiler_flags_RelWithDebInfo}>" "$<$:${sycl_compiler_flags_Debug}>" "$<$:${sycl_compiler_flags_Release}>" - COMMAND_EXPAND_LISTS - DEPENDS ${cycles_oneapi_kernel_sources}) + COMMAND_EXPAND_LISTS + DEPENDS ${cycles_oneapi_kernel_sources}) else() - list(APPEND sycl_compiler_flags -fPIC) - - # We avoid getting __FAST_MATH__ to be defined when building on CentOS-7 until the compilation - # crash it triggers at either AoT or JIT stages gets fixed. - # TODO: check if this is still needed on Rocky-8. - list(APPEND sycl_compiler_flags -fhonor-nans) - - # add $ORIGIN to cycles_kernel_oneapi.so rpath so libsycl.so and - # libpi_level_zero.so can be placed next to it and get found. - list(APPEND sycl_compiler_flags -Wl,-rpath,'$$ORIGIN') - if(NOT IGC_INSTALL_DIR) get_filename_component(IGC_INSTALL_DIR "${sycl_compiler_root}/../lib/igc" ABSOLUTE) endif() + # The following join/replace operations are to prevent cmake from + # escaping space chars with backslashes in add_custom_command. + list(JOIN sycl_compiler_flags_Release " " sycl_compiler_flags_Release_str) + string(REPLACE " " ";" sycl_compiler_flags_Release_str ${sycl_compiler_flags_Release_str}) + list(JOIN sycl_compiler_flags_RelWithDebInfo " " sycl_compiler_flags_RelWithDebInfo_str) + string(REPLACE " " ";" sycl_compiler_flags_RelWithDebInfo_str ${sycl_compiler_flags_RelWithDebInfo_str}) + list(JOIN sycl_compiler_flags_Debug " " sycl_compiler_flags_Debug_str) + string(REPLACE " " ";" sycl_compiler_flags_Debug_str ${sycl_compiler_flags_Debug_str}) add_custom_command( OUTPUT ${cycles_kernel_oneapi_lib} COMMAND ${CMAKE_COMMAND} -E env "LD_LIBRARY_PATH=${sycl_compiler_root}/../lib:${OCLOC_INSTALL_DIR}/lib:${IGC_INSTALL_DIR}/lib" # `$ENV{PATH}` is for compiler to find `ld`. "PATH=${OCLOC_INSTALL_DIR}/bin:${sycl_compiler_root}:$ENV{PATH}" - ${SYCL_COMPILER} $<$:-g>$<$:-g> ${sycl_compiler_flags} + ${SYCL_COMPILER} + "$<$:${sycl_compiler_flags_Release_str}>" + "$<$:${sycl_compiler_flags_RelWithDebInfo_str}>" + "$<$:${sycl_compiler_flags_Debug_str}>" + "$<$:${sycl_compiler_flags_Release_str}>" + COMMAND_EXPAND_LISTS DEPENDS ${cycles_oneapi_kernel_sources}) endif() diff --git a/intern/cycles/kernel/camera/projection.h b/intern/cycles/kernel/camera/projection.h index 1d16aa35abe..644b7d0cc56 100644 --- a/intern/cycles/kernel/camera/projection.h +++ b/intern/cycles/kernel/camera/projection.h @@ -202,7 +202,7 @@ ccl_device float2 direction_to_mirrorball(float3 dir) } /* Single face of a equiangular cube map projection as described in - https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/ */ + * https://blog.google/products/google-ar-vr/bringing-pixels-front-and-center-vr-video/ */ ccl_device float3 equiangular_cubemap_face_to_direction(float u, float v) { u = (1.0f - u); diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index bf9fca7597a..6bf463f9301 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -136,7 +136,7 @@ ccl_device_forceinline float3 microfacet_beckmann_sample_vndf(const float3 wi, /* Find root in a monotonic interval using newton method, under given precision and maximal * iterations. Falls back to bisection if newton step produces results outside of the valid - * interval.*/ + * interval. */ const float precision = 1e-6f; const int max_iter = 3; int iter = 0; diff --git a/intern/cycles/kernel/device/cpu/bvh.h b/intern/cycles/kernel/device/cpu/bvh.h index 2d7d8c2d704..d2fbdd23296 100644 --- a/intern/cycles/kernel/device/cpu/bvh.h +++ b/intern/cycles/kernel/device/cpu/bvh.h @@ -15,12 +15,19 @@ #include "kernel/bvh/util.h" #include "kernel/geom/object.h" #include "kernel/integrator/state.h" +#include "kernel/integrator/state_util.h" #include "kernel/sample/lcg.h" #include "util/vector.h" CCL_NAMESPACE_BEGIN +#if INTEGRATOR_SHADOW_ISECT_SIZE < 256 +using numhit_t = uint8_t; +#else +using numhit_t = uint32_t; +#endif + #define EMBREE_IS_HAIR(x) (x & 1) /* Intersection context. */ @@ -41,12 +48,11 @@ struct CCLIntersectContext { const Ray *ray; /* for shadow rays */ - Intersection *isect_s; - uint max_hits; - uint num_hits; - uint num_recorded_hits; + IntegratorShadowState isect_s; + numhit_t max_hits; + numhit_t num_hits; + numhit_t num_recorded_hits; float throughput; - float max_t; bool opaque_hit; /* for SSS Rays: */ @@ -54,16 +60,18 @@ struct CCLIntersectContext { int local_object_id; uint *lcg_state; + /* for Volume */ + Intersection *vol_isect; + CCLIntersectContext(KernelGlobals kg_, RayType type_) { kg = kg_; type = type_; ray = NULL; - max_hits = 1; - num_hits = 0; - num_recorded_hits = 0; + max_hits = numhit_t(1); + num_hits = numhit_t(0); + num_recorded_hits = numhit_t(0); throughput = 1.0f; - max_t = FLT_MAX; opaque_hit = false; isect_s = NULL; local_isect = NULL; @@ -112,31 +120,17 @@ ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray, ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg, const RTCHit *hit, - const Ray *ray) + const Ray *ray, + const intptr_t prim_offset) { int object, prim; + object = (hit->instID[0] != RTC_INVALID_GEOMETRY_ID ? hit->instID[0] : hit->geomID) / 2; - if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) { - object = hit->instID[0] / 2; - if ((ray->self.object == object) || (ray->self.light_object == object)) { - RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData( - rtcGetGeometry(kernel_data.device_bvh, hit->instID[0])); - prim = hit->primID + - (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)); - } - else { - return false; - } + if ((ray->self.object == object) || (ray->self.light_object == object)) { + prim = hit->primID + prim_offset; } else { - object = hit->geomID / 2; - if ((ray->self.object == object) || (ray->self.light_object == object)) { - prim = hit->primID + - (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(kernel_data.device_bvh, hit->geomID)); - } - else { - return false; - } + return false; } const bool is_hair = hit->geomID & 1; @@ -150,21 +144,12 @@ ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, - Intersection *isect) + Intersection *isect, + const intptr_t prim_offset) { isect->t = ray->tfar; - if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) { - RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData( - rtcGetGeometry(kernel_data.device_bvh, hit->instID[0])); - isect->prim = hit->primID + - (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)); - isect->object = hit->instID[0] / 2; - } - else { - isect->prim = hit->primID + (intptr_t)rtcGetGeometryUserData( - rtcGetGeometry(kernel_data.device_bvh, hit->geomID)); - isect->object = hit->geomID / 2; - } + isect->prim = hit->primID + prim_offset; + isect->object = hit->instID[0] != RTC_INVALID_GEOMETRY_ID ? hit->instID[0] / 2 : hit->geomID / 2; const bool is_hair = hit->geomID & 1; if (is_hair) { @@ -181,16 +166,35 @@ ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg, } } -ccl_device_inline void kernel_embree_convert_sss_hit( - KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, int object) +ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg, + const RTCRay *ray, + const RTCHit *hit, + Intersection *isect) +{ + intptr_t prim_offset; + if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) { + RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData( + rtcGetGeometry(kernel_data.device_bvh, hit->instID[0])); + prim_offset = intptr_t(rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID))); + } + else { + prim_offset = intptr_t( + rtcGetGeometryUserData(rtcGetGeometry(kernel_data.device_bvh, hit->geomID))); + } + kernel_embree_convert_hit(kg, ray, hit, isect, prim_offset); +} + +ccl_device_inline void kernel_embree_convert_sss_hit(KernelGlobals kg, + const RTCRay *ray, + const RTCHit *hit, + Intersection *isect, + int object, + const intptr_t prim_offset) { isect->u = hit->u; isect->v = hit->v; isect->t = ray->tfar; - RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData( - rtcGetGeometry(kernel_data.device_bvh, object * 2)); - isect->prim = hit->primID + - (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID)); + isect->prim = hit->primID + prim_offset; isect->object = object; isect->type = kernel_data_fetch(objects, object).primitive_type; } @@ -211,7 +215,8 @@ ccl_device void kernel_embree_filter_intersection_func(const RTCFilterFunctionNA const KernelGlobalsCPU *kg = ctx->kg; const Ray *cray = ctx->ray; - if (kernel_embree_is_self_intersection(kg, hit, cray)) { + if (kernel_embree_is_self_intersection( + kg, hit, cray, reinterpret_cast(args->geometryUserPtr))) { *args->valid = 0; } } @@ -226,7 +231,7 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum /* Current implementation in Cycles assumes only single-ray intersection queries. */ assert(args->N == 1); - const RTCRay *ray = (RTCRay *)args->ray; + RTCRay *ray = (RTCRay *)args->ray; RTCHit *hit = (RTCHit *)args->hit; CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt; const KernelGlobalsCPU *kg = ctx->kg; @@ -235,7 +240,8 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum switch (ctx->type) { case CCLIntersectContext::RAY_SHADOW_ALL: { Intersection current_isect; - kernel_embree_convert_hit(kg, ray, hit, ¤t_isect); + kernel_embree_convert_hit( + kg, ray, hit, ¤t_isect, reinterpret_cast(args->geometryUserPtr)); if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) { *args->valid = 0; return; @@ -265,20 +271,21 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum } /* Test if we need to record this transparent intersection. */ - const uint max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE); - if (ctx->num_recorded_hits < max_record_hits || ray->tfar < ctx->max_t) { + const numhit_t max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE); + if (ctx->num_recorded_hits < max_record_hits) { /* If maximum number of hits was reached, replace the intersection with the * highest distance. We want to find the N closest intersections. */ - const uint num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits); - uint isect_index = num_recorded_hits; + const numhit_t num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits); + numhit_t isect_index = num_recorded_hits; if (num_recorded_hits + 1 >= max_record_hits) { - float max_t = ctx->isect_s[0].t; - uint max_recorded_hit = 0; + float max_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, 0, t); + numhit_t max_recorded_hit = numhit_t(0); - for (uint i = 1; i < num_recorded_hits; ++i) { - if (ctx->isect_s[i].t > max_t) { + for (numhit_t i = numhit_t(1); i < num_recorded_hits; ++i) { + const float isect_t = INTEGRATOR_STATE_ARRAY(ctx->isect_s, shadow_isect, i, t); + if (isect_t > max_t) { max_recorded_hit = i; - max_t = ctx->isect_s[i].t; + max_t = isect_t; } } @@ -286,14 +293,11 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum isect_index = max_recorded_hit; } - /* Limit the ray distance and stop counting hits beyond this. - * TODO: is there some way we can tell Embree to stop intersecting beyond - * this distance when max number of hits is reached?. Or maybe it will - * become irrelevant if we make max_hits a very high number on the CPU. */ - ctx->max_t = max(current_isect.t, max_t); + /* Limit the ray distance and stop counting hits beyond this. */ + ray->tfar = max(current_isect.t, max_t); } - ctx->isect_s[isect_index] = current_isect; + integrator_state_write_shadow_isect(ctx->isect_s, ¤t_isect, isect_index); } /* Always increase the number of recorded hits, even beyond the maximum, @@ -309,10 +313,16 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum /* Check if it's hitting the correct object. */ Intersection current_isect; if (ctx->type == CCLIntersectContext::RAY_SSS) { - kernel_embree_convert_sss_hit(kg, ray, hit, ¤t_isect, ctx->local_object_id); + kernel_embree_convert_sss_hit(kg, + ray, + hit, + ¤t_isect, + ctx->local_object_id, + reinterpret_cast(args->geometryUserPtr)); } else { - kernel_embree_convert_hit(kg, ray, hit, ¤t_isect); + kernel_embree_convert_hit( + kg, ray, hit, ¤t_isect, reinterpret_cast(args->geometryUserPtr)); if (ctx->local_object_id != current_isect.object) { /* This tells Embree to continue tracing. */ *args->valid = 0; @@ -387,13 +397,14 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum /* Append the intersection to the end of the array. */ if (ctx->num_hits < ctx->max_hits) { Intersection current_isect; - kernel_embree_convert_hit(kg, ray, hit, ¤t_isect); + kernel_embree_convert_hit( + kg, ray, hit, ¤t_isect, reinterpret_cast(args->geometryUserPtr)); if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) { *args->valid = 0; return; } - Intersection *isect = &ctx->isect_s[ctx->num_hits]; + Intersection *isect = &ctx->vol_isect[ctx->num_hits]; ++ctx->num_hits; *isect = current_isect; /* Only primitives from volume object. */ @@ -409,7 +420,8 @@ ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArgum } case CCLIntersectContext::RAY_REGULAR: default: - if (kernel_embree_is_self_intersection(kg, hit, cray)) { + if (kernel_embree_is_self_intersection( + kg, hit, cray, reinterpret_cast(args->geometryUserPtr))) { *args->valid = 0; return; } @@ -433,7 +445,8 @@ ccl_device void kernel_embree_filter_func_backface_cull(const RTCFilterFunctionN const KernelGlobalsCPU *kg = ctx->kg; const Ray *cray = ctx->ray; - if (kernel_embree_is_self_intersection(kg, hit, cray)) { + if (kernel_embree_is_self_intersection( + kg, hit, cray, reinterpret_cast(args->geometryUserPtr))) { *args->valid = 0; } } @@ -544,9 +557,8 @@ ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg, ccl_private float *throughput) { CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_SHADOW_ALL); - Intersection *isect_array = (Intersection *)state->shadow_isect; - ctx.isect_s = isect_array; - ctx.max_hits = max_hits; + ctx.isect_s = state; + ctx.max_hits = numhit_t(max_hits); ctx.ray = ray; IntersectContext rtc_ctx(&ctx); RTCRay rtc_ray; @@ -567,9 +579,9 @@ ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg, const uint visibility) { CCLIntersectContext ctx(kg, CCLIntersectContext::RAY_VOLUME_ALL); - ctx.isect_s = isect; - ctx.max_hits = max_hits; - ctx.num_hits = 0; + ctx.vol_isect = isect; + ctx.max_hits = numhit_t(max_hits); + ctx.num_hits = numhit_t(0); ctx.ray = ray; IntersectContext rtc_ctx(&ctx); RTCRay rtc_ray; diff --git a/intern/cycles/kernel/device/gpu/parallel_sorted_index.h b/intern/cycles/kernel/device/gpu/parallel_sorted_index.h index 749221af8f9..f5053587853 100644 --- a/intern/cycles/kernel/device/gpu/parallel_sorted_index.h +++ b/intern/cycles/kernel/device/gpu/parallel_sorted_index.h @@ -38,7 +38,7 @@ ccl_device_inline void gpu_parallel_sort_bucket_pass(const uint num_states, ccl_gpu_shared int *buckets, const ushort local_id, const ushort local_size, - const ushort grid_id) + const uint grid_id) { /* Zero the bucket sizes. */ if (local_id < max_shaders) { @@ -89,7 +89,7 @@ ccl_device_inline void gpu_parallel_sort_write_pass(const uint num_states, ccl_gpu_shared int *local_offset, const ushort local_id, const ushort local_size, - const ushort grid_id) + const uint grid_id) { /* Calculate each partition's global offset from the prefix sum of the active state counts per * partition. */ diff --git a/intern/cycles/kernel/device/metal/compat.h b/intern/cycles/kernel/device/metal/compat.h index 93d0747cd69..27fca24b92c 100644 --- a/intern/cycles/kernel/device/metal/compat.h +++ b/intern/cycles/kernel/device/metal/compat.h @@ -109,7 +109,7 @@ struct kernel_gpu_##name \ const uint metal_global_id, \ const ushort metal_local_id, \ const ushort metal_local_size, \ - const ushort metal_grid_id, \ + const uint metal_grid_id, \ uint simdgroup_size, \ uint simd_lane_index, \ uint simd_group_index, \ @@ -122,7 +122,7 @@ kernel void cycles_metal_##name(device const kernel_gpu_##name *params_struct, \ const uint metal_global_id [[thread_position_in_grid]], \ const ushort metal_local_id [[thread_position_in_threadgroup]], \ const ushort metal_local_size [[threads_per_threadgroup]], \ - const ushort metal_grid_id [[threadgroup_position_in_grid]], \ + const uint metal_grid_id [[threadgroup_position_in_grid]], \ uint simdgroup_size [[threads_per_simdgroup]], \ uint simd_lane_index [[thread_index_in_simdgroup]], \ uint simd_group_index [[simdgroup_index_in_threadgroup]], \ @@ -135,7 +135,7 @@ void kernel_gpu_##name::run(thread MetalKernelContext& context, \ const uint metal_global_id, \ const ushort metal_local_id, \ const ushort metal_local_size, \ - const ushort metal_grid_id, \ + const uint metal_grid_id, \ uint simdgroup_size, \ uint simd_lane_index, \ uint simd_group_index, \ diff --git a/intern/cycles/kernel/integrator/guiding.h b/intern/cycles/kernel/integrator/guiding.h index 93c80539140..1cc347ae63e 100644 --- a/intern/cycles/kernel/integrator/guiding.h +++ b/intern/cycles/kernel/integrator/guiding.h @@ -53,7 +53,7 @@ ccl_device_forceinline void guiding_record_surface_segment(KernelGlobals kg, #endif } -/* Records the surface scattering event at the current vertex position of the segment.*/ +/* Records the surface scattering event at the current vertex position of the segment. */ ccl_device_forceinline void guiding_record_surface_bounce(KernelGlobals kg, IntegratorState state, ccl_private const ShaderData *sd, @@ -134,7 +134,7 @@ ccl_device_forceinline void guiding_record_bssrdf_segment(KernelGlobals kg, } /* Records the transmission of the path at the point of entry while passing - * the surface boundary.*/ + * the surface boundary. */ ccl_device_forceinline void guiding_record_bssrdf_weight(KernelGlobals kg, IntegratorState state, const Spectrum weight, @@ -161,7 +161,7 @@ ccl_device_forceinline void guiding_record_bssrdf_weight(KernelGlobals kg, /* Records the direction at the point of entry the path takes when sampling the SSS contribution. * If not terminated this function is usually followed by a call of * guiding_record_volume_transmission to record the transmittance between the point of entry and - * the point of exit.*/ + * the point of exit. */ ccl_device_forceinline void guiding_record_bssrdf_bounce(KernelGlobals kg, IntegratorState state, const float pdf, @@ -216,7 +216,7 @@ ccl_device_forceinline void guiding_record_volume_segment(KernelGlobals kg, #endif } -/* Records the volume scattering event at the current vertex position of the segment.*/ +/* Records the volume scattering event at the current vertex position of the segment. */ ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg, IntegratorState state, ccl_private const ShaderData *sd, @@ -247,7 +247,7 @@ ccl_device_forceinline void guiding_record_volume_bounce(KernelGlobals kg, } /* Records the transmission (a.k.a. transmittance weight) between the current path segment - * and the next one, when the path is inside or passes a volume.*/ + * and the next one, when the path is inside or passes a volume. */ ccl_device_forceinline void guiding_record_volume_transmission(KernelGlobals kg, IntegratorState state, const float3 transmittance_weight) @@ -330,7 +330,7 @@ ccl_device_forceinline void guiding_record_light_surface_segment( /* Records/Adds a final path segment when the path leaves the scene and * intersects with a background light (e.g., background color, * distant light, or env map). The vertex for this segment is placed along - * the current ray far out the scene.*/ + * the current ray far out the scene. */ ccl_device_forceinline void guiding_record_background(KernelGlobals kg, IntegratorState state, const Spectrum L, @@ -359,7 +359,7 @@ ccl_device_forceinline void guiding_record_background(KernelGlobals kg, /* Records the scattered contribution of a next event estimation * (i.e., a direct light estimate scattered at the current path vertex - * towards the previous vertex).*/ + * towards the previous vertex). */ ccl_device_forceinline void guiding_record_direct_light(KernelGlobals kg, IntegratorShadowState state) { @@ -397,7 +397,7 @@ ccl_device_forceinline void guiding_record_continuation_probability( /* Path guiding debug render passes. */ /* Write a set of path guiding related debug information (e.g., guiding probability at first - * bounce) into separate rendering passes.*/ + * bounce) into separate rendering passes. */ ccl_device_forceinline void guiding_write_debug_passes(KernelGlobals kg, IntegratorState state, ccl_private const ShaderData *sd, diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h index 3c01a162d01..12639715465 100644 --- a/intern/cycles/kernel/integrator/shade_background.h +++ b/intern/cycles/kernel/integrator/shade_background.h @@ -149,7 +149,7 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, ((ls.shader & SHADER_EXCLUDE_TRANSMIT) && (path_flag & PATH_RAY_TRANSMIT)) || ((ls.shader & SHADER_EXCLUDE_CAMERA) && (path_flag & PATH_RAY_CAMERA)) || ((ls.shader & SHADER_EXCLUDE_SCATTER) && (path_flag & PATH_RAY_VOLUME_SCATTER))) - return; + continue; } #endif @@ -159,7 +159,7 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, * generate a firefly for small lights since it is improbable. */ const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp); if (klight->use_caustics) - return; + continue; } #endif /* __MNEE__ */ @@ -169,7 +169,7 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage); Spectrum light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, ray_time); if (is_zero(light_eval)) { - return; + continue; } /* MIS weighting. */ diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index 5b460a2fe7a..835df3baa68 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -1019,7 +1019,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass); # if defined(__PATH_GUIDING__) && PATH_GUIDING_LEVEL >= 1 - /* The current path throughput which is used later to calculate per-segment throughput.*/ + /* The current path throughput which is used later to calculate per-segment throughput. */ const float3 initial_throughput = INTEGRATOR_STATE(state, path, throughput); /* The path throughput used to calculate the throughput for direct light. */ float3 unlit_throughput = initial_throughput; @@ -1063,7 +1063,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, if (result.direct_sample_method == VOLUME_SAMPLE_DISTANCE) { /* If the direct scatter event is generated using VOLUME_SAMPLE_DISTANCE the direct event * will happen at the same position as the indirect event and the direct light contribution - * will contribute to the position of the next path segment.*/ + * will contribute to the position of the next path segment. */ float3 transmittance_weight = spectrum_to_rgb( safe_divide_color(result.indirect_throughput, initial_throughput)); guiding_record_volume_transmission(kg, state, transmittance_weight); @@ -1076,7 +1076,8 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, /* If the direct scatter event is generated using VOLUME_SAMPLE_EQUIANGULAR the direct * event will happen at a separate position as the indirect event and the direct light * contribution will contribute to the position of the current/previous path segment. The - * unlit_throughput has to be adjusted to include the scattering at the previous segment.*/ + * unlit_throughput has to be adjusted to include the scattering at the previous segment. + */ float3 scatterEval = one_float3(); if (state->guiding.path_segment) { pgl_vec3f scatteringWeight = state->guiding.path_segment->scatteringWeight; diff --git a/intern/cycles/kernel/integrator/state.h b/intern/cycles/kernel/integrator/state.h index ebb459f476e..c06e0019081 100644 --- a/intern/cycles/kernel/integrator/state.h +++ b/intern/cycles/kernel/integrator/state.h @@ -126,16 +126,16 @@ typedef struct IntegratorStateGPU { /* Count number of kernels queued for specific shaders. */ ccl_global int *sort_key_counter[DEVICE_KERNEL_INTEGRATOR_NUM]; - /* Index of shadow path which will be used by a next shadow path. */ + /* Index of shadow path which will be used by a next shadow path. */ ccl_global int *next_shadow_path_index; - /* Index of main path which will be used by a next shadow catcher split. */ + /* Index of main path which will be used by a next shadow catcher split. */ ccl_global int *next_main_path_index; /* Partition/key offsets used when writing sorted active indices. */ ccl_global int *sort_partition_key_offsets; - /* Divisor used to partition active indices by locality when sorting by material. */ + /* Divisor used to partition active indices by locality when sorting by material. */ uint sort_partition_divisor; } IntegratorStateGPU; diff --git a/intern/cycles/kernel/integrator/surface_shader.h b/intern/cycles/kernel/integrator/surface_shader.h index df8c826e7be..573a35f0808 100644 --- a/intern/cycles/kernel/integrator/surface_shader.h +++ b/intern/cycles/kernel/integrator/surface_shader.h @@ -38,7 +38,7 @@ ccl_device_inline void surface_shader_prepare_guiding(KernelGlobals kg, const float surface_guiding_probability = kernel_data.integrator.surface_guiding_probability; float rand_bsdf_guiding = path_state_rng_1D(kg, rng_state, PRNG_SURFACE_BSDF_GUIDING); - /* Compute proportion of diffuse BSDF and BSSRDFs .*/ + /* Compute proportion of diffuse BSDF and BSSRDFs. */ float diffuse_sampling_fraction = 0.0f; float bssrdf_sampling_fraction = 0.0f; float bsdf_bssrdf_sampling_sum = 0.0f; diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index d6fb00bbd20..a8886d8c99c 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -57,7 +57,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, return svm_node_closure_bsdf_skip(kg, offset, type); } - float3 N = stack_valid(data_node.x) ? stack_load_float3(stack, data_node.x) : sd->N; + float3 N = stack_valid(data_node.x) ? safe_normalize(stack_load_float3(stack, data_node.x)) : + sd->N; if (!(sd->type & PRIMITIVE_CURVE)) { N = ensure_valid_reflection(sd->Ng, sd->wi, N); } diff --git a/intern/cycles/scene/light_tree.cpp b/intern/cycles/scene/light_tree.cpp index 1261f09cda0..da30c5c77f6 100644 --- a/intern/cycles/scene/light_tree.cpp +++ b/intern/cycles/scene/light_tree.cpp @@ -259,7 +259,7 @@ int LightTree::recursive_build( bool should_split = false; if (try_splitting) { /* Find the best place to split the primitives into 2 nodes. - * If the best split cost is no better than making a leaf node, make a leaf instead.*/ + * If the best split cost is no better than making a leaf node, make a leaf instead. */ float min_cost = min_split_saoh( centroid_bounds, start, end, bbox, bcone, split_dim, split_bucket, num_left_prims, prims); should_split = num_prims > max_lights_in_leaf_ || min_cost < energy_total; diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h index c2face0b40d..8a5b879badc 100644 --- a/intern/cycles/scene/scene.h +++ b/intern/cycles/scene/scene.h @@ -351,7 +351,7 @@ class Scene : public NodeOwner { /* Get maximum number of closures to be used in kernel. */ int get_max_closure_count(); - /* Get size of a volume stack needed to render this scene. */ + /* Get size of a volume stack needed to render this scene. */ int get_volume_stack_size() const; template void delete_node_impl(T *node) diff --git a/intern/cycles/scene/shader.cpp b/intern/cycles/scene/shader.cpp index dfd86f82bb6..da8c5719fa2 100644 --- a/intern/cycles/scene/shader.cpp +++ b/intern/cycles/scene/shader.cpp @@ -153,6 +153,16 @@ static float3 output_estimate_emission(ShaderOutput *output, bool &is_constant) estimate *= node->get_float(strength_in->socket_type); } + /* Lower importance of emission nodes from automatic value/color to shader + * conversion, as these are likely used for previewing and can be slow to + * build a light tree for on dense meshes. */ + if (node->type == EmissionNode::get_node_type()) { + EmissionNode *emission_node = static_cast(node); + if (emission_node->from_auto_conversion) { + estimate *= 0.1f; + } + } + return estimate; } else if (node->type == LightFalloffNode::get_node_type() || diff --git a/intern/cycles/scene/shader_graph.cpp b/intern/cycles/scene/shader_graph.cpp index b9e8892765b..4a653f3345c 100644 --- a/intern/cycles/scene/shader_graph.cpp +++ b/intern/cycles/scene/shader_graph.cpp @@ -260,6 +260,7 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) if (to->type() == SocketType::CLOSURE) { EmissionNode *emission = create_node(); + emission->from_auto_conversion = true; emission->set_color(one_float3()); emission->set_strength(1.0f); convert = add(emission); diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index 35c5a7a61ac..0c36d17107c 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -723,6 +723,8 @@ class EmissionNode : public ShaderNode { NODE_SOCKET_API(float3, color) NODE_SOCKET_API(float, strength) NODE_SOCKET_API(float, surface_mix_weight) + + bool from_auto_conversion = false; }; class BackgroundNode : public ShaderNode { diff --git a/intern/cycles/session/session.cpp b/intern/cycles/session/session.cpp index 581cb474985..42b15d0530c 100644 --- a/intern/cycles/session/session.cpp +++ b/intern/cycles/session/session.cpp @@ -507,7 +507,7 @@ void Session::do_delayed_reset() params = delayed_reset_.session_params; buffer_params_ = delayed_reset_.buffer_params; - /* Store parameters used for buffers access outside of scene graph. */ + /* Store parameters used for buffers access outside of scene graph. */ buffer_params_.samples = params.samples; buffer_params_.exposure = scene->film->get_exposure(); buffer_params_.use_approximate_shadow_catcher = diff --git a/intern/cycles/util/boundbox.h b/intern/cycles/util/boundbox.h index 982f538f57f..afddb24d5ac 100644 --- a/intern/cycles/util/boundbox.h +++ b/intern/cycles/util/boundbox.h @@ -56,8 +56,8 @@ class BoundBox { __forceinline void grow(const BoundBox &bbox) { - grow(bbox.min); - grow(bbox.max); + min = ccl::min(bbox.min, min); + max = ccl::max(bbox.max, max); } __forceinline void grow_safe(const float3 &pt) @@ -81,8 +81,12 @@ class BoundBox { __forceinline void grow_safe(const BoundBox &bbox) { - grow_safe(bbox.min); - grow_safe(bbox.max); + if (isfinite_safe(bbox.min)) { + min = ccl::min(bbox.min, min); + } + if (isfinite_safe(bbox.max)) { + max = ccl::max(bbox.max, max); + } } __forceinline void intersect(const BoundBox &bbox) diff --git a/intern/ffmpeg/ffmpeg_compat.h b/intern/ffmpeg/ffmpeg_compat.h index d32cc5bb015..a8254a99032 100644 --- a/intern/ffmpeg/ffmpeg_compat.h +++ b/intern/ffmpeg/ffmpeg_compat.h @@ -13,6 +13,7 @@ #ifndef __FFMPEG_COMPAT_H__ #define __FFMPEG_COMPAT_H__ +#include #include /* Check if our ffmpeg is new enough, avoids user complaints. diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index e02ff7fe51e..26c37d2000e 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -943,6 +943,11 @@ extern void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn); */ extern void GHOST_UseWindowFocus(bool use_focus); +/** + * Focus and raise windows on mouse hover. + */ +extern void GHOST_SetAutoFocus(bool auto_focus); + /** * If window was opened using native pixel size, it returns scaling factor. */ diff --git a/intern/ghost/GHOST_ISystem.h b/intern/ghost/GHOST_ISystem.h index edaeca1e159..e53026107e7 100644 --- a/intern/ghost/GHOST_ISystem.h +++ b/intern/ghost/GHOST_ISystem.h @@ -332,6 +332,11 @@ class GHOST_ISystem { */ virtual void useWindowFocus(const bool use_focus) = 0; + /** + * Focus and raise windows on mouse hover. + */ + virtual void setAutoFocus(const bool auto_focus) = 0; + /** * Get the Window under the cursor. * \param x: The x-coordinate of the cursor. diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp index 4da9392d4d0..feba10752e2 100644 --- a/intern/ghost/intern/GHOST_C-api.cpp +++ b/intern/ghost/intern/GHOST_C-api.cpp @@ -918,6 +918,12 @@ void GHOST_UseWindowFocus(bool use_focus) return system->useWindowFocus(use_focus); } +void GHOST_SetAutoFocus(bool auto_focus) +{ + GHOST_ISystem *system = GHOST_ISystem::getSystem(); + system->setAutoFocus(auto_focus); +} + float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle) { GHOST_IWindow *window = (GHOST_IWindow *)windowhandle; diff --git a/intern/ghost/intern/GHOST_Context.cpp b/intern/ghost/intern/GHOST_Context.cpp index dc040cc2c76..2f8ab7f8b9e 100644 --- a/intern/ghost/intern/GHOST_Context.cpp +++ b/intern/ghost/intern/GHOST_Context.cpp @@ -103,6 +103,9 @@ bool win32_chk(bool result, const char *file, int line, const char *text) _ftprintf( stderr, "%s:%d: [%s] -> Win32 Error# (%lu): %s", file, line, text, ulong(error), msg); # else + (void)file; + (void)line; + (void)text; _ftprintf(stderr, "Win32 Error# (%lu): %s", ulong(error), msg); # endif diff --git a/intern/ghost/intern/GHOST_ContextVK.cpp b/intern/ghost/intern/GHOST_ContextVK.cpp index 271d4a9c69e..5ac0e4727e8 100644 --- a/intern/ghost/intern/GHOST_ContextVK.cpp +++ b/intern/ghost/intern/GHOST_ContextVK.cpp @@ -401,13 +401,15 @@ static bool checkLayerSupport(vector &layers_available, const static void enableLayer(vector &layers_available, vector &layers_enabled, - const char *layer_name) + const char *layer_name, + const bool debug) { if (checkLayerSupport(layers_available, layer_name)) { layers_enabled.push_back(layer_name); } - else { - fprintf(stderr, "Error: %s not supported.\n", layer_name); + else if (debug) { + fprintf( + stderr, "Warning: Layer requested, but not supported by the platform. [%s]\n", layer_name); } } @@ -862,7 +864,7 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext() vector layers_enabled; if (m_debug) { - enableLayer(layers_available, layers_enabled, "VK_LAYER_KHRONOS_validation"); + enableLayer(layers_available, layers_enabled, "VK_LAYER_KHRONOS_validation", m_debug); } vector extensions_device; @@ -878,7 +880,7 @@ GHOST_TSuccess GHOST_ContextVK::initializeDrawingContext() } extensions_device.push_back("VK_KHR_dedicated_allocation"); extensions_device.push_back("VK_KHR_get_memory_requirements2"); - /* Enable MoltenVK required instance extensions.*/ + /* Enable MoltenVK required instance extensions. */ #ifdef VK_MVK_MOLTENVK_EXTENSION_NAME requireExtension( extensions_available, extensions_enabled, "VK_KHR_get_physical_device_properties2"); diff --git a/intern/ghost/intern/GHOST_ContextVK.h b/intern/ghost/intern/GHOST_ContextVK.h index 0daa9e40027..1fdf6658a82 100644 --- a/intern/ghost/intern/GHOST_ContextVK.h +++ b/intern/ghost/intern/GHOST_ContextVK.h @@ -126,8 +126,8 @@ class GHOST_ContextVK : public GHOST_Context { void *image, void *framebuffer, void *render_pass, void *extent, uint32_t *fb_id); /** - * Sets the swap interval for swapBuffers. - * \param interval The swap interval to use. + * Sets the swap interval for `swapBuffers`. + * \param interval: The swap interval to use. * \return A boolean success indicator. */ GHOST_TSuccess setSwapInterval(int /* interval */) @@ -137,7 +137,7 @@ class GHOST_ContextVK : public GHOST_Context { /** * Gets the current swap interval for swapBuffers. - * \param intervalOut Variable to store the swap interval if it can be read. + * \param intervalOut: Variable to store the swap interval if it can be read. * \return Whether the swap interval can be read. */ GHOST_TSuccess getSwapInterval(int &) diff --git a/intern/ghost/intern/GHOST_DropTargetWin32.cpp b/intern/ghost/intern/GHOST_DropTargetWin32.cpp index 86483118b3d..a26377ca6d1 100644 --- a/intern/ghost/intern/GHOST_DropTargetWin32.cpp +++ b/intern/ghost/intern/GHOST_DropTargetWin32.cpp @@ -78,7 +78,7 @@ ULONG __stdcall GHOST_DropTargetWin32::Release(void) * Implementation of IDropTarget::DragEnter */ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *p_data_object, - DWORD grf_key_state, + DWORD /*grf_key_state*/, POINTL pt, DWORD *pdw_effect) { @@ -95,7 +95,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragEnter(IDataObject *p_data_object, /* * Implementation of IDropTarget::DragOver */ -HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD grf_key_state, +HRESULT __stdcall GHOST_DropTargetWin32::DragOver(DWORD /*grf_key_state*/, POINTL pt, DWORD *pdw_effect) { @@ -128,7 +128,7 @@ HRESULT __stdcall GHOST_DropTargetWin32::DragLeave(void) * the implementation of IDropTarget::DragOver */ HRESULT __stdcall GHOST_DropTargetWin32::Drop(IDataObject *p_data_object, - DWORD grf_key_state, + DWORD /*grf_key_state*/, POINTL pt, DWORD *pdw_effect) { diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp index 780d93ac995..764a6a1e241 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.cpp +++ b/intern/ghost/intern/GHOST_ImeWin32.cpp @@ -140,7 +140,7 @@ void GHOST_ImeWin32::SetImeWindowStyle( ::DefWindowProc(window_handle, message, wparam, lparam); } -void GHOST_ImeWin32::DestroyImeWindow(HWND window_handle) +void GHOST_ImeWin32::DestroyImeWindow(HWND /*window_handle*/) { /* Destroy the system caret if we have created for this IME input context. */ if (system_caret_) { @@ -149,7 +149,7 @@ void GHOST_ImeWin32::DestroyImeWindow(HWND window_handle) } } -void GHOST_ImeWin32::MoveImeWindow(HWND window_handle, HIMC imm_context) +void GHOST_ImeWin32::MoveImeWindow(HWND /*window_handle*/, HIMC imm_context) { int x = caret_rect_.m_l; int y = caret_rect_.m_t; @@ -228,7 +228,7 @@ void GHOST_ImeWin32::CheckFirst(HWND window_handle) } } -void GHOST_ImeWin32::ResetComposition(HWND window_handle) +void GHOST_ImeWin32::ResetComposition(HWND /*window_handle*/) { /* Currently, just reset the composition status. */ is_composing_ = false; diff --git a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp index 0ccf4dc9bfb..d3b4161307e 100644 --- a/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp +++ b/intern/ghost/intern/GHOST_NDOFManagerUnix.cpp @@ -3,23 +3,26 @@ #include "GHOST_NDOFManagerUnix.h" #include "GHOST_System.h" +/* Logging, use `ghost.ndof.unix.*` prefix. */ +#include "CLG_log.h" + #include #include #include -#define SPNAV_SOCK_PATH "/var/run/spnav.sock" +static const char *spnav_sock_path = "/var/run/spnav.sock"; + +static CLG_LogRef LOG_NDOF_UNIX = {"ghost.ndof.unix"}; +#define LOG (&LOG_NDOF_UNIX) GHOST_NDOFManagerUnix::GHOST_NDOFManagerUnix(GHOST_System &sys) : GHOST_NDOFManager(sys), available_(false) { - if (access(SPNAV_SOCK_PATH, F_OK) != 0) { -#ifdef DEBUG - /* annoying for official builds, just adds noise and most people don't own these */ - puts("ndof: spacenavd not found"); - /* This isn't a hard error, just means the user doesn't have a 3D mouse. */ -#endif + if (access(spnav_sock_path, F_OK) != 0) { + CLOG_INFO(LOG, 1, "'spacenavd' not found at \"%s\"", spnav_sock_path); } else if (spnav_open() != -1) { + CLOG_INFO(LOG, 1, "'spacenavd' found at\"%s\"", spnav_sock_path); available_ = true; /* determine exactly which device (if any) is plugged in */ diff --git a/intern/ghost/intern/GHOST_System.cpp b/intern/ghost/intern/GHOST_System.cpp index 670ede35989..2830c621215 100644 --- a/intern/ghost/intern/GHOST_System.cpp +++ b/intern/ghost/intern/GHOST_System.cpp @@ -23,6 +23,7 @@ GHOST_System::GHOST_System() : m_nativePixel(false), m_windowFocus(true), + m_autoFocus(true), m_displayManager(nullptr), m_timerManager(nullptr), m_windowManager(nullptr), @@ -412,6 +413,11 @@ void GHOST_System::useWindowFocus(const bool use_focus) m_windowFocus = use_focus; } +void GHOST_System::setAutoFocus(const bool auto_focus) +{ + m_autoFocus = auto_focus; +} + bool GHOST_System::supportsCursorWarp() { return true; diff --git a/intern/ghost/intern/GHOST_System.h b/intern/ghost/intern/GHOST_System.h index 924a4bff790..db28603c289 100644 --- a/intern/ghost/intern/GHOST_System.h +++ b/intern/ghost/intern/GHOST_System.h @@ -160,6 +160,12 @@ class GHOST_System : public GHOST_ISystem { bool m_windowFocus; + /** + * Focus and raise windows on mouse hover. + */ + void setAutoFocus(const bool auto_focus); + bool m_autoFocus; + /** * Get the Window under the cursor. * \param x: The x-coordinate of the cursor. diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index 2a9186ba1ae..b66c59038af 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -217,7 +217,7 @@ GHOST_IWindow *GHOST_SystemWin32::createWindow(const char *title, uint32_t height, GHOST_TWindowState state, GHOST_GLSettings glSettings, - const bool exclusive, + const bool /*exclusive*/, const bool is_dialog, const GHOST_IWindow *parentWindow) { @@ -568,7 +568,7 @@ GHOST_TKey GHOST_SystemWin32::hardKey(RAWINPUT const &raw, bool *r_key_down) * This function was added in response to bug #25715. * This is going to be a long list #42426. */ -GHOST_TKey GHOST_SystemWin32::processSpecialKey(short vKey, short scanCode) const +GHOST_TKey GHOST_SystemWin32::processSpecialKey(short vKey, short /*scanCode*/) const { GHOST_TKey key = GHOST_kKeyUnknown; if (vKey == 0xFF) { @@ -1148,7 +1148,9 @@ GHOST_EventCursor *GHOST_SystemWin32::processCursorEvent(GHOST_WindowWin32 *wind GHOST_TABLET_DATA_NONE); } -void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, WPARAM wParam, LPARAM lParam) +void GHOST_SystemWin32::processWheelEvent(GHOST_WindowWin32 *window, + WPARAM wParam, + LPARAM /*lParam*/) { GHOST_SystemWin32 *system = (GHOST_SystemWin32 *)getSystem(); @@ -1826,10 +1828,13 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, if (!window->m_mousePresent) { WINTAB_PRINTF("HWND %p mouse enter\n", window->getHWND()); TRACKMOUSEEVENT tme = {sizeof(tme)}; - /* Request WM_MOUSELEAVE message when the cursor leaves the client area, and - * WM_MOUSEHOVER message after 50ms when in the client area. */ - tme.dwFlags = TME_LEAVE | TME_HOVER; - tme.dwHoverTime = 50; + /* Request WM_MOUSELEAVE message when the cursor leaves the client area. */ + tme.dwFlags = TME_LEAVE; + if (system->m_autoFocus) { + /* Request WM_MOUSEHOVER message after 100ms when in the client area. */ + tme.dwFlags |= TME_HOVER; + tme.dwHoverTime = 100; + } tme.hwndTrack = hwnd; TrackMouseEvent(&tme); window->m_mousePresent = true; @@ -2213,7 +2218,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, uint msg, WPARAM wParam, return lResult; } -char *GHOST_SystemWin32::getClipboard(bool selection) const +char *GHOST_SystemWin32::getClipboard(bool /*selection*/) const { if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL)) { wchar_t *buffer; diff --git a/intern/ghost/intern/GHOST_TrackpadWin32.cpp b/intern/ghost/intern/GHOST_TrackpadWin32.cpp index d5317f0f780..4d5ce6fabe1 100644 --- a/intern/ghost/intern/GHOST_TrackpadWin32.cpp +++ b/intern/ghost/intern/GHOST_TrackpadWin32.cpp @@ -265,14 +265,14 @@ HRESULT GHOST_DirectManipulationViewportEventHandler::OnViewportStatusChanged( } HRESULT GHOST_DirectManipulationViewportEventHandler::OnViewportUpdated( - IDirectManipulationViewport *viewport) + IDirectManipulationViewport * /*viewport*/) { /* Nothing to do here. */ return S_OK; } HRESULT GHOST_DirectManipulationViewportEventHandler::OnContentUpdated( - IDirectManipulationViewport *viewport, IDirectManipulationContent *content) + IDirectManipulationViewport * /*viewport*/, IDirectManipulationContent *content) { float transform[6]; HRESULT hr = content->GetContentTransform(transform, ARRAYSIZE(transform)); diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index 3e82f55c583..06d9ea939e0 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -898,7 +898,7 @@ GHOST_TSuccess GHOST_WindowWin32::hasCursorShape(GHOST_TStandardCursor cursorSha } GHOST_TSuccess GHOST_WindowWin32::getPointerInfo( - std::vector &outPointerInfo, WPARAM wParam, LPARAM lParam) + std::vector &outPointerInfo, WPARAM wParam, LPARAM /*lParam*/) { int32_t pointerId = GET_POINTERID_WPARAM(wParam); int32_t isPrimary = IS_POINTER_PRIMARY_WPARAM(wParam); @@ -1109,8 +1109,13 @@ static uint16_t uns16ReverseBits(uint16_t shrt) } #endif -GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape( - uint8_t *bitmap, uint8_t *mask, int sizeX, int sizeY, int hotX, int hotY, bool canInvertColor) +GHOST_TSuccess GHOST_WindowWin32::setWindowCustomCursorShape(uint8_t *bitmap, + uint8_t *mask, + int sizeX, + int sizeY, + int hotX, + int hotY, + bool /*canInvertColor*/) { uint32_t andData[32]; uint32_t xorData[32]; @@ -1175,7 +1180,7 @@ GHOST_TSuccess GHOST_WindowWin32::endProgressBar() } #ifdef WITH_INPUT_IME -void GHOST_WindowWin32::beginIME(int32_t x, int32_t y, int32_t w, int32_t h, bool completed) +void GHOST_WindowWin32::beginIME(int32_t x, int32_t y, int32_t /*w*/, int32_t h, bool completed) { m_imeInput.BeginIME(m_hWnd, GHOST_Rect(x, y - h, x, y), completed); } diff --git a/intern/guardedalloc/intern/mallocn_intern.h b/intern/guardedalloc/intern/mallocn_intern.h index c2e9f9117bc..14e5c171e7e 100644 --- a/intern/guardedalloc/intern/mallocn_intern.h +++ b/intern/guardedalloc/intern/mallocn_intern.h @@ -10,6 +10,9 @@ #ifdef __GNUC__ # define UNUSED(x) UNUSED_##x __attribute__((__unused__)) +#elif defined(_MSC_VER) +/* NOTE: This suppresses the warning for the line, not the attribute. */ +# define UNUSED(x) UNUSED_##x __pragma(warning(suppress : 4100)) #else # define UNUSED(x) UNUSED_##x #endif diff --git a/intern/mantaflow/CMakeLists.txt b/intern/mantaflow/CMakeLists.txt index 60ca19c35ff..7a92301b9ed 100644 --- a/intern/mantaflow/CMakeLists.txt +++ b/intern/mantaflow/CMakeLists.txt @@ -15,6 +15,13 @@ if(WIN32) add_definitions(-D_USE_MATH_DEFINES) endif() +if(WIN32) + # Some files in extern are being included which brings up a bunch of + # "unreferenced formal parameter" warnings. + # So restore warn C4100 (unreferenced formal parameter) back to w4 + remove_cc_flag(/w34100) +endif() + set(INC extern diff --git a/locale/po/ab.po b/locale/po/ab.po index 8b1e06be6d6..c143195f7be 100644 --- a/locale/po/ab.po +++ b/locale/po/ab.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" "\"POT-Creation-Date: 2019-02-25 20:41:30\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" diff --git a/locale/po/ar.po b/locale/po/ar.po index 60dafcc9ede..04778f22adb 100644 --- a/locale/po/ar.po +++ b/locale/po/ar.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2016-04-23 22:41+0300\n" "Last-Translator: Yousef Harfoush \n" "Language-Team: Yousef Harfoush, Amine Moussaoui \n" @@ -7801,10 +7801,6 @@ msgid "Effective but slow compression" msgstr "ءﻲﻄﺑ ﻦﻜﻟ ﻝﺎﻌﻓ ﻂﻐﺿ" -msgid "Number" -msgstr "ﺩﺪﻌﻟﺍ" - - msgid "Delete" msgstr "ﻑﺬﺣﺍ" @@ -9387,22 +9383,6 @@ msgid "Editable falloff curve" msgstr "ﺮﻳﺮﺤﺘﻠﻟ ﻞﺑﺎﻗ ﻁﻮﻘﺳ ﻰﻨﺤﻨﻣ" -msgid "Root" -msgstr "ﺓﺪﻋﺎﻗ" - - -msgid "Sharp" -msgstr "ﺩﺎﺣ" - - -msgid "Sharper" -msgstr "ﺩﺎﺣ" - - -msgid "Inverse Square" -msgstr "ﻲﺴﻜﻋ ﻲﻌﻴﺑﺮﺗ" - - msgid "Fill Threshold" msgstr "ﺔﺌﺒﻌﺘﻟﺍ ﺔﺒﺘﻋ" @@ -11635,6 +11615,10 @@ msgid "Inverse Linear" msgstr "ﺱﻮﻜﻌﻣ ﻲﻄﺧ" +msgid "Inverse Square" +msgstr "ﻲﺴﻜﻋ ﻲﻌﻴﺑﺮﺗ" + + msgid "Lin/Quad Weighted" msgstr "ﻲﻌﻴﺑﺮﺗ/ﻲﻄﺧ ﻥﻭﺯﻮﻣ" @@ -13463,6 +13447,10 @@ msgid "Show guide hairs" msgstr "ﻞﻴﻟﺪﻟﺍ ﺕﺍﺮﻌﺷ ﺮﻬﻇﺍ" +msgid "Number" +msgstr "ﺩﺪﻌﻟﺍ" + + msgid "Show particle number" msgstr "ءﻱﺰﺠﻟﺍ ﻢﻗﺭ ﺮﻬﻇﺃ" @@ -14185,10 +14173,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "ﺓﺮﻛﺍﺬﻟﺍ ﻲﻓ ﺩﻮﺟﻮﻤﻟﺍ ﻦﻋ ﻒﻠﺘﺨﻣ ﺹﺮﻘﻟﺍ ﻰﻠﻋ ﻲﺼﻨﻟﺍ ﻒﻠﻤﻟﺍ" -msgid "Lines" -msgstr "ﻁﻮﻄﺨﻟﺍ" - - msgid "Lines of text" msgstr "ﺺﻨﻟﺍ ﺭﻮﻄﺳ" @@ -14797,10 +14781,18 @@ msgid "Use soft marble" msgstr "ﻢﻋﺎﻧ ﻡﺎﺧﺭ ﻡﺪﺨﺘﺳﺍ" +msgid "Sharp" +msgstr "ﺩﺎﺣ" + + msgid "Use more clearly defined marble" msgstr "ﺎﺣﻮﺿﻭ ﺮﺜﻛﺍ ﻞﻜﺸﺑ ﻑﺮّﻌﻣ ﻡﺎﺧﺭ ﻡﺪﺨﺘﺳﺇ" +msgid "Sharper" +msgstr "ﺩﺎﺣ" + + msgid "Use very clearly defined marble" msgstr "ﺍﺪﺟ ﺢﺿﺍﻭ ﻞﻜﺸﺑ ﻑﺮّﻌﻣ ﻡﺎﺧﺭ ﻡﺪﺨﺘﺳﺇ" @@ -17420,6 +17412,10 @@ msgid "Radius of the skin" msgstr "ﺓﺮﺸﻘﻟﺍ ﻚﻤﺳ" +msgid "Root" +msgstr "ﺓﺪﻋﺎﻗ" + + msgid "Mesh Skin Vertex Layer" msgstr "ﻢﺴﺠﻤﻟﺍ ﺓﺮﺸﻘﻟ ﺔﻄﻘﻨﻟﺍ ﺔﻘﺒﻃ" @@ -19083,6 +19079,10 @@ msgid "Line Thickness" msgstr "ﻂﺨﻟﺍ ﻚﻤﺳ" +msgid "Lines" +msgstr "ﻁﻮﻄﺨﻟﺍ" + + msgid "Motion Path Points" msgstr "ﺔﻛﺮﺤﻟﺍ ﺭﺎﺴﻣ ﻂﻘﻧ" @@ -38072,10 +38072,6 @@ msgid "Author:" msgstr ":ﺭﺮﺤﻣ" -msgid "author" -msgstr "ﺐﺗﺎﻛ" - - msgid "Version:" msgstr ":ﺔﺨﺴﻧ" diff --git a/locale/po/ca.po b/locale/po/ca.po index 1acc671553c..365c3d31fef 100644 --- a/locale/po/ca.po +++ b/locale/po/ca.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -271,7 +271,7 @@ msgstr "Complement" msgid "Python add-ons to be loaded automatically" -msgstr "[Add-on]: Complements de Python que es carreguen automàticament" +msgstr "[Add-on]: Complements de python que es carreguen automàticament" msgid "Module" @@ -903,7 +903,7 @@ msgstr "Edita protocols (scripts) i documentació adjunta inserida al document" msgid "Python Console" -msgstr "Consola de Python" +msgstr "Consola de python" msgid "Interactive programmatic console for advanced editing and script development" @@ -1035,7 +1035,7 @@ msgstr "Referents de Restricció de Deformacions d'esquelet" msgid "Collection of target bones and weights" -msgstr "Col·lecció d’ossos referents i forces" +msgstr "Col·lecció d’ossos referents i pesos" msgid "Armature EditBones" @@ -1106,6 +1106,10 @@ msgid "Simple name of the asset's catalog, for debugging and data recovery purpo msgstr "Nom senzill de catàleg del recurs per a depuracions i rescats de dades" +msgid "Copyright" +msgstr "Copyright" + + msgid "Description" msgstr "Descripció" @@ -1847,11 +1851,11 @@ msgstr "[Tilt]: Inclinació en la visualització 3D" msgid "Weight" -msgstr "Influència" +msgstr "Pesos" msgid "Softbody goal weight" -msgstr "[Weight]: Influència del destí del cos tou" +msgstr "[Weight]: Pesos del destí del cos tou" msgid "Blend-File Data" @@ -2191,11 +2195,11 @@ msgstr "[Windows Managers]: Blocs de dades dels gestors de finestres" msgid "Workspaces" -msgstr "Espais de treball" +msgstr "Obradors" msgid "Workspace data-blocks" -msgstr "Blocs de dades d'espais de treball" +msgstr "Blocs de dades d'obrador" msgid "Worlds" @@ -2487,11 +2491,11 @@ msgstr "Col·lecció de gestors de finestres" msgid "Main Workspaces" -msgstr "Espais de treball principals" +msgstr "Obradors principals" msgid "Collection of workspaces" -msgstr "Col·lecció d'espais de treball" +msgstr "Col·lecció d'obradors" msgid "Main Worlds" @@ -3201,11 +3205,11 @@ msgstr "[Envelope Deform Distance]: Distància de deformació de l'os (només pe msgid "Envelope Deform Weight" -msgstr "Influència de deformació de funda" +msgstr "Pes de deformació de funda" msgid "Bone deformation weight (for Envelope deform only)" -msgstr "[Envelope Deform Weight]: Influència de deformació de l'os (només per a deformacions de funda)" +msgstr "[Envelope Deform Weight]: Pes de deformació de l'os (només per a deformacions de funda)" msgid "Head" @@ -3401,7 +3405,7 @@ msgstr "Multiplicar el grup de vèrtexs per la funda" msgid "When deforming bone, multiply effects of Vertex Group weights with Envelope influence" -msgstr "[Multiply Vertex Groups with Envelope]: En deformar l'os, es multipliquen els efectes de les forces del grup de vèrtexs per la influència de funda" +msgstr "[Multiply Vertex Groups with Envelope]: En deformar l'os, es multipliquen els efectes dels pesos del grup de vèrtexs per la influència de funda" msgid "Inherit Rotation" @@ -3489,7 +3493,7 @@ msgstr "Indicacions no editables d'operacions admeses" msgid "Has Overlay" -msgstr "Té revestit" +msgstr "Té bambolina" msgid "Has Random Texture Angle" @@ -3597,11 +3601,11 @@ msgstr "Potencialitats del pintat de vèrtexs" msgid "Weight Paint Capabilities" -msgstr "Potencialitats del pintat de força" +msgstr "Potencialitats del pintat de pesos" msgid "Has Weight" -msgstr "Té força" +msgstr "Té pes" msgid "Curves Sculpt Brush Settings" @@ -4665,7 +4669,7 @@ msgstr "[Rotation]: Rotació per a la imatge de rerefons (només vista ortogonal msgid "Scale" -msgstr "Escalar" +msgstr "Escala" msgid "Scale the background image" @@ -5125,7 +5129,7 @@ msgstr "Densitat màxima de pèl" msgid "Effector Weights" -msgstr "Influència dels efectors" +msgstr "Persos d'efectors" msgid "Fluid Density" @@ -5157,7 +5161,7 @@ msgstr "Màxim del destí" msgid "Goal maximum, vertex group weights are scaled to match this range" -msgstr "[Goal Maximum]: Màxim del destí, les forces dels grups de vèrtexs s'escalaran per coincidir amb aquest interval" +msgstr "[Goal Maximum]: Màxim del destí, els pesos dels grups de vèrtexs s'escalaran per coincidir amb aquest interval" msgid "Goal Minimum" @@ -5165,7 +5169,7 @@ msgstr "Mínim del destí" msgid "Goal minimum, vertex group weights are scaled to match this range" -msgstr "[Goal Minimum]: El mínim del destí, les forces dels grups de vèrtexs s'escalaran per coincidir amb aquest interval" +msgstr "[Goal Minimum]: El mínim del destí, els pesos dels grups de vèrtexs s'escalaran per coincidir amb aquest interval" msgid "Goal Stiffness" @@ -5652,6 +5656,10 @@ msgid "Enabled" msgstr "Activat" +msgid "Enable this object as a collider for physics systems" +msgstr "Habilita aquest objecte com a col·lisionador per a sistemes físics" + + msgid "Single Sided" msgstr "D'una cara" @@ -5877,7 +5885,7 @@ msgstr "Pantalla" msgid "Overlay" -msgstr "Revestit" +msgstr "Superposició" msgid "Soft Light" @@ -5893,7 +5901,7 @@ msgstr "Diferència" msgid "Divide" -msgstr "Dividir" +msgstr "Divisió" msgid "Brightness" @@ -6406,7 +6414,7 @@ msgstr "Esquelet" msgid "Apply weight-blended transformation from multiple bones like the Armature modifier" -msgstr "[Armature]: Aplica transformació de fusió per forces des de múltiples ossos com ara el modificador d'esquelet" +msgstr "[Armature]: Aplica transformació de fusió per pesos des de múltiples ossos com ara el modificador d'esquelet" msgid "Child Of" @@ -6630,7 +6638,7 @@ msgstr "Usa fundes" msgid "Multiply weights by envelope for all bones, instead of acting like Vertex Group based blending. The specified weights are still used, and only the listed bones are considered" -msgstr "[Use Envelopes]: Multiplica les forces per funda per a tots els ossos, enlloc d'actuar com una fusió basada en grup de vèrtexs. Els pesos definits encara s'utilitzen, i només es té en compte els ossos indicats" +msgstr "[Use Envelopes]: Multiplica els pesos per funda per a tots els ossos, enlloc d'actuar com una fusió basada en grup de vèrtexs. Els pesos definits encara s'utilitzen, i només es té en compte els ossos indicats" msgid "Use Current Location" @@ -7386,11 +7394,11 @@ msgstr "[Lock Z Rotation]: Restringeix la rotació al llarg de l'eix Z" msgid "Orientation Weight" -msgstr "Força d'orientació" +msgstr "Pes d'orientació" msgid "For Tree-IK: Weight of orientation control for this target" -msgstr "[Orientationh Weight]: Per a l'arbre de CI: control de la força d'orientació per al referent" +msgstr "[Orientationh Weight]: Per a l'arbre de CI: control del pes de l'orientació per al referent" msgid "Pole Angle" @@ -7446,7 +7454,7 @@ msgstr "[Use Tail]: Inclou la cua de l'os com a últim element de la cadena" msgid "For Tree-IK: Weight of position control for this target" -msgstr "Per a l'arbre de CI: Control de la força d'ubicació per a aquest referent" +msgstr "Per a l'arbre de CI: Control del pes d'ubicació per a aquest referent" msgid "Limit Distance Constraint" @@ -7726,11 +7734,11 @@ msgstr "[Use Relative Offset]: La separació serà un punt absolut en l'espai en msgid "Python Constraint" -msgstr "Restricció de Python" +msgstr "Restricció de python" msgid "Use Python script for constraint evaluation" -msgstr "[Python Constraint]: Utilitza un protocol de Python per avaluar la restricció" +msgstr "[Python Constraint]: Utilitza un protocol de python per avaluar la restricció" msgid "Script Error" @@ -7738,7 +7746,7 @@ msgstr "Error de protocol" msgid "The linked Python script has thrown an error" -msgstr "[Script Error]: El protocol de Python en qüestió ha donat un error" +msgstr "[Script Error]: El protocol de python en qüestió ha donat un error" msgid "Number of Targets" @@ -7758,7 +7766,7 @@ msgstr "Protocol" msgid "The text object that contains the Python script" -msgstr "[Script]: L'objecte de text que conté el protocol de Python" +msgstr "[Script]: L'objecte de text que conté el protocol de python" msgid "Use Targets" @@ -8466,11 +8474,11 @@ msgstr "Esquelet referent" msgid "Blend Weight" -msgstr "Fusió per forces" +msgstr "Pes de fusió" msgid "Blending weight of this bone" -msgstr "[Blend Weight]: La força de fusió d'aquest os" +msgstr "[Blend Weight]: El pes de la fusió d'aquest os" msgid "Curve in a curve mapping" @@ -9822,7 +9830,7 @@ msgstr "Gestor de finestres" msgctxt "ID" msgid "Workspace" -msgstr "Espai de treball" +msgstr "Obrador" msgctxt "ID" @@ -10647,11 +10655,11 @@ msgstr "Ubicació de l'extrem de la cua de l'os" msgid "Effector weights for physics simulation" -msgstr "Forces en operació per a simulació d'efectes físics" +msgstr "Pesos d'efectuador per a simulació d'efectes físics" msgid "All effector's weight" -msgstr "Tots les forces efectuadores" +msgstr "Tot el pes de l'efectuador" msgid "Use For Growing Hair" @@ -10667,7 +10675,7 @@ msgstr "Floc" msgid "Boid effector weight" -msgstr "[Boid]: Influència de l'efectuador floc" +msgstr "[Boid]: Pes de l'efectuador floc" msgid "Charge" @@ -10675,7 +10683,7 @@ msgstr "Càrrega" msgid "Charge effector weight" -msgstr "Influència de l'efectuador de càrrega" +msgstr "Pes de l'efectuador de càrrega" msgid "Effector Collection" @@ -10691,7 +10699,7 @@ msgstr "Guia en corba" msgid "Curve guide effector weight" -msgstr "[Curve Guide] Força efectuadora que guia per una corba" +msgstr "[Curve Guide] Pes efectuador que guia per una corba" msgid "Drag" @@ -10699,11 +10707,11 @@ msgstr "Arrossega" msgid "Drag effector weight" -msgstr "[Drag]: Arrossegar força d'efectuador" +msgstr "[Drag]: Arrossegar pes d'efectuador" msgid "Force effector weight" -msgstr "Forçar força d'efectuador" +msgstr "Forçar pes d'efectuador" msgid "Global gravity weight" @@ -10715,7 +10723,7 @@ msgstr "Harmònic" msgid "Harmonic effector weight" -msgstr "[Harmonic]: Influència d'efectuador harmònica" +msgstr "[Harmonic]: Pes d'efectuació harmònica" msgid "Lennard-Jones" @@ -10723,7 +10731,7 @@ msgstr "Lennard-Jones" msgid "Lennard-Jones effector weight" -msgstr "Influència de l'efectuador de Lennard-Jones" +msgstr "Pes d'efectuador de Lennard-Jones" msgid "Magnetic" @@ -10731,7 +10739,7 @@ msgstr "Magnètic" msgid "Magnetic effector weight" -msgstr "Influència d'efectuador magnètica" +msgstr "Pes d'efectuador magnètic" msgid "Fluid Flow" @@ -10739,11 +10747,11 @@ msgstr "Flux de fluid" msgid "Fluid Flow effector weight" -msgstr "[Fluid Flow]: Influència d'efectuador de flux fluid" +msgstr "[Fluid Flow]: Pes d'efectuador de flux fluid" msgid "Texture effector weight" -msgstr "Influència d'efectuador de textura" +msgstr "Pes d'efectuador de textura" msgid "Turbulence" @@ -10751,7 +10759,7 @@ msgstr "Turbulència" msgid "Turbulence effector weight" -msgstr "Influència d'efectuador de turbulència" +msgstr "Pes d'efectuador de turbulència" msgid "Vortex" @@ -10759,7 +10767,7 @@ msgstr "Vòrtex" msgid "Vortex effector weight" -msgstr "Influència d'efectuador de vòrtex" +msgstr "Pes d'efectuador de vòrtex" msgid "Wind" @@ -10767,7 +10775,7 @@ msgstr "Vent" msgid "Wind effector weight" -msgstr "Influència d'efectuador de vent" +msgstr "Pes d'efectuador de vent" msgid "Enum Item Definition" @@ -11801,7 +11809,7 @@ msgstr "Amplitud del soroll - la quantitat amb que modifica la corba subjacent" msgid "Python F-Modifier" -msgstr "Modificador-F en Python" +msgstr "Modificador-F en python" msgid "Perform user-defined operation on the modified F-Curve" @@ -12297,7 +12305,7 @@ msgstr "Pesos" msgid "Use curve weights to influence the particle influence along the curve" -msgstr "[Weights]: Utilitza forces de corba per influir en la influència de partícula al llarg de la corba" +msgstr "[Weights]: Utilitza pesos de corba per influir en la influència de partícula al llarg de la corba" msgid "Use Max" @@ -12513,7 +12521,7 @@ msgstr "Mostra/oculta els blocs de dades de volums" msgid "Show workspace data-blocks" -msgstr "Mostra els blocs de dades d'espais de treball" +msgstr "Mostrar blocs de dades d'obrador" msgid "Show Action data-blocks" @@ -13490,7 +13498,7 @@ msgstr "[Upper Bound]: Límit superior de l'interval de ressaltat" msgid "Guiding weight (higher value results in greater lag)" -msgstr "Força guia (valor més alt dona retard més gran)" +msgstr "Pes guia (valor més alt dona retard més gran)" msgid "Guiding size (higher value results in larger vortices)" @@ -13693,10 +13701,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "Nombre mínim de partícules per cel·la (s'assegura que cada cel·la té almenys aquesta quantitat de partícules )" -msgid "Number" -msgstr "Nombre" - - msgid "Particle number factor (higher value results in more particles)" msgstr "Factor de nombre de partícules (un valor més alt dona més partícules)" @@ -14034,7 +14038,7 @@ msgstr "[Adaptive Domain]: Adapta la resolució i la mida de la simulació al fl msgid "Use Adaptive Time Steps" -msgstr "Usa els passos de temps adaptatius" +msgstr "Usa els cronolapses adaptatius" msgid "Bubble" @@ -14966,7 +14970,7 @@ msgstr "Mòdul d'estil" msgid "Python script to define a style module" -msgstr "Protocol de Python per a definir un mòdul d'estil" +msgstr "Protocol de python per a definir un mòdul d'estil" msgid "Use" @@ -15030,11 +15034,11 @@ msgstr "[Control Mode]: Seleccioneu el mode de control del traç manual" msgid "Python Scripting" -msgstr "Protocols de Python" +msgstr "Protocols de python" msgid "Advanced mode for using style modules written in Python" -msgstr "[Python Scripting]: Mode avançat per a utilitzar mòduls d'estil escrits en Python" +msgstr "[Python Scripting]: Mode avançat per a utilitzar mòduls d'estil escrits en python" msgid "Parameter Editor" @@ -16415,6 +16419,10 @@ msgid "Texture Mapping" msgstr "Mapejat de textura" +msgid "Change stroke UV texture values" +msgstr "[Texture Mapping]: Canvia els valors de textura d'UV del traç" + + msgid "Time Offset" msgstr "Desfasament temporal" @@ -16424,19 +16432,19 @@ msgstr "[Time Offset]: Desfasa les fotofites" msgid "Vertex Weight Angle" -msgstr "Angle de força del vèrtex" +msgstr "Angle dels pesos de vèrtex" msgid "Generate Vertex Weights base on stroke angle" -msgstr "[Vertex Weight Angle]: Genera la base de forces de vèrtex en l'angle del traç" +msgstr "[Vertex Weight Angle]: Genera la base de pesos de vèrtex sobre l'angle del traç" msgid "Vertex Weight Proximity" -msgstr "Proximitat de forces de vèrtex" +msgstr "Proximitat de pesos de vèrtex" msgid "Generate Vertex Weights base on distance to object" -msgstr "[Vertex Weight Proximity]: Genera la base de forces de vèrtex a partir de la distància respecte de l'objecte" +msgstr "[Vertex Weight Proximity]: Genera la base dels pesos de vèrtex a partir de la distància respecte de l'objecte" msgid "Array" @@ -17925,6 +17933,10 @@ msgid "Amount of noise to apply to thickness" msgstr "[Thickness Factor]: Quantitat de soroll per aplicar al gruix" +msgid "Amount of noise to apply to UV rotation" +msgstr "Quantitat de soroll per aplicar a la rotació d'UV" + + msgid "Noise Offset" msgstr "Separació de soroll" @@ -18038,11 +18050,11 @@ msgstr "[Uniform Opacity]: Substitueix l'opacitat del traç" msgid "Weighted" -msgstr "Per força" +msgstr "Ponderat" msgid "Use weight to modulate effect" -msgstr "[Weighted]: Utilitza la força per modular l'efecte" +msgstr "[Weighted]: Utilitza pesos per modular l'efecte" msgid "Outline Modifier" @@ -18550,15 +18562,15 @@ msgstr "Usa una corba maniobrera per definir l'efecte de color de vèrtex al lla msgid "Weight Modifier Angle" -msgstr "Angle del modificador força" +msgstr "Angle del modificador de pesos" msgid "Calculate Vertex Weight dynamically" -msgstr "Calcula dinàmicament la força dels vèrtexs" +msgstr "Calcula dinàmicament els pesos dels vèrtexs" msgid "Minimum value for vertex weight" -msgstr "Valor mínim de força de vèrtexs" +msgstr "Valor mínim dels pesos de vèrtexs" msgid "Space" @@ -18570,19 +18582,19 @@ msgstr "Espai de coordenades" msgid "Invert output weight values" -msgstr "Invertir els valors emesos de força" +msgstr "Invertir els valors de pesos emesos" msgid "Multiply Weights" -msgstr "Multiplica forces" +msgstr "Multiplicar pesos" msgid "Multiply the calculated weights with the existing values in the vertex group" -msgstr "[Multiply Weights]: Multiplica les forces calculades pels valors existents al grup de vèrtexs" +msgstr "[Multiply Weights]: Multiplica els pesos calculats pels valors existents al grup de vèrtexs" msgid "Weight Modifier Proximity" -msgstr "Proximitat de modificador força" +msgstr "Proximitat de modificador de pesos" msgid "Highest" @@ -18590,7 +18602,7 @@ msgstr "Altura màxima" msgid "Distance mapping to 1.0 weight" -msgstr "[Highest]: Mapejat de distància a força 1,0" +msgstr "[Highest]: Mapejat de distància a pes 1,0" msgid "Lowest" @@ -18598,7 +18610,7 @@ msgstr "Alçada mínima" msgid "Distance mapping to 0.0 weight" -msgstr "[Lowest]: Mapejat de distància a força 0,0" +msgstr "[Lowest]: Mapejat de distància a pes 0,0" msgid "Object used as distance reference" @@ -18610,7 +18622,7 @@ msgstr "Element de grup de vèrtexs" msgid "Weight value of a vertex in a vertex group" -msgstr "[Vertex Group Element]: Valor força d'un vèrtex en un grup de vèrtexs" +msgstr "[Vertex Group Element]: Valor del pes d'un vèrtex en un grup de vèrtexs" msgid "Group Index" @@ -18618,7 +18630,7 @@ msgstr "Índex de grup" msgid "Vertex Weight" -msgstr "Força de vèrtex" +msgstr "Pesos de vèrtex" msgid "Grid and Canvas Settings" @@ -19031,11 +19043,11 @@ msgstr "[Visible Layers]: Visibilitat de la capa d'esquelet" msgid "Layer Proxy Protection" -msgstr "Protecció de la capa per mitjancer" +msgstr "Protecció de capa de intermediaris" msgid "Protected layers in Proxy Instances are restored to Proxy settings on file reload and undo" -msgstr "[Layer Proxy Protection]: Les capes protegides en instances de mitjancers es retornen a la configuració de mediació quan es recarrega el document i es fa desfer" +msgstr "[Layer Proxy Protection]: Les capes protegides en instàncies intermediades es retornen a la configuració dels intermediaris mediació quan es recarrega el document i es fa desfer" msgid "Pose Position" @@ -19530,30 +19542,6 @@ msgid "Editable falloff curve" msgstr "Corba editable de decaïment" -msgid "Curve Preset" -msgstr "Predefinit de corba" - - -msgid "Smoother" -msgstr "Suavitzar" - - -msgid "Root" -msgstr "Arrel" - - -msgid "Sharp" -msgstr "Brusc" - - -msgid "Sharper" -msgstr "Més brusc" - - -msgid "Inverse Square" -msgstr "Quadrat invers" - - msgid "Curves Sculpt Settings" msgstr "Configuració de corbes d'escultura" @@ -19779,11 +19767,11 @@ msgstr "Eina llapis de greix per pintar vèrtexs" msgid "Grease Pencil Weight Paint Tool" -msgstr "Eina de llapis de greix per pintat de força" +msgstr "Eina pintat de pesos amb llapis de greix" msgid "Weight Paint for Vertex Groups" -msgstr "Pintar força per a grups de vèrtexs" +msgstr "Pintar pesos a grups de vèrtexs" msgid "Gradient Spacing" @@ -19963,11 +19951,11 @@ msgstr "[Normal Radius]: Relació entre el radi del pinzell i el radi que s'util msgid "Normal Weight" -msgstr "Força de normal" +msgstr "Pes de normal" msgid "How much grab will pull vertices out of surface during a grab" -msgstr "Quanta força d'agafar extraurà els vèrtexs de la superfície durant un agafament" +msgstr "[Normal Weight]: Quanta força extraurà els vèrtexs de la superfície durant un agafament" msgid "Paint Curve" @@ -20523,11 +20511,11 @@ msgstr "[Use Cursor Overlay]: Mostra el cursor al mirador" msgid "Override Overlay" -msgstr "Sobreseure sopreposat" +msgstr "Sobreseure bambolina" msgid "Don't show overlay during a stroke" -msgstr "[Override Overlay]: No mostra la sobreposició durant un traç" +msgstr "[Override Overlay]: No mostra la bambolina durant un traç" msgid "Define the stroke curve with a bezier curve. Dabs are separated according to spacing" @@ -20707,11 +20695,11 @@ msgstr "[Use Vertex]: Usa aquest pinzell en el mode de pintat de vèrtexs" msgid "Use Weight" -msgstr "Usar força" +msgstr "Usar pesos" msgid "Use this brush in weight paint mode" -msgstr "[Use Weight]: Utilitza aquest pinzell en mode de pintura de força" +msgstr "[Use Weight]: Utilitza aquest pinzell en mode de pintura de pesos" msgid "Sculpt on a persistent layer of the mesh" @@ -20799,7 +20787,7 @@ msgstr "[Strength Pressure]: Activa en la tauleta la sensibilitat a la pressió msgid "Use Texture Overlay" -msgstr "Usar sobrecobert de textura" +msgstr "Usar bambolina de textura" msgid "Show texture in viewport" @@ -20887,11 +20875,11 @@ msgstr "Eina pintar vèrtexs" msgid "Vertex weight when brush is applied" -msgstr "Influència dels vèrtexs quan s'hi aplica el pinzell" +msgstr "Pesos dels vèrtexs quan s'hi aplica el pinzell" msgid "Weight Paint Tool" -msgstr "Eina d'influenciar" +msgstr "Eina pintura de pesos" msgid "Wet Mix" @@ -20998,18 +20986,10 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "[Velocity Attribute]: Nom de l'atribut d'Alembic utilitzat per generar dades de difuminat de moviment" -msgid "Velocity Unit" -msgstr "Unitat de velocitat" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "[Velocity Unit]: Defineix com s'interpreten els vectors de velocitat respecte del temps, «fotograma» implica que el temps delta és 1 fotograma, «segon» significa que el temps delta és 1 / FPS" -msgid "Second" -msgstr "Segon" - - msgid "Camera data-block for storing camera settings" msgstr "Bloc de dades de càmera per guardar-hi la configuració de la càmera" @@ -21115,7 +21095,7 @@ msgstr "Alfa passepartout" msgid "Opacity (alpha) of the darkened overlay in Camera view" -msgstr "[Passepartout Alpha]: Opacitat (alfa) de la sobreposició enfosquida des de la vista de càmera" +msgstr "[Passepartout Alpha]: Opacitat (alfa) de la bambolina enfosquida des de la vista de càmera" msgid "Sensor Fit" @@ -21271,7 +21251,7 @@ msgstr "Mostra passepartout" msgid "Show a darkened overlay outside the image area in Camera view" -msgstr "Mostra una sobreposició fosca per fora de l'àrea de la imatge en la vista de càmera" +msgstr "Mostra una bambolina fosca per fora de l'àrea de la imatge en la vista de càmera" msgid "Show Safe Areas" @@ -22839,11 +22819,11 @@ msgstr "Pintura de vèrtex amb del llapis de greix" msgid "Stroke Weight Paint Mode" -msgstr "Mode pintat de força amb traç" +msgstr "Mode pintura de pesos amb traç" msgid "Grease Pencil weight paint" -msgstr "[Stroke Weight Paint Mode]: Pintar força amb el llapis de greix" +msgstr "[Stroke Weight Paint Mode]: Pintura de pesos amb llapis de greix" msgid "Onion Opacity" @@ -23793,6 +23773,10 @@ msgid "Inverse Linear" msgstr "Lineal inversa" +msgid "Inverse Square" +msgstr "Quadrat invers" + + msgid "Inverse Coefficients" msgstr "Coeficients inversos" @@ -24510,19 +24494,19 @@ msgstr "[Edges]: Arestes de la malla" msgid "Has Edge Bevel Weight" -msgstr "Té afectació de xamfrans" +msgstr "Té pesos de xamfrans" msgid "True if the mesh has an edge bevel weight layer" -msgstr "[Has Edge Bevel Weight]: Ver si la malla té una capa d'afectació de xamfrans d'aresta" +msgstr "[Has Edge Bevel Weight]: Ver si la malla té una capa de pesos de xamfrans d'aresta" msgid "Has Vertex Bevel Weight" -msgstr "Té afectació de xamfrans" +msgstr "Té pesos de xamfrans" msgid "True if the mesh has an vertex bevel weight layer" -msgstr "Ver si la malla té una capa d'afectació de xamfrans d'aresta" +msgstr "Ver si la malla té una capa de pesos de xamfrans d'aresta" msgid "Has Edge Crease" @@ -24570,7 +24554,7 @@ msgstr "Capes de propietat Float" msgid "Int Property Layers" -msgstr "Capes de propietat Int" +msgstr "Capes de propietat d'enter" msgid "String Property Layers" @@ -24958,19 +24942,19 @@ msgstr "Document de vídeo" msgid "Use Proxy / Timecode" -msgstr "Usar palla/Timecode" +msgstr "Usar simulació / timecode" msgid "Use a preview proxy and/or timecode index for this clip" -msgstr "[Use Proxy / Timecode]: Usa un vídeo de palla per previsualitzar i /o un índex de timecodes per a aquest clip" +msgstr "[Use Proxy / Timecode]: Usa un vídeo de simulació per previsualitzar i /o un índex de timecodes per a aquest clip" msgid "Proxy Custom Directory" -msgstr "Directori personalitzat de vídeo de palla" +msgstr "Directori personalitzat de simulació" msgid "Create proxy images in a custom directory (default is movie location)" -msgstr "[Proxy Custom Directory]: Crea les imatges o vídeos de palla en un directori personalitzat (per defecte és la ubicació del vídeo en qüestió)" +msgstr "[Proxy Custom Directory]: Crea les imatges simulades en un directori personalitzat (per defecte és la ubicació del vídeo en qüestió)" msgid "Node tree consisting of linked nodes used for shading, textures and compositing" @@ -25726,7 +25710,7 @@ msgstr "Pintura de vèrtexs" msgid "Weight Paint" -msgstr "Pintat de força" +msgstr "Pintura de pesos" msgid "Texture Paint" @@ -25754,7 +25738,7 @@ msgstr "Pinta traços de llapis de greix" msgid "Grease Pencil Weight Paint Strokes" -msgstr "Traços de pintura de força amb llapis de greix" +msgstr "Traços de pintura de pesos amb llapis de greix" msgid "Grease Pencil Vertex Paint Strokes" @@ -26534,11 +26518,11 @@ msgstr "Mostra aquest objecte en lloc de les partícules" msgid "Instance Collection Weights" -msgstr "Magnituds de la col·lecció d'instàncies" +msgstr "Pesos de col·lecció d'instàncies" msgid "Weights for all of the objects in the instance collection" -msgstr "[Instance Collection Weights]: Magnituds per a tots els objectes de la col·lecció d'instàncies" +msgstr "[Instance Collection Weights]: Pesos de tots els objectes de la col·lecció d'instàncies" msgid "Integration" @@ -26734,19 +26718,19 @@ msgstr "La mida de les partícules" msgid "Path End" -msgstr "Final trajecte" +msgstr "Final de trajectòria" msgid "End time of path" -msgstr "[Path End]: Temps de finalització del trajecte" +msgstr "[Path End]: Temps de finalització de la trajectòria" msgid "Path Start" -msgstr "Inici trajecte" +msgstr "Inici de trajectòria" msgid "Starting time of path" -msgstr "[Path Start]: Temps d'inici del trajecte" +msgstr "[Path Start]: Temps d'inici de la trajectòria" msgid "Rotation around the chosen orientation axis" @@ -26790,7 +26774,7 @@ msgstr "Reacció envers" msgid "The event of target particles to react on" -msgstr "[React On]: Situació davant de la qual les partícules de referència reaccionen" +msgstr "[React On]: Situació davant de la qual les partícules referents reaccionen" msgid "Death" @@ -26802,7 +26786,7 @@ msgstr "Reactor" msgid "Let the vector away from the target particle's location give the particle a starting velocity" -msgstr "Fa que el vector distant de la ubicació de la partícula de referència doni a la partícula una velocitat inicial" +msgstr "Fa que el vector distant de la ubicació de la partícula referent doni a la partícula una velocitat inicial" msgid "How many steps paths are rendered with (power of 2)" @@ -26949,6 +26933,10 @@ msgid "Display boid health" msgstr "Mostrar salut del floc" +msgid "Number" +msgstr "Nombre" + + msgid "Show particle number" msgstr "Mostra nombre de partícules" @@ -27235,7 +27223,7 @@ msgstr "Deflectir amb mida" msgid "Use particle's size in deflection" -msgstr "[Size Deflect]: Utilitza la mida de la partícula en la deflecció" +msgstr "[Size Deflect]: Utilitza la mida de la partícula en la deflexió" msgid "Strand Render" @@ -28024,10 +28012,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "[Modified]: El document de text del disc és diferent del de la memòria" -msgid "Lines" -msgstr "Línies" - - msgid "Lines of text" msgstr "Línies del text" @@ -28061,7 +28045,7 @@ msgstr "Registrar" msgid "Run this text as a Python script on loading" -msgstr "[Register]: Executa aquest text com a protocol Python en carregar" +msgstr "[Register]: Executa aquest text com a protocol python en carregar" msgid "Texture data-block used by materials, lights, worlds and brushes" @@ -28698,10 +28682,18 @@ msgid "Use soft marble" msgstr "Usa marbre tou" +msgid "Sharp" +msgstr "Brusc" + + msgid "Use more clearly defined marble" msgstr "Usa marbre més definit" +msgid "Sharper" +msgstr "Més brusc" + + msgid "Use very clearly defined marble" msgstr "Usa marbre clarament definit" @@ -28971,35 +28963,35 @@ msgstr "Escala la intensitat del soroll" msgid "Weight 1" -msgstr "Constant 1" +msgstr "Pes 1" msgid "Voronoi feature weight 1" -msgstr "Constant de Worley 1 per a Voronoi" +msgstr "Voronoi pes relatiu 1" msgid "Weight 2" -msgstr "Constant 2" +msgstr "Pes 2" msgid "Voronoi feature weight 2" -msgstr "Constant de Worley 2 per a Voronoi" +msgstr "Voronoi pes relatiu 2" msgid "Weight 3" -msgstr "Constant 3" +msgstr "Pes 3" msgid "Voronoi feature weight 3" -msgstr "Constant de Worley 3 per a Voronoi" +msgstr "Constant pes relatiu 3" msgid "Weight 4" -msgstr "Constant 4" +msgstr "Pes 4" msgid "Voronoi feature weight 4" -msgstr "Constant de Worley 4 per a Voronoi" +msgstr "Voronoi pes relatiu 4" msgid "Wood Texture" @@ -29251,11 +29243,11 @@ msgstr "Informació d'estat del temps d'execució sobre la sessió de RV" msgid "Workspace" -msgstr "Espai de treball" +msgstr "Obrador" msgid "Workspace data-block, defining the working environment for the user" -msgstr "[Workspace]: Bloc de dades de l'espai de treball, que defineix l'entorn de treball per a la usuària" +msgstr "[Workspace]: Bloc de dades de l'obrador, que defineix l'entorn de treball per a la usuària" msgid "Active Pose Asset" @@ -29263,7 +29255,7 @@ msgstr "Recurs actiu de posa" msgid "Per workspace index of the active pose asset" -msgstr "[Active Pose Asset]: Per índex d'espai de treball del recurs actiu de posa" +msgstr "[Active Pose Asset]: Per índex d'obrador del recurs actiu de posa" msgid "Active asset library to show in the UI, not used by the Asset Browser (which has its own active asset library)" @@ -29271,7 +29263,7 @@ msgstr "Biblioteca de recursos actius a mostrar a la IU, no utilitzat pel navega msgid "Switch to this object mode when activating the workspace" -msgstr "Es muda a aquest mode objecte quan s'activa l'espai de treball" +msgstr "Es muda a aquest mode objecte quan s'activa l'obrador" msgid "Grease Pencil Edit Mode" @@ -29291,7 +29283,7 @@ msgstr "Pintura de vèrtexs amb llapis de greix" msgid "Grease Pencil Weight Paint" -msgstr "[Grease Pencil Vertex Paint]: Es pinten els vèrtexs amb el llapis de greix" +msgstr "Pintura de pesos amb llapis de greix" msgid "UI Tags" @@ -29299,7 +29291,7 @@ msgstr "Etiquetes de la IU" msgid "Screen layouts of a workspace" -msgstr "[UI Tags]: Disposicions de pantalla d'un espai de treball" +msgstr "[UI Tags]: Disposicions de pantalla d'un obrador" msgid "Use UI Tags" @@ -29315,7 +29307,7 @@ msgstr "Fixar escena" msgid "Remember the last used scene for the workspace and switch to it whenever this workspace is activated again" -msgstr "[Pin Scene]: Recorda l'última escena usada per a l'espai de treball i s'hi recol·loca quan es torna a activar el dit espai de treball" +msgstr "[Pin Scene]: Recorda l'última escena usada a l'obrador i s'hi recol·loca quan es torna a activar el dit obrador" msgid "World data-block describing the environment and ambient lighting of a scene" @@ -29683,7 +29675,7 @@ msgstr "Max passos" msgid "Higher bound for timestep in second in case of automatic substeps" -msgstr "[Max Step]: Límit superior per als passos de temps per segon en el cas de subpassos automàtics" +msgstr "[Max Step]: Límit superior per al cronolapse en segons en el cas de subpassos automàtics" msgid "Min Step" @@ -29691,7 +29683,7 @@ msgstr "Min passos" msgid "Lower bound for timestep in second in case of automatic substeps" -msgstr "[Min Step]: Límit infoerir per als passos de temps per segon en el cas de subpassos automàtics" +msgstr "[Min Step]: Límit inferior per al cronolapse en segons en el cas de subpassos automàtics" msgid "Auto Step" @@ -31354,7 +31346,7 @@ msgstr "NdofRCCW" msgctxt "UI_Events_KeyMaps" msgid "NDOF Spin CW" -msgstr "NDOF Gir CW" +msgstr "NDOF Tornejar CW" msgid "NdofSCW" @@ -31363,7 +31355,7 @@ msgstr "NdofSCW" msgctxt "UI_Events_KeyMaps" msgid "NDOF Spin CCW" -msgstr "NDOF Gir CCW" +msgstr "NDOF Tornejar CCW" msgid "NdofSCCW" @@ -32327,7 +32319,7 @@ msgstr "Ubicació deformada" msgid "Weights for the vertex groups this point is member of" -msgstr "Influència dels grups de vèrtexs a què pertany aquest punt" +msgstr "Pesos dels grups de vèrtexs a què pertany aquest punt" msgid "Point selected" @@ -33444,11 +33436,11 @@ msgstr "Evita que la vora borrosa faci autointerseccions" msgid "Weight Interpolation" -msgstr "Interpolació de força" +msgstr "Interpolació de pesos" msgid "The type of weight interpolation for spline" -msgstr "[Weight Interpolation]: El tipus d’interpolació de força pel spline" +msgstr "[Weight Interpolation]: El tipus d’interpolació de pesos pel spline" msgid "Mask Spline Point" @@ -33476,7 +33468,7 @@ msgstr "Alineada senzilla" msgid "Weight of the point" -msgstr "Influència del punt" +msgstr "Pes del punt" msgid "Mask Spline UW Point" @@ -33492,7 +33484,7 @@ msgstr "Coordenada U del punt al llarg del segment de spline" msgid "Weight of feather point" -msgstr "Influència del punt de vora borrosa" +msgstr "Pes del punt de vora borrosa" msgid "Mask Spline Points" @@ -33794,7 +33786,7 @@ msgstr "Especials d'imatge en rastreig de pla" msgid "Proxy" -msgstr "Substitut" +msgstr "Simulació" msgid "Reconstruction" @@ -34358,7 +34350,7 @@ msgstr "Conjunts de cares inicials" msgid "Generate Weights" -msgstr "Generar forces" +msgstr "Generar pesos" msgid "Hooks" @@ -34498,7 +34490,7 @@ msgstr "Predefinits d'operador" msgid "Splash" -msgstr "Esquitxada" +msgstr "Careta" msgid "About" @@ -34518,15 +34510,15 @@ msgstr "[Mesh Edge]: Aresta d'un bloc de dades de malla" msgid "Bevel Weight" -msgstr "Afectació de xamfrà" +msgstr "Pesos de bisell" msgid "Weight used by the Bevel modifier" -msgstr "[Bevel Weight]: Influència exercida pel modificador de xamfrà" +msgstr "[Bevel Weight]: Pesos usats pel modificador de xamfrà" msgid "Weight used by the Subdivision Surface modifier for creasing" -msgstr "Influència exercida pel modificado de subdivisió de superfície per a la retenció" +msgstr "Pesos usats pel modificador de subdivisió de superfície per a la retenció" msgid "Index of this edge" @@ -34929,6 +34921,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "[Radius of the skin]: Si el vèrtex té múltiples arestes adjacents, s'hi encasqueta directament" +msgid "Root" +msgstr "Arrel" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "El vèrtex és una arrel per als càlculs de rotació i la generació d'esquelet, activant aquesta marca no elimina pas altres arrels de la mateixa illa de malla" @@ -35057,6 +35053,10 @@ msgid "UV Pin" msgstr "Fixació UV" +msgid "UV pinned state in the UV editor" +msgstr "[UV Pin]: Estat de fixació de l'UV a l'editor d'UV" + + msgid "UV coordinates on face corners" msgstr "Coordenades UV als cantells de cara" @@ -35106,11 +35106,11 @@ msgstr "[Mesh Vertex]: Vèrtex en un bloc de dades de malla" msgid "Weight used by the Bevel modifier 'Only Vertices' option" -msgstr "Influència utilitzada per l'opció \"només vèrtexs\" del modificador xamfrà" +msgstr "Pesos usats per l'opció \"només vèrtexs\" del modificador xamfrà" msgid "Weights for the vertex groups this vertex is member of" -msgstr "Influències per als grups de vèrtexs a què pertany aquest vèrtex" +msgstr "Pesos per als grups de vèrtexs a què pertany aquest vèrtex" msgid "Index of this vertex" @@ -35302,11 +35302,11 @@ msgstr "[Normal Edit]: Modifica la direcció de les normals de superfície" msgid "Weighted Normal" -msgstr "Normal influent" +msgstr "Normal ponderada" msgid "Modify the direction of the surface normals using a weighting method" -msgstr "[Weighted Normal]: Modifica la direcció de les normals de superfície usant un mètode de ponderació d'incluència" +msgstr "[Weighted Normal]: Modifica la direcció de les normals de superfície usant un mètode de pesos" msgid "UV Project" @@ -35326,23 +35326,23 @@ msgstr "[UV Warp]: Transforma el mapa UV usant la diferència entre dos objectes msgid "Vertex Weight Edit" -msgstr "Edita força de vèrtexs" +msgstr "Edita pesos de vèrtexs" msgid "Modify of the weights of a vertex group" -msgstr "[Vertex Weight Edit]: Modifica les forces d'un grup de vèrtexs" +msgstr "[Vertex Weight Edit]: Modifica els pesos d'un grup de vèrtexs" msgid "Vertex Weight Mix" -msgstr "Mescla de forces de vèrtexs" +msgstr "Mescla de pesos de vèrtexs" msgid "Mix the weights of two vertex groups" -msgstr "[Vertex Weight Mix]: Combina les forces de dos grups de vèrtexs" +msgstr "[Vertex Weight Mix]: Combina els pesos de dos grups de vèrtexs" msgid "Set the vertex group weights based on the distance to another target object" -msgstr "Determina les forces del grup de vèrtexs en funció de la distància a un altre objecte referent" +msgstr "Determina els pesos del grup de vèrtexs en funció de la distància a un altre objecte referent" msgid "Create copies of the shape with offsets" @@ -35838,11 +35838,11 @@ msgstr "Només aixamfrana les arestes amb angles suficientment aguts entre cares msgid "Use bevel weights to determine how much bevel is applied in edge mode" -msgstr "Usar afectació de xamfrans per a determinar quant s'aixamfrana en mode aresta" +msgstr "Usar pesos de xamfrans per a determinar quant s'aixamfrana en mode aresta" msgid "Use vertex group weights to select whether vertex or edge is beveled" -msgstr "Usar afectació de grups de vèrtexs per seleccionar si s'aixamfranen vèrtexs o arestes" +msgstr "Usar pesos de grups de vèrtexs per seleccionar si s'aixamfranen vèrtexs o arestes" msgid "Loop Slide" @@ -36314,7 +36314,7 @@ msgstr "Usar mitjana de les arestes/vèrtexs adjacents" msgid "Length Weight" -msgstr "Afectació de longitud" +msgstr "Pesos de longitud" msgid "Use the average of adjacent edge-vertices weighted by their length" @@ -36390,7 +36390,7 @@ msgstr "Transferir valors de retenció de subdivisió" msgid "Transfer bevel weights" -msgstr "[Transfer subdivision crease values]: Transfereix l'afectació dels xamfrans" +msgstr "[Transfer subdivision crease values]: Transfereix pesos dels xamfrans" msgid "Freestyle" @@ -36634,7 +36634,7 @@ msgstr "Distància màxima permesa entre l'element d'origen i referència, per a msgid "Factor to use when applying data to destination (exact behavior depends on mix mode, multiplied with weights from vertex group when defined)" -msgstr "Factor a usar quan s'apliquen dades a la referència (el comportament exacte depèn del mode de combinació, multiplicat per l'afectació dels grups de vèrtexs quan quan estan definits)" +msgstr "Factor a usar quan s'apliquen dades a la referència (el comportament exacte depèn del mode de combinació, multiplicat pels pesos dels grups de vèrtexs quan estan definits)" msgid "How to affect destination elements with source values" @@ -37178,7 +37178,7 @@ msgstr "[Bound]: Si la geometria ha estat estacada a ancoratges" msgid "Anchor Weights" -msgstr "Vèrtexs àncora" +msgstr "Pesos àncora" msgid "Name of Vertex Group which determines Anchors" @@ -37246,11 +37246,11 @@ msgstr "Usar vèrtexs que no formen part de la regió definida" msgid "Weights over this threshold remain" -msgstr "Les forces per sobre d'aquest llindar es conserven" +msgstr "Els pesos per sobre d'aquest llindar es conserven" msgid "Use vertex group weights to cut faces at the weight contour" -msgstr "Usa les forces dels grups de vèrtexs per a tallar cares del seu contorn" +msgstr "Usa els pesos dels grups de vèrtexs per a tallar cares del seu contorn" msgid "Cache Modifier" @@ -38483,7 +38483,7 @@ msgstr "Xanfrà convex" msgid "Edge bevel weight to be added to outside edges" -msgstr "[Bevel Convex]: Ponderació del xamfrà de les arestes que s'afegeix a les externes" +msgstr "[Bevel Convex]: Pesos del xamfrà de les arestes que s'afegeixen a les externes" msgid "Inner Crease" @@ -38647,7 +38647,7 @@ msgstr "Cares aplanades" msgid "Make faces use the minimal vertex weight assigned to their vertices(ensures new faces remain parallel to their original ones, slow, disable when not needed)" -msgstr "[Flat Faces]: Fa que les cares utilitzin la mínima força de vèrtex assignada als seus vèrtexs (assegura que les cares noves queden paral·leles a les originals, lent, desactivar si no cal)" +msgstr "[Flat Faces]: Fa que les cares utilitzin els pesos mínims de vèrtex assignats als seus vèrtexs (assegura que les cares noves queden paral·leles a les originals, lent, desactivar si no cal)" msgid "Flip Normals" @@ -38827,7 +38827,7 @@ msgstr "[Fixed Alternate]: Dividir els quads en els vèrtexs 2n i 4t" msgid "Shortest Diagonal" -msgstr "Diagonal més curta" +msgstr "Diagonal mínima" msgid "Split the quads along their shortest diagonal" @@ -38890,6 +38890,10 @@ msgid "UVWarp Modifier" msgstr "Modificador aberració UV" +msgid "Add target position to UV coordinates" +msgstr "[UVWarp Modifier]: Afegeix la posició de referència a les coordenades UV" + + msgid "U-Axis" msgstr "Eix U" @@ -38951,11 +38955,11 @@ msgstr "[UV Layer]: Nom de la capa UV" msgid "WeightVG Edit Modifier" -msgstr "Modificador d'edició de forces-GV" +msgstr "Modificador d'edició de pesos-GV" msgid "Edit the weights of vertices in a group" -msgstr "[WeightVG Edit Modifier]: Edita les forces dels vèrtexs en un grup" +msgstr "[WeightVG Edit Modifier]: Edita els pesos dels vèrtexs en un grup" msgid "Add Threshold" @@ -38963,19 +38967,19 @@ msgstr "Llindar de suma" msgid "Lower bound for a vertex's weight to be added to the vgroup" -msgstr "[Add Threshold]: Límit inferior de la força d'un vèrtex a sumar a un grup-v" +msgstr "[Add Threshold]: Límit inferior de pes d'un vèrtex a sumar a un grup-v" msgid "Default Weight" -msgstr "Influència per defecte" +msgstr "Pesos per defecte" msgid "Default weight a vertex will have if it is not in the vgroup" -msgstr "[Default Weight]: Influència predeterminada que tindrà un vèrtex si no pertany al grup-v" +msgstr "[Default Weight]: Pes predeterminada que tindrà un vèrtex si no pertany al grup-v" msgid "How weights are mapped to their new values" -msgstr "Com es mapegen les forces als seus valors nous" +msgstr "Com es mapegen els pesos als seus valors nous" msgid "Null action" @@ -39006,7 +39010,7 @@ msgstr "Inverteix decaïment" msgid "Invert the resulting falloff weight" -msgstr "[Invert Falloff]: Inverteix la força resultant del decaïment" +msgstr "[Invert Falloff]: Inverteix el pes resultant del decaïment" msgid "Invert vertex group mask influence" @@ -39078,11 +39082,11 @@ msgstr "[Mask Vertex Group]: Nom del grup de vèrtexs d'emmascarament" msgid "Normalize Weights" -msgstr "Normalitza forces" +msgstr "Normalitza pesos" msgid "Normalize the resulting weights (otherwise they are only clamped within 0.0 to 1.0 range)" -msgstr "[Normalize Weights]: Normalitza les forces resultants (en cas contrari només s'estrenyen dins de l'interval 0,0 a 1,0)" +msgstr "[Normalize Weights]: Normalitza els pesos resultants (en cas contrari només s'estrenyen dins de l'interval 0,0 a 1,0)" msgid "Remove Threshold" @@ -39090,7 +39094,7 @@ msgstr "Llindar de supressió" msgid "Upper bound for a vertex's weight to be removed from the vgroup" -msgstr "[Remove Threshold]: Límit superior perquè la força d'un vèrtex s'elimini del grop-v" +msgstr "[Remove Threshold]: Límit superior perquè el pes d'un vèrtex s'elimini del grop-v" msgid "Group Add" @@ -39098,7 +39102,7 @@ msgstr "Afegir grup" msgid "Add vertices with weight over threshold to vgroup" -msgstr "[Group Add]: Afegeix vèrtexs amb força superior al llindar de grup-v" +msgstr "[Group Add]: Afegeix vèrtexs amb pesos superiors al llindar de grup-v" msgid "Group Remove" @@ -39106,31 +39110,31 @@ msgstr "Eliminar grup" msgid "Remove vertices with weight below threshold from vgroup" -msgstr "[Group Remove]: Elimina vèrtexs de força inferior al llindar del grup-v" +msgstr "[Group Remove]: Elimina vèrtexs de pesos inferiors al llindar del grup-v" msgid "WeightVG Mix Modifier" -msgstr "Modificador mescla força-GV" +msgstr "Modificador mescla pesos-GV" msgid "Default Weight A" -msgstr "Influència per defecte A" +msgstr "Pes per defecte A" msgid "Default weight a vertex will have if it is not in the first A vgroup" -msgstr "[Default Weight A]: Influència predeterminada que tindrà un vèrtex si no està en el primer grup-v A" +msgstr "[Default Weight A]: Pes predeterminat que tindrà un vèrtex si no està en el primer grup-v A" msgid "Default Weight B" -msgstr "Influència per defecte B" +msgstr "Pes per defecte B" msgid "Default weight a vertex will have if it is not in the second B vgroup" -msgstr "Influència predeterminada que tindrà un vèrtex si no està en el segon grup-v B" +msgstr "Pes predeterminat que tindrà un vèrtex si no està en el segon grup-v B" msgid "Invert Weights A" -msgstr "Invertir forces A" +msgstr "Invertir pes A" msgid "Invert the influence of vertex group A" @@ -39138,7 +39142,7 @@ msgstr "[Invert Weights A]: Inverteix la influència del grup de vèrtexs A" msgid "Invert Weights B" -msgstr "Invertir forces B" +msgstr "Invertir pes B" msgid "Invert the influence of vertex group B" @@ -39146,43 +39150,43 @@ msgstr "Inverteix la influència del grup de vèrtexs B" msgid "How weights from vgroup B affect weights of vgroup A" -msgstr "Com afecten les forces del grup-v B a les del grup-v A" +msgstr "Com afecten els pesos del grup-v B els del grup-v A" msgid "Replace VGroup A's weights by VGroup B's ones" -msgstr "Substitueix forces del grup A per les del grup-v B" +msgstr "Substitueix els pesos del grup A pels del grup-v B" msgid "Add VGroup B's weights to VGroup A's ones" -msgstr "Suma les forces del grup-v B a les del grup-v A" +msgstr "Suma els pesos del grup-v B als del grup-v A" msgid "Subtract VGroup B's weights from VGroup A's ones" -msgstr "Resta les forces de grup-v B's de les del grup-v A" +msgstr "Resta els pesos de grup-v B's dels del grup-v A" msgid "Multiply VGroup A's weights by VGroup B's ones" -msgstr "Multiplica les forces del grup-v A per les del grup-v B" +msgstr "Multiplica els pesos del grup-v A pels del grup-v B" msgid "Divide VGroup A's weights by VGroup B's ones" -msgstr "Divideix les forces del grup-v A per les del grup-v B" +msgstr "Divideix els pesos del grup-v A pels del grup-v B" msgid "Difference between VGroup A's and VGroup B's weights" -msgstr "Diferència entre les forces del grup-v A i el grup-v B" +msgstr "Diferència entre els pesos del grup-v A i el grup-v B" msgid "Average value of VGroup A's and VGroup B's weights" -msgstr "Mitjana de les forces del grup-v A i del grup-v B" +msgstr "Mitjana dels pesos del grup-v A i del grup-v B" msgid "Minimum of VGroup A's and VGroup B's weights" -msgstr "Mínimes forces del grup-v A i del grup-v B" +msgstr "Mínims pesos del grup-v A i del grup-v B" msgid "Maximum of VGroup A's and VGroup B's weights" -msgstr "Màximes forces del grup-v A i del grup-v B" +msgstr "Màxims pesos del grup-v A i del grup-v B" msgid "Vertex Set" @@ -39246,19 +39250,19 @@ msgstr "Nom del segon grup de vèrtexs" msgid "WeightVG Proximity Modifier" -msgstr "Modificador proximitat a força-GV" +msgstr "Modificador proximitat a pesos-GV" msgid "Set the weights of vertices in a group from a target object's distance" -msgstr "[WeightVG Proximity Modifier]: Consigna les forces dels vèrtexs d'un grup a partir de la distància d'un objecte de referència" +msgstr "[WeightVG Proximity Modifier]: Consigna els pesos dels vèrtexs d'un grup a partir de la distància d'un objecte de referència" msgid "Distance mapping to weight 1.0" -msgstr "Mapejat distància a força 1,0" +msgstr "Mapejat distància a pes 1,0" msgid "Distance mapping to weight 0.0" -msgstr "Mapejat distància a força 0,0" +msgstr "Mapejat distància a pes 0,0" msgid "Proximity Geometry" @@ -39266,7 +39270,7 @@ msgstr "Geometria de proximitat" msgid "Use the shortest computed distance to target object's geometry as weight" -msgstr "[Proximity Geometry]: Usa com a força la distància calculada més curta a la geometria de l'objecte referent" +msgstr "[Proximity Geometry]: Usa com a pes la distància calculada més curta a la geometria de l'objecte referent" msgid "Compute distance to nearest vertex" @@ -39506,7 +39510,7 @@ msgstr "Distància entre ones" msgid "WeightedNormal Modifier" -msgstr "Modificador de normal amb força" +msgstr "Modificador de normal amb pesos" msgid "Keep Sharp" @@ -39514,15 +39518,15 @@ msgstr "Mantenir agut" msgid "Keep sharp edges as computed for default split normals, instead of setting a single weighted normal for each vertex" -msgstr "[Keep Sharp]: Manté els cantells aguts segons còmput per a normals partides per defecte, en lloc de definir una normal amb força per a cada vèrtex" +msgstr "[Keep Sharp]: Manté els cantells aguts segons còmput per a normals partides per defecte, en lloc de definir una normal amb pesos per a cada vèrtex" msgid "Weighting Mode" -msgstr "Mode força" +msgstr "Mode pesos" msgid "Weighted vertex normal mode to use" -msgstr "[Weighting Mode]: El mode de normal amb força de vèrtexs triat" +msgstr "[Weighting Mode]: El mode de normal amb pesos de vèrtexs triat" msgid "Face Area" @@ -39530,11 +39534,11 @@ msgstr "Àrea de cara" msgid "Generate face area weighted normals" -msgstr "[Face Area]: Genera normals influents per àrea de cara" +msgstr "[Face Area]: Genera normals amb pesos per àrea de cara" msgid "Generate corner angle weighted normals" -msgstr "Genera normals influents d'angles de cantells" +msgstr "Genera normals amb pesos d'angles de cantells" msgid "Face Area & Angle" @@ -39546,7 +39550,7 @@ msgstr "[Face Area & Angle]: Les normals generades es ponderen tant per l'àrea msgid "Threshold value for different weights to be considered equal" -msgstr "Valor del llindar per considerar iguals diferents forces i ponderacions" +msgstr "Valor del llindar per considerar iguals diferents pesos" msgid "Face Influence" @@ -39562,7 +39566,7 @@ msgstr "Nom del grup de vèrtex per a modificar les àrees seleccionades" msgid "Corrective factor applied to faces' weights, 50 is neutral, lower values increase weight of weak faces, higher values increase weight of strong faces" -msgstr "Factor correctiu aplicat a les forces de cares, 50 és neutral, els valors menors augmenten la força de les cares febles, els valors més alts augmenten el de les cares fortes" +msgstr "Factor correctiu aplicat als pesos de cares, 50 és neutral, els valors menors augmenten els pesos de les cares febles, els valors més alts augmenten els de les cares fortes" msgid "Weld Modifier" @@ -39602,7 +39606,7 @@ msgstr "[Wireframe Modifier]: Modificador que fa l'efecte d'un filat" msgid "Crease weight (if active)" -msgstr "Influència de retenció (si és activa)" +msgstr "Pesos de retenció (si és activa)" msgid "Thickness factor" @@ -39673,6 +39677,10 @@ msgid "Line thickness for motion path" msgstr "[Line Thinkness]: Gruix de la línia per a trajecte de rodatge" +msgid "Lines" +msgstr "Línies" + + msgid "Use straight lines between keyframe points" msgstr "Usa línies rectes entre els punts fotofita" @@ -39714,27 +39722,27 @@ msgstr "Punt de trajectòria seleccionat per a l'edició" msgid "Movie Clip Proxy" -msgstr "Vídeo de palla" +msgstr "Simulació del vídeo" msgid "Proxy parameters for a movie clip" -msgstr "[Movie Clip Proxy]: Paràmetres del clip substitut d'un vídeo" +msgstr "[Movie Clip Proxy]: Paràmetres del clip simulat d'un vídeo" msgid "Build proxy resolution 100% of the original footage dimension" -msgstr "Confegir resolució del substitut al 100% de la dimensió del metratge original" +msgstr "Confegir resolució de la simulació al 100% de la dimensió del metratge original" msgid "Build proxy resolution 25% of the original footage dimension" -msgstr "Confegir resolució del substitut al 25% de la dimensió del metratge original" +msgstr "Confegir resolució de la simulació al 25% de la dimensió del metratge original" msgid "Build proxy resolution 50% of the original footage dimension" -msgstr "Confegir resolució del substitut al 50% de la dimensió del metratge original" +msgstr "Confegir resolució de la simulació al 50% de la dimensió del metratge original" msgid "Build proxy resolution 75% of the original footage dimension" -msgstr "Confegir resolució del substitut al 75% de la dimensió del metratge original" +msgstr "Confegir resolució de la simulació al 75% de la dimensió del metratge original" msgid "Free Run" @@ -39762,27 +39770,27 @@ msgstr "[Rec Run]: Crea índex de timecodes de projecció de gravació" msgid "Build proxy resolution 100% of the original undistorted footage dimension" -msgstr "Crear la resolució del substitut al 100% de la dimensió original del metratge sense distorsió" +msgstr "Crear resolució de la simulació al 100% de la dimensió original del metratge sense distorsió" msgid "Build proxy resolution 25% of the original undistorted footage dimension" -msgstr "Crear la resolució del substitut al 25% de la dimensió original del metratge sense distorsió" +msgstr "Crear resolució de la silmulació al 25% de la dimensió original del metratge sense distorsió" msgid "Build proxy resolution 50% of the original undistorted footage dimension" -msgstr "Crear la resolució del substitut al 50% de la dimensió original del metratge sense distorsió" +msgstr "Crear resolució de la silmulació al 50% de la dimensió original del metratge sense distorsió" msgid "Build proxy resolution 75% of the original undistorted footage dimension" -msgstr "Crear la resolució del substitut al 75% de la dimensió original del metratge sense distorsió" +msgstr "Crear resolució de la silmulació al 75% de la dimensió original del metratge sense distorsió" msgid "Location to store the proxy files" -msgstr "Ubicació per a guardar els documents dels vídeos de palla" +msgstr "Ubicació per a guardar els documents dels vídeos simulats" msgid "JPEG quality of proxy images" -msgstr "Qualitat JPEG de les imatges de palla" +msgstr "Qualitat JPEG de les imatges simulades" msgid "Timecode" @@ -39834,11 +39842,11 @@ msgstr "Número del fotograma actual del vídeo o seqüència d'imatges" msgid "Proxy Render Size" -msgstr "Mida de revelat del substitut" +msgstr "Mida de revelat simulat" msgid "Display preview using full resolution or different proxy resolutions" -msgstr "Previsualització de resolució completa o de diferents resolucions del substitut" +msgstr "Previsualització de resolució completa o de diferents resolucions de simulació" msgid "None, full render" @@ -39850,7 +39858,7 @@ msgstr "Revelar sense distorsió" msgid "Render preview using undistorted proxy" -msgstr "[Render Undistorted]: Previsualització del revelat en base a un substitut no distorsionat" +msgstr "[Render Undistorted]: Previsualització del revelat en base a simulació no distorsionada" msgid "Movie tracking reconstructed camera data" @@ -40959,7 +40967,7 @@ msgstr "Influència d'aquest rastre en la resolutiva final" msgid "Stab Weight" -msgstr "Força estabilitzadora" +msgstr "Pesos d'estabilització" msgid "Influence of this track on 2D stabilization" @@ -42172,7 +42180,7 @@ msgstr "Grup personalitzat del conformador" msgid "Custom Compositor Group Node for Python nodes" -msgstr "[Compositor Custom Group]: Grup de nodes del conformador personalitzat per a nodes Python" +msgstr "[Compositor Custom Group]: Grup de nodes del conformador personalitzat per a nodes python" msgid "Directional Blur" @@ -42188,7 +42196,7 @@ msgstr "Centre Y" msgid "Spin" -msgstr "Voltar" +msgstr "Tornejar" msgid "Zoom" @@ -42356,7 +42364,7 @@ msgstr "Dilata/Erosiona" msgid "Distance to grow/shrink (number of iterations)" -msgstr "[Dilate/Erode]: Distància a créixer/encongir (nombre d'iteracions)" +msgstr "[Dilate/Erode]: Distància a engrandir/encongir (nombre d'iteracions)" msgid "Edge to inset" @@ -42676,7 +42684,7 @@ msgstr "Distància de vora borrosa" msgid "Distance to grow/shrink the feather" -msgstr "[Feather Distance]: Distància per a fer créixer/encongir la vora borrosa" +msgstr "[Feather Distance]: Distància per a ampliar/encongir la vora borrosa" msgctxt "Curve" @@ -44305,7 +44313,7 @@ msgstr "Grup personalitzat de geometria" msgid "Custom Geometry Group Node for Python nodes" -msgstr "[Geometry Custom Group]: Node de grup de geometria personalitzat per a nodes de Python" +msgstr "[Geometry Custom Group]: Node de grup de geometria personalitzat per a nodes de python" msgid "Deform Curves on Surface" @@ -46071,7 +46079,7 @@ msgstr "Grup personalitzat d'aspectors" msgid "Custom Shader Group Node for Python nodes" -msgstr "Node de grup personalitzat d'aspectors per a nodes Python" +msgstr "Node de grup personalitzat d'aspectors per a nodes python" msgid "Displace the surface along the surface normal" @@ -46159,7 +46167,7 @@ msgstr "Inverteix un color, produint un negatiu" msgid "Layer Weight" -msgstr "Influència de capa" +msgstr "Pes de capa" msgid "" @@ -46927,7 +46935,7 @@ msgstr "Capa de color de vèrtexs" msgid "Vertex group weight" -msgstr "Influència del grup de vèrtexs" +msgstr "Pes del grup de vèrtexs" msgid "XYZ normal vector mapped to RGB colors" @@ -48634,7 +48642,7 @@ msgstr "[Push Down Action]: Espitja l'acció en avall a l'estiba ANL com a nou s msgctxt "Operator" msgid "Sample Keyframes" -msgstr "Mostrejar fotofites" +msgstr "Redistribuir fotofites" msgid "Add keyframes on every frame between the selected keyframes" @@ -50811,11 +50819,11 @@ msgstr "[Delete Marker]: Suprimeix el marcador per al fotograma actual a partir msgctxt "Operator" msgid "Delete Proxy" -msgstr "Suprimir vídeo de palla" +msgstr "Suprimir simulació" msgid "Delete movie clip proxy files from the hard drive" -msgstr "[Delete Proxy]: Suprimeix del disc dur els documents del clip substitutiu" +msgstr "[Delete Proxy]: Suprimeix del disc dur els documents del clip simulat" msgctxt "Operator" @@ -51183,11 +51191,11 @@ msgstr "Precarrega fotogrames des del disc per a una reproducció/rastreig més msgctxt "Operator" msgid "Rebuild Proxy and Timecode Indices" -msgstr "Recompon els índexs del vídeo de palla i del timecode" +msgstr "Recompon els índexs del vídeo simulat i del timecode" msgid "Rebuild all selected proxies and timecode indices in the background" -msgstr "Reconstrueix tots els índexs dels vídeos de substitució i de timecode en segon pla" +msgstr "Reconstrueix tots els índexs dels vídeos simulats i de timecode en segon pla" msgctxt "Operator" @@ -52206,11 +52214,11 @@ msgstr "Mou la restricció cap amunt en la l'estiba de restriccions" msgctxt "Operator" msgid "Normalize Weights" -msgstr "Normalitzar forces" +msgstr "Normalitzar pesos" msgid "Normalize weights of all target bones" -msgstr "[Normalize Weights]: Normalitza les forces de tots els ossos de referència" +msgstr "[Normalize Weights]: Normalitza els pesos de tots els ossos de referència" msgid "Clear inverse correction for Object Solver constraint" @@ -52987,16 +52995,16 @@ msgstr "[Smooth Curve Tilt]: Interpola la inclinació dels punts seleccionats" msgctxt "Operator" msgid "Smooth Curve Weight" -msgstr "Suavitzar força de corba" +msgstr "Suavitzar pesos de corba" msgid "Interpolate weight of selected points" -msgstr "[Smooth Curve Weight]: Interpola la força dels punts seleccionats" +msgstr "[Smooth Curve Weight]: Interpola els pesos dels punts seleccionats" msgctxt "Operator" msgid "Spin" -msgstr "Girar" +msgstr "Tornejar" msgid "Extrude selected boundary row around pivot point and current view axis" @@ -53030,11 +53038,11 @@ msgstr "[Handles]: Utilitza nanses en convertir corbes Bézier en polígons" msgctxt "Operator" msgid "Set Goal Weight" -msgstr "Establir objectiu de força" +msgstr "Establir pes que es busca" msgid "Set softbody goal weight for selected points" -msgstr "[Set Goal Weight]: Estableix l'objectiu de força del cos tou per als punts seleccionats" +msgstr "[Set Goal Weight]: Estableix l'objectiu de pes del cos tou per als punts seleccionats" msgid "Split off selected points from connected unselected points" @@ -53512,7 +53520,7 @@ msgstr "Desa el document en format ASCII" msgid "Batch Mode" -msgstr "Mode per lots" +msgstr "Mode de repetició" msgid "All data in one file" @@ -53877,7 +53885,7 @@ msgstr "[Only Deform Bones]: Només actua sobre ossos deformants (i els no defor msgid "Batch Own Dir" -msgstr "Directori propi per lot" +msgstr "Directori propi de repetició" msgid "Create a dir for each exported file" @@ -54029,14 +54037,18 @@ msgid "Export vertex colors with meshes" msgstr "Exportar colors de vèrtexs amb malles" -msgid "Copyright" -msgstr "Copyright" - - msgid "Legal rights and conditions for the model" msgstr "Drets i condicions legals del model" +msgid "Use Current Frame" +msgstr "Usar fotograma actual" + + +msgid "Export the scene in the current animation frame" +msgstr "Exporta l'escena del fotograma d'animació actual" + + msgid "Export Deformation Bones Only" msgstr "Exportar només ossos de deformació" @@ -54058,7 +54070,7 @@ msgstr "Bits de quantificació genèrics" msgid "Quantization bits for generic values like weights or joints (0 = no quantization)" -msgstr "[Generic quantization bits]: Bits de quantificació per a valors genèrics com forces o articulacions (0 = sense quantificació)" +msgstr "[Generic quantization bits]: Bits de quantificació per a valors genèrics com pesos o articulacions (0 = sense quantificació)" msgid "Draco mesh compression" @@ -54233,6 +54245,14 @@ msgid "Export vertex tangents with shape keys (morph targets)" msgstr "[Shape Key Tangents]: Exporta les tangents de vèrtex amb morfofites (referents mòrfics)" +msgid "Group by NLA Track" +msgstr "Agrupar segons pista d'ANL" + + +msgid "When on, multiple actions become part of the same glTF animation if they're pushed onto NLA tracks with the same name. When off, all the currently assigned actions become one glTF animation" +msgstr "Quan està actiu, múltiples accions esdevenen parts de la mateixa animació gITF si se les empeny envers pistes d'ANL de nom igual. Quan està inactiu, totes les accions presentment assignades esdevenen una animació gITF" + + msgid "Merged Animation Name" msgstr "Nom d'animació fusionada" @@ -55921,11 +55941,11 @@ msgstr "[Link Strokes]: Si s'han d'enllaçar els traços amb seccions de radi ze msgid "Normalize Weight" -msgstr "Normalitzar força" +msgstr "Normalitzar pesos" msgid "Normalize weight (set from stroke width)" -msgstr "[Normalize Weight]: Normalitza la força (treta de l'amplada de traç)" +msgstr "[Normalize Weight]: Normalitza els pesos (tret de l'amplada de traç)" msgid "Whether the path control curve reproduces the drawing in realtime, starting from Start Frame" @@ -56211,11 +56231,11 @@ msgstr "Duplicar fotogrames actius en totes les capes" msgctxt "Operator" msgid "Generate Automatic Weights" -msgstr "Generar forces automàtiques" +msgstr "Generar pesos automàtics" msgid "Generate automatic weights for armatures (requires armature modifier)" -msgstr "Generar forces automàtiques per a esquelets (requereix modificador esquelet)" +msgstr "Generar pesos automàtics per a esquelets (requereix modificador esquelet)" msgid "Armature to use" @@ -56235,7 +56255,7 @@ msgstr "Grups buits" msgid "Automatic Weights" -msgstr "Influències automàtiques" +msgstr "Pesos automàtics" msgid "Ratio between bone length and influence radius" @@ -57838,7 +57858,7 @@ msgstr "Invertir grup de vèrtexs" msgid "Invert weights to the active vertex group" -msgstr "[Invert Vertex Group]: Inverteix les forces al grup de vèrtexs actiu" +msgstr "[Invert Vertex Group]: Inverteix els pesos al grup de vèrtexs actiu" msgctxt "Operator" @@ -57847,7 +57867,7 @@ msgstr "Normalitzar grup de vèrtexs" msgid "Normalize weights to the active vertex group" -msgstr "Normalitza les forces del grup de vèrtexs actiu" +msgstr "Normalitza els pesos del grup de vèrtexs actiu" msgctxt "Operator" @@ -57856,7 +57876,7 @@ msgstr "Normalitzar tots els grups de vèrtexs" msgid "Normalize all weights of all vertex groups, so that for each vertex, the sum of all weights is 1.0" -msgstr "Normalitza totes les forces de tots els grups de vèrtexs, de manera que per a cada vèrtex, la suma de totes les forces sigui 1.0" +msgstr "Normalitza tots els pesos de tots els grups de vèrtexs, de manera que per a cada vèrtex, la suma de tots els pesos sigui 1.0" msgid "Lock Active" @@ -57891,7 +57911,7 @@ msgstr "Suavitzar grup de vèrtexs" msgid "Smooth weights to the active vertex group" -msgstr "[Smooth Vertex Group]: Suavitza les forces al grup de vèrtexs actiu" +msgstr "[Smooth Vertex Group]: Suavitzar pesos al grup de vèrtexs actiu" msgctxt "Operator" @@ -57914,16 +57934,16 @@ msgstr "Entra/Surt del mode de pintat de vèrtexs per als traços de llapis de g msgctxt "Operator" msgid "Stroke Weight Paint" -msgstr "Pintat de força amb traç" +msgstr "Pintura de pesos amb traç" msgctxt "Operator" msgid "Strokes Weight Mode Toggle" -msgstr "Revesar mode de força amb traços" +msgstr "Revesar mode de pesos de traç" msgid "Enter/Exit weight paint mode for Grease Pencil strokes" -msgstr "Entra/Surt del mode de pintat de força amb traços del llapis de greix" +msgstr "Entra/Surt del mode de pintura de pesos amb traços del llapis de greix" msgctxt "Operator" @@ -59884,11 +59904,11 @@ msgstr "Duplicar màscara" msgctxt "Operator" msgid "Clear Feather Weight" -msgstr "Descartar força de vora borrosa" +msgstr "Descartar pesos de vora borrosa" msgid "Reset the feather weight to zero" -msgstr "[Clear Feather Weight]: Restableix la força de la vora borrosa a zero" +msgstr "[Clear Feather Weight]: Restableix el pes de la vora borrosa a zero" msgctxt "Operator" @@ -60042,7 +60062,7 @@ msgstr "Animació de reinici de vora borrosa" msgid "Reset feather weights on all selected points animation values" -msgstr "[Feather Reset Animation]: Restableix les forces de vora borrosa en tots els valors d'animació de punts seleccionats" +msgstr "[Feather Reset Animation]: Restableix el pes de la vora borrosa en tots els valors d'animació de punts seleccionats" msgctxt "Operator" @@ -60241,7 +60261,7 @@ msgstr "Determinar totes les normals del vèrtex per angle de cantell" msgid "Weight applied per face" -msgstr "Influència aplicada per cara" +msgstr "Pesos aplicats per cara" msgctxt "Operator" @@ -60563,38 +60583,38 @@ msgstr "Comparar VCols" msgctxt "Operator" msgid "Add Edge Bevel Weight" -msgstr "Afegir força a bisell d'aresta" +msgstr "Afegir pesos a bisell d'aresta" msgid "Add an edge bevel weight layer" -msgstr "[Add Edge Bevel Weight]: Afegeix una capa de força al bisell d'aresta" +msgstr "[Add Edge Bevel Weight]: Afegeix una capa de pes al bisell d'aresta" msgctxt "Operator" msgid "Clear Edge Bevel Weight" -msgstr "Descartar força de bisell d'aresta" +msgstr "Descartar pes de bisell d'aresta" msgid "Clear the edge bevel weight layer" -msgstr "Neteja la capa de força del bisell d'aresta" +msgstr "Neteja la capa de pes del bisell d'aresta" msgctxt "Operator" msgid "Add Vertex Bevel Weight" -msgstr "Afegir força de bisells de vèrtexs" +msgstr "Afegir pesos de bisells de vèrtexs" msgid "Add a vertex bevel weight layer" -msgstr "[Add Vertex Bevel Weight]: Afegeix una capa de força de bisells de vèrtexs" +msgstr "[Add Vertex Bevel Weight]: Afegeix una capa de pesos de bisells de vèrtexs" msgctxt "Operator" msgid "Clear Vertex Bevel Weight" -msgstr "Descartar força de bisells de vèrtexs" +msgstr "Descartar pesos de bisells de vèrtexs" msgid "Clear the vertex bevel weight layer" -msgstr "Neteja la capa de força del bisells de vèrtexs" +msgstr "Neteja la capa de pesos de bisells de vèrtexs" msgctxt "Operator" @@ -61665,11 +61685,11 @@ msgstr "Intensitat de normals de cares" msgid "Set/Get strength of face (used in Weighted Normal modifier)" -msgstr "[Face Normals Strength]: Determina/Obté la força de la cara (usat en el Modificador de normal influent)" +msgstr "[Face Normals Strength]: Determina/Obté la força de la cara (usat en el Modificador de normal amb pesos)" msgid "Strength to use for assigning or selecting face influence for weighted normal modifier" -msgstr "Intensitat a emprar per a assignar o seleccionar la influència de la cara per al modificador de normals influents" +msgstr "Intensitat a emprar per a assignar o seleccionar la influència de la cara per al modificador de normals amb pesos" msgid "Weak" @@ -61893,11 +61913,11 @@ msgstr "Càlcul del centre per despartir la cara" msgid "Weighted Median" -msgstr "Mediana ponderada" +msgstr "Mediana amb pesos" msgid "Weighted median face center" -msgstr "[Weighted Median]: Centre de cara per mitjana ponderada" +msgstr "[Weighted Median]: Centre de cara per mediana amb pesos" msgid "Median" @@ -62946,7 +62966,7 @@ msgstr "[Smooth Normals Vectors]: Suavitza les normals personalitzades basades e msgid "Specifies weight of smooth vs original normal" -msgstr "Especificar la força de la normal suavitzada en contrast amb l'original" +msgstr "Especificar el pes de la normal suavitzada en contrast amb l'original" msgctxt "Operator" @@ -63328,7 +63348,7 @@ msgstr "[Wireframe]: Crea un bastiment sòlid a partir de cares" msgid "Crease Weight" -msgstr "Influència de retenció" +msgstr "Pesos de retenció" msgid "Crease hub edges for an improved subdivision surface" @@ -64984,7 +65004,7 @@ msgstr "Transferir dades de malla" msgid "Transfer data layer(s) (weights, edge sharp, etc.) from active to selected meshes" -msgstr "Transfereix les capes de dades (forces, arestes cantelludes, etc.) des de les malles actives a les seleccionades" +msgstr "Transfereix les capes de dades (pesos, arestes cantelludes, etc.) des de les malles actives a les seleccionades" msgid "Which data to transfer" @@ -65527,6 +65547,10 @@ msgid "Hook selected vertices to the first selected object" msgstr "Enganxa els vèrtexs seleccionats al primer objecte seleccionat" +msgid "Assign the hook to the hook object's active bone" +msgstr "Assignar el ganxo a l'os actiu de l'objecte ganxo" + + msgctxt "Operator" msgid "Assign to Hook" msgstr "Assignar a ganxo" @@ -66352,11 +66376,11 @@ msgstr " amb grups buits" msgid " With Automatic Weights" -msgstr " amb forces automàtiques" +msgstr " amb pesos automàtics" msgid " With Envelope Weights" -msgstr " amb forces de funda" +msgstr " amb pesos de funda" msgid "Bone Relative" @@ -66384,7 +66408,7 @@ msgstr "Emmirallar X" msgid "Apply weights symmetrically along X axis, for Envelope/Automatic vertex groups creation" -msgstr "Aplica les forces de manera simètrica seguint l'eix X, per la creació de grups de vèrtexs automàtics/de funda" +msgstr "Aplica pesos de manera simètrica seguint l'eix X, per la creació de grups de vèrtexs automàtics/de funda" msgctxt "Operator" @@ -67103,7 +67127,7 @@ msgstr "Netejar morfofites" msgid "Clear weights for all shape keys" -msgstr "Elimina les forces per a totes les morfofites" +msgstr "Elimina els pesos per a totes les morfofites" msgctxt "Operator" @@ -67450,7 +67474,7 @@ msgstr "Assigna els vèrtexs seleccionats a un nou grup de vèrtexs" msgctxt "Operator" msgid "Clean Vertex Group Weights" -msgstr "Neteja forces de grups de vèrtex" +msgstr "Neteja pesos de grups de vèrtex" msgid "Remove vertex group assignments which are not required" @@ -67474,7 +67498,7 @@ msgstr "[Keep Single]: Manté els vèrtexs assignats a almenys un grup quan es n msgid "Remove vertices which weight is below or equal to this limit" -msgstr "Eliminar els vèrtexs la força dels quals és per sota o igual a aquest límit" +msgstr "Eliminar els vèrtexs els pesos dels quals sigui per sota o igual a aquest límit" msgctxt "Operator" @@ -67501,7 +67525,7 @@ msgstr "Corregeix deformació de grup de vèrtexs" msgid "Modify the position of selected vertices by changing only their respective groups' weights (this tool may be slow for many vertices)" -msgstr "[Fix Vertex Group Deform]: Modifica la posició dels vèrtexs seleccionats canviant només les forces respectives (eina que amb molts vèrtexs pot esdevenir lenta)" +msgstr "[Fix Vertex Group Deform]: Modifica la posició dels vèrtexs seleccionats canviant només els pesos respectius (eina que amb molts vèrtexs pot esdevenir lenta)" msgid "Change Sensitivity" @@ -67509,7 +67533,7 @@ msgstr "Canviar sensibilitat" msgid "Change the amount weights are altered with each iteration: lower values are slower" -msgstr "[Change Sensitivity]: Canvia la dimensió de l'alteració de les forces en cada iteració: els valors més baixos són més lents" +msgstr "[Change Sensitivity]: Canvia la dimensió de l'alteració dels pesos en cada iteració: els valors més baixos són més lents" msgid "The distance to move to" @@ -67521,23 +67545,23 @@ msgstr "Aquest multiplicador pot canviar la distància moguda" msgid "Invert active vertex group's weights" -msgstr "Invertir forces de grup de vèrtexs actiu" +msgstr "Invertir pesos de grup de vèrtexs actiu" msgid "Add Weights" -msgstr "Afegir forces" +msgstr "Afegir pesos" msgid "Add vertices from groups that have zero weight before inverting" -msgstr "[Add Weights]: Afegeix vèrtexs des de grups que tenen força zero abans de capgirar" +msgstr "[Add Weights]: Afegeix vèrtexs des de grups que tenen pes zero abans de capgirar" msgid "Remove Weights" -msgstr "Eliminar forces" +msgstr "Eliminar pesos" msgid "Remove vertices from groups that have zero weight after inverting" -msgstr "Elimina els vèrtexs des de grups que tenen força zero després de capgirar" +msgstr "Elimina els vèrtexs des de grups que tenen pes zero després de capgirar" msgctxt "Operator" @@ -67546,28 +67570,28 @@ msgstr "Nivells de grups de vèrtexs" msgid "Add some offset and multiply with some gain the weights of the active vertex group" -msgstr "Afegeix algun desplaçament i multiplica amb alguns guanys les forces del grup de vèrtex actiu" +msgstr "Afegeix algun desplaçament i multiplica amb alguns guanys els pesos del grup de vèrtex actiu" msgid "Value to multiply weights by" -msgstr "Valor a què multiplicar les forces" +msgstr "Valor a què multiplicar els pesos" msgid "Value to add to weights" -msgstr "Valor a sumar a les forces" +msgstr "Valor a sumar als pesos" msgctxt "Operator" msgid "Limit Number of Weights per Vertex" -msgstr "Limitar nombre dìnfluències per vèrtex" +msgstr "Limitar nombre de pesos per vèrtex" msgid "Limit deform weights associated with a vertex to a specified number by removing lowest weights" -msgstr "Limita forces deformadores associades a un vèrtex a un nombre especificat eliminant les forces més baixes" +msgstr "Limita deformacions de pesos associades a un vèrtex a un nombre especificat eliminant els pesos més baixos" msgid "Maximum number of deform weights" -msgstr "Nombre màxim de forces deformadores" +msgstr "Nombre màxim de deformadors de pesos" msgctxt "Operator" @@ -67629,7 +67653,7 @@ msgstr "Emmirallar grup de vèrtexs" msgid "Mirror vertex group, flip weights and/or names, editing only selected vertices, flipping when both sides are selected otherwise copy from unselected" -msgstr "Emmiralla el grup de vèrtexs, capgira les forces i/o els noms, editant només els vèrtexs seleccionats, capgirant quan ambdós costats estan seleccionats, en cas contrari copia des de no seleccionats" +msgstr "Emmiralla el grup de vèrtexs, capgira els pesos i/o els noms, editant només els vèrtexs seleccionats, capgirant quan ambdós costats estan seleccionats, en cas contrari copia des de no seleccionats" msgid "All Groups" @@ -67637,7 +67661,7 @@ msgstr "Tots els grups" msgid "Mirror all vertex groups weights" -msgstr "Emmiralla totes les forces dels grups de vèrtexs" +msgstr "Emmiralla totes els pesos dels grups de vèrtexs" msgid "Flip Group Names" @@ -67649,11 +67673,11 @@ msgstr "Inverteix els noms dels grups de vèrtexs" msgid "Mirror Weights" -msgstr "Influències d'emmirallat" +msgstr "Emmirallar pesos" msgid "Mirror weights" -msgstr "Influències d'emmirallaments" +msgstr "Emmiralla els pesos" msgctxt "Operator" @@ -67666,7 +67690,7 @@ msgstr "Mou el grup de vèrtexs actiu amunt/avall de la llista" msgid "Normalize weights of the active vertex group, so that the highest ones are now 1.0" -msgstr "Normalitzar forces del grup de vèrtexs actiu, de manera que els més alts siguin ara 1.0" +msgstr "Normalitzar pesos del grup de vèrtexs actiu, de manera que els més alts siguin ara 1.0" msgctxt "Operator" @@ -67676,11 +67700,11 @@ msgstr "Normalitzar tots els grups de vèrtexs" msgctxt "Operator" msgid "Quantize Vertex Weights" -msgstr "Quantificar forces de vèrtexs" +msgstr "Quantificar pesos de vèrtexs" msgid "Set weights to a fixed number of steps" -msgstr "Estableix les forces a un nombre fix de passos" +msgstr "Estableix els pesos a un nombre fix de passos" msgid "Number of steps between 0 and 1" @@ -67735,11 +67759,11 @@ msgstr "Grup de vèrtexs a definir com a actiu" msgctxt "Operator" msgid "Smooth Vertex Weights" -msgstr "Suavitzar forces de vèrtexs" +msgstr "Suavitzar pesos de vèrtexs" msgid "Smooth weights for selected vertices" -msgstr "[Smooth Vertex Weights]: Suavitzar forces per als vèrtexs seleccionats" +msgstr "[Smooth Vertex Weights]: Suavitzar pesos per als vèrtexs seleccionats" msgid "Expand/Contract" @@ -67747,7 +67771,7 @@ msgstr "Expandir/Contraure" msgid "Expand/contract weights" -msgstr "[Expand/Contract]: Expandir/contraure forces" +msgstr "[Expand/Contract]: Expandir/contraure pesos" msgctxt "Operator" @@ -67786,24 +67810,24 @@ msgstr "Copiar d'actius" msgid "Copy weights from active to selected" -msgstr "Copiar forces des d'actiu a seleccionat" +msgstr "Copiar pesos des d'actiu a seleccionat" msgctxt "Operator" msgid "Delete Weight" -msgstr "Suprimir força" +msgstr "Suprimir pesos" msgid "Delete this weight from the vertex (disabled if vertex group is locked)" -msgstr "Suprimeix aquesta força del vèrtex (inhabilitat si el grup de vèrtexs està bloquejat)" +msgstr "Suprimeix aquest pes del vèrtex (inhabilitat si el grup de vèrtexs està bloquejat)" msgid "Weight Index" -msgstr "Índex de força" +msgstr "Índex de pesos" msgid "Index of source weight in active vertex group" -msgstr "[Weight Index]: Índex de la força d'origen en el grup de vèrtex actiu" +msgstr "[Weight Index]: Índex dels pesos d'origen en el grup de vèrtex actiu" msgctxt "Operator" @@ -67812,16 +67836,16 @@ msgstr "Normalitzar actius" msgid "Normalize active vertex's weights" -msgstr "[Normalize Active]: Normalitza les forces de vèrtexs actius" +msgstr "[Normalize Active]: Normalitza els pesos de vèrtexs actius" msgctxt "Operator" msgid "Paste Weight to Selected" -msgstr "Enganxar força a la selecció" +msgstr "Enganxar pesos a la selecció" msgid "Copy this group's weight to other selected vertices (disabled if vertex group is locked)" -msgstr "[Paste Weight to Selected]: Copia la força d'aquest grup a altres vèrtexs seleccionats (inhabilitat si el grup de vèrtexs està bloquejat)" +msgstr "[Paste Weight to Selected]: Copia el pes d'aquest grup a altres vèrtexs seleccionats (inhabilitat si el grup de vèrtexs està bloquejat)" msgctxt "Operator" @@ -68405,6 +68429,14 @@ msgid "Library Operation" msgstr "[Outliner Library Operation]: Operació de la biblioteca" +msgid "" +"Delete this library and all its items.\n" +"Warning: No undo" +msgstr "" +"Suprimir aquesta biblioteca i tots els elements que conté.\n" +"Avís: No es pot desfer" + + msgid "Relocate" msgstr "Reubicar" @@ -68823,6 +68855,10 @@ msgid "Add Simple UVs" msgstr "Afegir UVs simples" +msgid "Add cube map UVs on mesh" +msgstr "Afegir UVs de cubografia a la malla" + + msgctxt "Operator" msgid "Add Paint Slot" msgstr "Afegir epígraf de pintat" @@ -69221,11 +69257,11 @@ msgstr "Normalitzar els colors, augmentant el contrast" msgctxt "Operator" msgid "Vertex Color from Weight" -msgstr "Color de vèrtexs des de força" +msgstr "Color de vèrtexs des del pes" msgid "Convert active weight into gray scale vertex colors" -msgstr "[Vertex Color from Weight]: Converteix la força activa en colors de vèrtex d'escala de grisos" +msgstr "[Vertex Color from Weight]: Converteix els pesos actius en colors de vèrtex d'escala de grisos" msgctxt "Operator" @@ -69266,19 +69302,19 @@ msgstr "Revesa el mode de pintat de vèrtex en la vista 3D" msgctxt "Operator" msgid "Weight from Bones" -msgstr "Influència des d'ossos" +msgstr "Pesos des d'ossos" msgid "Set the weights of the groups matching the attached armature's selected bones, using the distance between the vertices and the bones" -msgstr "Determina forces dels grups que aparellen els ossos seleccionats de l'esquelet lligada, utilitzant la distància entre els vèrtexs i els ossos" +msgstr "Determina pesos dels grups que aparellen els ossos seleccionats de l'esquelet lligada, utilitzant la distància entre els vèrtexs i els ossos" msgid "Method to use for assigning weights" -msgstr "Mètode per a assignar forces" +msgstr "Mètode per a assignar pesos" msgid "Automatic weights from bones" -msgstr "Influències automàtiques des dels ossos" +msgstr "Pesos automàtics des dels ossos" msgid "From Envelopes" @@ -69286,48 +69322,48 @@ msgstr "Des de fundes" msgid "Weights from envelopes with user defined radius" -msgstr "[From Envelopes]: Influències usant fundes de radi definit per la usuària" +msgstr "[From Envelopes]: Pesos usant fundes de radi definit per la usuària" msgctxt "Operator" msgid "Weight Gradient" -msgstr "Gradient de força" +msgstr "Gradient de pesos" msgid "Draw a line to apply a weight gradient to selected vertices" -msgstr "[Weight Gradient]: Dibuixa una línia per a aplicar una gradació de força als vèrtexs seleccionats" +msgstr "[Weight Gradient]: Dibuixa una línia per a aplicar una gradació de pesos als vèrtexs seleccionats" msgctxt "Operator" msgid "Weight Paint" -msgstr "Pintat de força" +msgstr "Pintura de pesos" msgid "Paint a stroke in the current vertex group's weights" -msgstr "[Weight Paint]: Pinta un traç en les forces del grup de vèrtexs present" +msgstr "[Weight Paint]: Pinta un traç en els pesos del grup de vèrtexs present" msgctxt "Operator" msgid "Weight Paint Mode" -msgstr "Mode pintat de força" +msgstr "Mode pintura de pesos" msgid "Toggle weight paint mode in 3D view" -msgstr "Revesa el mode de pintura de força en la vista 3D" +msgstr "Revesa el mode de pintura de pesos en la vista 3D" msgctxt "Operator" msgid "Weight Paint Sample Weight" -msgstr "Mostreig de força en pintat d'influència" +msgstr "Mostra de pes de pintura de pesos" msgid "Use the mouse to sample a weight in the 3D view" -msgstr "[Weight Paint Sample Weight]: Utilitza el ratolí per a mostrejar una força en la vista 3D" +msgstr "[Weight Paint Sample Weight]: Utilitza el ratolí per a mostrejar un pes en la vista 3D" msgctxt "Operator" msgid "Weight Paint Sample Group" -msgstr "Grup de mostra de pintat de força" +msgstr "Grup de mostra de pintura de força" msgid "Select one of the vertex groups available under current mouse position" @@ -69336,11 +69372,11 @@ msgstr "Selecciona un dels grups de vèrtexs disponibles sota la posició actual msgctxt "Operator" msgid "Set Weight" -msgstr "Determinar força" +msgstr "Determinar pesos" msgid "Fill the active vertex group with the current paint weight" -msgstr "[Set Weight]: Omple el grup de vèrtexs actiu amb el pintat de força actual" +msgstr "[Set Weight]: Omple el grup de vèrtexs actiu amb la pintura de pesos present" msgctxt "Operator" @@ -69462,7 +69498,7 @@ msgstr "Copia els sistemes de partícules de l'objecte actiu als objectes selecc msgid "Remove Target Particles" -msgstr "Eliminar partícules en referents" +msgstr "Eliminar partícules referents" msgid "Remove particle systems on the target objects" @@ -69556,7 +69592,7 @@ msgstr "Refrescar objectes instància" msgid "Refresh list of instance objects and their weights" -msgstr "Refresca la llista d'objectes instàncies i les forces" +msgstr "Refresca la llista d'objectes instàncies i els pesos" msgctxt "Operator" @@ -69762,15 +69798,15 @@ msgstr "[Unify Length]: Fa el pèl seleccionat de la mateixa longitud" msgctxt "Operator" msgid "Weight Set" -msgstr "Assignar força" +msgstr "Assignar pesos" msgid "Set the weight of selected keys" -msgstr "[Weight Set]: Estableix la força dels nòduls seleccionats" +msgstr "[Weight Set]: Estableix els pesos dels nòduls seleccionats" msgid "Interpolation factor between current brush weight, and keys' weights" -msgstr "Factor d'interpolació entre la força del pinzell actual i la força dels nòduls" +msgstr "Factor d'interpolació entre els pesos del pinzell actual i la força dels nòduls" msgctxt "Operator" @@ -69951,7 +69987,7 @@ msgstr "Propietats personalitzades" msgid "Weighting factor for which keyframe is favored more" -msgstr "Factor força per a la fotofita més afavorida" +msgstr "Factor de ponderació per a la fotofita més afavorida" msgid "Next Keyframe" @@ -71286,8 +71322,8 @@ msgid "Fill Range by Selection" msgstr "Emplenar interval per selecció" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Omple les entrades mín/màx de l'interval amb la distància mín/màx entre els objectes de malla seleccionats i l'objecte d'origen" +msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object (either a user-specified object or the active camera)" +msgstr "Emplena les entrades de l'interval mín/màx amb la distància mín/màx entre els objectes de malla seleccionats i l'objecte d'origen (o bé un objecte especificat per la usuària o la càmera activa)" msgid "Name of the modifier to work on" @@ -72136,16 +72172,16 @@ msgstr "Experimental" msgctxt "Operator" msgid "Cycle Workspace" -msgstr "Ciclar espai de treball" +msgstr "Ciclitzar obradors" msgid "Cycle through workspaces" -msgstr "[Cycle Workspace]: Recorre en cicle els espais de treball" +msgstr "[Cycle Workspace]: Recorre en cicle els obradors" msgctxt "Operator" msgid "Execute a Python Preset" -msgstr "Executar predefinit en Python" +msgstr "Executar predefinit en python" msgid "Load a preset" @@ -72162,11 +72198,11 @@ msgstr "Nom d'ID del menú des del qual s'ha cridat" msgctxt "Operator" msgid "Run Python File" -msgstr "Executar document Python" +msgstr "Executar document python" msgid "Run Python file" -msgstr "Executa el document Python" +msgstr "Executa el document python" msgctxt "Operator" @@ -72711,11 +72747,11 @@ msgstr "Crea conjunts de cares usant les arestes retingudes com a límits" msgid "Face Sets from Bevel Weight" -msgstr "Conjunts de cares des de força de bisell" +msgstr "Conjunts de cares des de pes de bisell" msgid "Create Face Sets using Bevel Weights as boundaries" -msgstr "Crea conjunts de cares usant forces de bisells com a límits" +msgstr "Crea conjunts de cares usant pesos de bisells com a límits" msgid "Face Sets from Sharp Edges" @@ -73595,7 +73631,7 @@ msgstr "Definir segments seleccionats com simulacions" msgid "Enable selected proxies on all selected Movie and Image strips" -msgstr "[Set Selected Strip Proxies]: Activa els intercessors seleccionats en tots els segments d'imatges i pel·lícules" +msgstr "[Set Selected Strip Proxies]: Activa les simulacions seleccionades en tots els segments d'imatges i pel·lícules" msgctxt "Operator" @@ -75248,11 +75284,11 @@ msgstr "Suprimeix l'orientació de transformació" msgctxt "Operator" msgid "Edge Bevel Weight" -msgstr "Força de bisellat d'aresta" +msgstr "Pesos de bisellat d'aresta" msgid "Change the bevel weight of edges" -msgstr "Canvia la força la força de bisell de les vores" +msgstr "Canvia els pesos de bisell d'arestes" msgctxt "Operator" @@ -75710,11 +75746,11 @@ msgstr "Copiar camí de dades sencer" msgctxt "Operator" msgid "Copy Python Command" -msgstr "Copiar ordre Python" +msgstr "Copiar ordre python" msgid "Copy the Python command matching this button" -msgstr "Copia l'ordre Python que coincideix amb aquest botó" +msgstr "Copia l'ordre python que coincideix amb aquest botó" msgctxt "Operator" @@ -76028,7 +76064,7 @@ msgstr "Mostra un bloc de dades des de la vista 3D per a emmagatzemar en una pro msgctxt "Operator" msgid "I18n Add-on Export" -msgstr "Exportació de complement I18n" +msgstr "Exportació de complement i18n" msgid "Export given add-on's translation data as PO files" @@ -76057,7 +76093,7 @@ msgstr "Actualitza els documents PO existents, si n'hi ha, en lloc de sobreescri msgctxt "Operator" msgid "I18n Add-on Import" -msgstr "Importar complement I18n" +msgstr "Importar complement i18n" msgid "Import given add-on's translation data from PO files" @@ -76066,7 +76102,7 @@ msgstr "[I18n Add-on Import]: Importa les dades de traducció del complement ind msgctxt "Operator" msgid "Update I18n Add-on" -msgstr "Actualitzar complement I18n" +msgstr "Actualitzar complement i18n" msgid "Wrapper operator which will invoke given op after setting its module_name" @@ -76087,7 +76123,7 @@ msgstr "Actualitza les dades de traducció del complement referit (que es troben msgctxt "Operator" msgid "Clean up I18n Branches" -msgstr "Netejar branques d'I18n" +msgstr "Netejar branques d'i18n" msgid "Clean up i18n svn's branches (po files)" @@ -76105,7 +76141,7 @@ msgstr "Intenta «compilar» el document PO indicat en el document corresponent msgctxt "Operator" msgid "I18n Load Settings" -msgstr "Paràmetres de càrrega d'I18n" +msgstr "Paràmetres de càrrega d'i18n" msgid "Load translations' settings from a persistent JSon file" @@ -76118,7 +76154,7 @@ msgstr "Camí al document de configuració desat" msgctxt "Operator" msgid "I18n Save Settings" -msgstr "Paràmetres de desat d'I18n" +msgstr "Paràmetres de desat d'i18n" msgid "Save translations' settings in a persistent JSon file" @@ -76127,7 +76163,7 @@ msgstr "Desa la configuració de les traduccions en un document JSon persistent" msgctxt "Operator" msgid "Update I18n Branches" -msgstr "Actualitzar branques d'I18n" +msgstr "Actualitzar branques d'i18n" msgid "Update i18n svn's branches (po files)" @@ -76144,7 +76180,7 @@ msgstr "[Skip POT]: Omet la generació de documents POT" msgctxt "Operator" msgid "Init I18n Update Settings" -msgstr "Paràmetres d'actualització d'I18n d'inici" +msgstr "Paràmetres d'actualització d'i18n d'inici" msgid "Init settings for i18n svn's update operators" @@ -76153,7 +76189,7 @@ msgstr "Configuració d'inici per als operadors d'actualització de l'SVN i18n" msgctxt "Operator" msgid "Init I18n Update Select Languages" -msgstr "Iniciar actualització d'I18n en llengües seleccionades" +msgstr "Iniciar actualització d'i18n en llengües seleccionades" msgid "(De)select (or invert selection of) all languages for i18n svn's update operators" @@ -76178,7 +76214,7 @@ msgstr "Ho selecciona tot si és ver, en cas contrari ho desselecciona tot" msgctxt "Operator" msgid "Update I18n Statistics" -msgstr "Actualitzar estadístiques d'I18n" +msgstr "Actualitzar estadístiques d'i18n" msgid "Create or extend a 'i18n_info.txt' Text datablock" @@ -76203,7 +76239,7 @@ msgstr "[Check Trunk]: Comprova els documents PO troncals" msgctxt "Operator" msgid "Update I18n Trunk" -msgstr "Actualitzar troncal I18n" +msgstr "Actualitzar troncal i18n" msgctxt "Operator" @@ -76393,6 +76429,10 @@ msgid "Align Rotation" msgstr "Alinear rotació" +msgid "Align the UV island's rotation" +msgstr "Alinea la rotació d'illa d'UV" + + msgid "Axis to align to" msgstr "Eix al qual alinear" @@ -76841,6 +76881,10 @@ msgid "Use orthographic projection" msgstr "Usar projecció ortogràfica" +msgid "Randomize the UV island's location, rotation, and scale" +msgstr "Aleatoritzar ubicació, rotació i escala de l'illa UV" + + msgid "Maximum rotation" msgstr "Rotació màxima" @@ -76859,7 +76903,7 @@ msgstr "Fusionar UVs segons distància" msgid "Selected UV vertices that are within a radius of each other are welded together" -msgstr "Als vèrtexs UV seleccionats que estan dins d'un radi l'un de l'altre se'ls solda junts" +msgstr "[Merge UVs by Distance]: Als vèrtexs UV seleccionats que estan dins d'un radi l'un de l'altre se'ls solda junts" msgid "Maximum distance between welded vertices" @@ -76879,6 +76923,321 @@ msgid "Reveal all hidden UV vertices" msgstr "Evidenciar tots els vèrtexs UV ocults" +msgctxt "Operator" +msgid "UV Rip" +msgstr "Arrencar UV" + + +msgid "Rip selected vertices or a selected region" +msgstr "[UV Rip]: Arrenca els vèrtexs seleccionats o una regió seleccionada" + + +msgctxt "Operator" +msgid "UV Rip Move" +msgstr "More UV arrencat" + + +msgid "Unstitch UVs and move the result" +msgstr "Descus els UVs i mou el resultat" + + +msgid "UV Rip" +msgstr "Arrencar UV" + + +msgctxt "Operator" +msgid "Seams from Islands" +msgstr "Costures d'illes" + + +msgid "Set mesh seams according to island setup in the UV editor" +msgstr "Estableix les costures de malla segons la configuració de l'illa a l'editor UV" + + +msgid "Mark boundary edges as seams" +msgstr "Marcar arestes de límits com a costures" + + +msgid "Mark boundary edges as sharp" +msgstr "Marcar arestes de límits com a agudes" + + +msgid "Select UV vertices" +msgstr "Selecció de vèrtexs UV" + + +msgid "Change selection of all UV vertices" +msgstr "Canvia la selecció de tots els vèrtexs UV" + + +msgid "Select UV vertices using box selection" +msgstr "Seleccionar vèrtexs UV amb la selecció de caixa" + + +msgid "Pinned" +msgstr "Fixats" + + +msgid "Border select pinned UVs only" +msgstr "Selecció de límit selecciona només UVs fixats" + + +msgid "Select UV vertices using circle selection" +msgstr "Seleccionar vèrtexs UV amb selecció de cercle" + + +msgid "Select an edge ring of connected UV vertices" +msgstr "Seleccionar un anell d'arestes de vèrtexs UV connectats" + + +msgctxt "Operator" +msgid "Lasso Select UV" +msgstr "Llaç de selecció UV" + + +msgid "Select UVs using lasso selection" +msgstr "[Lasso Select UV]: Selecciona UVs amb la selecció per llaç" + + +msgid "Deselect UV vertices at the boundary of each selection region" +msgstr "Desselecciona els vèrtexs UV al límit de cada regió de selecció" + + +msgid "Select all UV vertices linked to the active UV map" +msgstr "Seleccionar tots els vèrtexs UV enllaçats al mapa UV actiu" + + +msgid "Select all UV vertices linked under the mouse" +msgstr "Seleccionar tots els vèrtexs UV enllaçats sota el ratolí" + + +msgid "Deselect linked UV vertices rather than selecting them" +msgstr "Desseleccionar els vèrtexs UV enllaçats en lloc de seleccionar-los" + + +msgid "Select a loop of connected UV vertices" +msgstr "Seleccionar una anella de vèrtexs UV connectats" + + +msgctxt "Operator" +msgid "UV Select Mode" +msgstr "Mode de selecció UV" + + +msgid "Change UV selection mode" +msgstr "Canvia el mode de selecció UV" + + +msgid "Island" +msgstr "Illa" + + +msgid "Island selection mode" +msgstr "[Island]: Mode de selecció illa" + + +msgid "Select more UV vertices connected to initial selection" +msgstr "Seleccionar més vèrtexs UV connectats a la selecció inicial" + + +msgctxt "Operator" +msgid "Select Overlap" +msgstr "[Select Overlap]: Seleccionar superposició" + + +msgid "Select all UV faces which overlap each other" +msgstr "Selecciona totes les cares UV que se superposen entre elles" + + +msgctxt "Operator" +msgid "Selected Pinned" +msgstr "Seleccionar fixats" + + +msgid "Select all pinned UV vertices" +msgstr "Selecciona tots els vèrtexs UV fixats" + + +msgid "Select similar UVs by property types" +msgstr "Seleccionar UVs similars per tipus de propietat" + + +msgctxt "Operator" +msgid "Select Split" +msgstr "Dividir selecció" + + +msgid "Select only entirely selected faces" +msgstr "[Select Split]: Selecciona només les cares completament seleccionades" + + +msgctxt "Operator" +msgid "Smart UV Project" +msgstr "Projecte UV llest" + + +msgid "Projection unwraps the selected faces of mesh objects" +msgstr "[Smart UV Project]: La projecció desembolcalla les cares seleccionades dels objectes malla" + + +msgid "Lower for more projection groups, higher for less distortion" +msgstr "Més baix per més grups de projecció, més alt per menys distorsió" + + +msgid "Area Weight" +msgstr "Pes d'àrea" + + +msgid "Weight projection's vector by faces with larger areas" +msgstr "[Area Weight]: Vector de projecció de pesos per part de cares amb àrees més grans" + + +msgid "Island Margin" +msgstr "Marge d'illa" + + +msgid "Margin to reduce bleed from adjacent islands" +msgstr "[Island Margin]: Marge per a reduir el sobreeixit d'illes adjacents" + + +msgctxt "Operator" +msgid "Snap Cursor" +msgstr "Acoblar cursor" + + +msgid "Snap cursor to target type" +msgstr "Atrapa el cursor al tipus de referència" + + +msgid "Target to snap the selected UVs to" +msgstr "Referència a què acoblar els UVs seleccionats" + + +msgctxt "Operator" +msgid "Snap Selection" +msgstr "Acoblar selecció" + + +msgid "Snap selected UV vertices to target type" +msgstr "[Snap Selection]: Atrapa els vèrtexs UV seleccionats al tipus de referència" + + +msgid "Cursor (Offset)" +msgstr "Cursor (separació)" + + +msgid "Adjacent Unselected" +msgstr "Adjacents desseleccionats" + + +msgctxt "Operator" +msgid "Sphere Projection" +msgstr "Projecció d'esfera" + + +msgid "Project the UV vertices of the mesh over the curved surface of a sphere" +msgstr "Projecta els vèrtexs UV de la malla sobre la superfície corba d'una esfera" + + +msgctxt "Operator" +msgid "Stitch" +msgstr "Cosir" + + +msgid "Stitch selected UV vertices by proximity" +msgstr "[Stitch]: Cus els vèrtexs UV seleccionats per proximitat" + + +msgid "Index of the active object" +msgstr "Índex de l'objecte actiu" + + +msgid "Clear seams of stitched edges" +msgstr "Descarta costures d'arestes cosides" + + +msgid "Limit distance in normalized coordinates" +msgstr "Limitar distància en coordenades normalitzades" + + +msgid "Snap at Midpoint" +msgstr "Acoblar a mig camí" + + +msgid "UVs are stitched at midpoint instead of at static island" +msgstr "Es cusen els UVs al punt mig en lloc d'a l'illa estàtica" + + +msgid "Operation Mode" +msgstr "Mode operació" + + +msgid "Use vertex or edge stitching" +msgstr "Usar cosit de vèrtexs o arestes" + + +msgid "Objects Selection Count" +msgstr "Recompte d'objectes seleccionats" + + +msgid "Snap Islands" +msgstr "Acoblar illes" + + +msgid "Snap islands together (on edge stitch mode, rotates the islands too)" +msgstr "[Snap Islands]: Ajunta les illes (en el mode de cosir arestes, també rota les illes)" + + +msgid "Static Island" +msgstr "Illa estàtica" + + +msgid "Island that stays in place when stitching islands" +msgstr "Illa que es manté al seu lloc quan s'estan cosint illes" + + +msgid "Stored Operation Mode" +msgstr "Mode operació emmagatzemada" + + +msgid "Use Limit" +msgstr "Usar límit" + + +msgid "Stitch UVs within a specified limit distance" +msgstr "[Use Limit]: Cus UVs dins d'una distància límit especificada" + + +msgctxt "Operator" +msgid "Unwrap" +msgstr "Desembocallar" + + +msgid "Unwrap the mesh of the object being edited" +msgstr "[Unwrap]: Desplega la malla de l'objecte en edició" + + +msgid "Unwrapping method (Angle Based usually gives better results than Conformal, while being somewhat slower)" +msgstr "Mètode de desembolcallat (el Basat en l'angle normalment dona millors resultats que el Conformal, tot i ser una mica més lent)" + + +msgid "Use Subdivision Surface" +msgstr "Usar subdivisió de superfície" + + +msgid "Map UVs taking vertex position after Subdivision Surface modifier has been applied" +msgstr "[Use Subdivision Surface]: Mapeja UVs prenent la posició del vèrtex després d'aplicar el modificador de superfície de subdivisió" + + +msgctxt "Operator" +msgid "Weld" +msgstr "Soldar" + + +msgid "Weld selected UV vertices together" +msgstr "[Weld]: Solda els vèrtexs UV seleccionats" + + msgctxt "Operator" msgid "View Edge Pan" msgstr "Visualitzar escombratge de vora" @@ -76888,104 +77247,8088 @@ msgid "Pan the view when the mouse is held at an edge" msgstr "Escombratge de l'escena quan el ratolí es manté en una vora" +msgid "Delta X" +msgstr "Delta X" + + +msgid "Delta Y" +msgstr "Delta Y" + + +msgctxt "Operator" +msgid "Reset View" +msgstr "Reiniciar vista" + + +msgid "Reset the view" +msgstr "Reinicia la visualització" + + +msgctxt "Operator" +msgid "Scroll Down" +msgstr "Rodolar avall" + + +msgid "Scroll the view down" +msgstr "Desplaça la vista cap avall" + + +msgid "Page" +msgstr "Pàgina" + + +msgid "Scroll down one page" +msgstr "Desplaça avall una pàgina" + + +msgctxt "Operator" +msgid "Scroll Left" +msgstr "Rodolar a esquerra" + + +msgid "Scroll the view left" +msgstr "Desplaça la vista cap a l'esquerra" + + +msgctxt "Operator" +msgid "Scroll Right" +msgstr "Rodolar a dreta" + + +msgid "Scroll the view right" +msgstr "Desplaça la vista cap a la dreta" + + +msgctxt "Operator" +msgid "Scroll Up" +msgstr "Rodolar amunt" + + +msgid "Scroll the view up" +msgstr "Desplaça la vista cap amunt" + + +msgctxt "Operator" +msgid "Scroller Activate" +msgstr "Activar rodolador" + + +msgid "Scroll view by mouse click and drag" +msgstr "Visualització de rodolat amb clic i rossec del ratolí" + + +msgctxt "Operator" +msgid "Smooth View 2D" +msgstr "Suavitzar vista 2D" + + +msgctxt "Operator" +msgid "Zoom 2D View" +msgstr "Ampliar vista 2D" + + +msgid "Zoom Factor X" +msgstr "Factor d'ampliació X" + + +msgid "Zoom Factor Y" +msgstr "Factor d'ampliació Y" + + +msgctxt "Operator" +msgid "New Camera from VR Landmark" +msgstr "Càmera nova de marca RV" + + +msgid "Create a new Camera from the selected VR Landmark" +msgstr "[New Camera from VR Landmark]: Crea una càmera nova a partir de la marca de terme d'RV seleccionada" + + +msgctxt "Operator" +msgid "Add Background Image" +msgstr "Afegir imatge rerefons" + + +msgid "Add a new background image" +msgstr "Afegeix una imatge de fons nova" + + +msgctxt "Operator" +msgid "Remove Background Image" +msgstr "Eliminar imatge rerefons" + + +msgid "Remove a background image from the 3D view" +msgstr "Suprimeix una imatge de fons de la vista 3D" + + +msgid "Background image index to remove" +msgstr "Índex de la imatge rerefons a eliminar" + + +msgctxt "Operator" +msgid "Select Menu" +msgstr "Menú de selecció" + + +msgid "Menu bone selection" +msgstr "Selecció d'os amb menú" + + +msgctxt "Operator" +msgid "Align Camera to View" +msgstr "Alinear càmera a vista" + + +msgid "Set camera view to active view" +msgstr "Estableix la vista de la càmera com a vista activa" + + +msgctxt "Operator" +msgid "Camera Fit Frame to Selected" +msgstr "Enquadrar càmera a selecció" + + +msgid "Move the camera so selected objects are framed" +msgstr "Mou la càmera perquè els objectes seleccionats hi quedin enquadrats" + + +msgctxt "Operator" +msgid "Scene Camera to VR Landmark" +msgstr "Càmera d'escena a marca d'RV" + + +msgid "Position the scene camera at the selected landmark" +msgstr "Col·loca la càmera de l'escena a la marca de terme seleccionada" + + +msgid "Clear the boundaries of the border render and disable border render" +msgstr "Descartar els límits del revelat de vora i desactivar revelat de vora" + + +msgctxt "Operator" +msgid "Clipping Region" +msgstr "Segar regió" + + +msgid "Set the view clipping region" +msgstr "[Clipping Region]: Estableix la regió amb visualització segada" + + +msgctxt "Operator" +msgid "Copy Objects" +msgstr "Copiar objectes" + + +msgid "Selected objects are copied to the clipboard" +msgstr "Els objectes seleccionats es copien al porta-retalls" + + +msgctxt "Operator" +msgid "Set 3D Cursor" +msgstr "Ubicar cursor 3D" + + +msgid "Set the location of the 3D cursor" +msgstr "Estableix la ubicació del cursor 3D" + + +msgid "Preset viewpoint to use" +msgstr "Punt de vista predefinit a usar" + + +msgid "Leave orientation unchanged" +msgstr "Deixar orientació invariada" + + +msgid "Orient to the viewport" +msgstr "Orientar al mirador" + + +msgid "Orient to the current transform setting" +msgstr "Orienta al paràmetre de transformació actual" + + +msgid "Match the surface normal" +msgstr "Igualar normal de superfície" + + +msgid "Surface Project" +msgstr "Projecció de superfície" + + +msgid "Project onto the surface" +msgstr "Projecció a la superfície" + + +msgctxt "Operator" +msgid "Cursor to VR Landmark" +msgstr "Cursor a marca d'RV" + + +msgid "Move the 3D Cursor to the selected VR Landmark" +msgstr "Mou el cursor 3D a la marca de terme d'RV seleccionada" + + +msgctxt "Operator" +msgid "Dolly View" +msgstr "Visió de dolly" + + +msgid "Dolly in/out in the view" +msgstr "La dolly va/torna en la visualització" + + +msgid "Region Position X" +msgstr "Posició de regió X" + + +msgid "Region Position Y" +msgstr "Posició de regió Y" + + +msgctxt "Operator" +msgid "Drop World" +msgstr "Llançar món" + + +msgid "Drop a world into the scene" +msgstr "Deixa caure un món dins l'escena" + + +msgctxt "Operator" +msgid "Extrude Individual and Move" +msgstr "Extrudir individu i moure'l" + + +msgctxt "Operator" +msgid "Extrude Manifold Along Normals" +msgstr "Extrudir polivalents seguint normals" + + +msgid "Extrude manifold region along normals" +msgstr "Extrudeix regió polivalent seguint les normals" + + +msgctxt "Operator" +msgid "Extrude and Move on Normals" +msgstr "Extrudir i moure en normals" + + +msgid "Dissolves adjacent faces and intersects new geometry" +msgstr "Dissol les cares adjacents i interseca la nova geometria" + + +msgctxt "Operator" +msgid "Extrude and Move on Individual Normals" +msgstr "Extrudir i moure en normals individuals" + + +msgctxt "Operator" +msgid "Fly Navigation" +msgstr "Navegació de vol" + + +msgid "Interactively fly around the scene" +msgstr "Vola interactivament per l'escena" + + +msgctxt "Operator" +msgid "Add Primitive Object" +msgstr "Afegir objecte primitiu" + + +msgid "Interactively add an object" +msgstr "Afegeix un objecte interactivament" + + +msgid "The initial aspect setting" +msgstr "La configuració inicial d'aspecte" + + +msgid "Use an unconstrained aspect" +msgstr "Usar un aspecte no restringit" + + +msgid "Use a fixed 1:1 aspect" +msgstr "Usar un aspecte fix 1:1" + + +msgid "Plane Axis" +msgstr "Eix de pla" + + +msgid "The axis used for placing the base region" +msgstr "L'eix utilitzat per a col·locar la regió base" + + +msgid "Auto Axis" +msgstr "Eix automàtic" + + +msgid "Select the closest axis when placing objects (surface overrides)" +msgstr "[Auto Axis]: Selecciona l'eix més proper en col·locar objectes (sobreseïments de superfície)" + + +msgid "The initial depth used when placing the cursor" +msgstr "La profunditat inicial usada en col·locar el cursor" + + +msgid "Start placing on the surface, using the 3D cursor position as a fallback" +msgstr "Començar tot col·locant a la superfície, usant la posició del cursor 3D com a alternativa" + + +msgid "Cursor Plane" +msgstr "Pla del cursor" + + +msgid "Start placement using a point projected onto the orientation axis at the 3D cursor position" +msgstr "Comença la col·locació a partir d'un punt projectat sobre l'eix d'orientació en la posició del cursor 3D" + + +msgid "Cursor View" +msgstr "Visualització de cursor" + + +msgid "Start placement using a point projected onto the view plane at the 3D cursor position" +msgstr "Comença la col·locació a partir d'un punt projectat al pla de visualització en la posició del cursor 3D" + + +msgid "Use the surface normal (using the transform orientation as a fallback)" +msgstr "Usar normal de superfície (usant l'orientació de transformació com a darrer recurs)" + + +msgid "Use the current transform orientation" +msgstr "Usar l'orientació de transformació actual" + + +msgid "The initial position for placement" +msgstr "La posició inicial per a la col·locació" + + +msgid "Start placing the edge position" +msgstr "Comença a col·locar la ubicació d'aresta" + + +msgid "Start placing the center position" +msgstr "Comença a col·locar la ubicació central" + + +msgid "ICO Sphere" +msgstr "Esfera Ico" + + +msgid "Snap to" +msgstr "Acoblar a" + + +msgid "The target to use while snapping" +msgstr "[Snap to]: Referent de l'acoblament" + + +msgid "Snap to all geometry" +msgstr "Acoblar a tota la geometria" + + +msgid "Use the current snap settings" +msgstr "Usar la configuració actual d'acoblament" + + +msgctxt "Operator" +msgid "Local View" +msgstr "Vista local" + + +msgid "Toggle display of selected object(s) separately and centered in view" +msgstr "Revesa la visualització dels objectes seleccionats separadament i centrats a la vista" + + +msgid "Frame Selected" +msgstr "Enquadrar seleccionats" + + +msgid "Move the view to frame the selected objects" +msgstr "[Frame Selected]: Mou la visualització per enquadrar els objectes seleccionats" + + +msgctxt "Operator" +msgid "Remove from Local View" +msgstr "Treure de la vista local" + + +msgid "Move selected objects out of local view" +msgstr "Mou els objectes seleccionats fora de la vista local" + + +msgid "Move the view" +msgstr "Mou la visualització" + + +msgctxt "Operator" +msgid "View Navigation (Walk/Fly)" +msgstr "Navegació de Visualització (a peu/volant)" + + +msgid "Interactively navigate around the scene (uses the mode (walk/fly) preference)" +msgstr "[View Navigation (Walk/Fly)]: Navega interactivament per l'escena (utilitza la preferència de mode (a peu/volant))" + + +msgctxt "Operator" +msgid "NDOF Transform View" +msgstr "Transformació de visualització NDOF" + + msgid "Pan and rotate the view with the 3D mouse" -msgstr "Escombratge i rotació d'escena amb el ratolí 3D" +msgstr "[NDOF Transform View]: Escombra i rota la vista amb el ratolí 3D" + + +msgctxt "Operator" +msgid "NDOF Orbit View" +msgstr "Visualització orbital NDOF" + + +msgid "Orbit the view using the 3D mouse" +msgstr "Orbita la visualització amb el ratolí 3D" + + +msgctxt "Operator" +msgid "NDOF Orbit View with Zoom" +msgstr "Vista orbital i zoom NDOF" + + +msgid "Orbit and zoom the view using the 3D mouse" +msgstr "Moviment orbital i d'ampliació amb el ratolí 3D" msgctxt "Operator" msgid "NDOF Pan View" -msgstr "Vista escombratge NDOF" +msgstr "Visualització d'escombratge NDOF" msgid "Pan the view with the 3D mouse" -msgstr "Escombratge de l'escena amb el ratolí 3D" +msgstr "[NDOF Pan View]: Escombratge d'escena amb el ratolí 3D" + + +msgctxt "Operator" +msgid "Set Active Object as Camera" +msgstr "Configura l'objecte actiu com a càmera" + + +msgid "Set the active object as the active camera for this view or scene" +msgstr "Estableix l'objecte actiu com a càmera activa per a aquesta vista o escena" + + +msgctxt "Operator" +msgid "Object Mode Menu" +msgstr "Menú de mode objecte" + + +msgctxt "Operator" +msgid "Paste Objects" +msgstr "Enganxar objectes" + + +msgid "Objects from the clipboard are pasted" +msgstr "S'enganxen els objectes del porta-retalls" + + +msgid "Put pasted objects in the active collection" +msgstr "Posar objectes enganxats dins la col·lecció activa" + + +msgid "Select pasted objects" +msgstr "Seleccionar objectes enganxats" + + +msgctxt "Operator" +msgid "Set Render Region" +msgstr "Definir regió de revelat" + + +msgid "Set the boundaries of the border render and enable border render" +msgstr "[Set Render Region]: Defineix els límits del revelat de vora i activa el revelat de vora" + + +msgctxt "Operator" +msgid "Rotate View" +msgstr "Rotar visualització" + + +msgid "Rotate the view" +msgstr "Fa rotar la vista" + + +msgctxt "Operator" +msgid "Ruler Add" +msgstr "Afegir regle" + + +msgid "Add ruler" +msgstr "Afegeix un regle" + + +msgctxt "Operator" +msgid "Ruler Remove" +msgstr "Eliminar regle" + + +msgid "Select and activate item(s)" +msgstr "Seleccionar i activar element(s)" + + +msgid "Enumerate" +msgstr "Enumerar" + + +msgid "List objects under the mouse (object mode only)" +msgstr "Llistar els objectes de sota el ratolí (només en mode objecte)" + + +msgid "Use object selection (edit mode only)" +msgstr "Usar la selecció d'objectes (només en mode edició)" + + +msgid "Control Point Without Handles" +msgstr "Punt de control sense anses" + + +msgid "Only select the curve control point, not its handles" +msgstr "Selecciona només el punt de control i no les nanses de la corba" + + +msgid "Select items using box selection" +msgstr "Seleccionar elements usant selecció de caixa" + + +msgid "Select items using circle selection" +msgstr "Seleccionar elements usant selecció de cercle" + + +msgid "Select items using lasso selection" +msgstr "Seleccionar elements usant selecció de llaç" + + +msgid "Menu object selection" +msgstr "Menú selecció d'objectes" + + +msgid "Object Name" +msgstr "Nom d'objecte" + + +msgctxt "Operator" +msgid "Smooth View" +msgstr "Suavitzar visualització" + + +msgctxt "Operator" +msgid "Snap Cursor to Active" +msgstr "Acoblar cursor a actiu" + + +msgid "Snap 3D cursor to the active item" +msgstr "Lliga el cursor 3D a l'element actiu" + + +msgctxt "Operator" +msgid "Snap Cursor to World Origin" +msgstr "Acoblar cursor a origen mundial" + + +msgid "Snap 3D cursor to the world origin" +msgstr "Lliga el cursor 3D a l'origen del món" + + +msgctxt "Operator" +msgid "Snap Cursor to Grid" +msgstr "Acoblar cursor a graella" + + +msgid "Snap 3D cursor to the nearest grid division" +msgstr "Lliga el cursor 3D a la divisió de quadrícula més pròxima" + + +msgctxt "Operator" +msgid "Snap Cursor to Selected" +msgstr "Acoblar cursor a selecció" + + +msgid "Snap 3D cursor to the middle of the selected item(s)" +msgstr "Lliga el cursor 3D al centre dels elements seleccionats" + + +msgctxt "Operator" +msgid "Snap Selection to Active" +msgstr "Acoblar selecció a actiu" + + +msgid "Snap selected item(s) to the active item" +msgstr "Lliga els elements seleccionats a l'element actiu" + + +msgid "Snap selected item(s) to the 3D cursor" +msgstr "Acoblar els elements seleccionats al cursor 3D" + + +msgid "If the selection should be snapped as a whole or by each object center" +msgstr "Si la selecció s'ha d'acoblar com un tot o per cada centre de l'objecte" + + +msgid "Snap selected item(s) to their nearest grid division" +msgstr "Acoblar els elements seleccionats a la seva divisió de quadrícula més pròxima" + + +msgctxt "Operator" +msgid "Flip MatCap" +msgstr "Invertir matcap" + + +msgid "Flip MatCap" +msgstr "Inverteix un matcap" + + +msgctxt "Operator" +msgid "Toggle Shading Type" +msgstr "Revesar tipus d'aspector" + + +msgid "Toggle shading type in 3D viewport" +msgstr "Alterna el tipus d'aspector al mirador 3D" + + +msgid "Shading type to toggle" +msgstr "Tipus d'aspector a revesar" + + +msgid "Toggle wireframe shading" +msgstr "Revesar aspecció de filat" + + +msgid "Toggle solid shading" +msgstr "Revesar aspecció sòlida" + + +msgid "Material Preview" +msgstr "Previsualitzar material" + + +msgid "Toggle material preview shading" +msgstr "Alterna la previsualització d'aspecció de material" + + +msgid "Toggle rendered shading" +msgstr "Revesar aspecció de revelat" + + +msgctxt "Operator" +msgid "Toggle X-Ray" +msgstr "Revesar raigs-X" + + +msgid "Transparent scene display. Allow selecting through items" +msgstr "Mostra l'escena transparent. Es pot seleccionar a través d'elements" + + +msgctxt "Operator" +msgid "Transform Gizmo Set" +msgstr "Configurar Transformació de flòstic" + + +msgid "Set the current transform gizmo" +msgstr "[Transform Gizmo Set]: Estableix el flòstic de transformació actual" + + +msgctxt "Operator" +msgid "Update Custom VR Landmark" +msgstr "Actualitzar marques personalitzades d'RV" + + +msgid "Update the selected landmark from the current viewer pose in the VR session" +msgstr "[Update Custom VR Landmark]: Actualitza la marca de terme seleccionada des de la posa de visualització present en la sessió d'EV" + + +msgid "View all objects in scene" +msgstr "Visualitzar tots els objectes en escena" + + +msgid "All Regions" +msgstr "Totes les regions" + + +msgid "View selected for all regions" +msgstr "Visualitza els seleccionats de totes les regions" + + +msgctxt "Operator" +msgid "View Axis" +msgstr "Visualitzar eix" + + +msgid "Use a preset viewpoint" +msgstr "Utilitza un punt de vista predefinit" + + +msgid "Align Active" +msgstr "Alinear a actiu" + + +msgid "Align to the active object's axis" +msgstr "[Align Active]: Alinea a l'eix de l'objecte actiu" + + +msgid "Rotate relative to the current orientation" +msgstr "Rotar en relació a l'orientació actual" + + +msgctxt "View3D" +msgid "View" +msgstr "Visualització" + + +msgctxt "View3D" +msgid "Left" +msgstr "Esquerra" + + +msgid "View from the left" +msgstr "Vista des de l'esquerra" + + +msgctxt "View3D" +msgid "Right" +msgstr "Dreta" + + +msgid "View from the right" +msgstr "Vista des de la dreta" + + +msgctxt "View3D" +msgid "Bottom" +msgstr "Part inferior" + + +msgid "View from the bottom" +msgstr "Visualitza des de baix" + + +msgctxt "View3D" +msgid "Top" +msgstr "Part superior" + + +msgid "View from the top" +msgstr "Vista des de dalt" + + +msgctxt "View3D" +msgid "Front" +msgstr "Frontal" + + +msgid "View from the front" +msgstr "Vista des del davant" + + +msgctxt "View3D" +msgid "Back" +msgstr "Darrere" + + +msgid "View from the back" +msgstr "Vista des del darrere" + + +msgctxt "Operator" +msgid "View Camera" +msgstr "Visualització de càmera" + + +msgid "Toggle the camera view" +msgstr "Alterna la vista de la càmera" + + +msgctxt "Operator" +msgid "Frame Camera Bounds" +msgstr "Enquadrar límits de càmera" + + +msgid "Center the camera view, resizing the view to fit its bounds" +msgstr "[Frame Camera Bounds]: Centra la visualització de la càmera, redimensionant la vista per ajustar-la als seus límits" + + +msgctxt "Operator" +msgid "View Lock Center" +msgstr "Centrar bloqueig de visualització" + + +msgid "Center the view lock offset" +msgstr "[View Lock Center]: Centra el desplaçament del bloqueig de visualització" + + +msgctxt "Operator" +msgid "Center View to Mouse" +msgstr "Centrar visualització a ratolí" + + +msgid "Center the view to the Z-depth position under the mouse cursor" +msgstr "Centra la visualització a la posició de profunditat-Z sota el cursor del ratolí" + + +msgctxt "Operator" +msgid "View Lock Clear" +msgstr "Anul·lar bloqueig de visualització" + + +msgid "Clear all view locking" +msgstr "Anul·la qualsevol bloqueig de visualització" + + +msgctxt "Operator" +msgid "View Lock to Active" +msgstr "Bloqueig de visualització a actiu" + + +msgid "Lock the view to the active object/bone" +msgstr "[View Lock to Active]: Bloqueja la vista a l'objecte/os actiu" + + +msgctxt "Operator" +msgid "View Orbit" +msgstr "Visualització orbital" + + +msgid "Orbit the view" +msgstr "Orbita la vista" + + +msgid "Orbit" +msgstr "Orbitació" + + +msgid "Direction of View Orbit" +msgstr "[Orbit]: Direcció de l'òrbita de visualització" + + +msgid "Orbit Left" +msgstr "Orbitar a esquerra" + + +msgid "Orbit the view around to the left" +msgstr "Orbita la visualització cap a l'esquerra" + + +msgid "Orbit Right" +msgstr "Orbitar a dreta" + + +msgid "Orbit the view around to the right" +msgstr "Oblida la visualització cap a la dreta" + + +msgid "Orbit Up" +msgstr "Orbitar cap amunt" + + +msgid "Orbit the view up" +msgstr "Orbita la visualització cap amunt" + + +msgid "Orbit Down" +msgstr "Orbitar cap avall" + + +msgid "Orbit the view down" +msgstr "Orbita la visualització cap avall" msgctxt "Operator" msgid "Pan View Direction" -msgstr "Direcció de l'escombratge" +msgstr "Escombratge de visualització" msgid "Pan the view in a given direction" -msgstr "Escombratge de la vista en una direcció donada" +msgstr "[Pan View Direction]: Escombra la visualització en una direcció donada" msgid "Pan" -msgstr "Escombratge" +msgstr "Escombrar" msgid "Direction of View Pan" -msgstr "Direcció de l'escombratge d'escena" +msgstr "[Pan]: Direcció d'escombratge d'escena" msgid "Pan Left" -msgstr "Escombratge esquerre" +msgstr "Escombrar a esquerra" msgid "Pan the view to the left" -msgstr "Escombratge de la vista cap a l'esquerra" +msgstr "Visualitza en forma d'escombratge cap a l'esquerra" msgid "Pan Right" -msgstr "Escombratge a la dreta" +msgstr "Escombrar a dreta" msgid "Pan the view to the right" -msgstr "Escombratge de l'escena a la dreta" +msgstr "Visualitza en forma d'escombratge a la dreta" msgid "Pan Up" -msgstr "Escombratge amunt" +msgstr "Escombrar cap amunt" msgid "Pan the view up" -msgstr "Escombratge cap amunt" +msgstr "Visualitza en forma d'escombratge cap amunt" msgid "Pan Down" -msgstr "Escombratge avall" +msgstr "Visualitza en forma d'escombratge cap avall" msgid "Pan the view down" msgstr "Escombratge cap avall" +msgctxt "Operator" +msgid "View Perspective/Orthographic" +msgstr "Visualització perspectiva/ortogràfica" + + +msgid "Switch the current view from perspective/orthographic projection" +msgstr "Alterna la visualització actual des de la projecció perspectiva/ortogràfica" + + +msgctxt "Operator" +msgid "View Roll" +msgstr "Ródol de visualització" + + +msgid "Roll the view" +msgstr "[View Roll]: Rodola la visualització" + + +msgid "Roll Angle Source" +msgstr "Font d'angle de ròdol" + + +msgid "How roll angle is calculated" +msgstr "Com es calcula l'angle de ròdol" + + +msgid "Roll Angle" +msgstr "Angle de ròdol" + + +msgid "Roll the view using an angle value" +msgstr "[Roll Angle]: Rodola la visualització en base a un valor angular" + + +msgid "Roll Left" +msgstr "Rodolar a l'esquerra" + + +msgid "Roll the view around to the left" +msgstr "Rodola la visualització cap a l'esquerra" + + +msgid "Roll Right" +msgstr "Rodolar a la dreta" + + +msgid "Roll the view around to the right" +msgstr "Rodola la visualització cap a la dreta" + + +msgid "Move the view to the selection center" +msgstr "Moure la vista al centre de la selecció" + + +msgctxt "Operator" +msgid "Add Camera and VR Landmark from Session" +msgstr "Afegir càmera i marca d'RV de sessió" + + +msgid "Create a new Camera and VR Landmark from the viewer pose of the running VR session and select it" +msgstr "Crea una càmera nova i una marca de terme d'RV a partir del posat del visor de la sessió d'RV en execució i la selecciona" + + +msgctxt "Operator" +msgid "Activate VR Landmark" +msgstr "Activar marca d'RV" + + +msgid "Change to the selected VR landmark from the list" +msgstr "Canviar a la marca de terme d'RV seleccionada de la llista" + + +msgctxt "Operator" +msgid "Add VR Landmark" +msgstr "Afegir marca d'RV" + + +msgid "Add a new VR landmark to the list and select it" +msgstr "Afegeix una nova marca de terme d'RV a la llista i la selecciona" + + +msgctxt "Operator" +msgid "Add VR Landmark from Camera" +msgstr "Afegir marca d'RV des de càmera" + + +msgid "Add a new VR landmark from the active camera object to the list and select it" +msgstr "Afegeix una marca de terme d'RV nova des de l'objecte de càmera actiu a la llista i la selecciona" + + +msgctxt "Operator" +msgid "Add VR Landmark from Session" +msgstr "Afegir una marca d'RV de la sessió" + + +msgid "Add VR landmark from the viewer pose of the running VR session to the list and select it" +msgstr "Afegeix una marca de terme d'RV des del posat de visor de la sessió d'RV en execució a la llista i la selecciona" + + +msgctxt "Operator" +msgid "Remove VR Landmark" +msgstr "Eliminar marca d'RV" + + +msgid "Delete the selected VR landmark from the list" +msgstr "Suprimeix la marca de terme d'RV seleccionada de la llista" + + +msgctxt "Operator" +msgid "Walk Navigation" +msgstr "Navegació a peu" + + +msgid "Interactively walk around the scene" +msgstr "Camina interactivament per l'escena" + + +msgid "Zoom in/out in the view" +msgstr "Ampliar/allunyar la vista" + + +msgid "Zoom in the view to the nearest object contained in the border" +msgstr "Concentra la vista a l'objecte més proper contingut dins la vora" + + +msgctxt "Operator" +msgid "Zoom Camera 1:1" +msgstr "Zoom de càmera 1:1" + + +msgid "Match the camera to 1:1 to the render output" +msgstr "Fa coincidir la càmera en un 1:1 de l'emissió del revelat" + + +msgctxt "Operator" +msgid "Export Alembic" +msgstr "Exportar Alembic" + + +msgid "Export current scene in an Alembic archive" +msgstr "Exporta l'escena actual a un arxiu Alembic" + + +msgid "Apply Subdivision Surface" +msgstr "Aplicar subdivisió de superfície" + + +msgid "Export subdivision surfaces as meshes" +msgstr "Exporta les superfícies subdividides com a malles" + + +msgid "Run as Background Job" +msgstr "Executa com a tasca en segon pla" + + +msgid "Enable this to run the import in the background, disable to block Blender while importing. This option is deprecated; EXECUTE this operator to run in the foreground, and INVOKE it to run as a background job" +msgstr "Habiliteu-ho per a executar la importació en segon pla, desactiveu-ho perquè bloquegi Blender mentres importa. Aquesta opció és obsoleta; EXECUTEU aquest operador per a què corri en primer pla i INVOQUEU-lo per a executar-lo com a tasca en segon pla" + + +msgid "Curves as Mesh" +msgstr "Corbes com a malla" + + +msgid "Export curves and NURBS surfaces as meshes" +msgstr "Exporta les corbes i les superfícies NURBS com a malles" + + +msgid "End frame of the export, use the default value to take the end frame of the current scene" +msgstr "Fotograma final de l'exportació, usar el valor predeterminat per a agafar el fotograma final de l'escena actual" + + +msgid "Use Settings for" +msgstr "Usar configuració per a" + + +msgid "Determines visibility of objects, modifier settings, and other areas where there are different settings for viewport and rendering" +msgstr "Determina la visibilitat dels objectes, la configuració de modificadors, i altres àrees on hi ha paràmetres diferents per al mirador i el revelat" + + +msgid "Use Render settings for object visibility, modifier settings, etc" +msgstr "Usar configuració de revelat per a visibilitat d'objecte, configuració de modificador, etc" + + +msgid "Use Viewport settings for object visibility, modifier settings, etc" +msgstr "Usar configuració de mirador per a visibilitat d'objecte, configuració de modificador, etc" + + +msgid "Export Custom Properties" +msgstr "Exportar propietats personalitzades" + + +msgid "Export custom properties to Alembic .userProperties" +msgstr "Exporta les propietats personalitzades a .userProperties d'Alembic" + + +msgid "Export Hair" +msgstr "Exportar pèl" + + +msgid "Exports hair particle systems as animated curves" +msgstr "Exporta els sistemes de partícules pèl com a corbes animades" + + +msgid "Export Particles" +msgstr "Exportar partícules" + + +msgid "Exports non-hair particle systems" +msgstr "Exporta sistemes de partícules que no són pèl" + + +msgid "Export per face shading group assignments" +msgstr "Exportar per a les assignacions de grup d'aspecció de cares" + + +msgid "Flatten Hierarchy" +msgstr "Aplanar jerarquia" + + +msgid "Do not preserve objects' parent/children relationship" +msgstr "No conserva la relació pare/fill dels objectes" + + +msgid "Value by which to enlarge or shrink the objects with respect to the world's origin" +msgstr "Valor pel qual s'amplien o redueixen els objectes respecte de l'origen del món" + + +msgid "Geometry Samples" +msgstr "Mostres de geometria" + + +msgid "Number of times per frame object data are sampled" +msgstr "[Geometry Samples]: Nombre de cops per fotograma que es prenen mostres de dades d'objecte" + + +msgid "Export normals" +msgstr "Exportar normals" + + +msgid "Export undeformed mesh vertex coordinates" +msgstr "Exporta les coordenades de vèrtexs de malla no deformades" + + +msgid "Export UVs with packed island" +msgstr "Exportar UVs amb una illa empaquetada" + + +msgid "Selected Objects Only" +msgstr "Només objectes seleccionats" + + +msgid "Export only selected objects" +msgstr "Exporta només els objectes seleccionats" + + +msgid "Shutter Close" +msgstr "Obturador tancat" + + +msgid "Time at which the shutter is closed" +msgstr "[Shutter Close]: Moment en què l'obturador està tancat" + + +msgid "Shutter Open" +msgstr "Obturador obert" + + +msgid "Time at which the shutter is open" +msgstr "Moment en què l'obturador està obert" + + +msgid "Start frame of the export, use the default value to take the start frame of the current scene" +msgstr "Fotograma inicial de l'exportació, usar el valor predeterminat per a agafar el fotograma inicial de l'escena actual" + + +msgid "Use Subdivision Schema" +msgstr "Usar esquema de subdivisió" + + +msgid "Export meshes using Alembic's subdivision schema" +msgstr "Exporta les malles usant l'esquema de subdivisió d'Alembic" + + +msgid "Export polygons (quads and n-gons) as triangles" +msgstr "Exportar polígons (quads i n-gons) com a triangles" + + +msgid "Use Instancing" +msgstr "Usar instanciació" + + +msgid "Export data of duplicated objects as Alembic instances; speeds up the export and can be disabled for compatibility with other software" +msgstr "[Use Instancing]: Exporta dades d'objectes duplicats com a instàncies Alembic; accelera l'exportació i es pot inhabilitar per compatibilitat amb altres programaris" + + +msgid "Export UVs" +msgstr "Exportar UVs" + + +msgid "Export color attributes" +msgstr "Exporta atributs de color" + + +msgid "Visible Objects Only" +msgstr "Només objectes visibles" + + +msgid "Export only objects that are visible" +msgstr "Exporta només objectes que siguin visibles" + + +msgid "Transform Samples" +msgstr "Transformar mostres" + + +msgid "Number of times per frame transformations are sampled" +msgstr "Nombre de vegades per fotograma que es prenen mostres de transformacions" + + +msgctxt "Operator" +msgid "Import Alembic" +msgstr "Importar Alembic" + + +msgid "Load an Alembic archive" +msgstr "[Import Alembic]: Carrega un arxiu Alembic" + + +msgid "Always Add Cache Reader" +msgstr "Afegir sempre el lector de memòria cau" + + +msgid "Add cache modifiers and constraints to imported objects even if they are not animated so that they can be updated when reloading the Alembic archive" +msgstr "Afegeix modificadors i restriccions de la memòria cau als objectes importats encara que no siguin animats, de manera que es puguin actualitzar en tornar a carregar l'arxiu Alembic" + + +msgid "Enable this to run the export in the background, disable to block Blender while exporting. This option is deprecated; EXECUTE this operator to run in the foreground, and INVOKE it to run as a background job" +msgstr "Habiliteu-ho per a executar l'exportació en segon pla, desactiveu-ho per a blocar el Blender mentre s'exporta. Aquesta opció és obsoleta; EXECUTEU aquest operador per a fer-ho córrer en primer pla i INVOQUEU-lo per a executar-lo com a tasca de segon pla" + + +msgid "Is Sequence" +msgstr "És seqüència" + + +msgid "Set to true if the cache is split into separate files" +msgstr "Posar com a ver si la memòria cau està dividida en documents separats" + + +msgid "Set Frame Range" +msgstr "Definir interval de fotogrames" + + +msgid "If checked, update scene's start and end frame to match those of the Alembic archive" +msgstr "Si està marcada, s'actualitza el fotograma d'inici i final de l'escena perquè coincideixi amb els de l'arxiu Alembic" + + +msgid "Validate Meshes" +msgstr "Validar malles" + + +msgid "Check imported mesh objects for invalid data (slow)" +msgstr "Comprova si hi ha dades no vàlides als objectes de malla importats (lent)" + + +msgctxt "Operator" +msgid "Append" +msgstr "Incorporar" + + +msgid "Append from a Library .blend file" +msgstr "[Append]: Incorpora des d'un document biblioteca .blend" + + +msgid "Put new objects on the active collection" +msgstr "Posar objectes nous a la col·lecció activa" + + +msgid "Select new objects" +msgstr "Seleccionar objectes nous" + + +msgid "Clear Asset Data" +msgstr "Descartar dades de recurs" + + +msgid "Don't add asset meta-data or tags from the original data-block" +msgstr "[Clear Asset Data]: No afegeix metadades o etiquetes de recursos des del bloc de dades d'origen" + + +msgid "Re-Use Local Data" +msgstr "Reutilitzar dades locals" + + +msgid "Try to re-use previously matching appended data-blocks instead of appending a new copy" +msgstr "Intenta reutilitzar els blocs de dades incorporats que coincideixin prèviament en lloc d'incorporar-ne una còpia nova" + + +msgid "Instance Collections" +msgstr "Col·leccions d'instàncies" + + +msgid "Create instances for collections, rather than adding them directly to the scene" +msgstr "Crea instàncies per a col·leccions, preferiblement a afegir-les directament a l'escena" + + +msgid "Instance Object Data" +msgstr "Dades d'objecte instància" + + +msgid "Create instances for object data which are not referenced by any objects" +msgstr "Crea instàncies per a dades d'objecte que no estan referenciades per cap objecte" + + +msgid "Link the objects or data-blocks rather than appending" +msgstr "Enllaçar els objectes o blocs de dades en lloc d'afegir-los" + + +msgid "Set \"Fake User\" for appended items (except objects and collections)" +msgstr "Assigna «usador fals» per als elements incorporats (excepte en objectes i col·leccions)" + + +msgid "Localize All" +msgstr "Localitzar-ho tot" + + +msgid "Localize all appended data, including those indirectly linked from other libraries" +msgstr "Localitza totes les dades incorporades, incloses les que estan enllaçades indirectament des d'altres biblioteques" + + +msgctxt "Operator" +msgid "Batch Rename" +msgstr "Rebateig de repetició" + + +msgid "Rename multiple items at once" +msgstr "[Batch Rename]: Reanomena diversos elements alhora" + + +msgid "Type of data to rename" +msgstr "Tipus de dades a rebatejar" + + +msgid "Grease Pencils" +msgstr "Llapis de greix" + + +msgid "Sequence Strips" +msgstr "Segments de seqüència" + + +msgid "Action Clips" +msgstr "Clips d'acció" + + +msgctxt "Operator" +msgid "Validate .blend strings" +msgstr "Validar cadenes .blend" + + +msgid "Check and fix all strings in current .blend file to be valid UTF-8 Unicode (needed for some old, 2.4x area files)" +msgstr "Comprova i corregeix totes les cadenes del document .blend actual perquè siguin UTF-8 Unicode vàlides (necessari per a alguns documents antics d'àrea 2.4x)" + + +msgctxt "Operator" +msgid "Call Menu" +msgstr "Cridar menú" + + +msgid "Open a predefined menu" +msgstr "Obre un menú predefinit" + + +msgid "Name of the menu" +msgstr "Nom del menú" + + +msgctxt "Operator" +msgid "Call Pie Menu" +msgstr "Cridar menú de pastís" + + +msgid "Open a predefined pie menu" +msgstr "Obre un menú de pastís predefinit" + + +msgid "Name of the pie menu" +msgstr "Nom del menú de pastís" + + +msgctxt "Operator" +msgid "Call Panel" +msgstr "Cridar plafó" + + +msgid "Open a predefined panel" +msgstr "Obre un plafó predefinit" + + +msgid "Keep Open" +msgstr "Mantenir obert" + + +msgctxt "Operator" +msgid "Export COLLADA" +msgstr "Exportar COLLADA" + + +msgid "Save a Collada file" +msgstr "Desa un document Collada" + + +msgid "Only Selected UV Map" +msgstr "Només el mapa UV seleccionat" + + +msgid "Export only the selected UV Map" +msgstr "Exporta només el mapa UV seleccionat" + + +msgid "Apply Global Orientation" +msgstr "Aplicar orientació global" + + +msgid "Rotate all root objects to match the global orientation settings otherwise set the global orientation per Collada asset" +msgstr "Fa rotar tots els objectes arrel perquè coincideixin amb els paràmetres d'orientació global, altrament estableix l'orientació global per a recurs de Collada" + + +msgid "Apply modifiers to exported mesh (non destructive))" +msgstr "Aplicar els modificadors a la malla exportada (no destructiu)" + + +msgid "Deform Bones Only" +msgstr "Només ossos de deformació" + + +msgid "Only export deforming bones with armatures" +msgstr "Exporta només els ossos deformants amb esquelets" + + +msgid "Transformation type for translation, scale and rotation. Note: The Animation transformation type in the Anim Tab is always equal to the Object transformation type in the Geom tab" +msgstr "Tipus de transformació per a la translació, escala i rotació. Nota: el tipus de transformació d'animació de la pestanya Anim sempre és igual al tipus de transformació de l'objecte de la pestanya Geom" + + +msgid "Use representation for exported transformations" +msgstr "Usar representació per a les transformacions exportades" + + +msgid "Decomposed" +msgstr "Descompost" + + +msgid "Use , and representation for exported transformations" +msgstr "Usa la representació , i per a les transformacions exportades" + + +msgid "Key Type" +msgstr "Tipus de fites" + + +msgid "Type for exported animations (use sample keys or Curve keys)" +msgstr "[Key Type]: Tipus per a les animacions exportades (s'usen fites redistribuïdes of fites de corba)" + + +msgid "Export Sampled points guided by sampling rate" +msgstr "Exportar punts mostrejats guiats per la freqüència de mostreig" + + +msgid "Export Curves (note: guided by curve keys)" +msgstr "Exportar corbes (nota: guiades per les fites de corba)" + + +msgid "Global Forward Axis" +msgstr "Eix global endavant" + + +msgid "Global Forward axis for export" +msgstr "[Global Forward Axis]: Eix global endavant per a l'exportació" + + +msgid "Global Forward is positive X Axis" +msgstr "Eix global endavant és X positiu" + + +msgid "Global Forward is positive Y Axis" +msgstr "Eix global endavant és Y positiu" + + +msgid "Global Forward is positive Z Axis" +msgstr "Eix global endavant és Z positiu" + + +msgid "Global Forward is negative X Axis" +msgstr "Eix global endavant és X negatiu" + + +msgid "Global Forward is negative Y Axis" +msgstr "Eix global endavant és Y negatiu" + + +msgid "Global Forward is negative Z Axis" +msgstr "Eix global endavant és Z negatiu" + + +msgid "Global Up Axis" +msgstr "Eix global amunt" + + +msgid "Global Up axis for export" +msgstr "[Global Up Axis]: Eix global amunt per a l'exportació" + + +msgid "Global UP is positive X Axis" +msgstr "Eix global amunt és X positiu" + + +msgid "Global UP is positive Y Axis" +msgstr "Eix global amunt és Y positiu" + + +msgid "Global UP is positive Z Axis" +msgstr "Eix global amunt és Z positiu" + + +msgid "Global UP is negative X Axis" +msgstr "Eix global amunt és X negatiu" + + +msgid "Global UP is negative Y Axis" +msgstr "Eix global amunt és Y negatiu" + + +msgid "Global UP is negative Z Axis" +msgstr "Eix global amunt és Z negatiu" + + +msgid "Modifier resolution for export" +msgstr "Resolució de modificador per a l'exportació" + + +msgid "Apply modifier's viewport settings" +msgstr "Aplicar la configuració de mirador del modificador" + + +msgid "Apply modifier's render settings" +msgstr "Aplicar la configuració de revelat del modificador" + + +msgid "Object Transformation type for translation, scale and rotation" +msgstr "Tipus de transformació d'objecte per a la translació, escala i rotació" + + +msgid "Include all Actions" +msgstr "Incloure totes les accions" + + +msgid "Export also unassigned actions (this allows you to export entire animation libraries for your character(s))" +msgstr "Exporta també les accions sense assignar (això permet exportar biblioteques senceres d'animació per al(s) vostre(s) personatge(s))" + + +msgid "Include Animations" +msgstr "Incloure animacions" + + +msgid "Export animations if available (exporting animations will enforce the decomposition of node transforms into and components)" +msgstr "Exporta les animacions si estan disponibles (l'exportació d'animacions forçarà la descomposició de transformacions de node en components de i )" + + +msgid "Include Armatures" +msgstr "Incloure esquelets" + + +msgid "Export related armatures (even if not selected)" +msgstr "Exporta esquelets relacionats (encara que no estiguin seleccionats)" + + +msgid "Include Children" +msgstr "Incloure fills" + + +msgid "Export all children of selected objects (even if not selected)" +msgstr "Exporta tots els fills dels objectes seleccionats (encara que no estiguin seleccionats)" + + +msgid "Include Shape Keys" +msgstr "Incloure morfofites" + + +msgid "Export all Shape Keys from Mesh Objects" +msgstr "Exporta totes les morfofites des d'objectes de malla" + + +msgid "Keep Bind Info" +msgstr "Mantir informació de lligams" + + +msgid "Store Bindpose information in custom bone properties for later use during Collada export" +msgstr "Emmagatzema la informació de posa amb lligam en propietats personalitzades d'ossos per al seu ús posterior durant l'exportació a Collada" + + +msgid "All Keyed Curves" +msgstr "Totes corbes fitades" + + +msgid "Export also curves which have only one key or are totally flat" +msgstr "Exporta també les corbes que només tenen una fita o són totalment planes" + + +msgid "Keep Keyframes" +msgstr "Mantenir fotofites" + + +msgid "Use existing keyframes as additional sample points (this helps when you want to keep manual tweaks)" +msgstr "Utilitza les fotofites existents com a punts de distribució addicionals ( això ajuda quan vols mantenir ajustos fets manualment )" + + +msgid "Keep Smooth curves" +msgstr "Mantenir corbes suaus" + + +msgid "Export also the curve handles (if available) (this does only work when the inverse parent matrix is the unity matrix, otherwise you may end up with odd results)" +msgstr "Exporta també les nanses de corba (si estan disponibles) (això només funciona quan la matriu pare inversa és la matriu unity, en cas contrari podeu acabar amb resultats estranys)" + + +msgid "Limit Precision" +msgstr "Limitar precisió" + + +msgid "Reduce the precision of the exported data to 6 digits" +msgstr "Redueix la precisió de les dades exportades a 6 dígits" + + +msgid "Export to SL/OpenSim" +msgstr "Exportar a SL/OpenSim" + + +msgid "Compatibility mode for SL, OpenSim and other compatible online worlds" +msgstr "Mode de compatibilitat per a SL, OpenSim i altres mons en línia compatibles" + + +msgid "Export Section" +msgstr "Exportar secció" + + +msgid "Only for User Interface organization" +msgstr "Només per a l'organització de la interfície d'usuària" + + +msgid "Data export section" +msgstr "Secció exportació de dades" + + +msgid "Geom" +msgstr "Geom" + + +msgid "Geometry export section" +msgstr "Secció d'exportació de geometria" + + +msgid "Arm" +msgstr "Esq" + + +msgid "Armature export section" +msgstr "Secció d'exportació d'esquelets" + + +msgid "Anim" +msgstr "Anim" + + +msgid "Animation export section" +msgstr "Secció d'exportació d'animació" + + +msgid "Extra" +msgstr "Extra" + + +msgid "Collada export section" +msgstr "Secció d'exportació de Collada" + + +msgid "The distance between 2 keyframes (1 to key every frame)" +msgstr "La distància entre 2 fotofites (1 per a fitar cada fotograma)" + + +msgid "Export only selected elements" +msgstr "Exportar només elements seleccionats" + + +msgid "Sort by Object name" +msgstr "Ordenar per nom d'objecte" + + +msgid "Sort exported data by Object name" +msgstr "Ordena les dades exportades pel nom de l'objecte" + + +msgid "Use Blender Profile" +msgstr "Usar perfil de Blender" + + +msgid "Export additional Blender specific information (for material, shaders, bones, etc.)" +msgstr "Exporta informació específica addicional del Blender (per a materials, aspectors, ossos, etc.)" + + +msgid "Use Object Instances" +msgstr "Usar instàncies d'objectes" + + +msgid "Instantiate multiple Objects from same Data" +msgstr "Instancia múltiples objectes des de les mateixes dades" + + +msgid "Copy textures to same folder where the .dae file is exported" +msgstr "Copia les textures a la mateixa carpeta on s'exporta el document .dae" + + +msgctxt "Operator" +msgid "Import COLLADA" +msgstr "Importar Collada" + + +msgid "Load a Collada file" +msgstr "Carrega un document Collada" + + +msgid "Auto Connect" +msgstr "Autoconnectar" + + +msgid "Set use_connect for parent bones which have exactly one child bone" +msgstr "Especifica «use_connect» per als ossos pares que tenen exactament un os fill" + + +msgid "Import custom normals, if available (otherwise Blender will compute them)" +msgstr "Importar normals personalitzades, si estan disponibles (en cas contrari, el Blender les calcularà)" + + +msgid "Find Bone Chains" +msgstr "Trobar cadenes d'os" + + +msgid "Find best matching Bone Chains and ensure bones in chain are connected" +msgstr "Troba les Cadenes d'ossos que més s'assemblen i assegura que els ossos en cadena estan connectats" + + +msgid "Fix Leaf Bones" +msgstr "Esmenar ossos fulla" + + +msgid "Fix Orientation of Leaf Bones (Collada does only support Joints)" +msgstr "Corregeix l'orientació dels ossos fulla (Collada només admet les articulacions de suport)" + + +msgid "Import Units" +msgstr "Importar unitats" + + +msgid "If disabled match import to Blender's current Unit settings, otherwise use the settings from the Imported scene" +msgstr "Si està desactivat, adscriu a la importació la configuració de la unitat actual del Blender, altrament usa la configuració de l'escena importada" + + +msgid "Minimum Chain Length" +msgstr "Longitud mínima de cadena" + + +msgid "When searching Bone Chains disregard chains of length below this value" +msgstr "En cercar cadenes d'ossos, s'ignoren les cadenes per sota d'aquesta longitud" + + +msgctxt "Operator" +msgid "Context Collection Boolean Set" +msgstr "Conjunt booleà de col·lecció de context" + + +msgid "Set boolean values for a collection of items" +msgstr "Estableix els valors booleans per a una col·lecció d'elements" + + +msgid "The data path from each iterable to the value (int or float)" +msgstr "El camí de dades de cada iterable al valor (enter o flotant)" + + +msgid "The data path relative to the context, must point to an iterable" +msgstr "El camí de dades relatiu al context, ha d'apuntar a un iterable" + + +msgctxt "Operator" +msgid "Context Array Cycle" +msgstr "Cicle de formació de context" + + +msgid "Set a context array value (useful for cycling the active mesh edit mode)" +msgstr "Estableix un valor de formació de context (útil per a ciclitzar el mode d'edició de malla activa)" + + +msgid "Context Attributes" +msgstr "Atributs de context" + + +msgid "Context data-path (expanded using visible windows in the current .blend file)" +msgstr "Camí de les dades de context (expandit mitjançant finestres visibles al document .blend actual)" + + +msgid "Cycle backwards" +msgstr "Ciclitzar enrere" + + +msgctxt "Operator" +msgid "Context Enum Cycle" +msgstr "Cicle d'enumeració de context" + + +msgid "Toggle a context value" +msgstr "Revesar un valor de context" + + +msgid "Wrap back to the first/last values" +msgstr "Reembolcalla als valors primer/últim" + + +msgctxt "Operator" +msgid "Context Int Cycle" +msgstr "Cicle d'enter de context" + + +msgid "Set a context value (useful for cycling active material, shape keys, groups, etc.)" +msgstr "Estableix un valor de context (útil per a ciclitzar material actiu, morfofites, grups, etc.)" + + +msgctxt "Operator" +msgid "Context Enum Menu" +msgstr "Menú d'enumeració de context" + + +msgctxt "Operator" +msgid "Context Modal Mouse" +msgstr "Ratolí modal de context" + + +msgid "Adjust arbitrary values with mouse input" +msgstr "Ajusta els valors arbitraris amb ingressos del ratolí" + + +msgid "Header Text" +msgstr "Text de capçalera" + + +msgid "Text to display in header during scale" +msgstr "Text a mostrar a la capçalera durant l'escalat" + + +msgid "Scale the mouse movement by this value before applying the delta" +msgstr "Escalar el moviment del ratolí per aquest valor abans d'aplicar el delta" + + +msgid "Invert the mouse input" +msgstr "Invertir ingrés de ratolí" + + +msgctxt "Operator" +msgid "Context Enum Pie" +msgstr "Pastís d'enumeració de context" + + +msgctxt "Operator" +msgid "Context Scale Float" +msgstr "Flotant d'escalat de context" + + +msgid "Scale a float context value" +msgstr "Escala un valor de context flotant" + + +msgid "Assign value" +msgstr "Assignar valor" + + +msgctxt "Operator" +msgid "Context Scale Int" +msgstr "Enter d'escala de context" + + +msgid "Scale an int context value" +msgstr "Escala un valor enter de context" + + +msgid "Always Step" +msgstr "Sempre a pas" + + +msgid "Always adjust the value by a minimum of 1 when 'value' is not 1.0" +msgstr "Ajusta sempre el valor amb un mínim d'1 quan «valor» no és 1.0" + + +msgctxt "Operator" +msgid "Context Set Boolean" +msgstr "Fixar booleà de context" + + +msgid "Set a context value" +msgstr "Estableix un valor de context" + + +msgid "Assignment value" +msgstr "Valor d'assignació" + + +msgctxt "Operator" +msgid "Context Set Enum" +msgstr "Fixar enumeració de context" + + +msgid "Assignment value (as a string)" +msgstr "Valor d'assignació (com a cadena)" + + +msgctxt "Operator" +msgid "Context Set Float" +msgstr "Fixar flotant de context" + + +msgid "Apply relative to the current value (delta)" +msgstr "Aplica en relació al valor actual (delta)" + + +msgctxt "Operator" +msgid "Set Library ID" +msgstr "Definir ID de biblioteca" + + +msgid "Set a context value to an ID data-block" +msgstr "Estableix un valor de context a un bloc de dades ID" + + +msgctxt "Operator" +msgid "Context Set" +msgstr "Fixar context" + + +msgctxt "Operator" +msgid "Context Set String" +msgstr "Cadena del fixar" + + +msgctxt "Operator" +msgid "Context Set Value" +msgstr "Fixar valor de context" + + +msgctxt "Operator" +msgid "Context Toggle" +msgstr "Revesador de context" + + +msgid "Optionally override the context with a module" +msgstr "Sobreseu opcionalment el context amb un mòdul" + + +msgctxt "Operator" +msgid "Context Toggle Values" +msgstr "Valors de revesar de context" + + +msgid "Toggle enum" +msgstr "Revesar enumeració" + + +msgctxt "Operator" +msgid "Debug Menu" +msgstr "Menú depuració" + + +msgid "Open a popup to set the debug level" +msgstr "Obre una finestra emergent per establir el nivell de depuració" + + +msgid "Debug Value" +msgstr "Valor de depuració" + + +msgctxt "Operator" +msgid "Demo" +msgstr "Demo" + + +msgctxt "Operator" +msgid "Control" +msgstr "Control" + + +msgid "Prev" +msgstr "Prev" + + +msgid "Pause" +msgstr "Pausa" + + +msgctxt "Operator" +msgid "Demo Mode (Start)" +msgstr "Mode demostració (inici)" + + +msgctxt "Operator" +msgid "Demo Mode (Setup)" +msgstr "Mode demostració (configuració)" + + +msgid "Create a demo script and optionally execute it" +msgstr "Crea un protocol demo i opcionalment l'executa" + + +msgid "Number of times to play the animation" +msgstr "Nombre de vegades a reproduir l'animació" + + +msgid "Render Anim" +msgstr "Revelar anim" + + +msgid "Render entire animation (render mode only)" +msgstr "Revela l'animació sencera (sols mode revelat)" + + +msgid "Screen Switch" +msgstr "Canvi de pantalla" + + +msgid "Time between switching screens (in seconds) or 0 to disable" +msgstr "Temps entre pantalles (en segons) o 0 per a desactivar" + + +msgid "Time Max" +msgstr "Temps màx" + + +msgid "Maximum number of seconds to show the animation for (in case the end frame is very high for no reason)" +msgstr "Nombre màxim de segons per a mostrar l'animació (en cas que el fotograma final sigui molt alt sense motiu)" + + +msgid "Time Min" +msgstr "Temps mín" + + +msgid "Minimum number of seconds to show the animation for (for small loops)" +msgstr "Nombre mínim de segons per a mostrar l'animació (per a bucles petits)" + + +msgid "Search Path" +msgstr "Cercar camí" + + +msgid "Directory used for importing the file" +msgstr "Directori per importar el document" + + +msgid "Render Delay" +msgstr "Retard de revelat" + + +msgid "Time to display the rendered image before moving on (in seconds)" +msgstr "Temps per mostrar la imatge revelada abans de seguir endavant (en segons)" + + +msgid "Run once and exit" +msgstr "Executar una cop i sortir" + + +msgid "Play" +msgstr "Reproduir" + + +msgid "Random Order" +msgstr "Ordre aleatori" + + +msgid "Select files randomly" +msgstr "Selecciona documents aleatòriament" + + +msgid "Run Immediately!" +msgstr "Executar ja!" + + +msgid "Run demo immediately" +msgstr "Executa la demostració immediatament" + + +msgctxt "Operator" +msgid "View Documentation" +msgstr "Visualitzar documentació" + + +msgid "Open online reference docs in a web browser" +msgstr "Obre els documents de referència en línia en un navegador web" + + +msgid "Doc ID" +msgstr "ID del doc" + + +msgctxt "Operator" +msgid "View Manual" +msgstr "Mostrar manual" + + +msgid "Load online manual" +msgstr "Carrega el manual en línia" + + +msgctxt "Operator" +msgid "View Online Manual" +msgstr "Mostrar manual en línia" + + +msgid "View a context based online manual in a web browser" +msgstr "Visualitza un manual en línia contextualitzat en un navegador web" + + +msgctxt "Operator" +msgid "Handle dropped .blend file" +msgstr "L'ansa ha llançat el document .blend" + + +msgctxt "Operator" +msgid "Export to PDF" +msgstr "Exportar a PDF" + + +msgid "Export grease pencil to PDF" +msgstr "Exporta el llapis de greix a PDF" + + +msgid "Which frames to include in the export" +msgstr "Quins fotogrames s'inclouran a l'exportació" + + +msgid "Include only active frame" +msgstr "Incloure sols fotograma actiu" + + +msgid "Include selected frames" +msgstr "Incloure fotogrames seleccionats" + + +msgid "Include all scene frames" +msgstr "Incloure tots els fotogrames d'escena" + + +msgid "Which objects to include in the export" +msgstr "Quins objectes s'han d'incloure a l'exportació" + + +msgid "Include only the active object" +msgstr "Incloure sols l'objecte actiu" + + +msgid "Include selected objects" +msgstr "Incloure els objectes seleccionats" + + +msgid "Include all visible objects" +msgstr "Incloure tots els objectes visibles" + + +msgid "Precision of stroke sampling. Low values mean a more precise result, and zero disables sampling" +msgstr "Precisió del mostreig del traç. Els valors baixos donen un resultat més precís, i zero inhabilita el mostreig" + + +msgid "Export strokes with fill enabled" +msgstr "Exportar traços amb emplenat habilitat" + + +msgid "Export strokes with constant thickness" +msgstr "Exporta els traços amb gruix constant" + + +msgctxt "Operator" +msgid "Export to SVG" +msgstr "Exportar a SVG" + + +msgid "Export grease pencil to SVG" +msgstr "Exporta el llapis de greix a SVG" + + +msgid "Clip Camera" +msgstr "Retall de càmera" + + +msgid "Clip drawings to camera size when export in camera view" +msgstr "[Clip Camera]: Retalla els dibuixos a la mida de la càmera en exportar en visualització de càmera" + + +msgid "Import SVG into grease pencil" +msgstr "Importar SVG al llapis de greix" + + +msgid "Resolution of the generated strokes" +msgstr "Resolució dels traços generats" + + +msgid "Scale of the final strokes" +msgstr "Escala dels traços finals" + + +msgctxt "Operator" +msgid "Add Theme Preset" +msgstr "Afegeix predefinit del tema" + + +msgid "Add or remove a theme preset" +msgstr "[Add Theme Preset]: Afegeix o elimina un tema predefinit" + + +msgctxt "Operator" +msgid "Add Keyconfig Preset" +msgstr "Afegir predefinit de fita" + + +msgid "Add or remove a Key-config Preset" +msgstr "[Add Keyconfig Preset]: Afegeix o elimina un predefinit de configuració de fita" + + +msgctxt "Operator" +msgid "Reload Library" +msgstr "Recarregar biblioteca" + + +msgid "Reload the given library" +msgstr "Torna a carregar la biblioteca indicada" + + +msgid "Library to reload" +msgstr "Biblioteca a recarregar" + + +msgid "Relocate the given library to one or several others" +msgstr "Reubica la biblioteca indicada a una o diverses altres" + + +msgid "Library to relocate" +msgstr "Biblioteca a reubicar" + + +msgctxt "Operator" +msgid "Link" +msgstr "Enllaç" + + +msgid "Link from a Library .blend file" +msgstr "Enllaç des d'un document .blend de biblioteca" + + +msgctxt "Operator" +msgid "Memory Statistics" +msgstr "Estadístiques de memòria" + + +msgid "Print memory statistics to the console" +msgstr "Imprimeix les estadístiques de memòria a la consola" + + +msgctxt "Operator" +msgid "Export Wavefront OBJ" +msgstr "Exporta a OBJ Wavefront" + + +msgid "Save the scene to a Wavefront OBJ file" +msgstr "Desa l'escena en un document OBJ Wavefront" + + +msgid "Apply modifiers to exported meshes" +msgstr "Aplicar modificadors a malles exportades" + + +msgid "The last frame to be exported" +msgstr "L'últim fotograma a exportar" + + +msgid "Export Animation" +msgstr "Exportar animació" + + +msgid "Export multiple frames instead of the current frame only" +msgstr "Exporta múltiples fotogrames en lloc de només el fotograma actual" + + +msgid "Export Colors" +msgstr "Exportar colors" + + +msgid "Export per-vertex colors" +msgstr "Exporta colors per-vèrtex" + + +msgid "Export Curves as NURBS" +msgstr "Exportar corbes com a NURBS" + + +msgid "Export curves in parametric form instead of exporting as mesh" +msgstr "Exportar corbes en forma paramètrica en lloc d'exportar com a malla" + + +msgid "Object Properties" +msgstr "Propietats de l'objecte" + + +msgid "Determines properties like object visibility, modifiers etc., where they differ for Render and Viewport" +msgstr "Determina propietats com la visibilitat de l'objecte, modificadors, etc., on difereixen entre revelat i mirador" + + +msgid "Export objects as they appear in render" +msgstr "Exportar objectes com apareixen al revelat" + + +msgid "Export objects as they appear in the viewport" +msgstr "Exportar objectes com apareixen al mirador" + + +msgid "Export Material Groups" +msgstr "Exportar grups de materials" + + +msgid "Export Materials" +msgstr "Exportar materials" + + +msgid "Export MTL library. There must be a Principled-BSDF node for image textures to be exported to the MTL file" +msgstr "Exportar biblioteca MTL. Ha d'haver-hi un node BSDF-postulat perquè les imatges textura s'exportin al document MTL" + + +msgid "Export Normals" +msgstr "Exportar normals" + + +msgid "Export per-face normals if the face is flat-shaded, per-face-per-loop normals if smooth-shaded" +msgstr "Exporta normals per-cara si la cara és aplanada, per-cara-per-anella si és suavitzada" + + +msgid "Export Object Groups" +msgstr "Exportar grups d'objectes" + + +msgid "Append mesh name to object name, separated by a '_'" +msgstr "Incorporar nom de malla al nom de l'objecte, separat per un «_»" + + +msgid "Export Materials with PBR Extensions" +msgstr "Exportar materials amb extensions PBR" + + +msgid "Export MTL library using PBR extensions (roughness, metallic, sheen, clearcoat, anisotropy, transmission)" +msgstr "Exporta la biblioteca MTL usant extensions PBR (rugositat, metàl·lic, lluïssor, vernís, anisotropia, transmissió)" + + +msgid "Export Selected Objects" +msgstr "Exportar objectes seleccionats" + + +msgid "Export only selected objects instead of all supported objects" +msgstr "Exporta només els objectes seleccionats en lloc de tots els objectes compatibles" + + +msgid "Export Smooth Groups" +msgstr "Exportar grups suavitzats" + + +msgid "Every smooth-shaded face is assigned group \"1\" and every flat-shaded face \"off\"" +msgstr "A cada cara d'aspectació suavitzada se li assigna el grup «1» i a cada cara d'aplanada «off»" + + +msgid "Export Triangulated Mesh" +msgstr "Exportar malla triangulada" + + +msgid "All ngons with four or more vertices will be triangulated. Meshes in the scene will not be affected. Behaves like Triangulate Modifier with ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4" +msgstr "Tots els ngons amb quatre o més vèrtexs seran triangulats. Les malles de l'escena no es veuran afectades. Es comporta com el modificador triangular amb mètode ngon: «Preciós», mètode quad, «Diagonal mínima», vèrtexs mínims: 4" + + +msgid "Export Vertex Groups" +msgstr "Exportar grups de vèrtexs" + + +msgid "Export the name of the vertex group of a face. It is approximated by choosing the vertex group with the most members among the vertices of a face" +msgstr "Exporta el nom del grup de vèrtexs d'una cara. Es fa l'aproximació escollint el grup de vèrtexs amb més membres d'entre els vèrtexs d'una cara" + + +msgid "Positive X axis" +msgstr "Eix X positiu" + + +msgid "Positive Y axis" +msgstr "Eix Y positiu" + + +msgid "Positive Z axis" +msgstr "Eix Z positiu" + + +msgid "Negative X axis" +msgstr "Eix X negatiu" + + +msgid "Negative Y axis" +msgstr "Eix Y negatiu" + + +msgid "Negative Z axis" +msgstr "Eix Z negatiu" + + +msgid "Write relative paths where possible" +msgstr "Escriure camins relatius quan es pot" + + +msgid "Write filename only" +msgstr "Escriure sols nom de document" + + +msgid "Copy the file to the destination path" +msgstr "Copiar document al camí de destinació" + + +msgid "Generate Bitflags for Smooth Groups" +msgstr "Generar semàfors per a grups suavitzats" + + +msgid "The first frame to be exported" +msgstr "El primer fotograma a exportar" + + +msgctxt "Operator" +msgid "Import Wavefront OBJ" +msgstr "Importar OBJ Wavefront" + + +msgid "Load a Wavefront OBJ scene" +msgstr "Carrega una escena OBJ de Wavefront" + + +msgid "Clamp Bounding Box" +msgstr "Estrènyer capsa contenidora" + + +msgid "Resize the objects to keep bounding box under this value. Value 0 disables clamping" +msgstr "Redimensiona els objectes per a mantenir la capsa contenidora per sota d'aquest valor. El valor 0 inhabilita l'estrenyiment" + + +msgid "Split By Group" +msgstr "Separar per grup" + + +msgid "Import each OBJ 'g' as a separate object" +msgstr "Importa cada «g» OBJ com a objecte separat" + + +msgid "Split By Object" +msgstr "Separar per objecte" + + +msgid "Import each OBJ 'o' as a separate object" +msgstr "Importa cada «o» OBJ com a objecte separat" + + +msgctxt "Operator" +msgid "Open" +msgstr "Obrir" + + +msgid "Open a Blender file" +msgstr "Obre un document Blender" + + +msgid "Display File Selector" +msgstr "Mostrar selector de documents" + + +msgid "Load UI" +msgstr "Carregar IU" + + +msgid "Load user interface setup in the .blend file" +msgstr "Carrega la configuració de la interfície d'usuària al document .blend" + + +msgid "State" +msgstr "Estat" + + +msgid "Trusted Source" +msgstr "Font de confiança" + + +msgid "Allow .blend file to execute scripts automatically, default available from system preferences" +msgstr "Permet que el document .blend executi protocols automàticament, per defecte disponible a les preferències del sistema" + + +msgctxt "Operator" +msgid "Operator Cheat Sheet" +msgstr "Xuleta d'operadors" + + +msgid "List all the operators in a text-block, useful for scripting" +msgstr "[Operator Cheat Sheet]: Llista de tots els operadors d'un bloc de text, útil per a escriure protocols" + + +msgctxt "Operator" +msgid "Restore Operator Defaults" +msgstr "Restaurar predeterminats d'operador" + + +msgid "Set the active operator to its default values" +msgstr "Posa l'operador actiu en els seus valors predeterminats" + + +msgctxt "Operator" +msgid "Operator Enum Pie" +msgstr "Menú pastís d'operadors" + + msgid "Operator name (in python as string)" -msgstr "Nom de l'operador (a python com a cadena)" +msgstr "[Operator Enum Pie]: Nom de l'operador (a python com a cadena)" + + +msgid "Property name (as a string)" +msgstr "Nom de propietat (com a cadena)" + + +msgctxt "Operator" +msgid "Operator Preset" +msgstr "Predefinit d'operador" + + +msgid "Add or remove an Operator Preset" +msgstr "Afegeix o elimina un valor predefinit de l'operador" + + +msgid "Disable add-on for workspace" +msgstr "Desactivar complement per l'obrador" + + +msgid "UI Tag" +msgstr "Etiqueta d'IU" + + +msgid "Enable add-on for workspace" +msgstr "Activar complement per l'obrador" + + +msgid "Open a path in a file browser" +msgstr "Obrir un camí al navegador de documents" + + +msgctxt "Operator" +msgid "Batch-Clear Previews" +msgstr "Descartar previsualitzacions a l'engròs" + + +msgid "Clear selected .blend file's previews" +msgstr "[Batch-Clear Previews]: Neteja les previsualitzacions del document .blend seleccionat" + + +msgid "Save Backups" +msgstr "Desar còpies de seguretat" + + +msgid "Keep a backup (.blend1) version of the files when saving with cleared previews" +msgstr "Manté una versió de còpia de seguretat (.blend1) dels documents en desar amb les visualitzacions descartades" + + +msgid "Clear collections' previews" +msgstr "Descartar previsualitzacions de col·leccions" + + +msgid "Materials & Textures" +msgstr "Materials i textures" + + +msgid "Clear 'internal' previews (materials, textures, images, etc.)" +msgstr "Descarta previsualitzacions «internes» (materials, textures, imatges, etc.)" + + +msgid "Clear objects' previews" +msgstr "Descartar previsualitzacions d'objectes" + + +msgid "Clear scenes' previews" +msgstr "Descartar previsualitzacions d'escenes" + + +msgid "Trusted Blend Files" +msgstr "Docs Blend de confiança" msgid "Enable python evaluation for selected files" msgstr "Activa l'avaluació del python per als documents seleccionats" +msgctxt "Operator" +msgid "Batch-Generate Previews" +msgstr "Generar previsualitzacions a l'engròs" + + +msgid "Generate selected .blend file's previews" +msgstr "[Batch-Generate Previews]: Genera les vistes prèvies del document .blend seleccionat" + + +msgid "Root path of all files listed in `files` collection" +msgstr "Camí arrel de tots els documents llistats a la col·lecció «documents»" + + +msgid "Collection of file paths with common `directory` root" +msgstr "Col·lecció de camins de documents amb l'arrel comuna «directori»" + + +msgid "Show Blender files in the File Browser" +msgstr "Mostrar documents Blender al navegador de documents" + + +msgid "Show folders in the File Browser" +msgstr "Mostrar carpetes al navegador de documents" + + +msgid "Keep a backup (.blend1) version of the files when saving with generated previews" +msgstr "Mantenir una versió de còpia de seguretat (.blend1) dels documents en desar amb vistes prèvies generades" + + +msgid "Generate collections' previews" +msgstr "Generar previsualitzacions de col·leccions" + + +msgid "Generate 'internal' previews (materials, textures, images, etc.)" +msgstr "Generar previsualitzacions «internes» (materials, textures, imatges, etc.)" + + +msgid "Generate objects' previews" +msgstr "Generar previsualitzacions d'objectes" + + +msgid "Generate scenes' previews" +msgstr "Generar previsualitzacions d'escenes" + + +msgctxt "Operator" +msgid "Clear Data-Block Previews" +msgstr "Descartar previsualitzacions de blocs de dades" + + +msgid "Clear data-block previews (only for some types like objects, materials, textures, etc.)" +msgstr "[Clear Data-Block Previews]: Neteja les vistes prèvies de blocs de dades (només per a alguns tipus com objectes, materials, textures, etc.)" + + +msgid "Data-Block Type" +msgstr "Tipus de bloc de dades" + + +msgid "Which data-block previews to clear" +msgstr "Quines previsualitzacions de blocs de dades cal descartar" + + +msgid "All Types" +msgstr "Tots els tipus" + + +msgid "All Geometry Types" +msgstr "Tots els tipus geomètrics" + + +msgid "Clear previews for scenes, collections and objects" +msgstr "Descartar previsualitzacions per a escenes, col·leccions i objectes" + + +msgid "All Shading Types" +msgstr "Tots els tipus d'aspecte" + + +msgid "Clear previews for materials, lights, worlds, textures and images" +msgstr "Neteja les vistes prèvies per a materials, llums, mons, textures i imatges" + + +msgctxt "Operator" +msgid "Refresh Data-Block Previews" +msgstr "Refrescar previsualitzacions de blocs de dades" + + +msgid "Ensure data-block previews are available and up-to-date (to be saved in .blend file, only for some types like materials, textures, etc.)" +msgstr "Assegura que les vistes prèvies dels blocs de dades estan disponibles i actualitzades (per ser desades en un document .blend, només per a alguns tipus com materials, textures, etc.)" + + +msgctxt "Operator" +msgid "Add Property" +msgstr "Afegir propietat" + + +msgid "Add your own property to the data-block" +msgstr "Afegeix la teva pròpia propietat al bloc de dades" + + +msgid "Property Edit" +msgstr "Editar propietat" + + +msgid "Property data_path edit" +msgstr "Edició de propietat data_path" + + +msgid "Jump to a different tab inside the properties editor" +msgstr "Salta a una pestanya diferent dins l'editor de propietats" + + +msgid "Context" +msgstr "Context" + + +msgctxt "Operator" +msgid "Edit Property" +msgstr "Editar propietat" + + +msgid "Change a custom property's type, or adjust how it is displayed in the interface" +msgstr "Canvia el tipus d'una propietat personalitzada, o ajusta com es mostra a la interfície" + + +msgid "Array Length" +msgstr "Longitud de corrua" + + +msgid "Python value for unsupported custom property types" +msgstr "Valor de python per als tipus de propietats personalitzades no admeses" + + +msgid "Library Overridable" +msgstr "Biblioteca sobreseïble" + + +msgid "Allow the property to be overridden when the data-block is linked" +msgstr "Permet que la propietat se sobresegui quan s'enllaci el bloc de dades" + + +msgid "Property Name" +msgstr "Nom de propietat" + + +msgid "Property name edit" +msgstr "Edita el nom de la propietat" + + +msgid "A single floating-point value" +msgstr "Un únic valor en coma flotant" + + +msgid "Float Array" +msgstr "Corrua flotant" + + +msgid "An array of floating-point values" +msgstr "Una corrua de valors de coma flotant" + + +msgid "A single integer" +msgstr "Un enter únic" + + +msgid "Integer Array" +msgstr "Corrua d'enters" + + +msgid "An array of integers" +msgstr "Una corrua d'enters" + + +msgid "A true or false value" +msgstr "Valor ver of fals" + + +msgid "Boolean Array" +msgstr "Corrua booleana" + + +msgid "An array of true or false values" +msgstr "Una corrua de valors ver/fals" + + +msgid "A string value" +msgstr "Un valor de cadena" + + msgid "Edit a python value directly, for unsupported property types" -msgstr "Edita un valor de python directament, per als tipus de propietats no suportades" +msgstr "[A string value]: Edita un valor de python directament, per als tipus de propietats no suportades" + + +msgid "Soft Max" +msgstr "Màx. suau" + + +msgid "Soft Min" +msgstr "Mín. suau" + + +msgid "Subtype" +msgstr "Subtipus" + + +msgid "Plain Data" +msgstr "Dades bàsiques" + + +msgid "Data values without special behavior" +msgstr "Valors de dades sense comportament especial" + + +msgid "Linear Color" +msgstr "Color lineal" + + +msgid "Color in the linear space" +msgstr "[Linear Color]: Color en l'espai lineal" + + +msgid "Gamma-Corrected Color" +msgstr "Color de gamma corregit" + + +msgid "Color in the gamma corrected space" +msgstr "[Gamma-Corrected Color]: Color en l'espai gamma corregit" + + +msgid "Euler Angles" +msgstr "Angles d'Euler" + + +msgid "Euler rotation angles in radians" +msgstr "Angles de gir d'Euler en radians" + + +msgid "Quaternion rotation (affects NLA blending)" +msgstr "Rotació de quaternions (afecta la fusió d'ANL)" + + +msgid "Soft Limits" +msgstr "Límits suaus" + + +msgid "Limits the Property Value slider to a range, values outside the range must be inputted numerically" +msgstr "Limita el lliscador del valors de propietat a un interval, els valors fora de l'interval s'han d'ingressar numèricament" + + +msgctxt "Operator" +msgid "Edit Property Value" +msgstr "Editar valor de propietat" + + +msgid "Edit the value of a custom property" +msgstr "Edita el valor d'una propietat personalitzada" + + +msgid "Value for custom property types that can only be edited as a Python expression" +msgstr "Valor per als tipus de propietats personalitzades que només es poden editar com una expressió de python" + + +msgctxt "Operator" +msgid "Remove Property" +msgstr "Suprimir propietat" + + +msgid "Internal use (edit a property data_path)" +msgstr "Ús intern (editar un data_path d'una propietat)" + + +msgctxt "Operator" +msgid "Quit Blender" +msgstr "Sortir del Blender" + + +msgid "Quit Blender" +msgstr "Surt del Blender" + + +msgctxt "Operator" +msgid "Radial Control" +msgstr "Control radial" + + +msgid "Set some size property (e.g. brush size) with mouse wheel" +msgstr "[Radial Control]: Estableix alguna propietat de mida (p. ex. mida del pinzell) amb la roda del ratolí" + + +msgid "Color Path" +msgstr "Camí del color" + + +msgid "Path of property used to set the color of the control" +msgstr "Camí de la propietat utilitzada per a establir el color del control" + + +msgid "Primary Data Path" +msgstr "Camí de dades primari" + + +msgid "Primary path of property to be set by the radial control" +msgstr "[Primary Data Path]: Camí primari de la propietat a establir pel control radial" + + +msgid "Secondary Data Path" +msgstr "Camí de dades secundari" + + +msgid "Secondary path of property to be set by the radial control" +msgstr "Camí secundari de la propietat a establir pel control radial" + + +msgid "Fill Color Override Path" +msgstr "Camí de sobreseïment de color d'emplenat" + + +msgid "Fill Color Override Test" +msgstr "Prova de sobreseïment de color d'emplenat" + + +msgid "Fill Color Path" +msgstr "Camí de color d'emplenat" + + +msgid "Path of property used to set the fill color of the control" +msgstr "Camí de la propietat utilitzada per a establir el color d'emplenat del control" + + +msgid "Image ID" +msgstr "ID d'imatge" + + +msgid "Path of ID that is used to generate an image for the control" +msgstr "Camí de l'identificador que s'utilitza per a generar una imatge per al control" + + +msgid "Confirm On Release" +msgstr "Confirmar en deixar anar" + + +msgid "Finish operation on key release" +msgstr "[Confirm On Release]: Finalitza l'operació en alliberar la tecla" + + +msgid "Rotation Path" +msgstr "Camí de rotació" + + +msgid "Path of property used to rotate the texture display" +msgstr "Camí de la propietat utilitzada per a rotar la visualització de la textura" + + +msgid "Secondary Texture" +msgstr "Textura secundària" + + +msgid "Tweak brush secondary/mask texture" +msgstr "Ajusta la textura secundària/màscara del pinzell" + + +msgid "Use Secondary" +msgstr "Utilitza secundari" + + +msgid "Path of property to select between the primary and secondary data paths" +msgstr "Camí de la propietat per seleccionar entre els camins de dades primari i secundari" + + +msgid "Zoom Path" +msgstr "Camí del zoom" + + +msgid "Path of property used to set the zoom level for the control" +msgstr "Camí de la propietat utilitzada per a establir el nivell de zoom per al control" + + +msgctxt "Operator" +msgid "Load Factory Settings" +msgstr "Carregar configuració de fàbrica" + + +msgid "Load factory default startup file and preferences. To make changes permanent, use \"Save Startup File\" and \"Save Preferences\"" +msgstr "Carrega el document d'inici i les preferències predeterminades de fàbrica. Per fer canvis permanents, utilitzeu «Desar document d'inici» i «Desar preferències»" + + +msgid "Factory Startup App-Template Only" +msgstr "Només la plantilla d'aplicació de planificació de fàbrica" + + +msgctxt "Operator" +msgid "Load Factory Preferences" +msgstr "Carregar preferències de fàbrica" + + +msgid "Load factory default preferences. To make changes to preferences permanent, use \"Save Preferences\"" +msgstr "Carrega les preferències predeterminades de fàbrica. Per fer canvis permanents a les preferències, usar «Desar preferències»" + + +msgctxt "Operator" +msgid "Reload History File" +msgstr "Recarregar document d'historial" + + +msgid "Reloads history and bookmarks" +msgstr "Torna a carregar l'historial i les adreces d'interès" + + +msgctxt "Operator" +msgid "Reload Start-Up File" +msgstr "Recarregar document d'inici" + + +msgid "Open the default file (doesn't save the current file)" +msgstr "Obre el document predeterminat (no desa el document actual)" + + +msgid "Path to an alternative start-up file" +msgstr "Camí a un document d'inici alternatiu" + + +msgid "Load user interface setup from the .blend file" +msgstr "Carrega la configuració de la interfície d'usuària des del document .blend" + + +msgid "Factory Startup" +msgstr "Inici de fàbrica" + + +msgctxt "Operator" +msgid "Load Preferences" +msgstr "Carregar preferències" + + +msgid "Load last saved preferences" +msgstr "Carrega les últimes preferències desades" + + +msgctxt "Operator" +msgid "Recover Auto Save" +msgstr "Recuperació d'autoguardar" + + +msgid "Open an automatically saved file to recover it" +msgstr "[Recover Auto Save]: Obre un document desat automàticament per recuperar-lo" + + +msgctxt "Operator" +msgid "Recover Last Session" +msgstr "Recuperar última sessió" + + +msgid "Open the last closed file (\"quit.blend\")" +msgstr "Obre l'últim document tancat («quit.blend»)" + + +msgctxt "Operator" +msgid "Redraw Timer" +msgstr "Repassar temporitzador" + + +msgid "Simple redraw timer to test the speed of updating the interface" +msgstr "[Redraw Timer]: Simple reaplicació del temporitzador per provar la rapidesa d'actualització de la interfície" + + +msgid "Number of times to redraw" +msgstr "Nombre de cops a repassar" + + +msgid "Time Limit" +msgstr "Límit de temps" + + +msgid "Seconds to run the test for (override iterations)" +msgstr "Segons per executar la prova (sobreseu iteracions)" + + +msgid "Draw Region" +msgstr "Passar regió" + + +msgid "Draw region" +msgstr "[Draw Region]: Passa la regió" + + +msgid "Draw Region & Swap" +msgstr "Passar la regió i intercanviar" + + +msgid "Draw region and swap" +msgstr "[Draw Region & Swap]: Passa la regió i intercanvia" + + +msgid "Draw Window" +msgstr "Passar finestra" + + +msgid "Draw window" +msgstr "[Draw Window]: Passa la finestra" + + +msgid "Draw Window & Swap" +msgstr "Passar finestra i intercanviar" + + +msgid "Draw window and swap" +msgstr "Passa la finestra i intercanvia" + + +msgid "Animation Step" +msgstr "Pas d'animació" + + +msgid "Animation steps" +msgstr "[Animation Step]: Passos de l'animació" + + +msgid "Animation Play" +msgstr "Reproduir l'animació" + + +msgid "Animation playback" +msgstr "[Animation Play]: Reproducció d'animació" + + +msgid "Undo/Redo" +msgstr "Desfer/Refer" + + +msgid "Undo and redo" +msgstr "Desfa i refa" + + +msgctxt "Operator" +msgid "Revert" +msgstr "Revertir" + + +msgid "Reload the saved file" +msgstr "[Revert]: Torna a carregar el document desat" + + +msgid "Save the current file in the desired location" +msgstr "Desa el document actual a la ubicació desitjada" + + +msgid "Write compressed .blend file" +msgstr "Escriu el document .blend comprimit" + + +msgid "Save Copy" +msgstr "Desar còpia" + + +msgid "Save a copy of the actual working state but does not make saved file active" +msgstr "Desa una còpia de l'estat operatiu real, però no activa pas el document desat" + + +msgid "Remap Relative" +msgstr "Remapejar relatius" + + +msgid "Remap relative paths when saving to a different directory" +msgstr "[Remap Relative]: Reassigna els camins relatius en desar a un directori diferent" + + +msgctxt "Operator" +msgid "Save Startup File" +msgstr "Desar document d'inici" + + +msgid "Make the current file the default .blend file" +msgstr "Fa que el document actual sigui el document .blend predeterminat" + + +msgctxt "Operator" +msgid "Save Blender File" +msgstr "Desar document Blender" + + +msgid "Save the current Blender file" +msgstr "Desa el document del Blender actual" + + +msgid "Exit Blender after saving" +msgstr "Sortir del Blender després de desar" + + +msgctxt "Operator" +msgid "Save Preferences" +msgstr "Preferències de desas" + + +msgid "Make the current preferences default" +msgstr "Converteix les preferències actuals en predeterminades" + + +msgctxt "Operator" +msgid "Search Menu" +msgstr "Menú de cerca" + + +msgid "Pop-up a search over all menus in the current context" +msgstr "Finestra emergent de cerca dins tots els menús del context present" + + +msgctxt "Operator" +msgid "Search Operator" +msgstr "Operador de cerca" + + +msgid "Pop-up a search over all available operators in current context" +msgstr "Finestra emergent de cerca sobre tots els operadors disponibles en el context present" + + +msgctxt "Operator" +msgid "Set Stereo 3D" +msgstr "Aplicar estèreo 3D" + + +msgid "Toggle 3D stereo support for current window (or change the display mode)" +msgstr "Alterna el suport a estèreo 3D dins finestra actual (o canvia el mode de visualització)" + + +msgid "Anaglyph Type" +msgstr "Tipus anàglif" + + +msgid "Red-Cyan" +msgstr "Vermell-cian" + + +msgid "Green-Magenta" +msgstr "Verd-magenta" + + +msgid "Yellow-Blue" +msgstr "Groc-blau" + + +msgid "Anaglyph" +msgstr "Anàglif" + + +msgid "Render views for left and right eyes as two differently filtered colors in a single image (anaglyph glasses are required)" +msgstr "[Anaglyph]: Revela la visualització per als ulls esquerre i dret en base a dos colors filtrats de manera diferent en una sola imatge (es requereixen ulleres d'anàglif)" + + +msgid "Interlace" +msgstr "Entrellaçat" + + +msgid "Render views for left and right eyes interlaced in a single image (3D-ready monitor is required)" +msgstr "[Interlace]: Revela la visualització per als ulls esquerre i dret entrellaçada en una sola imatge (cal un monitor 3D-ready)" + + +msgid "Time Sequential" +msgstr "Seqüencial de temps" + + +msgid "Render alternate eyes (also known as page flip, quad buffer support in the graphic card is required)" +msgstr "[Time Sequential]: Revela per a cada ull alternativament (també coneguts com de girar pàgina, es requereix suport de quads de memòria intermèdia a la targeta gràfica)" + + +msgid "Side-by-Side" +msgstr "De costat" + + +msgid "Render views for left and right eyes side-by-side" +msgstr "[Side-by-Side]: Revela visualitzacions per als ulls esquerre i dret un al costat de l'altre" + + +msgid "Top-Bottom" +msgstr "De dalt a baix" + + +msgid "Render views for left and right eyes one above another" +msgstr "Revela la visualització per als ulls esquerre i dret un sobre l'altre" + + +msgid "Interlace Type" +msgstr "Tipus d'entrellaçat" + + +msgid "Row Interleaved" +msgstr "Files entrellaçades" + + +msgid "Column Interleaved" +msgstr "Columnes entrellaçades" + + +msgid "Checkerboard Interleaved" +msgstr "Entrellaçat de quadrícula" + + +msgid "Swap Left/Right" +msgstr "[Swap Left/Right]: Invertir esquerra/dreta" + + +msgid "Swap left and right stereo channels" +msgstr "[Swap Left/Right]: Intercanvia els canals estèreo esquerre i dret" + + +msgid "Cross-Eyed" +msgstr "Guenyo" + + +msgid "Right eye should see left image and vice versa" +msgstr "[Cross-Eyed]: L'ull dret ha de veure la imatge esquerra i viceversa" + + +msgctxt "Operator" +msgid "Splash Screen" +msgstr "Careta d'entrada" + + +msgid "Open the splash screen with release info" +msgstr "[Splash Screen]: Obre la pantalla de presentació amb informació de la versió" + + +msgctxt "Operator" +msgid "About Blender" +msgstr "Quant al Blender" + + +msgid "Open a window with information about Blender" +msgstr "Obre una finestra amb informació sobre el Blender" + + +msgid "Import an STL file as an object" +msgstr "Importa un document STL com a objecte" + + +msgid "Validate Mesh" +msgstr "Validar malla" + + +msgid "Validate and correct imported mesh (slow)" +msgstr "[Validate Mesh]: Valida i corregeix la malla importada (lent)" + + +msgctxt "Operator" +msgid "Save System Info" +msgstr "Desar informació del sistema" + + +msgid "Generate system information, saved into a text file" +msgstr "Genera informació del sistema, i la desa en un document de text" + + +msgctxt "Operator" +msgid "Set Tool by Name" +msgstr "Arranja eina per nom" + + +msgid "Set the tool by name (for keymaps)" +msgstr "[Set Tool by Name]: Estableix l'eina per nom (per als teclaris)" + + +msgid "Set Fallback" +msgstr "Definir segona opció" + + +msgid "Set the fallback tool instead of the primary tool" +msgstr "[Set Fallback]: Estableix l'eina de reserva en lloc de l'eina primària" + + +msgid "Cycle" +msgstr "Ciclitzar" + + +msgid "Cycle through tools in this group" +msgstr "[Cycle]: Recorre les eines d'aquest grup" + + +msgid "Identifier of the tool" +msgstr "Identificador d'eina" + + +msgctxt "Operator" +msgid "Set Tool by Index" +msgstr "Arranja eina per índex" + + +msgid "Set the tool by index (for keymaps)" +msgstr "Estableix l'eina per índex (per als teclaris)" + + +msgid "Set the fallback tool instead of the primary" +msgstr "Establir l'eina de reserva en lloc de la primària" + + +msgid "Include tool subgroups" +msgstr "Incloure subgrups d'eines" + + +msgid "Index in Toolbar" +msgstr "Índex de barra d'eines" + + +msgctxt "Operator" +msgid "Toolbar" +msgstr "Barra d'eines" + + +msgctxt "Operator" +msgid "Fallback Tool Pie Menu" +msgstr "Menú pastís d'eines alternatives" + + +msgctxt "Operator" +msgid "Toolbar Prompt" +msgstr "Barra d'eines emergent" + + +msgid "Leader key like functionality for accessing tools" +msgstr "Guia de funcionalitats de teclat per accedir a les eines" + + +msgid "Open a website in the web browser" +msgstr "Obre lloc web al navegador web" + + +msgid "URL" +msgstr "URL" + + +msgid "URL to open" +msgstr "URL per obrir" + + +msgctxt "Operator" +msgid "Open Preset Website" +msgstr "Obrir web predefinit" + + +msgid "Open a preset website in the web browser" +msgstr "Obre un lloc web predefinit al navegador web" + + +msgid "Optional identifier" +msgstr "Identificador opcional" + + +msgid "Site" +msgstr "Lloc" + + +msgctxt "Operator" +msgid "Export USD" +msgstr "Exportar USD" + + +msgid "Export current scene in a USD archive" +msgstr "Exporta l'escena actual en un arxiu USD" + + +msgid "Export all frames in the render frame range, rather than only the current frame" +msgstr "Exporta tots els fotogrames de l'interval de fotogrames de revelat, en lloc de només del fotograma actual" + + +msgid "Export hair particle systems as USD curves" +msgstr "Exportar els sistemes de partícules pèl com a corbes d'USD" + + +msgid "Export viewport settings of materials as USD preview materials, and export material assignments as geometry subsets" +msgstr "Exportar la configuració de l'àrea de visualització dels materials com a materials de vista prèvia USD, i exporta les assignacions de materials com a subconjunts de geometria" + + +msgid "Include normals of exported meshes in the export" +msgstr "Incloure normals de malles exportades a l'exportació" + + +msgid "Export Textures" +msgstr "Exportar textures" + + +msgid "If exporting materials, export textures referenced by material nodes to a 'textures' directory in the same directory as the USD file" +msgstr "Si s'exporten materials, s'exporten textures referenciades pels nodes materials a un directori «textures» al mateix directori que el document USD" + + +msgid "UV Maps" +msgstr "Mapes UV" + + +msgid "Include all mesh UV maps in the export" +msgstr "Inclou en l'exportació tots els mapes UV de malles" + + +msgid "To USD Preview Surface" +msgstr "A vista prèvia de superfície d'USD" + + +msgid "Generate an approximate USD Preview Surface shader representation of a Principled BSDF node network" +msgstr "[To USD Preview Surface]: Genera una previsualització aproximada de la superfície amb l'aspector d'USD d'una xarxa de nodes de BSDF postulats" + + +msgid "Overwrite Textures" +msgstr "Sobrescriure textures" + + +msgid "Allow overwriting existing texture files when exporting textures" +msgstr "Permet sobreescriure els documents de textura existents en exportar les textures" + + +msgid "Use relative paths to reference external files (i.e. textures, volumes) in USD, otherwise use absolute paths" +msgstr "Usar camins relatius per a referenciar documents externs (és a dir, textures, volums) en USD, altrament usar camins absoluts" + + +msgid "Only export selected objects. Unselected parents of selected objects are exported as empty transform" +msgstr "Exportar només els objectes seleccionats. Els pares no seleccionats dels objectes seleccionats s'exporten com a transformació buida" + + +msgid "Instancing" +msgstr "Instanciar" + + +msgid "Export instanced objects as references in USD rather than real objects" +msgstr "[Instancing] Exporta els objectes instanciats com a referències en USD en lloc d'objectes reals" + + +msgid "Visible Only" +msgstr "Només visible" + + +msgid "Only export visible objects. Invisible parents of exported objects are exported as empty transforms" +msgstr "Exporta només els objectes visibles. Els pares invisibles dels objectes exportats s'exporten com a transformacions buides" + + +msgctxt "Operator" +msgid "Import USD" +msgstr "Importar USD" + + +msgid "Import USD stage into current scene" +msgstr "Importa l'escena USD a l'actual" + + +msgid "Create Collection" +msgstr "Crear col·lecció" + + +msgid "Add all imported objects to a new collection" +msgstr "Afegeix tots els objectes importats a una nova col·lecció" + + +msgid "Import All Materials" +msgstr "Importar tots els materials" + + +msgid "Also import materials that are not used by any geometry. Note that when this option is false, materials referenced by geometry will still be imported" +msgstr "També importa materials no usats per cap geometria. Noteu que quan aquesta opció és falsa, els materials referenciats per la geometria s'importaran igualment" + + +msgid "Import guide geometry" +msgstr "Importar geometria guia" + + +msgid "Import Instance Proxies" +msgstr "Importar intermediaris d'instància" + + +msgid "Create unique Blender objects for USD instances" +msgstr "[Import Instance Proxies]: Crea objectes Blender únics per a instàncies USD" + + +msgid "Import proxy geometry" +msgstr "Importar geometria intermediària" + + +msgid "Import final render geometry" +msgstr "Importar geometria de revelat final" + + +msgid "Shapes" +msgstr "Formes" + + +msgid "Import Subdivision Scheme" +msgstr "Importar esquema de subdivisió" + + +msgid "Create subdivision surface modifiers based on the USD SubdivisionScheme attribute" +msgstr "[Import Subdivision Scheme]: Crea modificadors de subdivisió de superfície basats en l'atribut SubdivisionScheme d'USD" + + +msgid "Textures Directory" +msgstr "Directori de textures" + + +msgid "Path to the directory where imported textures will be copied" +msgstr "[Textures Directory]: Camí al directori on es copiaran les textures importades" + + +msgid "Import Textures" +msgstr "Importar textures" + + +msgid "Behavior when importing textures from a USDZ archive" +msgstr "Comportament en importar textures des d'arxiu USDZ" + + +msgid "Don't import textures" +msgstr "No importar extures" + + +msgid "Packed" +msgstr "Empaquetades" + + +msgid "Import textures as packed data" +msgstr "[Packed]: Importa textures com a dades empaquetades" + + +msgid "Copy files to textures directory" +msgstr "Copiar documents al directori de textures" + + +msgid "Import USD Preview" +msgstr "Importar previsualització USD" + + +msgid "Convert UsdPreviewSurface shaders to Principled BSDF shader networks" +msgstr "Converteix els aspectors UsdPreviewSurface en xarxes d'aspectors de BSDFs postulats" + + +msgid "Visible Primitives Only" +msgstr "Només primitius visibles" + + +msgid "Do not import invisible USD primitives. Only applies to primitives with a non-animated visibility attribute. Primitives with animated visibility will always be imported" +msgstr "[Visible Primitives Only]: No importa primitius invisibles d'USD. Només s'aplica als primitius amb un atribut de visibilitat no animada. Els primitius amb visibilitat animada sempre s'importaran" + + +msgid "Light Intensity Scale" +msgstr "Escala d'intensitat de llum" + + +msgid "Scale for the intensity of imported lights" +msgstr "Escala per a la intensitat de les llums importades" + + +msgid "Material Name Collision" +msgstr "Col·lisió amb nom de material" + + +msgid "Behavior when the name of an imported material conflicts with an existing material" +msgstr "[Material Name Collision]: Comportament quan el nom d'un material importat entra en conflicte amb un material existent" + + +msgid "Make Unique" +msgstr "Fer únics" + + +msgid "Import each USD material as a unique Blender material" +msgstr "[Make Unique]: Importar cada material USD com un material de Blender únic" + + +msgid "Reference Existing" +msgstr "Referenciar existents" + + +msgid "If a material with the same name already exists, reference that instead of importing" +msgstr "[Reference Existing]: Si ja existeix un material amb el mateix nom, es referencia en lloc d'importar-lo" + + +msgid "Path Mask" +msgstr "Màscara de camí" + + +msgid "Import only the subset of the USD scene rooted at the given primitive" +msgstr "[Path Mask]: Importa només el subconjunt de l'escena del USD arrelat al primitiu donat" + + +msgid "Read mesh color attributes" +msgstr "Llegir atributs de color de malla" + + +msgid "Read mesh UV coordinates" +msgstr "Llegir coordenades UV de malla" + + +msgid "Update the scene's start and end frame to match those of the USD archive" +msgstr "Actualitzar fotogrames d'inici i final de l'escena perquè coincideixin amb els de l'arxiu USD" + + +msgid "Set Material Blend" +msgstr "Definir fusió de material" + + +msgid "If the Import USD Preview option is enabled, the material blend method will automatically be set based on the shader's opacity and opacityThreshold inputs" +msgstr "[Set Material Blend]: Si l'opció d'importar previsualització USD està activada, el mètode de fusió de material es configurarà automàticament en funció dels ingressos d'opacitat i d'interval d'opacitat de l'aspector" + + +msgid "File Name Collision" +msgstr "Col·lisió de nom de document" + + +msgid "Behavior when the name of an imported texture file conflicts with an existing file" +msgstr "Comportament quan el nom d'un document de textura importada entra en conflicte amb un document existent" + + +msgid "Use Existing" +msgstr "Usar l'existent" + + +msgid "If a file with the same name already exists, use that instead of copying" +msgstr "Si ja existeix un document amb el mateix nom, usar-lo en lloc de copiar-lo" + + +msgid "Overwrite existing files" +msgstr "Sobreescriure documents existents" + + +msgctxt "Operator" +msgid "Close Window" +msgstr "Tancar finestra" + + +msgid "Close the current window" +msgstr "Tanca la finestra actual" + + +msgctxt "Operator" +msgid "Toggle Window Fullscreen" +msgstr "Revesar finestra de pantalla completa" + + +msgid "Toggle the current window full-screen" +msgstr "Alterna la pantalla completa de la finestra" + + +msgctxt "Operator" +msgid "New Window" +msgstr "Nova finestra" + + +msgid "Create a new window" +msgstr "Crea una finestra nova" + + +msgctxt "Operator" +msgid "New Main Window" +msgstr "Nova finestra principal" + + +msgid "Create a new main window with its own workspace and scene selection" +msgstr "Crea una finestra principal nova amb el seu propi obrador i la selecció de l'escena" + + +msgctxt "Operator" +msgid "XR Navigation Fly" +msgstr "Vol de navegació en RS" + + +msgid "Move/turn relative to the VR viewer or controller" +msgstr "[XR Navigation Fly]: Mou/gira en en relació amb el visor o controlador de realitat estesa" + + +msgid "Lock Direction" +msgstr "Blocar direcció" + + +msgid "Limit movement to viewer's initial direction" +msgstr "[Lock Direction]: Limita el moviment a la direcció inicial del visor" + + +msgid "Lock Elevation" +msgstr "Blocar elevació" + + +msgid "Prevent changes to viewer elevation" +msgstr "Evita els canvis a l'elevació del visor" + + +msgid "Fly mode" +msgstr "Mode de vol" + + +msgid "Move along navigation forward axis" +msgstr "Moure's seguint l'eix endavant de navegació" + + +msgid "Move along navigation back axis" +msgstr "Moure's seguint l'eix enrere de navegació" + + +msgid "Move along navigation left axis" +msgstr "Moure's seguint l'eix esquerre de navegació" + + +msgid "Move along navigation right axis" +msgstr "Moure's seguint l'eix dret de navegació" + + +msgid "Move along navigation up axis" +msgstr "Moure's seguint l'eix en amunt de navegació" + + +msgid "Move along navigation down axis" +msgstr "Moure's seguint l'eix en avall de navegació" + + +msgid "Turn Left" +msgstr "Girar a l'esquerra" + + +msgid "Turn counter-clockwise around navigation up axis" +msgstr "Gira en sentit antihorari al voltant de l'eix de navegació en amunt" + + +msgid "Turn Right" +msgstr "Girar a la dreta" + + +msgid "Turn clockwise around navigation up axis" +msgstr "Gira en sentit horari al voltant de l'eix de navegació en amunt" + + +msgid "Viewer Forward" +msgstr "Visor endavant" + + +msgid "Move along viewer's forward axis" +msgstr "[Viewer Forward]: Es mou seguint l'eix endavant del visor" + + +msgid "Viewer Back" +msgstr "Visor enrere" + + +msgid "Move along viewer's back axis" +msgstr "[Viewer Back]: Es mou seguint l'eix enrere del visor" + + +msgid "Viewer Left" +msgstr "Visor esquerre" + + +msgid "Move along viewer's left axis" +msgstr "Es mou seguint l'eix esquerre del visor" + + +msgid "Viewer Right" +msgstr "Visor dret" + + +msgid "Move along viewer's right axis" +msgstr "Es mou seguint l'eix dret del visor" + + +msgid "Controller Forward" +msgstr "Controlador endavant" + + +msgid "Move along controller's forward axis" +msgstr "[Controller Forward]: Es mou seguint l'eix endavant del controlador" + + +msgid "Frame Based Speed" +msgstr "Rapidesa per fotogrames" + + +msgid "Apply fixed movement deltas every update" +msgstr "Aplicar deltes de moviment fix en cada actualització" + + +msgid "Speed Interpolation 0" +msgstr "Rapidesa d'interpolació 0" + + +msgid "First cubic spline control point between min/max speeds" +msgstr "Primer punt de control de spline cúbic entre rapideses mínimes i màximes" + + +msgid "Speed Interpolation 1" +msgstr "Rapidesa d'interpolació 1" + + +msgid "Second cubic spline control point between min/max speeds" +msgstr "Segon punt de control de spline cúbic entre rapideses mínimes i màximes" + + +msgid "Maximum Speed" +msgstr "Rapidesa màxima" + + +msgid "Maximum move (turn) speed in meters (radians) per second or frame" +msgstr "Rapidesa màxima de moviment (gir) en metres (radians) per segon o per fotograma" + + +msgid "Minimum Speed" +msgstr "Rapidesa mínima" + + +msgid "Minimum move (turn) speed in meters (radians) per second or frame" +msgstr "Rapidesa mínima de moviment (gir) en metres (radians) per segon o per fotograma" + + +msgctxt "Operator" +msgid "XR Navigation Grab" +msgstr "Navegació de RS a mà" + + +msgid "Navigate the VR scene by grabbing with controllers" +msgstr "[XR Navigation Grab]: Navega per l'escena de realitat estesa agafat als controls" + + +msgid "Prevent changes to viewer location" +msgstr "Evitar canvis d'ubicació del visor" + + +msgid "Prevent changes to viewer rotation" +msgstr "Evitar canvis de rotació del visor" + + +msgid "Lock Up Orientation" +msgstr "Bloquejar orientació" + + +msgid "Prevent changes to viewer up orientation" +msgstr "Evita els canvis d'orientació cap amunt del visor" + + +msgid "Prevent changes to viewer scale" +msgstr "Evitar els canvis d'escala del visor" + + +msgctxt "Operator" +msgid "XR Navigation Reset" +msgstr "Reiniciar navegació RS" + + +msgid "Reset VR navigation deltas relative to session base pose" +msgstr "[Reiniciar navegació RS]: Restableix les deltes de navegació de realitat virtual relatives a la posa base de la sessió" + + +msgid "Reset location deltas" +msgstr "Reiniciar deltes d'ubicació" + + +msgid "Reset rotation deltas" +msgstr "Reiniciar deltes de rotació" + + +msgid "Reset scale deltas" +msgstr "Reiniciar deltes d'escala" + + +msgctxt "Operator" +msgid "XR Navigation Teleport" +msgstr "Teleport de navegació RS" + + +msgid "Set VR viewer location to controller raycast hit location" +msgstr "[XR Navigation Teleport]: Estableix la ubicació del visor de RV a la ubicació on van a parar els raigs del raycasting" + + +msgid "Raycast axis in controller/viewer space" +msgstr "Eix de raycasting en l'espai controlador/visor" + + +msgid "Raycast color" +msgstr "Color de raycasting" + + +msgid "Maximum raycast distance" +msgstr "Distància màxima de raycasting" + + +msgid "From Viewer" +msgstr "Des del visor" + + +msgid "Use viewer pose as raycast origin" +msgstr "Usar posa del visor com a origen de raigs del raycasting" + + +msgid "Interpolation factor between viewer and hit locations" +msgstr "Factor d'interpolació entre l'espectador i els punts d'impacte" + + +msgid "Offset along hit normal to subtract from final location" +msgstr "Desplaçament seguint la normal d'impacte per a restar-ho la ubicació final" + + +msgid "Selectable Only" +msgstr "Seleccionable i prou" + + +msgid "Only allow selectable objects to influence raycast result" +msgstr "Permet només que els objectes seleccionables influeixin en el resultat del raycasting" + + +msgid "Teleport Axes" +msgstr "Eixos de teleportació" + + +msgid "Enabled teleport axes in navigation space" +msgstr "Eixos de teleportació habilitats a l'espai de navegació" + + +msgctxt "Operator" +msgid "Toggle VR Session" +msgstr "Revesar sessió de RV" + + +msgid "Open a view for use with virtual reality headsets, or close it if already opened" +msgstr "Obre una vista per a usar-la amb cascs de realitat virtual, o la tanca si ja és oberta" + + +msgctxt "Operator" +msgid "Add Workspace" +msgstr "Afegir obrador" + + +msgid "Add a new workspace by duplicating the current one or appending one from the user configuration" +msgstr "[Add Workspace]: Afegeix un obrador nou duplicant l'actual o incorporant-ne un a partir la configuració de la usuària" + + +msgctxt "Operator" +msgid "Append and Activate Workspace" +msgstr "Incorporar i activar obrador" + + +msgid "Append a workspace and make it the active one in the current window" +msgstr "Incorpora un obrador i el designa com a actiu dins la finestra actual" + + +msgid "Path to the library" +msgstr "Camí a la biblioteca" + + +msgid "Name of the workspace to append and activate" +msgstr "Nom de l'obrador per incorporar i activar" + + +msgctxt "Operator" +msgid "Delete Workspace" +msgstr "Suprimir obrador" + + +msgid "Delete the active workspace" +msgstr "Suprimeix l'obrador actiu" + + +msgctxt "Operator" +msgid "New Workspace" +msgstr "Nou obrador" + + +msgid "Add a new workspace" +msgstr "Afegeix un obrador nou" + + +msgctxt "Operator" +msgid "Workspace Reorder to Back" +msgstr "Reordenar obrador al darrere" + + +msgid "Reorder workspace to be last in the list" +msgstr "Reordena l'obrador perquè sigui l'últim de la llista" + + +msgctxt "Operator" +msgid "Workspace Reorder to Front" +msgstr "Reordenar l'obrador al davant" + + +msgid "Reorder workspace to be first in the list" +msgstr "Reordena l'obrador perquè sigui el primer de la llista" + + +msgctxt "Operator" +msgid "Pin Scene to Workspace" +msgstr "Fixar escena a obrador" + + +msgid "Remember the last used scene for the current workspace and switch to it whenever this workspace is activated again" +msgstr "Recorda l'última escena usada per a l'obrador present i se n'hi va quansevulgui que l'obrador sigui activat" + + +msgctxt "Operator" +msgid "New World" +msgstr "Nou món" + + +msgid "Create a new world Data-Block" +msgstr "[New World]: Crea un bloc de dades nou de món" + + +msgid "External file packed into the .blend file" +msgstr "Document extern empaquetat al document .blend" + + +msgid "Raw data (bytes, exact content of the embedded file)" +msgstr "Dades en brut (bytes, contingut exacte del document incrustat)" + + +msgid "Size of packed file in bytes" +msgstr "Mida del document empaquetat en bytes" + + +msgid "Active Brush" +msgstr "Pinzell actiu" + + +msgid "Editable cavity curve" +msgstr "Corba de cavitat editable" + + +msgid "Average multiple input samples together to smooth the brush stroke" +msgstr "Mitjana de múltiples mostres juntes d'ingrés per a suavitzar la pinzellada" + + +msgid "Active Palette" +msgstr "Paleta activa" + + +msgid "Show Brush" +msgstr "Mostrar pinzell" + + +msgid "Show Brush On Surface" +msgstr "Mostra el pinzell a la superfície" + + +msgid "Fast Navigate" +msgstr "Navegació ràpida" + + +msgid "For multires, show low resolution while navigating the view" +msgstr "[Fast Navigate]: Per a multiresolució, mostra una resolució baixa mentre navega per la visualització" + + +msgid "Tiling offset for the X Axis" +msgstr "Desplaçament de tessel·lat en l'eix X" + + +msgid "Stride at which tiled strokes are copied" +msgstr "[Tiling offset for the X Axis]: Distància a la que es copien el traços tessel·lats" + + +msgid "Tile X" +msgstr "X de tessel·la" + + +msgid "Tile along X axis" +msgstr "[Tile X]: Tessel·la dins l'eix X" + + +msgid "Tile Y" +msgstr "Y de tessel·la" + + +msgid "Tile along Y axis" +msgstr "Tessel·la dins l'eix Y" + + +msgid "Tile Z" +msgstr "Z de tessel·la" + + +msgid "Tile along Z axis" +msgstr "Tessel·la dins l'eix Z" + + +msgid "Paint Tool Slots" +msgstr "Epígrafs d'eina de pintar" + + +msgid "Mask painting according to mesh geometry cavity" +msgstr "Pintura de màscara d'acord amb la cavitat de la geometria de la malla" + + +msgid "Delay Viewport Updates" +msgstr "Retardar actualitzacions al mirador" + + +msgid "Update the geometry when it enters the view, providing faster view navigation" +msgstr "Actualitza la geometria quan es fa visible, proporcionant una navegació de visualització més ràpida" + + +msgid "Symmetry Feathering" +msgstr "Simetria de vora difusa" + + +msgid "Reduce the strength of the brush where it overlaps symmetrical daubs" +msgstr "[Symmetry Feathering]: Redueix la força del pinzell on se superposa a pinzellades simètriques" + + +msgid "Symmetry X" +msgstr "Simetria X" + + +msgid "Mirror brush across the X axis" +msgstr "Emmiralla el pinzell sobre l'eix X" + + +msgid "Symmetry Y" +msgstr "Simetria Y" + + +msgid "Mirror brush across the Y axis" +msgstr "Emmiralla el pinzell sobre l'eix Y" + + +msgid "Symmetry Z" +msgstr "Simetria Z" + + +msgid "Mirror brush across the Z axis" +msgstr "Emmiralla el pinzell sobre l'eix Z" + + +msgid "Curves Sculpt Paint" +msgstr "Pintura esculpir amb corbes" + + +msgid "Grease Pencil Paint" +msgstr "Pintura de llapis de greix" + + +msgid "Paint Mode" +msgstr "Mode pintura" + + +msgid "Paint using the active material base color" +msgstr "Pintar usant el color base del material actiu" + + +msgid "Paint the material with a color attribute" +msgstr "Pintar el material amb un atribut de color" + + +msgid "Grease Pencil Sculpt Paint" +msgstr "Pintura esculpir amb llapis de greix" + + +msgid "Image Paint" +msgstr "Pintura d'imatge" + + +msgid "Properties of image and texture painting mode" +msgstr "Propietats del mode de pintura d'imatge i textura" + + +msgid "Image used as canvas" +msgstr "Imatge usada com a llenç" + + +msgid "Image used as clone source" +msgstr "Imatge usada com a font de clonatge" + + +msgid "Dither" +msgstr "Fluctuació" + + +msgid "Amount of dithering when painting on byte images" +msgstr "Quantitat de fluctuació en pintar imatges de bytes" + + +msgid "Texture filtering type" +msgstr "Tipus de filtratge de textura" + + +msgid "Invert the stencil layer" +msgstr "Invertir capa plantilla" + + +msgid "Missing Materials" +msgstr "Materials extraviats" + + +msgid "The mesh is missing materials" +msgstr "[Missing Materials]: A la malla li falten materials" + + +msgid "Missing Stencil" +msgstr "Plantilla extraviada" + + +msgid "Image Painting does not have a stencil" +msgstr "[Missing Stencil]: El pintat d'imatge no té una plantilla" + + +msgid "Missing Texture" +msgstr "Textura extraviada" + + +msgid "Image Painting does not have a texture to paint on" +msgstr "[Missing Texture]: El pintat d'imatge no té una textura on pintar" + + +msgid "Missing UVs" +msgstr "UVs extraviats" + + +msgid "A UV layer is missing on the mesh" +msgstr "No es troba la capa d'UVs a la malla" + + +msgid "Mode of operation for projection painting" +msgstr "Mode d'operació per a projecció de pintura" + + +msgid "Detect image slots from the material" +msgstr "Detectar epígrafs d'imatge a partir del material" + + +msgid "Set image for texture painting directly" +msgstr "Situa la imatge per al pintat de textura de manera directa" + + +msgid "Screen Grab Size" +msgstr "Mida de presa de pantalla" + + +msgid "Size to capture the image for re-projecting" +msgstr "[Screen Grab Size]: Mida per a capturar la imatge per a la reprojecció" + + +msgid "Bleed" +msgstr "Sobreeixir" + + +msgid "Extend paint beyond the faces UVs to reduce seams (in pixels, slower)" +msgstr "[Bleed]: Estén la pintura més enllà de les cares UVs per reduir les costures (en píxels, més lent)" + + +msgid "Stencil Color" +msgstr "Color de plantilla" + + +msgid "Stencil color in the viewport" +msgstr "Color de la plantilla al mirador" + + +msgid "Stencil Image" +msgstr "Imatge plantilla" + + +msgid "Image used as stencil" +msgstr "[Stencil Image]: Imatge usada com a plantilla" + + +msgid "Cull" +msgstr "Esporgar" + + +msgid "Ignore faces pointing away from the view (faster)" +msgstr "[Cull]: Ignora les cares que apunten fora de la vista (més ràpid)" + + +msgid "Clone Map" +msgstr "Mapa clon" + + +msgid "Use another UV map as clone source, otherwise use the 3D cursor as the source" +msgstr "[Clone Map]: Usa un altre mapa UV com a font de clonació, altrament utilitza el cursor 3D com a font" + + +msgid "Paint most on faces pointing towards the view" +msgstr "Pintar la majoria de cares apuntant cap a la vista" + + +msgid "Occlude" +msgstr "Ocloure" + + +msgid "Only paint onto the faces directly under the brush (slower)" +msgstr "[Occlude]: Pinta només a les cares que són directament sota el pinzell (més lent)" + + +msgid "Stencil Layer" +msgstr "Capa plantilla" + + +msgid "Set the mask layer from the UV map buttons" +msgstr "Estableix la capa de màscara des dels botons del mapa UV" + + +msgid "Area Normal Falloff" +msgstr "Decaïment de normal d'àrea" + + +msgid "Extend the angular range with a falloff gradient" +msgstr "[Area Normal Falloff]: Amplia el rang angular amb un degradat descendent" + + +msgid "Area Normal Limit" +msgstr "Límit de normal d'àrea" + + +msgid "The range of angles that will be affected" +msgstr "[Area Normal Limit]: L'interval d'angles que es veuran afectats" + + +msgid "View Normal Falloff" +msgstr "Visió decaïment de normals" + + +msgid "View Normal Limit" +msgstr "Visió límit de normals" + + +msgid "Maximum edge length for dynamic topology sculpting (as divisor of blender unit - higher value means smaller edge length)" +msgstr "Longitud d'aresta màxima per esculpir topologia dinàmica (com a divisor de la unitat de blendere - un valor més alt significa una longitud d'aresta menor)" + + +msgid "Detail Percentage" +msgstr "Detallar percentatge" + + +msgid "Maximum edge length for dynamic topology sculpting (in brush percenage)" +msgstr "[Detail Percentage]: Longitud d'aresta màxima per esculpir topologia dinàmica (en percentatge de pinzell)" + + +msgid "Detail Refine Method" +msgstr "Detallar mètode refinació" + + +msgid "In dynamic-topology mode, how to add or remove mesh detail" +msgstr "[Detail Refine Method]: En mode de topologia dinàmica, com afegir o eliminar detall de malla" + + +msgid "Subdivide Edges" +msgstr "Subdividir arestes" + + +msgid "Subdivide long edges to add mesh detail where needed" +msgstr "Subdivideix les arestes llargues per afegir detall a la malla on cal" + + +msgid "Collapse Edges" +msgstr "Aglutinar arestes" + + +msgid "Collapse short edges to remove mesh detail where possible" +msgstr "[Collapse Edges]: Ajunta arestes curtes per a eliminar detall de malla on es pot" + + +msgid "Subdivide Collapse" +msgstr "Subdividir i aglutinar" + + +msgid "Both subdivide long edges and collapse short edges to refine mesh detail" +msgstr "[Subdivide Collapse]: Tant subdivideix arestes llargues com aglutina arestes curtes per refinar el detall de la malla" + + +msgid "Detail Size" +msgstr "Mida del detall" + + +msgid "Maximum edge length for dynamic topology sculpting (in pixels)" +msgstr "Longitud màxima d'aresta per a l'esculpir topologia dinàmica (en píxels)" + + +msgid "Detail Type Method" +msgstr "Mètode de tipus de detall" + + +msgid "In dynamic-topology mode, how mesh detail size is calculated" +msgstr "En el mode de topologia dinàmica, com es calcula la mida del detall de la malla" + + +msgid "Relative Detail" +msgstr "Detall relatiu" + + +msgid "Mesh detail is relative to the brush size and detail size" +msgstr "El detall de la malla és relatiu a la mida del pinzell i a la mida del detall" + + +msgid "Constant Detail" +msgstr "Detall constant" + + +msgid "Mesh detail is constant in world space according to detail size" +msgstr "El detall de la malla és constant a l'espai món d'acord amb la mida del detall" + + +msgid "Brush Detail" +msgstr "Detall del pinzell" + + +msgid "Mesh detail is relative to brush radius" +msgstr "El detall de la malla és relatiu al radi del pinzell" + + +msgid "Manual Detail" +msgstr "Detall manual" + + +msgid "Mesh detail does not change on each stroke, only when using Flood Fill" +msgstr "El detall de la malla no canvia a cada traç, només quan s'utilitza Emplenat complet" + + +msgid "Amount of gravity after each dab" +msgstr "Quantitat de gravetat després de cada refrec" + + +msgid "Object whose Z axis defines orientation of gravity" +msgstr "Objecte l'eix Z del qual defineix l'orientació de la gravetat" + + +msgid "Lock X" +msgstr "Bloquejar X" + + +msgid "Disallow changes to the X axis of vertices" +msgstr "Neutralitza canvis a l'eix X dels vèrtexs" + + +msgid "Lock Y" +msgstr "Bloquejar Y" + + +msgid "Disallow changes to the Y axis of vertices" +msgstr "Neutralitza canvis a l'eix Y dels vèrtexs" + + +msgid "Lock Z" +msgstr "Bloquejar Z" + + +msgid "Disallow changes to the Z axis of vertices" +msgstr "Neutralitza canvis a l'eix z dels vèrtexs" + + +msgid "Radial Symmetry Count X Axis" +msgstr "Recompte de simentria radial a eix X" + + +msgid "Number of times to copy strokes across the surface" +msgstr "Nombre de vegades per copiar traços en la superfície" + + +msgid "Source and destination for symmetrize operator" +msgstr "Origen i destinació de l'operador de simetrització" + + +msgid "Transform Mode" +msgstr "Mode transformació" + + +msgid "How the transformation is going to be applied to the target" +msgstr "Com s'aplicarà la transformació al referent" + + +msgid "Applies the transformation to all vertices in the mesh" +msgstr "Aplicar la transformació a tots els vèrtexs de la malla" + + +msgid "Applies the transformation simulating elasticity using the radius of the cursor" +msgstr "Aplicar la transformació simulant elasticitat en usar el radi del cursor" + + +msgid "Use Deform Only" +msgstr "Usar sols deformació" + + +msgid "Use only deformation modifiers (temporary disable all constructive modifiers except multi-resolution)" +msgstr "Utilitza només modificadors de deformació (desactiva temporalment tots els modificadors constructius excepte el multiresolució)" + + +msgid "Show faces in dynamic-topology mode with smooth shading rather than flat shaded" +msgstr "Mostrar les cares en mode de topologia dinàmica amb aspecció suavitzada preferiblement a aplanada" + + +msgid "UV Sculpting" +msgstr "Esculpir UVs" + + +msgid "Properties of vertex and weight paint mode" +msgstr "Propietats del mode de pintura de vèrtexs i pesos" + + +msgid "Restrict" +msgstr "Restringir" + + +msgid "Restrict painting to vertices in the group" +msgstr "Restringeix la pintura a vèrtexs del grup" + + +msgid "Properties of paint mode" +msgstr "Propietats del mode pintura" + + +msgid "Image used as painting target" +msgstr "Imatge utilitzada com a referent de pintura" + + +msgid "Source to select canvas from" +msgstr "Font d'on seleccionar el llenç" + + +msgid "Paint Tool Slot" +msgstr "Epígraf d'eina de pintura" + + +msgid "Palette Color" +msgstr "Color de paleta" + + +msgid "Palette Splines" +msgstr "Splines de paleta" + + +msgid "Collection of palette colors" +msgstr "Col·lecció de colors de paleta" + + +msgid "Active Palette Color" +msgstr "Color de paleta activa" + + +msgid "Panel containing UI elements" +msgstr "Plafó que conté elements de la IU" + + +msgid "Light Groups" +msgstr "Grups de llum" + + +msgid "Integrator Presets" +msgstr "Predefinits d'integrador" + + +msgid "Performance Presets" +msgstr "Predefinits de rendiment" + + +msgid "Sampling Presets" +msgstr "Predefinits de mostreig" + + +msgid "Viewport Sampling Presets" +msgstr "Predefinits de mostreig del mirador" + + +msgid "View Object Types" +msgstr "Visualitzar tipus d'objecte" + + +msgid "Asset Metadata" +msgstr "Metadades de recursos" + + +msgid "Chain Scaling" +msgstr "Escalat de cadena" + + +msgid "Fitting" +msgstr "Encaix" + + +msgid "Override Layers" +msgstr "Capes de sobreseïment" + + +msgid "Render Procedural" +msgstr "Revelat procedimental" + + +msgid "Bone Constraints" +msgstr "Restriccions d'ossos" + + +msgid "Bendy Bones" +msgstr "Ossos doblegables" + + +msgid "Viewport Display" +msgstr "Visualització de mirador" + + +msgid "Custom Shape" +msgstr "Forma personalitzada" + + +msgid "Camera Presets" +msgstr "Predefinits de càmera" + + +msgid "2D Cursor" +msgstr "Cursor 2D" + + +msgid "Active Point" +msgstr "Punt actiu" + + +msgid "Predefined tracking camera intrinsics" +msgstr "Intrínsecs de seguiment de càmera predefinits" + + +msgid "Clip Display" +msgstr "Visualització del clip" + + +msgid "Footage" +msgstr "Metratge" + + +msgid "Footage Settings" +msgstr "Paràmetres del metratge" + + +msgid "Marker Display" +msgstr "Mostrar marcador" + + +msgid "Mask Settings" +msgstr "Paràmetres de màscara" + + +msgid "Mask Display" +msgstr "Visualització de màscara" + + +msgid "Proxy/Timecode" +msgstr "Simulació/Timecode" + + +msgid "Stabilization" +msgstr "Estabilització" + + +msgid "2D Stabilization" +msgstr "Estabilització 2D" + + +msgid "Solve" +msgstr "Resolució" + + +msgid "Mask Tools" +msgstr "Eines de màscara" + + +msgid "Transforms" +msgstr "Transformacions" + + +msgctxt "MovieClip" +msgid "Scene Setup" +msgstr "Configuració d'escena" + + +msgid "Predefined track color" +msgstr "Color de pista predefinit" + + +msgid "Color Presets" +msgstr "Predefinits de color" + + +msgid "Tracking Settings" +msgstr "Configuració de tràveling" + + +msgid "Tracking Settings Extras" +msgstr "[Tracking Settings]: Extres de la configuració del seguiment" + + +msgid "Lens" +msgstr "Lent" + + +msgid "Tracking Settings Extra" +msgstr "Configuració extra de tràveling" + + +msgid "Predefined tracking settings" +msgstr "Configuració predefinida de tràveling" + + +msgid "Tracking Presets" +msgstr "[Predefined tracking settings]: Predefinits de tràveling" + + +msgid "Cloth Presets" +msgstr "Predefinits de tela" + + +msgid "Restrictions" +msgstr "Restriccions" + + +msgid "Aperture" +msgstr "Obertura" + + +msgid "Beam Shape" +msgstr "Forma del feix de llum" + + +msgid "Caustics" +msgstr "Càustica" + + +msgid "Fast GI Approximation" +msgstr "Aproximació ràpida d'IG" + + +msgid "Shadow Terminator" +msgstr "Anul·lador d'ombra" + + +msgid "Ray Visibility" +msgstr "Visibilitat de raigs" + + +msgid "Post Processing" +msgstr "Postprocessament" + + +msgid "Film" +msgstr "Pel·lícula" + + +msgid "Pixel Filter" +msgstr "Filtre de píxels" + + +msgid "Transparent" +msgstr "Transparent" + + +msgid "Light Paths" +msgstr "Camins de llums" + + +msgid "Clamping" +msgstr "Constrenyiment" + + +msgid "Max Bounces" +msgstr "Màxim de rebots" + + +msgid "Shutter Curve" +msgstr "Corba d'obturador" + + +msgid "Passes" +msgstr "Passades" + + +msgid "Performance" +msgstr "Rendiment" + + +msgid "Acceleration Structure" +msgstr "Estructura d'acceleració" + + +msgid "Final Render" +msgstr "Revelat final" + + +msgid "Threads" +msgstr "Fils" + + +msgid "Path Guiding" +msgstr "Guiatge de trajecte" + + +msgid "Subdivision" +msgstr "Subdivisió" + + +msgid "Render Pass" +msgstr "Pas de revelat" + + +msgid "Mist Pass" +msgstr "Passada de boira" + + +msgid "Custom Distance" +msgstr "Distància personalitzada" + + +msgid "Cascaded Shadow Map" +msgstr "Mapa d'ombres en cascada" + + +msgid "Contact Shadows" +msgstr "Ombres de contacte" + + +msgid "Composition Guides" +msgstr "Guies de composició" + + +msgid "Center-Cut Safe Areas" +msgstr "Àrees segures al centre" + + +msgid "Stereoscopy" +msgstr "Estereoscòpia" + + +msgid "Texture Space" +msgstr "Espai textura" + + +msgid "Geometry Data" +msgstr "Dades de geometria" + + +msgid "Start & End Mapping" +msgstr "Mapejat d'inici i fical" + + +msgid "Adjustments" +msgstr "Ajustament" + + +msgid "Probe" +msgstr "Sonda" + + +msgid "Custom Parallax" +msgstr "Paral·laxi personalitzada" + + +msgid "Paragraph" +msgstr "Paràgraf" + + +msgid "Path Animation" +msgstr "Animació de trajecte" + + +msgid "Effects" +msgstr "Efectes" + + +msgid "Skeleton" +msgstr "Esquelet" + + +msgid "Spot Shape" +msgstr "Forma del punt" + + +msgid "Text Boxes" +msgstr "Quadres de text" + + +msgid "OpenVDB File" +msgstr "Document OpenVDB" + + +msgid "Create Pose Asset" +msgstr "Crear recurs de posa" + + +msgid "Filters" +msgstr "Filtres" + + +msgid "Bake Animation" +msgstr "Precuinar animació" + + +msgid "Advanced Filter" +msgstr "Filtre avançat" + + +msgid "Bookmarks" +msgstr "Adreces d'interès" + + +msgid "Recent" +msgstr "Recents" + + +msgctxt "File browser" +msgid "Volumes" +msgstr "Volums" + + +msgid "Directory Path" +msgstr "Camí del directori" + + +msgid "Filter Settings" +msgstr "Configuració de filtre" + + +msgid "Fluid Presets" +msgstr "Predefinits de fluids" + + +msgid "PBR Extensions" +msgstr "Extensions PBR" + + +msgid "Exporter Extensions" +msgstr "Extensions d'exportador" + + +msgid "Importer Extensions" +msgstr "Extensions d'importador" + + +msgid "Active Tool" +msgstr "Eina activa" + + +msgid "Overlays" +msgstr "Bambolines" + + +msgid "Guides" +msgstr "Guies" + + +msgid "UV Editing" +msgstr "Edició UV" + + +msgid "Clone from Image/UV Map" +msgstr "Clonar des d'un mapa d'imatge/UV" + + +msgid "Color Picker" +msgstr "Selector de color" + + +msgid "Color Palette" +msgstr "Paleta de colors" + + +msgid "Scopes" +msgstr "Abast" + + +msgid "Sample Line" +msgstr "Línia de mostra" + + +msgid "Snapping" +msgstr "Acoblament" + + +msgctxt "Operator" +msgid "Sample" +msgstr "Mostrar" + + +msgid "Sample pixel values under the cursor" +msgstr "Fa un mostreig de valors dels píxels sota el cursor" + + +msgctxt "Operator" +msgid "Annotate" +msgstr "Anotar" + + +msgctxt "Operator" +msgid "Annotate Line" +msgstr "Línia d'anotació" + + +msgctxt "Operator" +msgid "Annotate Polygon" +msgstr "Polígon d'anotació" + + +msgctxt "Operator" +msgid "Annotate Eraser" +msgstr "Esborrador d'anotacions" + + +msgctxt "Operator" +msgid "Tweak" +msgstr "Manipular" + + +msgctxt "Operator" +msgid "Select Box" +msgstr "Selecció de caixa" + + +msgctxt "Operator" +msgid "Select Circle" +msgstr "Selecció de cercle" + + +msgctxt "Operator" +msgid "Select Lasso" +msgstr "Selecció de llaç" + + +msgctxt "Operator" +msgid "Cursor" +msgstr "Cursor" + + +msgid "Set the cursor location, drag to transform" +msgstr "Estableix la ubicació del cursor, arrossegar per a transformar" + + +msgctxt "Operator" +msgid "Scale" +msgstr "Escala" + + +msgid "Supports any combination of grab, rotate, and scale at once" +msgstr "Permet qualsevol combinació d'agafar, rotar i escalar alhora" + + +msgctxt "Operator" +msgid "Rip Region" +msgstr "Regió d'arrencar" + + +msgctxt "Operator" +msgid "Grab" +msgstr "Agafar" + + +msgctxt "Operator" +msgid "Relax" +msgstr "Relaxar" + + +msgctxt "Operator" +msgid "Pinch" +msgstr "Pessigar" + + +msgctxt "Operator" +msgid "Draw" +msgstr "Dibuixar" + + +msgctxt "Operator" +msgid "Soften" +msgstr "Suavitzar" + + +msgctxt "Operator" +msgid "Smear" +msgstr "Escampar" + + +msgctxt "Operator" +msgid "Clone" +msgstr "Clonar" + + +msgctxt "Operator" +msgid "Mask" +msgstr "Emmascarar" + + +msgid "Brush Tip" +msgstr "Punta de pinzell" + + +msgid "Tiling" +msgstr "Tessel·lació" + + +msgid "Texture Mask" +msgstr "Textura màscara" + + +msgid "Histogram" +msgstr "Histograma" + + +msgid "Vectorscope" +msgstr "Vectoscopi" + + +msgid "Waveform" +msgstr "Waveform" + + +msgid "Freestyle Line" +msgstr "Manual" + + +msgid "Material settings" +msgstr "Paràmetres de material" + + +msgid "Material Presets" +msgstr "Predefinits de material" + + +msgid "Grease Pencil Material Slots" +msgstr "Epígrafs de material de llapis de greix" + + +msgid "Math Vis" +msgstr "Math Vis" + + +msgid "Math Vis Console" +msgstr "Consola Math Vis" + + +msgid "Backdrop" +msgstr "Darrere" + + +msgid "Slot" +msgstr "Born" + + +msgid "Predefined node color" +msgstr "Color del node predefinit" + + +msgctxt "Operator" +msgid "Links Cut" +msgstr "Tallar enllaços" + + +msgid "Delta Transform" +msgstr "Transformació Delta" + + +msgid "Scale by Face Size" +msgstr "Escala per mida de caras" + + +msgid "Object Scatter" +msgstr "Dispersar objectes" msgid "Boid Brain" msgstr "Cervell de floc" +msgid "Clumping" +msgstr "Aglomeració" + + +msgid "Clump Noise" +msgstr "Soroll d'aglomeració" + + +msgid "Parting" +msgstr "Separament" + + +msgctxt "ParticleSettings" +msgid "Roughness" +msgstr "Rugositat" + + +msgctxt "ParticleSettings" +msgid "Emission" +msgstr "Emissió" + + +msgid "Field Weights" +msgstr "Pesos de camp" + + +msgid "Force Field Settings" +msgstr "Configuració de camp de força" + + +msgid "Type 1" +msgstr "Tipus 1" + + +msgid "Type 2" +msgstr "Tipus 2" + + +msgid "Hair Dynamics" +msgstr "Dinàmica de pèls" + + +msgid "Collisions" +msgstr "Col·lisions" + + +msgid "Hair Dynamics Presets" +msgstr "Predefinits de dinàmica de pèls" + + +msgid "Structure" +msgstr "Estructura" + + +msgid "Hair Shape" +msgstr "Forma del pèl" + + +msgid "Physics" +msgstr "Física" + + +msgid "Battle" +msgstr "Batalla" + + +msgid "Misc" +msgstr "Miscel·lània" + + +msgid "Movement" +msgstr "Moviment" + + +msgid "Deflection" +msgstr "Deflexió" + + +msgid "Fluid Interaction" +msgstr "Interacció de fluids" + + +msgid "Springs" +msgstr "Tensors" + + +msgid "Viscoelastic Springs" +msgstr "Tensors viscoelàstics" + + +msgid "Forces" +msgstr "Forces" + + +msgid "Border Collisions" +msgstr "Col·lisions de vores" + + +msgid "Internal Springs" +msgstr "Tensors interns" + + +msgid "Object Collisions" +msgstr "Col·lisions d'objectes" + + +msgid "Physical Properties" +msgstr "Propietats físiques" + + +msgid "Property Weights" +msgstr "Pesos de propietats" + + +msgid "Self Collisions" +msgstr "Autocol·lisions" + + +msgid "Softbody & Cloth" +msgstr "Cos tou i tela" + + +msgid "Diffusion" +msgstr "Difusió" + + +msgid "Falloff Ramp" +msgstr "Rampa de decaïment" + + +msgid "Smudge" +msgstr "Esborrallar" + + +msgid "Waves" +msgstr "Ones" + + +msgid "Paintmaps" +msgstr "Mapes de pintura" + + +msgid "Wetmaps" +msgstr "Mapes d'impregnació" + + +msgid "Force Fields" +msgstr "Camps de força" + + +msgid "Flow Source" +msgstr "Font de flux" + + +msgid "Sensitivity" +msgstr "Sensibilitat" + + +msgid "Surface Response" +msgstr "Resposta de superfície" + + +msgid "Override Iterations" +msgstr "Sobreseure iteracions" + + +msgid "Dynamics" +msgstr "Dinàmica" + + +msgid "Deactivation" +msgstr "Desactivació" + + +msgid "Self Collision" +msgstr "Autocol·lisió" + + +msgid "Aerodynamics" +msgstr "Aerodinàmica" + + +msgid "Strengths" +msgstr "Forces" + + +msgid "Diagnostics" +msgstr "Diagnòstic" + + +msgid "Helpers" +msgstr "Ajudadors" + + +msgid "Viscosity" +msgstr "Viscositat" + + +msgid "Show options for the properties editor" +msgstr "Mostrar opcions d'editor de propietats" + + +msgid "Creates a Panel in the Render Layers context of the properties editor" +msgstr "Crea un plafó d'edició de propietats en el context de les capes de revelat" + + +msgid "Freestyle Line Style SVG Export" +msgstr "Exportació SVG d'estil de línia manual" + + +msgid "Creates a Panel in the render context of the properties editor" +msgstr "Crea un plafó d'edició de propietats en el context de revelat" + + +msgid "Freestyle SVG Export" +msgstr "Exportació SVG d'estil manual" + + +msgid "Bloom" +msgstr "Floració" + + +msgid "Indirect Lighting" +msgstr "Il·luminació indirecta" + + +msgid "Shadows" +msgstr "Ombres" + + +msgid "Screen Space Reflections" +msgstr "Reflexions d'espai de pantalla" + + +msgid "Volumetrics" +msgstr "Volumeria" + + +msgid "Volumetric Lighting" +msgstr "Il·luminació volumètrica" + + +msgid "Volumetric Shadows" +msgstr "Ombres volumètriques" + + +msgid "Encoding" +msgstr "Codificació" + + +msgid "Audio" +msgstr "Àudio" + + +msgid "Video" +msgstr "Vídeo" + + +msgid "FFMPEG Presets" +msgstr "Predefinits FFMPEG" + + +msgid "Format Presets" +msgstr "Predefinits de format" + + +msgid "Views" +msgstr "Visualitzacions" + + +msgid "Metadata" +msgstr "Metadades" + + +msgid "Burn Into Image" +msgstr "Estampar a la imatge" + + +msgid "Note" +msgstr "Nota" + + +msgid "Time Stretching" +msgstr "Estirament de temps" + + +msgid "Keyframing Settings" +msgstr "Paràmetres de fotofites" + + +msgid "Onion Skin" +msgstr "Pell de ceba" + + +msgid "Cache Settings" +msgstr "Paràmetres de memòria cau" + + +msgid "Frame Overlay" +msgstr "Bambolina de fotograma" + + +msgid "Scene Strip Display" +msgstr "Mostrar segment d'escena" + + +msgid "Preview Overlays" +msgstr "Bambolines de previsualització" + + +msgid "Proxy Settings" +msgstr "Paràmetres de simulació" + + +msgid "Sequencer Overlays" +msgstr "Bambolines de seqüenciador" + + +msgid "Strip Cache" +msgstr "Memòria cau de pista" + + +msgid "Strip Proxy & Timecode" +msgstr "Timecode i simulació de pista" + + +msgctxt "Operator" +msgid "Blade" +msgstr "Cisalla" + + +msgid "Feature Weights" +msgstr "Pesos de característiques" + + +msgid "Find & Replace" +msgstr "Trobar i substituir" + + +msgid "Auto Keyframing" +msgstr "Autofotofites" + + msgid "Playback" -msgstr "Recorregut" +msgstr "Reproduir" + + +msgid "Rename Active Item" +msgstr "Rebatejar element actiu" + + +msgid "Rename Marker" +msgstr "Marcador de rebateig" + + +msgid "" +"\n" +" Popover panel for adding extra options that don't fit in the tool settings header\n" +" " +msgstr "" +"\n" +" Panell emergent per afegir opcions addicionals que no s'ajusten a la capçalera de la configuració de l'eina\n" +" " + + +msgid "Extra Options" +msgstr "Opcions addicionals" + + +msgid "I18n Update Translation" +msgstr "Actualitzar traducció d'i18n" + + +msgid "Timeline" +msgstr "Cronograma" + + +msgid "Duplicate Data" +msgstr "Duplicar dades" + + +msgid "New Objects" +msgstr "Objectes nous" + + +msgid "Debugging" +msgstr "Depuració" + + +msgid "New Features" +msgstr "Característiques noves" + + +msgid "Prototypes" +msgstr "Prototips" + + +msgid "Applications" +msgstr "Aplicacions" + + +msgid "Asset Libraries" +msgstr "Biblioteques de recursos" + + +msgid "Development" +msgstr "Desenvolupament" + + +msgid "Tablet" +msgstr "Taulet" + + +msgid "Touchpad" +msgstr "Ratolí tàctil" + + +msgid "Editors" +msgstr "Editors" + + +msgid "Menus" +msgstr "Menús" + + +msgid "Open on Mouse Over" +msgstr "Obrir en passar el ratolí" + + +msgid "Pie Menus" +msgstr "Menús de pastís" + + +msgid "Temporary Editors" +msgstr "Editors temporals" + + +msgid "Text Rendering" +msgstr "Revelat de text" + + +msgctxt "WindowManager" +msgid "Translation" +msgstr "Translació" + + +msgid "Preferences Navigation" +msgstr "Navegació de preferències" + + +msgid "Fly & Walk" +msgstr "Volant i a peu" + + +msgid "Walk" +msgstr "A peu" msgid "Orbit & Pan" -msgstr "Òrbota i escombratge" +msgstr "Orbitar i escombrar" + + +msgid "3D Mouse Settings" +msgstr "Paràmetres de ratolí 3D" + + +msgid "Save Preferences" +msgstr "Desar preferències" + + +msgid "Auto Run Python Scripts" +msgstr "Autoexecutar protocols python" + + +msgid "Blend Files" +msgstr "Documents Blend" + + +msgid "Auto Save" +msgstr "Autodesar" + + +msgid "Editor" +msgstr "Editor" + + +msgid "Studio Lights" +msgstr "Il·luminació d'estudi" + + +msgid "MatCaps" +msgstr "MatCaps" + + +msgid "HDRIs" +msgstr "HDRI" + + +msgid "Cycles Render Devices" +msgstr "Dispositius de revelat de Cycles" + + +msgid "GPU Backend" +msgstr "Internador de GPU" + + +msgid "Memory & Limits" +msgstr "Memòria i límits" + + +msgid "Operating System Settings" +msgstr "Configuració del sistema operatiu" + + +msgid "Bone Color Sets" +msgstr "Jocs de colors d'ossos" + + +msgid "Theme Space" +msgstr "Espai de tema" + + +msgid "Theme Space List" +msgstr "Llista d'espais de tema" + + +msgid "Panel Colors" +msgstr "Colors de plafó" + + +msgid "Collection Colors" +msgstr "Colors de col·lecció" + + +msgid "Axis & Gizmo Colors" +msgstr "Colors de flòstic i eixos" + + +msgid "Icon Colors" +msgstr "Colors d'icona" + + +msgid "Styles" +msgstr "Estils" + + +msgid "Transparent Checkerboard" +msgstr "Tauler transparent" + + +msgid "Menu" +msgstr "Menú" + + +msgid "Menu Back" +msgstr "Menú enrere" + + +msgid "Menu Item" +msgstr "Element del menú" + + +msgid "Number Field" +msgstr "Camp numèric" + + +msgid "Value Slider" +msgstr "Lliscador de valor" + + +msgid "Option" +msgstr "Opció" + + +msgid "Pie Menu" +msgstr "Menú de pastís" + + +msgid "Progress Bar" +msgstr "Barra de progrés" + + +msgid "Pulldown" +msgstr "Abaixar" + + +msgid "Radio Buttons" +msgstr "Botons de ràdio" + + +msgid "Scroll Bar" +msgstr "Barra de rodolar" + + +msgid "Tab" +msgstr "Tabulació" + + +msgid "Toolbar Item" +msgstr "Element de barra d'eines" + + +msgid "Strip Colors" +msgstr "Colors de pistes" + + +msgid "Text Style" +msgstr "Estil de text" + + +msgid "User Interface" +msgstr "Interfície d'usuària" + + +msgid "Gradient Colors" +msgstr "Colors de degradat" + + +msgid "Global Transform" +msgstr "Transformació global" + + +msgid "Curves Sculpt Add Curve Options" +msgstr "Afegir opcions de corbes a l'escultura amb corba" + + +msgid "Curves Grow/Shrink Scaling" +msgstr "Ampliar/Encongir Escala de corbes" + + +msgid "Curves Sculpt Parameter Falloff" +msgstr "Paràmetre de decaïment d'escultura amb corba" + + +msgid "Brush Presets" +msgstr "Predefinits de pinzells" + + +msgid "Draw Context Menu" +msgstr "Menú contextual de dibuix" + + +msgid "Drawing Plane" +msgstr "Pla de dibuix" + + +msgid "Multi Frame" +msgstr "Multifita" + + +msgid "Stroke Placement" +msgstr "Emplaçament del traç" + + +msgid "Auto-masking" +msgstr "Auto-màscara" + + +msgid "Sculpt Context Menu" +msgstr "Menú contextual d'escultura" + + +msgid "Vertex Paint Context Menu" +msgstr "Menú contextual de pintura de vèrtexs" + + +msgid "Weight Paint Context Menu" +msgstr "Menú contextual de pintura de pesos" + + +msgid "Masking" +msgstr "Emmascarar" + + +msgid "Curve Edit Mode" +msgstr "Mode edició de corba" + + +msgid "Mesh Edit Mode" +msgstr "Mode edició de malla" + + +msgid "Measurement" +msgstr "Mesurament" + + +msgid "Motion Tracking" +msgstr "Tràveling de seguiment" + + +msgid "Texture Paint Context Menu" +msgstr "Menú contextual de pintat de textura" msgid "Weights Context Menu" -msgstr "Menú contextual de forces" +msgstr "Menú contextual de pesos" + + +msgid "Pose Library" +msgstr "Biblioteca de poses" + + +msgid "3D-Print" +msgstr "Impressió 3D" + + +msgid "Analyze" +msgstr "Analitzar" + + +msgid "Quad View" +msgstr "Visualització de quads" + + +msgid "Auto-Masking" +msgstr "Auto-màscara" + + +msgid "Compositor" +msgstr "Conjuminador" + + +msgid "Shadow Settings" +msgstr "Paràmetres d'ombra" + + +msgid "SSAO Settings" +msgstr "Paràmetres de SSAO" + + +msgid "Stencil Mask" +msgstr "Màscara de plantilla" + + +msgctxt "Operator" +msgid "Scale Cage" +msgstr "Escalar gàbia" + + +msgctxt "Operator" +msgid "Measure" +msgstr "Medirr" + + +msgctxt "Operator" +msgid "Breakdowner" +msgstr "Dissociador" + + +msgctxt "Operator" +msgid "Push" +msgstr "Pitjar" + + +msgctxt "Operator" +msgid "Roll" +msgstr "Rodolar" + + +msgctxt "Operator" +msgid "Bone Size" +msgstr "Mida d'os" + + +msgctxt "Operator" +msgid "Bone Envelope" +msgstr "Funda d'os" + + +msgid "Extrude freely or along an axis" +msgstr "[Bone Envelope]: Extrudeix lliurement o seguint un eix" + + +msgctxt "Operator" +msgid "Extrude Along Normals" +msgstr "Extrudir seguint normals" + + +msgctxt "Operator" +msgid "Extrude Individual" +msgstr "Extrudir individualment" + + +msgctxt "Operator" +msgid "Offset Edge Loop Cut" +msgstr "Desplaçament bucle d'aresta" + + +msgctxt "Operator" +msgid "Knife" +msgstr "Navalla" + + +msgctxt "Operator" +msgid "Poly Build" +msgstr "Polimuntador" + + +msgctxt "Operator" +msgid "Spin Duplicates" +msgstr "Tornejar duplicacions" + + +msgctxt "Operator" +msgid "Rip Edge" +msgstr "Arrencar aresta" + + +msgctxt "Operator" +msgid "Radius" +msgstr "Radi" + + +msgid "Expand or contract the radius of the selected curve points" +msgstr "Expandeix o contrau el radi dels punts de corba seleccionats" + + +msgctxt "Operator" +msgid "Comb" +msgstr "Pentinar" + + +msgctxt "Operator" +msgid "Length" +msgstr "Llargada" + + +msgctxt "Operator" +msgid "Puff" +msgstr "Bufar" + + +msgctxt "Operator" +msgid "Weight" +msgstr "Pes" + + +msgctxt "Operator" +msgid "Draw Sharp" +msgstr "Dibuix constrastat" + + +msgctxt "Operator" +msgid "Clay" +msgstr "Argila" + + +msgctxt "Operator" +msgid "Clay Strips" +msgstr "Faixes d'argila" + + +msgctxt "Operator" +msgid "Clay Thumb" +msgstr "Ditada en argila" + + +msgctxt "Operator" +msgid "Layer" +msgstr "Capa" + + +msgctxt "Operator" +msgid "Inflate" +msgstr "Inflar" + + +msgctxt "Operator" +msgid "Blob" +msgstr "Bombollar" + + +msgctxt "Operator" +msgid "Crease" +msgstr "Replegar" + + +msgctxt "Operator" +msgid "Flatten" +msgstr "Aplanar" + + +msgctxt "Operator" +msgid "Scrape" +msgstr "Raspar" + + +msgctxt "Operator" +msgid "Multi-plane Scrape" +msgstr "Raspat multiplà" + + +msgctxt "Operator" +msgid "Elastic Deform" +msgstr "Deformació elàstica" + + +msgctxt "Operator" +msgid "Snake Hook" +msgstr "Ganxo de serp" + + +msgctxt "Operator" +msgid "Thumb" +msgstr "Aixafar" + + +msgctxt "Operator" +msgid "Pose" +msgstr "Posa" + + +msgctxt "Operator" +msgid "Nudge" +msgstr "Empènyer" + + +msgctxt "Operator" +msgid "Slide Relax" +msgstr "Equilibrar" + + +msgctxt "Operator" +msgid "Boundary" +msgstr "Rebava" + + +msgctxt "Operator" +msgid "Cloth" +msgstr "Tela" + + +msgctxt "Operator" +msgid "Simplify" +msgstr "Simplificar" + + +msgctxt "Operator" +msgid "Draw Face Sets" +msgstr "Dibuixar jocs de cares" + + +msgctxt "Operator" +msgid "Multires Displacement Eraser" +msgstr "Esborrar desplaçaments de multiresolució" + + +msgctxt "Operator" +msgid "Multires Displacement Smear" +msgstr "Escampar desplaçaments de multiresolució" + + +msgctxt "Operator" +msgid "Paint" +msgstr "Pintar" + + +msgctxt "Operator" +msgid "Box Mask" +msgstr "Màscara de caixa" + + +msgctxt "Operator" +msgid "Lasso Mask" +msgstr "Màscara de llaç" + + +msgctxt "Operator" +msgid "Line Mask" +msgstr "Màscara de línia" + + +msgctxt "Operator" +msgid "Box Hide" +msgstr "Amagar caixa" + + +msgctxt "Operator" +msgid "Box Face Set" +msgstr "Joc de cares de caixa" + + +msgctxt "Operator" +msgid "Lasso Face Set" +msgstr "Joc de cares de llaç" + + +msgctxt "Operator" +msgid "Box Trim" +msgstr "Rebaixat de caixa" + + +msgctxt "Operator" +msgid "Lasso Trim" +msgstr "Rebaixat de llaç" + + +msgctxt "Operator" +msgid "Line Project" +msgstr "Projecció de línia" + + +msgctxt "Operator" +msgid "Mesh Filter" +msgstr "Filtre de malla" + + +msgctxt "Operator" +msgid "Cloth Filter" +msgstr "Filtre de tela" + + +msgctxt "Operator" +msgid "Color Filter" +msgstr "Filtre de color" + + +msgctxt "Operator" +msgid "Blur" +msgstr "Difuminat" + + +msgctxt "Operator" +msgid "Average" +msgstr "Mitjana" + + +msgctxt "Operator" +msgid "Gradient" +msgstr "Degradat" + + +msgctxt "Operator" +msgid "Sample Weight" +msgstr "Mostrejar pesos" + + +msgctxt "Operator" +msgid "Sample Vertex Group" +msgstr "Mostrejar grup de vèrtexs" + + +msgctxt "Operator" +msgid "Erase" +msgstr "Esborrar" + + +msgctxt "Operator" +msgid "Tint" +msgstr "Tint" + + +msgctxt "Operator" +msgid "Cutter" +msgstr "Cisalla" + + +msgctxt "Operator" +msgid "Line" +msgstr "Línia" + + +msgctxt "Operator" +msgid "Polyline" +msgstr "Polilínia" + + +msgctxt "Operator" +msgid "Arc" +msgstr "Arc" + + +msgctxt "Operator" +msgid "Curve" +msgstr "Corba" + + +msgctxt "Operator" +msgid "Box" +msgstr "Caixa" + + +msgctxt "Operator" +msgid "Circle" +msgstr "Cercle" + + +msgctxt "Operator" +msgid "Interpolate" +msgstr "Interpolar" + + +msgid "Expand or contract the radius of the selected points" +msgstr "Expandeix o contrau el radi dels punts seleccionats" + + +msgctxt "Operator" +msgid "Transform Fill" +msgstr "Transformació emplenat" + + +msgctxt "Operator" +msgid "Thickness" +msgstr "Gruix" + + +msgctxt "Operator" +msgid "Strength" +msgstr "Intensitat" + + +msgctxt "Operator" +msgid "Twist" +msgstr "Roscar" + + +msgctxt "Operator" +msgid "Selection Paint" +msgstr "Pintura de selecció" + + +msgctxt "Operator" +msgid "Density" +msgstr "Densitat" + + +msgctxt "Operator" +msgid "Grow/Shrink" +msgstr "Engrandir/encongir" + + +msgctxt "Operator" +msgid "Slide" +msgstr "Lliscar" + + +msgid "Clone from Paint Slot" +msgstr "Clonar des d'epígraf de pintat" + + +msgid "Front-Face Falloff" +msgstr "Decaïment de cara davantera" + + +msgid "Normal Falloff" +msgstr "Decaïment de normals" + + +msgid "Gap Closure" +msgstr "Tancament de buit" + + +msgid "Post-Processing" +msgstr "Postprocessament" + + +msgid "Particle Tool" +msgstr "Eina de partícules" + + +msgid "Default tools for particle mode" +msgstr "Eines per defecte per al mode partícula" + + +msgid "Cut Particles to Shape" +msgstr "Retallar partícules a la forma" + + +msgid "Pose Options" +msgstr "Opcions de posa" + + +msgid "Transform Orientations" +msgstr "Orientacions de transformació" + + +msgid "View Lock" +msgstr "Bloqueig de visualització" + + +msgid "Viewport Debug" +msgstr "Depuració de mirador" + + +msgid "VR" +msgstr "RV" + + +msgid "Action Maps" +msgstr "Mapes d'acció" + + +msgid "Landmarks" +msgstr "Marques de terme" + + +msgid "VR Session" +msgstr "Sessió de RV" + + +msgid "Viewport Feedback" +msgstr "Notificacions del mirador" + + +msgid "Edge Detection" +msgstr "Detecció d'arestes" + + +msgid "Edge Type" +msgstr "Tipus d'aresta" + + +msgid "Face Marks" +msgstr "Marques de cares" + + +msgid "Freestyle Alpha" +msgstr "Alfa de línia manual" + + +msgid "Freestyle Color" +msgstr "Color de línia manual" + + +msgid "Freestyle Geometry" +msgstr "Geometria de línia manual" + + +msgid "Freestyle Strokes" +msgstr "Traços de línia manual" + + +msgid "Splitting" +msgstr "Divisió" + + +msgid "Split Pattern" +msgstr "Patró de divisió" + + +msgid "Freestyle Texture" +msgstr "Textura de línia manual" + + +msgid "Freestyle Thickness" +msgstr "Gruix de línia manual" + + +msgid "Filter Add-ons" +msgstr "Filtrar complements" + + +msgid "Particle in a particle system" +msgstr "Partícula en un sistema de partícules" + + +msgid "Alive State" +msgstr "Estat de vida" + + +msgid "Dying" +msgstr "Moribundes" + + +msgid "Birth Time" +msgstr "Moment de naixement" + + +msgid "Die Time" +msgstr "Moment de mort" + + +msgid "Exists" +msgstr "Existeix" + + +msgid "Particle Location" +msgstr "Ubicació de partícules" + + +msgid "Keyed States" +msgstr "Estats fitats" + + +msgid "Previous Angular Velocity" +msgstr "Velocitat angular anterior" + + +msgid "Previous Particle Location" +msgstr "Ubicació anterior de partícula" + + +msgid "Previous Rotation" +msgstr "Rotació anterior" + + +msgid "Previous Particle Velocity" +msgstr "Velocitat anterior de partícula" + + +msgid "Particle Brush" +msgstr "Pinzell de partícules" + + +msgid "Particle editing brush" +msgstr "Pinzell d'edició de partícules" + + +msgid "Particle count" +msgstr "Nombre de partícules" + + +msgid "Length Mode" +msgstr "Mode de longitud" + + +msgid "Make hairs longer" +msgstr "Fa més llargs els pèls" + + +msgid "Make hairs shorter" +msgstr "Fa més curts els pèls" + + +msgid "Puff Mode" +msgstr "Mode bufat" + + +msgid "Make hairs more puffy" +msgstr "Fa els pèls més bufats" + + +msgid "Sub" +msgstr "Resta" + + +msgid "Make hairs less puffy" +msgstr "Fa els pèls menys bufats" + + +msgid "Brush steps" +msgstr "Passades de pinzell" + + +msgid "Brush strength" +msgstr "Intensitat de pinzell" + + +msgid "Puff Volume" +msgstr "Volum de bufat" + + +msgid "Apply puff to unselected end-points (helps maintain hair volume when puffing root)" +msgstr "Aplica el bufat als punts finals no seleccionats (ajuda a mantenir el volum del cabell quan es bufa l'arrel)" + + +msgid "Particle Instance Object Weight" +msgstr "Pesos d'objecte en instància de partícules" + + +msgid "Weight of a particle instance object in a collection" +msgstr "Pes d'un objecte instància de partícula en una col·lecció" + + +msgid "The number of times this object is repeated with respect to other objects" +msgstr "El nombre de vegades que aquest objecte es repeteix respecte d'altres objectes" + + +msgid "Particle instance object name" +msgstr "Nom d'objecte de la instància de partícula" + + +msgid "Properties of particle editing mode" +msgstr "Propietats del mode d'edició de partícules" + + +msgid "Keys" +msgstr "Nòduls" + + +msgid "How many keys to make new particles with" +msgstr "[Keys]: De quants nòduls cal fer les partícules noves" + + +msgid "How many steps to display the path with" +msgstr "Amb quants passos cal mostrar el camí" + + +msgid "Emitter Distance" +msgstr "Distància d'emissor" + + +msgid "Distance to keep particles away from the emitter" +msgstr "[Emitter Distance]: Distància per mantenir les partícules lluny de l'emissor" + + +msgid "How many frames to fade" +msgstr "Quants fotogrames s'han d'esvair" + + +msgid "Editable" +msgstr "Editable" + + +msgid "A valid edit mode exists" +msgstr "Existeix un mode d'edició vàlid" + + +msgid "Editing hair" +msgstr "Cabell en edició" + + +msgid "The edited object" +msgstr "[Editing hair]: L'objecte editat" + + +msgid "Selection Mode" +msgstr "Mode selecció" + + +msgid "Particle select and display mode" +msgstr "Mode de selecció i visualització de partícules" + + +msgid "Path edit mode" +msgstr "Mode edició de camí" + + +msgid "Point select mode" +msgstr "Mode selecció de punts" + + +msgid "Tip" +msgstr "Consell" + + +msgid "Tip select mode" +msgstr "[Tip]: Mode selecció de consells" + + +msgid "Shape Object" +msgstr "Objecte forma" + + +msgid "Outer shape to use for tools" +msgstr "[Shape Object]: Forma exterior a usar per a les eines" + + +msgid "Display Particles" +msgstr "Mostrar partícules" + + +msgid "Display actual particles" +msgstr "Mostra les partícules en sí" + + +msgid "Comb" +msgstr "Pentinar" + + +msgid "Comb hairs" +msgstr "Pentina pèls" + + +msgid "Smooth hairs" +msgstr "Suavitzar pèls" + + +msgid "Add hairs" +msgstr "Afegir pèls" + + +msgid "Make hairs longer or shorter" +msgstr "Allargar o escurçar pèls" + + +msgid "Puff" +msgstr "Bufar" + + +msgid "Make hairs stand up" +msgstr "[Puff]: Fa aixecar els pèls" + + +msgid "Cut hairs" +msgstr "Tallar pèls" + + +msgid "Weight hair particles" +msgstr "Posar pesos a partícules de pèl" + + +msgid "Auto Velocity" +msgstr "Autovelocitat" + + +msgid "Calculate point velocities automatically" +msgstr "[Auto Velocity]: Calcula automàticament velocitats de punts" + + +msgid "Interpolate new particles from the existing ones" +msgstr "Interpolae partícules noves a partir de les existents" + + +msgid "Deflect Emitter" +msgstr "Emissor de deflexió" + + +msgid "Keep paths from intersecting the emitter" +msgstr "[Deflect Emitter]: Evita que les trajectòries intersequin amb l'emissor" + + +msgid "Fade Time" +msgstr "Temps d'esvaïment" + + +msgid "Fade paths and keys further away from current frame" +msgstr "[Fade Time]: Esvaeix les trajectòries i els nòduls més enllà del fotograma actual" + + +msgid "Keep Lengths" +msgstr "Mantenir longituds" + + +msgid "Keep path lengths constant" +msgstr "Manté constants les longituds de trajectòries" + + +msgid "Keep Root" +msgstr "Mantenir arrel" + + +msgid "Keep root keys unmodified" +msgstr "Manté els nòduls arrel sense modificar" + + +msgid "Particle Hair Key" +msgstr "Nòdul de partícula pèl" + + +msgid "Particle key for hair particle system" +msgstr "[Particle Hair Key]: Nòdul de partícula per a un sistema de partícules de pèl" + + +msgid "Location (Object Space)" +msgstr "Ubicació (espai d'objectes)" + + +msgid "Location of the hair key in object space" +msgstr "Ubicació del nòdul del pèl en l'espai de l'objecte" + + +msgid "Location of the hair key in its local coordinate system, relative to the emitting face" +msgstr "Ubicació del nòdul del pèl dins el sistema de coordenades local, en relació amb la cara emissora" + + +msgid "Relative time of key over hair length" +msgstr "Nombre relatiu de nòdul sobre la longitud del pèl" + + +msgid "Weight for cloth simulation" +msgstr "Pes per a simulació de tela" + + +msgid "Particle Key" +msgstr "Nòdul de partícula" + + +msgid "Key location for a particle over time" +msgstr "[Particle Key]: Ubicació del nòdul d'una partícula amb el temps" + + +msgid "Key angular velocity" +msgstr "Velocitat angular de nòdul" + + +msgid "Key location" +msgstr "Ubicació de nòdul" + + +msgid "Key rotation quaternion" +msgstr "Quaternió de rotació de la clau" + + +msgid "Time of key over the simulation" +msgstr "Temps de la clau sobre la simulació" + + +msgid "Key velocity" +msgstr "Velocitat de nòdul" + + +msgid "Particle system in an object" +msgstr "Sistema de partícules en un objecte" + + +msgid "Active Particle Target" +msgstr "Referent de partícula actiu" + + +msgid "Active Particle Target Index" +msgstr "[Active Particle Target]: Índex del referent de partícula actiu" + + +msgid "Child Particles" +msgstr "Partícules filles" + + +msgid "Child particles generated by the particle system" +msgstr "[Child Particles]: Partícules filles generades pel sistema de partícules" + + +msgid "Child Seed" +msgstr "Llavor de filles" + + +msgid "Offset in the random number table for child particles, to get a different randomized result" +msgstr "Desplaçament en la taula de nombres aleatoris per a les partícules filles, per a obtenir un resultat aleatori diferent" + + +msgid "Cloth dynamics for hair" +msgstr "Dinàmica de tela per a pèl" + + +msgid "The current simulation time step size, as a fraction of a frame" +msgstr "La mida del cronolapse de l'actual simulació, com a fracció d'un fotograma" + + +msgid "Multiple Caches" +msgstr "Múltiples memòries cau" + + +msgid "Particle system has multiple point caches" +msgstr "[Multiple Caches]: El sistema de partícules té memòries cau de punts múltiples" + + +msgid "Vertex Group Clump Negate" +msgstr "Negar l'aglomeració de grup de vèrtexs" + + +msgid "Negate the effect of the clump vertex group" +msgstr "[Vertex Group Clump Negate]: Nega l'efecte de grup de vèrtexs en aglomeració" + + +msgid "Vertex Group Density Negate" +msgstr "Negar densitat del grup de vèrtexs" + + +msgid "Negate the effect of the density vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en densitat" + + +msgid "Vertex Group Field Negate" +msgstr "Negar camp de grup de vèrtexs" + + +msgid "Negate the effect of the field vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en camp" + + +msgid "Vertex Group Kink Negate" +msgstr "Negar torsió de grup de vèrtexs" + + +msgid "Negate the effect of the kink vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en torsió" + + +msgid "Vertex Group Length Negate" +msgstr "Negar longitud del grup de vèrtexs" + + +msgid "Negate the effect of the length vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en longitud" + + +msgid "Vertex Group Rotation Negate" +msgstr "Negar rotació del grup de vèrtexs" + + +msgid "Negate the effect of the rotation vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en rotació" + + +msgid "Vertex Group Roughness 1 Negate" +msgstr "Negar rugositat 1 del grup de vèrtexs" + + +msgid "Negate the effect of the roughness 1 vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en rugositat 1" + + +msgid "Vertex Group Roughness 2 Negate" +msgstr "Negar rugositat 2 del grup de vèrtexs" + + +msgid "Negate the effect of the roughness 2 vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en rugositat 2" + + +msgid "Vertex Group Roughness End Negate" +msgstr "Negar rugositat de puntes del grup de vèrtexs" + + +msgid "Negate the effect of the roughness end vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en rugositat de puntes" + + +msgid "Vertex Group Size Negate" +msgstr "Negar mida del grup de vèrtexs" + + +msgid "Negate the effect of the size vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en mida" + + +msgid "Vertex Group Tangent Negate" +msgstr "Negar tangent del grup de vèrtexs" + + +msgid "Negate the effect of the tangent vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en tangent" + + +msgid "Vertex Group Twist Negate" +msgstr "Negar rosca del grup de vèrtexs" + + +msgid "Negate the effect of the twist vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en rosca" + + +msgid "Vertex Group Velocity Negate" +msgstr "Negar velocitat del grup de vèrtexs" + + +msgid "Negate the effect of the velocity vertex group" +msgstr "Nega l'efecte del grup de vèrtexs en velocitat" + + +msgid "Particle system can be edited in particle mode" +msgstr "El sistema de partícules es pot editar en mode partícula" + + +msgid "Edited" +msgstr "Editat" + + +msgid "Particle system has been edited in particle mode" +msgstr "El sistema de partícules s'ha editat en mode de partícula" + + +msgid "Global Hair" +msgstr "Pèl global" + + +msgid "Hair keys are in global coordinate space" +msgstr "Els nòduls de pèl estan a l'espai de coordenades global" + + +msgid "Particle system name" +msgstr "Nom del sistema de partícules" + + +msgid "Use this object's coordinate system instead of global coordinate system" +msgstr "Usa el sistema de coordenades d'aquest objecte en lloc del sistema de coordenades global" + + +msgid "Particles generated by the particle system" +msgstr "Partícules generades pel sistema de partícules" + + +msgid "Reactor Target Object" +msgstr "Objecte referent del reactor" + + +msgid "For reactor systems, the object that has the target particle system (empty if same object)" +msgstr "Per a sistemes de reactors, l'objecte que té el sistema de partícules de referent (buit si és el mateix objecte)" + + +msgid "Reactor Target Particle System" +msgstr "Sistema de partícules de referent de reactor" + + +msgid "For reactor systems, index of particle system on the target object" +msgstr "Per a sistemes de reactors, índex del sistema de partícules sobre l'objecte referent" + + +msgid "Offset in the random number table, to get a different randomized result" +msgstr "Desplaçament en la taula de nombres aleatoris, per a obtenir un resultat aleatori variat" + + +msgid "Particle system settings" +msgstr "Paràmetres de sistema de partícules" + + +msgid "Target particle systems" +msgstr "Sistema de partícules de referent" + + +msgid "Enable hair dynamics using cloth simulation" +msgstr "Habilitar dinàmica de pèl mitjançant simulació de tela" + + +msgid "Keyed Timing" +msgstr "Temporització amb fites" + + +msgid "Use key times" +msgstr "Usar temps de fites" + + +msgid "Vertex Group Clump" +msgstr "Grup de vèrtexs d'aglomeració" + + +msgid "Vertex group to control clump" +msgstr "[Vertex Group Clump]: Grup de vèrtexs per a controlar l'aglomeració" + + +msgid "Vertex Group Density" +msgstr "Grup de vèrtexs de densitat" + + +msgid "Vertex group to control density" +msgstr "[Vertex Group Density]: Grup de vèrtexs per a controlar la densitat" + + +msgid "Vertex Group Field" +msgstr "Grup de vèrtexs de camp" + + +msgid "Vertex group to control field" +msgstr "Grup de vèrtexs per controlar el camp" + + +msgid "Vertex Group Kink" +msgstr "Grup de vèrtexs de torsió" + + +msgid "Vertex group to control kink" +msgstr "Grup de vèrtexs per a controlar la torsió" + + +msgid "Vertex Group Length" +msgstr "Grup de vèrtexs de longitud" + + +msgid "Vertex group to control length" +msgstr "Grup de vèrtexs per a controlar la longitud" + + +msgid "Vertex Group Rotation" +msgstr "Grup de vèrtexs de rotació" + + +msgid "Vertex group to control rotation" +msgstr "Grup de vèrtexs per a controlar la rotació" + + +msgid "Vertex Group Roughness 1" +msgstr "Grup de vèrtexs de rugositat 1" + + +msgid "Vertex group to control roughness 1" +msgstr "Grup de vèrtexs per a controlar la rugositat 1" + + +msgid "Vertex Group Roughness 2" +msgstr "Grup de vèrtexs de rugositat 2" + + +msgid "Vertex group to control roughness 2" +msgstr "Grup de vèrtexs per a controlar la rugositat 2" + + +msgid "Vertex Group Roughness End" +msgstr "Grup de vèrtexs de rugositat de puntes" + + +msgid "Vertex group to control roughness end" +msgstr "Grup de vèrtexs per a controlar la rugositat de puntes" + + +msgid "Vertex Group Size" +msgstr "Grup de vèrtexs de mida" + + +msgid "Vertex group to control size" +msgstr "Grup de vèrtexs per a controlar la mida" + + +msgid "Vertex Group Tangent" +msgstr "Grup de vèrtexs de tangent" + + +msgid "Vertex group to control tangent" +msgstr "Grup de vèrtexs per a controlar la tangent" + + +msgid "Vertex Group Twist" +msgstr "Grup de vèrtexs de rosca" + + +msgid "Vertex group to control twist" +msgstr "Grup de vèrtex per a controlar la rosca" + + +msgid "Vertex Group Velocity" +msgstr "Grup de vèrtexs de velocitat" + + +msgid "Vertex group to control velocity" +msgstr "Grup de vèrtex per a controlar la velocitat" + + +msgid "Collection of particle systems" +msgstr "Col·lecció de sistemes de partícules" + + +msgid "Active Particle System" +msgstr "Sistema de partícules actiu" + + +msgid "Active particle system being displayed" +msgstr "Es mostra el sistema de partícules actiu" + + +msgid "Active Particle System Index" +msgstr "Índex del sistema de partícules actiu" + + +msgid "Index of active particle system slot" +msgstr "Índex de l'epígraf del sistema de partícules actiu" + + +msgid "Particle Target" +msgstr "Referent de partícula" + + +msgid "Target particle system" +msgstr "[Particle Target]: Sistema de partícules de referent" + + +msgid "Friend" +msgstr "Amic" + + +msgid "Neutral" +msgstr "Neutral" + + +msgid "Enemy" +msgstr "Enemic" + + +msgid "Keyed particles target is valid" +msgstr "El referent de partícules fitades és vàlid" + + +msgid "Particle target name" +msgstr "Nom del referent de partícula" + + +msgid "The object that has the target particle system (empty if same object)" +msgstr "L'objecte que té el sistema de partícules de referent (buit si és el mateix objecte)" + + +msgid "Target Particle System" +msgstr "Sistema de partícules de referent" + + +msgid "The index of particle system on the target object" +msgstr "[Target Particle System]: L'índex del sistema de partícules en l'objecte referent" + + +msgid "Path Compare" +msgstr "Comparar trajectòries" + + +msgid "Match paths against this value" +msgstr "Compara les trajectòries amb aquest valor" + + +msgid "Use Wildcard" +msgstr "Usar comodí" + + +msgid "Enable wildcard globbing" +msgstr "[Use Wildcard]: Habilita l'ús dels comodins" + + +msgid "Paths Compare" +msgstr "Comparar trajectòries" + + +msgid "Collection of paths" +msgstr "Col·lecció de trajectòries" + + +msgid "Point in a point cloud" +msgstr "Punt en un núvol de punts" + + +msgid "Active Point Cache" +msgstr "Memòria cau del punt actiu" + + +msgid "Active point cache for physics simulations" +msgstr "[Active Point Cache]: Cau de punts actius per a simulacions físiques" + + +msgid "Cache Compression" +msgstr "Compressió de memòria cau" + + +msgid "No compression" +msgstr "Sense compressió" + + +msgid "Lite" +msgstr "Lleugera" + + +msgid "Fast but not so effective compression" +msgstr "[Lite]: Compressió ràpida però no gaire efectiva" msgid "Heavy" -msgstr "Pesat" +msgstr "Pesada" + + +msgid "Cache file path" +msgstr "Camí al document de memòria cau" + + +msgid "Frame on which the simulation stops" +msgstr "Fotograma on s'atura la simulació" + + +msgid "Frame on which the simulation starts" +msgstr "Fotograma on s'inicia la simulació" + + +msgid "Cache Step" +msgstr "Pas de la memòria cau" + + +msgid "Number of frames between cached frames" +msgstr "[Cache Step]: Nombre de fotogrames entre fotogrames guardats en memòria cau" + + +msgid "Cache Index" +msgstr "Índex de memòria cau" + + +msgid "Index number of cache files" +msgstr "Número d'índex dels documents de memòria cau" + + +msgid "Cache Info" +msgstr "Informació de memòria cau" + + +msgid "Info on current cache status" +msgstr "Informació sobre l'estat actual de la memòria cau" + + +msgid "The cache is baked" +msgstr "La memòria cau està precuinada" + + +msgid "The cache is being baked" +msgstr "La memòria cau s'està precuinant" + + +msgid "Some frames were skipped while baking/saving that cache" +msgstr "S'han omès alguns fotogrames mentre es precuinava/desava aquesta cau" + + +msgid "Cache Is Outdated" +msgstr "La memòria cau està obsoleta" + + +msgid "Cache name" +msgstr "Nom de la memòria cau" + + +msgid "Point Cache List" +msgstr "Llista de memòria cau de punts" + + +msgid "Disk Cache" +msgstr "Memòria cau de disc" + + +msgid "Save cache files to disk (.blend file must be saved first)" +msgstr "Desa els documents de la memòria cau al disc (cal desar el document .blend en primer lloc)" + + +msgid "Read cache from an external location" +msgstr "Llegir memòria cau des d'una ubicació externa" + + +msgid "Library Path" +msgstr "Camí de la biblioteca" + + +msgid "Use this file's path for the disk cache when library linked into another file (for local bakes per scene file, disable this option)" +msgstr "Usa el camí d'aquest document per a la memòria cau del disc quan la biblioteca s'enllaça a un altre document (per a precuinats locals per document d'escena, desactiveu aquesta opció)" + + +msgid "Point cache for physics simulations" +msgstr "Memòria cau de punts per a simulacions físiques" + + +msgid "Point Caches" +msgstr "Memòria cau de punts" + + +msgid "Collection of point caches" +msgstr "Col·lecció de memòria cau de punts" + + +msgid "Polygon Float Properties" +msgstr "Propietats flotanta del polígon " + + +msgid "Collection of float properties" +msgstr "[Polygon Float Properties]: Col·lecció de propietats de coma flotant" + + +msgid "Polygon Int Properties" +msgstr "Propietats d'enter del polígon" + + +msgid "Collection of int properties" +msgstr "Col·lecció de propietats d'enter" + + +msgid "Polygon String Properties" +msgstr "Propietats de cadena de polígons" + + +msgid "Collection of string properties" +msgstr "Col·lecció de propietats de cadena" + + +msgid "A collection of pose channels, including settings for animating bones" +msgstr "Una col·lecció de canals de posa, incloent-hi la configuració per animar ossos" + + +msgid "Groups of the bones" +msgstr "Grups dels ossos" + + +msgid "Pose Bones" +msgstr "Ossos de posa" + + +msgid "Individual pose bones for the armature" +msgstr "[Pose Bones]: Ossos de posa individuals per a l'esquelet" + + +msgid "IK Param" +msgstr "Paràm de CI" + + +msgid "Parameters for IK solver" +msgstr "[IK Param]: Paràmetres per al resolutor de cinètica invertida" + + +msgid "Selection of IK solver for IK chain" +msgstr "Selecció del resolutor CI per a la cadena CI" + + +msgid "Auto IK" +msgstr "CI automàtica" + + +msgid "Add temporary IK constraints while grabbing bones in Pose Mode" +msgstr "[Auto IK]: Afegeix restriccions temporals de CI mentre s'agafen ossos en el mode de posa" + + +msgid "Relative Mirror" +msgstr "Mirall relatiu" + + +msgid "Apply relative transformations in X-mirror mode (not supported with Auto IK)" +msgstr "[Relative Mirror]: Aplica les transformacions relatives en el mode de mirall X (no compatible amb CI automàtica)" + + +msgid "Pose Bone" +msgstr "Os de posa" + + +msgid "Channel defining pose data for a bone in a Pose" +msgstr "Canal que defineix les dades de posa per a un os en una posa" + + +msgid "Bone associated with this PoseBone" +msgstr "Os associat amb aquest os posa" + + +msgid "Bone group this pose channel belongs to" +msgstr "Grup d'ossos al qual pertany aquest canal de posa" + + +msgid "Bone group this pose channel belongs to (0 means no group)" +msgstr "Grup d'ossos al qual pertany aquest canal de posa (0 significa que no hi ha grup)" + + +msgid "Child of this pose bone" +msgstr "Fill d'aquest os posa" + + +msgid "Constraints that act on this pose channel" +msgstr "Restriccions que actuen en aquest canal de posa" + + +msgid "Custom Object" +msgstr "Objecte personalitzat" + + +msgid "Object that defines custom display shape for this bone" +msgstr "Objecte que defineix una forma de visualització personalitzada per a aquest os" + + +msgid "Custom Shape Rotation" +msgstr "Rotació de forma personalitzada" + + +msgid "Adjust the rotation of the custom shape" +msgstr "[Custom Shape Rotation]: Ajusta el gir de la forma personalitzada" + + +msgid "Custom Shape Scale" +msgstr "Escala de forma personalitzada" + + +msgid "Adjust the size of the custom shape" +msgstr "[Custom Shape Scale]: Ajusta la mida de la forma personalitzada" + + +msgid "Custom Shape Transform" +msgstr "Transformació de forma personalitzada" + + +msgid "Bone that defines the display transform of this custom shape" +msgstr "Os que defineix la transformació de visualització d'aquesta forma personalitzada" + + +msgid "Custom Shape Translation" +msgstr "Translació de forma personalitzada" + + +msgid "Adjust the location of the custom shape" +msgstr "Ajusta la ubicació de la forma personalitzada" + + +msgid "Pose Head Position" +msgstr "Posició del cap en la posa" + + +msgid "Location of head of the channel's bone" +msgstr "Ubicació del cap de l'os del canal" + + +msgid "IK Lin Weight" +msgstr "Influència lineal de CI" + + +msgid "Weight of scale constraint for IK" +msgstr "Influència de la restricció d'escala per a CI" + + +msgid "IK X Maximum" +msgstr "Màxim X de CI" + + +msgid "Maximum angles for IK Limit" +msgstr "Angle màxim per al límit de CI" + + +msgid "IK Y Maximum" +msgstr "Màxim Y de CI" + + +msgid "IK Z Maximum" +msgstr "Màxim Z de CI" + + +msgid "IK X Minimum" +msgstr "Mínim X de CI" + + +msgid "Minimum angles for IK Limit" +msgstr "Angles mínims per al límit de CI" + + +msgid "IK Y Minimum" +msgstr "Mínim Y de CI" + + +msgid "IK Z Minimum" +msgstr "Mínim Z de CI" + + +msgid "IK Rotation Weight" +msgstr "Pes de rotació de CI" + + +msgid "Weight of rotation constraint for IK" +msgstr "Pes de la restricció de rotació per a CI" + + +msgid "IK X Stiffness" +msgstr "Rigidesa d'X de CI" + + +msgid "IK stiffness around the X axis" +msgstr "Rigidesa de CI al voltant de l'eix X" + + +msgid "IK Y Stiffness" +msgstr "Rigidesa d'Y de CI" + + +msgid "IK stiffness around the Y axis" +msgstr "Rigidesa de CI al voltant de l'eix Y" + + +msgid "IK Z Stiffness" +msgstr "Rigidesa de Z de CI" + + +msgid "IK stiffness around the Z axis" +msgstr "Rigidesa de CI al voltant de l'eix Z" + + +msgid "IK Stretch" +msgstr "Estirament de CI" + + +msgid "Allow scaling of the bone for IK" +msgstr "Permet escalar l'os per a CI" + + +msgid "Has IK" +msgstr "Té CI" + + +msgid "Is part of an IK chain" +msgstr "Forma part d'una cadena CI" + + +msgid "IK X Lock" +msgstr "Blocatge en X de CI" + + +msgid "Disallow movement around the X axis" +msgstr "Anul·la el moviment al voltant de l'eix X" + + +msgid "IK Y Lock" +msgstr "Blocatge en Y de CI" + + +msgid "Disallow movement around the Y axis" +msgstr "Anul·la el moviment al voltant de l'eix Y" + + +msgid "IK Z Lock" +msgstr "Blocatge en Z de CI" + + +msgid "Disallow movement around the Z axis" +msgstr "Anul·la el moviment al voltant de l'eix Y" + + +msgid "Pose Matrix" +msgstr "Matriu de posa" + + +msgid "Final 4x4 matrix after constraints and drivers are applied (object space)" +msgstr "Matriu final 4x4 després d'aplicar restriccions i controladors (espai d'objectes)" + + +msgid "Alternative access to location/scale/rotation relative to the parent and own rest bone" +msgstr "Accés alternatiu a la ubicació/escala/rotació en relació amb el pare i el propi os de repòs" + + +msgid "Channel Matrix" +msgstr "Matriu de canals" + + +msgid "4x4 matrix, before constraints" +msgstr "Matriu 4x4, abans de les restriccions" + + +msgid "Parent of this pose bone" +msgstr "Pare d'aquest os posa" + + +msgid "Pose Tail Position" +msgstr "Posició de la punta de posa" + + +msgid "Location of tail of the channel's bone" +msgstr "Ubicació de la punta de l'os del canal" + + +msgid "Scale to Bone Length" +msgstr "Escalar a la longitud d'os" + + +msgid "Scale the custom object by the bone length" +msgstr "Escala l'objecte personalitzat per la longitud de l'os" + + +msgid "IK X Limit" +msgstr "Límit X de CI" + + +msgid "Limit movement around the X axis" +msgstr "Limita el moviment al voltant de l'eix X" + + +msgid "IK Y Limit" +msgstr "Límit Y de CI" + + +msgid "Limit movement around the Y axis" +msgstr "Limita el moviment al voltant de l'eix Y" + + +msgid "IK Z Limit" +msgstr "Límit Z de CI" + + +msgid "Limit movement around the Z axis" +msgstr "Limita el moviment al voltant de l'eix Z" + + +msgid "IK Linear Control" +msgstr "Control lineal de CI" + + +msgid "Apply channel size as IK constraint if stretching is enabled" +msgstr "Aplica la mida del canal com a restricció de CI si l'estirament està activat" + + +msgid "IK Rotation Control" +msgstr "Control de rotació de CI" + + +msgid "Apply channel rotation as IK constraint" +msgstr "Aplica la rotació del canal com a restricció de CI" + + +msgid "PoseBone Constraints" +msgstr "Restriccions d'os de posa" + + +msgid "Collection of pose bone constraints" +msgstr "[PoseBone Constraints]: Col·lecció de restriccions d'ossos posa" + + +msgid "Active PoseChannel constraint" +msgstr "Restricció de canal de posa activa" + + +msgid "Global preferences" +msgstr "Preferències globals" + + +msgid "Active Section" +msgstr "Secció activa" + + +msgid "Active section of the preferences shown in the user interface" +msgstr "Secció activa de les preferències mostrades a la interfície d'usuària" + + +msgid "Application Template" +msgstr "Plantilla d'aplicació" + + +msgid "Apps" +msgstr "Aplicacions" + + +msgid "Preferences that work only for apps" +msgstr "Preferències que només funcionen per a aplicacions" + + +msgid "Auto-Execution Paths" +msgstr "Camins d'autoexecució" + + +msgid "Edit Methods" +msgstr "Editar mètodes" + + +msgid "Settings for interacting with Blender data" +msgstr "Paràmetres per a interactuar amb les dades del Blender" + + +msgid "Settings for features that are still early in their development stage" +msgstr "Configuració de les característiques que encara són en fase de desenvolupament inicial" + + +msgid "Default paths for external files" +msgstr "Camins per defecte a documents externs" + + +msgid "Settings for input devices" +msgstr "Paràmetres per als dispositius d'ingrés" + + +msgid "Preferences have changed" +msgstr "Les preferències han canviat" + + +msgid "Shortcut setup for keyboards and other input devices" +msgstr "Configuració de dreceres de teclats i altres dispositius d'ingrés" + + +msgid "System & OpenGL" +msgstr "Sistema i OpenGL" + + +msgid "Graphics driver and operating system settings" +msgstr "Paràmetres del controlador de gràfics i del sistema operatiu" + + +msgid "Save on Exit" +msgstr "Desar en sortir" + + +msgid "Save preferences on exit when modified (unless factory settings have been loaded)" +msgstr "Desa les preferències en sortir quan es modifiquen (llevat que s'hagin carregat els paràmetres de fàbrica)" + + +msgid "Version of Blender the userpref.blend was saved with" +msgstr "Versió del Blender amb la qual s'ha desat userpref.blend" + + +msgid "View & Controls" +msgstr "Visualització i controls" + + +msgid "Preferences related to viewing data" +msgstr "Preferències relacionades amb la visualització de dades" + + +msgid "Corner Splitting" +msgstr "Dividir en cantonades" + + +msgid "Split and join editors by dragging from corners" +msgstr "[Corner Splitting]: Divideix i ajunta editors arrossegant-los des de les cantonades" + + +msgid "Edge Resize" +msgstr "Redimensionar en vora" + + +msgid "Resize editors by dragging from the edges" +msgstr "[Edge Resize]: Redimensiona els editors arrossegant-los des de les vores" + + +msgid "Regions Visibility Toggle" +msgstr "Revesar visibilitat de regions" + + +msgid "Header and side bars visibility toggles" +msgstr "[Regions Visibility Toggle]: Alterna la visibilitat de barres laterals i capçalera" + + +msgid "Auto Keying Mode" +msgstr "Mode autofita" + + +msgid "Mode of automatic keyframe insertion for Objects and Bones (default setting used for new Scenes)" +msgstr "[Auto Keying Mode]: Mode d'inserció automàtica de fotofites per als objectes i els ossos (opció predeterminada usada per a escenes noves)" + + +msgid "Add/Replace" +msgstr "Afegir/substituir" + + +msgid "Collection Instance Empty Size" +msgstr "Mida de trivi en instàncies de col·lecció" + + +msgid "Display size of the empty when new collection instances are created" +msgstr "[Collection Instance Empty Size]: Mostra la mida del tribi quan es creen instàncies de col·lecció noves" + + +msgid "New Curve Smoothing Mode" +msgstr "Mode suavitzat de nova corba" + + +msgid "Auto Handle Smoothing mode used for newly added F-Curves" +msgstr "[New Curve Smoothing Mode]: Mode de suavitzat amb anses automàtiques per a les corbes-F que s'afegeixen de nou" + + +msgid "Unselected F-Curve Opacity" +msgstr "Opacitat de la corba-F no seleccionada" + + +msgid "The opacity of unselected F-Curves against the background of the Graph Editor" +msgstr "[Unselected F-Curve Opacity]: L'opacitat de les corbes-F no seleccionades contra el rerefons de l'Editor de grafiques" + + +msgid "Annotation Default Color" +msgstr "Color predeterminat d'anotació" + + +msgid "Color of new annotation layers" +msgstr "Color de noves capes d'anotacions" + + +msgid "Grease Pencil Eraser Radius" +msgstr "Radi d'esborrar de llapis de greix" + + +msgid "Radius of eraser 'brush'" +msgstr "Radi del «pinzell» esborrador" + + +msgid "Grease Pencil Euclidean Distance" +msgstr "Distància euclidiana del llapis de greix" + + +msgid "Distance moved by mouse when drawing stroke to include" +msgstr "Distància en què es mou el ratolí quan es dibuixa el traç a incloure" + + +msgid "Grease Pencil Manhattan Distance" +msgstr "Distància Manhattan del llapis de greix" + + +msgid "Pixels moved by mouse per axis when drawing stroke" +msgstr "Píxels en què es mou el ratolí per eix quan es dibuixa el traç" + + +msgid "New Handles Type" +msgstr "Tipus de nanses nous" + + +msgid "Handle type for handles of new keyframes" +msgstr "Tipus de nansa per a les nanses de les fotofites noves" + + +msgctxt "Action" +msgid "New Interpolation Type" +msgstr "Tipus d'interpolació nou" + + +msgid "Interpolation mode used for first keyframe on newly added F-Curves (subsequent keyframes take interpolation from preceding keyframe)" +msgstr "Mode d'interpolació utilitzat per a la primera fotofita en les noves corbes-F afegides ( les fotofites següents prenen la interpolació de la fotofita anterior)" + + +msgid "Material Link To" +msgstr "Enllaç de material a" + + +msgid "Toggle whether the material is linked to object data or the object block" +msgstr "[Material Link To]: Revesa si el material està enllaçat a dades de l'objecte o al bloc de l'objecte" + + +msgid "Auto-offset Margin" +msgstr "Marge de d'autodesplaçament" + + +msgid "Minimum distance between nodes for Auto-offsetting nodes" +msgstr "[Auto-offset Margin]: Distància mínima entre nodes per a desplaçament automàtic de nodes" + + +msgid "Align Object To" +msgstr "Alinear objecte a" + + +msgid "The default alignment for objects added from a 3D viewport menu" +msgstr "[Align Object To]: L'alineació predeterminada per als objectes afegits des d'un menú del mirador 3D" + + +msgid "Align newly added objects to the world coordinate system" +msgstr "Alinea els nous objectes afegits al sistema de coordenades del món" + + +msgid "Align newly added objects to the active 3D view orientation" +msgstr "Alinea els nous objectes afegits a l'orientació activa de la vista 3D" + + +msgid "Align newly added objects to the 3D Cursor's rotation" +msgstr "Alinea els nous objectes afegits a la rotació del cursor 3D" + + +msgid "Sculpt/Paint Overlay Color" +msgstr "Color de bambolina de l'esculpir/pintar" + + +msgid "Color of texture overlay" +msgstr "Color de bambolina de textura" + + +msgid "Undo Memory Size" +msgstr "Desfer mida de memòria" + + +msgid "Maximum memory usage in megabytes (0 means unlimited)" +msgstr "Ús màxim de la memòria en megabytes (0 significa il·limitat )" + + +msgid "Undo Steps" +msgstr "Desfer passos" + + +msgid "Number of undo steps available (smaller values conserve memory)" +msgstr "[Undo Steps]: Nombre de passos per desfer disponibles (els valors més petits estalvien memòria)" + + +msgid "Channel Group Colors" +msgstr "Colors de grups de canals" + + +msgid "Use animation channel group colors; generally this is used to show bone group colors" +msgstr "Usa els colors del grup del canal d'animació; generalment s'utilitza per a mostrar els colors de grups d'ossos" + + +msgid "Auto Keying Enable" +msgstr "Activar autofotofita" + + +msgid "Automatic keyframe insertion for Objects and Bones (default setting used for new Scenes)" +msgstr "[Auto Keying Enable]: Inserció automàtica de fotofites per a objectes i ossos (opció predeterminada utilitzada per a escenes noves)" + + +msgid "Show Auto Keying Warning" +msgstr "Mostrar avís d'Autofotofita" + + +msgid "Show warning indicators when transforming objects and bones if auto keying is enabled" +msgstr "Mostra indicadors d'avís en transformar objectes i ossos si hi ha la fotofita automàtica està activada" + + +msgid "Cursor Lock Adjust" +msgstr "Ajustar bloqueig de cursor" + + +msgid "Place the cursor without 'jumping' to the new location (when lock-to-cursor is used)" +msgstr "Col·loca el cursor sense «salts» a la nova ubicació (quan s'usa travar-a-cursor)" + + +msgid "Duplicate Action" +msgstr "Duplicar acció" + + +msgid "Causes actions to be duplicated with the data-blocks" +msgstr "Fa que les accions es dupliquin amb els blocs de dades" + + +msgid "Duplicate Armature" +msgstr "Duplicar esquelet" + + +msgid "Causes armature data to be duplicated with the object" +msgstr "Fa que les dades de l'esquelet es dupliquin amb l'objecte" + + +msgid "Duplicate Camera" +msgstr "Duplicar càmera" + + +msgid "Causes camera data to be duplicated with the object" +msgstr "Fa que les dades de la càmera es dupliquin amb l'objecte" msgid "Enable library override template in the python API" msgstr "Activa la plantilla de sobreseïment de la biblioteca a l'API de python" +msgid "Python Scripts Directory" +msgstr "Directori de protocols en python" + + msgid "Lock Camera Pan/Zoom" msgstr "Bloqueja escombratge/zoom de la càmera" @@ -77002,6 +85345,10 @@ msgid "Use the depth under the mouse to improve view pan/rotate/zoom functionali msgstr "Usa la profunditat sota el ratolí per a millorar la funcionalitat escombratge/rotació/zoom de la vista" +msgid "Show Splash" +msgstr "Mostrar careta" + + msgid "Use Weight Color Range" msgstr "Usa l'interval de color força" @@ -77078,6 +85425,10 @@ msgid "Blender 2.6 doesn't support python constraints yet" msgstr "Blender 2.6 encara no admet restriccions de python" +msgid "Second" +msgstr "Segon" + + msgid "Pan Angle" msgstr "Angle d'escombratge" @@ -77087,6 +85438,11 @@ msgid "Keying" msgstr "Fites" +msgctxt "Operator" +msgid "Batch Rename..." +msgstr "Rebateig de repetició..." + + msgid "Scripts" msgstr "Protocols" diff --git a/locale/po/cs.po b/locale/po/cs.po index d14d5fca11f..27e02909827 100644 --- a/locale/po/cs.po +++ b/locale/po/cs.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: \n" "Last-Translator: Martin Tabačan \n" "Language-Team: Taby \n" @@ -974,6 +974,10 @@ msgid "Index of the tag set for editing" msgstr "Index sady značek pro úpravy" +msgid "Copyright" +msgstr "Autorská práva" + + msgid "Description" msgstr "Popis" @@ -7511,10 +7515,6 @@ msgid "Compression" msgstr "Komprese" -msgid "Number" -msgstr "Číslo" - - msgid "Randomness" msgstr "Náhodnost" @@ -8687,26 +8687,6 @@ msgid "Editable falloff curve" msgstr "Křivka útlumu" -msgid "Smoother" -msgstr "Hladší" - - -msgid "Root" -msgstr "Kvadratické" - - -msgid "Sharp" -msgstr "Ostré" - - -msgid "Sharper" -msgstr "Ostřejší" - - -msgid "Inverse Square" -msgstr "Opustit Editační mód" - - msgid "Falloff Angle" msgstr "Úhel Poklesu" @@ -10305,6 +10285,10 @@ msgid "Inverse Linear" msgstr "Prohodit" +msgid "Inverse Square" +msgstr "Opustit Editační mód" + + msgid "Lin/Quad Weighted" msgstr "Lineární" @@ -11680,6 +11664,10 @@ msgid "Strand shape parameter" msgstr "Vlákna" +msgid "Number" +msgstr "Číslo" + + msgid "Show particle number" msgstr "Nastavení částic" @@ -12150,10 +12138,6 @@ msgid "Modified" msgstr "Modifikátory" -msgid "Lines" -msgstr "Čáry" - - msgid "Lines of text" msgstr "Pohled & Ovládání" @@ -12510,6 +12494,14 @@ msgid "Use soft marble" msgstr "Zobrazit nastavení vláken pro statické částice" +msgid "Sharp" +msgstr "Ostré" + + +msgid "Sharper" +msgstr "Ostřejší" + + msgid "Noise Basis 2" msgstr "Základ šumu" @@ -14852,6 +14844,10 @@ msgid "Skin Vertex" msgstr "Vrchol" +msgid "Root" +msgstr "Kvadratické" + + msgid "Mesh Skin Vertex Layer" msgstr "Přidat barvu" @@ -16547,6 +16543,10 @@ msgid "Line Thickness" msgstr "Tloušťka čáry" +msgid "Lines" +msgstr "Čáry" + + msgid "Motion Path Points" msgstr "Body cesty pohybu" @@ -22102,10 +22102,6 @@ msgid "Export scene as glTF 2.0 file" msgstr "Exportovat scénu jako soubor glTF 2.0" -msgid "Copyright" -msgstr "Autorská práva" - - msgid "Apply sampling to all animations" msgstr "Použít vzorkování pro všechny animace" @@ -41908,18 +41904,10 @@ msgid "Lifetime Randomness" msgstr "Životní Náhodnost" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Iterace: %d .. %d (průměr %d)" - - msgid "Multiply Mass with Size" msgstr "Násobit Hmotnost s Velikostí" -msgid "Spacing: %g" -msgstr "Rozestup: %g" - - msgid "Show Emitter" msgstr "Zobrazit Emitor" @@ -41961,6 +41949,14 @@ msgid "Use Timing" msgstr "Použít Čásování" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Iterace: %d .. %d (průměr %d)" + + +msgid "Spacing: %g" +msgstr "Rozestup: %g" + + msgid "Not yet functional" msgstr "Zatím nefunguje" @@ -42504,11 +42500,6 @@ msgid "Set Keyframe B" msgstr "Nastavit Klíčový Snímek B" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Přiblížit %d:%d" - - msgctxt "Operator" msgid "Enable Markers" msgstr "Povolit Značky" @@ -43204,10 +43195,6 @@ msgid "Rotation" msgstr "Rotace" -msgid "Original frame range: %d-%d (%d)" -msgstr "Původní rozsah snímků: %d-%d (%d)" - - msgid "Resolutions" msgstr "Rozlišení" @@ -43237,6 +43224,10 @@ msgid "Pack" msgstr "Zabalit" +msgid "Original frame range: %d-%d (%d)" +msgstr "Původní rozsah snímků: %d-%d (%d)" + + msgid "Source Channel" msgstr "Zdrojový kanál" @@ -43716,14 +43707,6 @@ msgid "Save as Studio light" msgstr "Uložit jako Studiové Světlo" -msgid "Color Set %d" -msgstr "Sada Barev %d" - - -msgid "Color %d" -msgstr "Barva %d" - - msgid "Player" msgstr "Hráč" @@ -43744,6 +43727,14 @@ msgid "No custom %s configured" msgstr "Žádná vlastní %s nastavena" +msgid "Color Set %d" +msgstr "Sada Barev %d" + + +msgid "Color %d" +msgstr "Barva %d" + + msgid "Description:" msgstr "Popis:" @@ -43760,10 +43751,6 @@ msgid "Author:" msgstr "Autor:" -msgid "author" -msgstr "autor" - - msgid "Version:" msgstr "Verze:" @@ -47533,22 +47520,6 @@ msgid "Unable to create new strip" msgstr "Není možné otevřít soubor" -msgid "Functions" -msgstr "Funkce" - - -msgid "Comparison" -msgstr "Porovnat" - - -msgid "Trigonometric" -msgstr "Trigonometrie" - - -msgid "Conversion" -msgstr "Konvertovat" - - msgid "Unable to locate link in node tree" msgstr "Povolit změnu barvy vertexů na aktivním mesh objektu" diff --git a/locale/po/de.po b/locale/po/de.po index 5ce4059fa7d..0d1053546c4 100644 --- a/locale/po/de.po +++ b/locale/po/de.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: \n" "Last-Translator: Martin Reininger \n" "Language-Team: German translation team\n" @@ -998,6 +998,10 @@ msgid "Catalog UUID" msgstr "Katalog UUID" +msgid "Copyright" +msgstr "Urheberrecht" + + msgid "Description" msgstr "Beschreibung" @@ -10520,10 +10524,6 @@ msgid "Data Depth" msgstr "Datentiefe" -msgid "Number" -msgstr "Nummer" - - msgid "Randomness" msgstr "Zufälligkeit" @@ -13085,30 +13085,6 @@ msgid "Mask Texture Overlay Alpha" msgstr "Maskentextur überlagert Alpha" -msgid "Curve Preset" -msgstr "Kurve Voreinstellung" - - -msgid "Smoother" -msgstr "Weicher" - - -msgid "Root" -msgstr "Wurzel" - - -msgid "Sharp" -msgstr "Scharf" - - -msgid "Sharper" -msgstr "Schärfer" - - -msgid "Inverse Square" -msgstr "Invers" - - msgid "Comb Curves" msgstr "Kombiniere Kurven" @@ -13721,14 +13697,6 @@ msgid "Velocity Attribute" msgstr "Geschwindigkeitsattribut" -msgid "Velocity Unit" -msgstr "Geschwindigkeitseinheit" - - -msgid "Second" -msgstr "Sekunde" - - msgid "Field of View" msgstr "An Ansicht ausrichten" @@ -15244,6 +15212,10 @@ msgid "Inverse Linear" msgstr "Invers" +msgid "Inverse Square" +msgstr "Invers" + + msgid "Inverse Coefficients" msgstr "Invertiere Koeffizienten" @@ -16891,6 +16863,10 @@ msgid "Strand shape parameter" msgstr "Strangformparameter" +msgid "Number" +msgstr "Nummer" + + msgid "Show particle size" msgstr "Dateien nach Größe sortieren" @@ -17529,10 +17505,6 @@ msgid "Modified" msgstr "Modifizieren" -msgid "Lines" -msgstr "Zeilen" - - msgid "Lines of text" msgstr "Textzeilen" @@ -17897,6 +17869,14 @@ msgid "Use soft marble" msgstr "Weichen Marmor verwenden" +msgid "Sharp" +msgstr "Scharf" + + +msgid "Sharper" +msgstr "Schärfer" + + msgid "Sin" msgstr "Sinus" @@ -21423,6 +21403,10 @@ msgid "Radius of the skin" msgstr "Radius der Haut" +msgid "Root" +msgstr "Wurzel" + + msgid "Mesh Skin Vertex Layer" msgstr "Maschenhaut Eckpunktebene" @@ -23587,6 +23571,10 @@ msgid "Line Thickness" msgstr "Linienstärke" +msgid "Lines" +msgstr "Zeilen" + + msgid "Use Bone Heads" msgstr "Knochenköpfe verwenden" @@ -30738,10 +30726,6 @@ msgid "Export cameras" msgstr "Kamera exportieren" -msgid "Copyright" -msgstr "Urheberrecht" - - msgid "Compression level" msgstr "Komprimierungsgrad" @@ -54969,10 +54953,6 @@ msgid "Invert Selection" msgstr "Auswahl umkehren" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Verfolgen" @@ -55179,14 +55159,6 @@ msgstr "" "%s nicht gestartet werden" -msgid "Remove Add-on: %r?" -msgstr "Add-on entfernen: %r?" - - -msgid "Path: %r" -msgstr "Pfad: %r" - - msgid "Reload Start-Up file to restore settings" msgstr "Startdatei erneut laden um die Einstellungen wiederherzustellen" @@ -55251,6 +55223,14 @@ msgid "Source file is in the add-on search path: %r" msgstr "Quelldatei ist in dem Add-On Suchpfad: %r" +msgid "Remove Add-on: %r?" +msgstr "Add-on entfernen: %r?" + + +msgid "Path: %r" +msgstr "Pfad: %r" + + msgid "Active face must be a quad" msgstr "Aktive Fläche muss ein Quadrat sein" @@ -55271,10 +55251,6 @@ msgid "See OperatorList.txt text block" msgstr "OperatorList.txt Textblock anschauen" -msgid "Rename %d %s" -msgstr "Umbenennen %d %s" - - msgid "Renamed %d of %d %s" msgstr "Umbenannt %d of %d %s" @@ -55292,18 +55268,6 @@ msgid "Open..." msgstr "Öffnen..." -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "Datum: %s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "Hash: %sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "Branch: %sutf-8replace" - - msgid "Blender is free software" msgstr "Blender ist eine kostenlose Software" @@ -55364,11 +55328,6 @@ msgid "Spacebar" msgstr "Leertaste" -msgctxt "Operator" -msgid "Load %d.%d SettingsOperator" -msgstr "Lade %d.%d Einstellungsoperator" - - msgctxt "Operator" msgid "Save New Settings" msgstr "Speichere neue Einstellungen" @@ -55468,6 +55427,10 @@ msgid "Strip From" msgstr "Entfernen von" +msgid "Rename %d %s" +msgstr "Umbenennen %d %s" + + msgid "Date: %s %s" msgstr "Datum: %s %s" @@ -55879,10 +55842,6 @@ msgid "Lock Invert All" msgstr "Alle Sperrungen invertieren" -msgid "%s ▶ %s" -msgstr "%s ▶ %s" - - msgctxt "Operator" msgid "Sort by Name" msgstr "Nach Namen sortieren" @@ -56388,10 +56347,6 @@ msgid "Coordinate System" msgstr "Koordinatensystem" -msgid "%d fluid particles for this frame" -msgstr "%d Flüssigkeits-Partikel für diesen Frame" - - msgctxt "Operator" msgid "Delete Edit" msgstr "Lösche Bearbeitung" @@ -56415,6 +56370,10 @@ msgid "Disconnect All" msgstr "Alles trennen" +msgid "%d fluid particles for this frame" +msgstr "%d Flüssigkeits-Partikel für diesen Frame" + + msgid "Speed Multiplier" msgstr "Geschwindigkeitsmultiplikator" @@ -56719,6 +56678,10 @@ msgid "Velocity Linear" msgstr "Lineare Geschwindigkeit" +msgid "Second" +msgstr "Sekunde" + + msgid "X Stiffness" msgstr "X Steifheit" @@ -57110,11 +57073,6 @@ msgid "Set Keyframe B" msgstr "Schlüsselbildtyp B festlegen" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Zoom %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "Ansicht einpassen" @@ -58259,14 +58217,6 @@ msgid "Clear Fade" msgstr "Ausblendung löschen" -msgid "%dx%d" -msgstr "%dx%d" - - -msgid "%.2f" -msgstr "%.2f" - - msgid "Custom Proxy" msgstr "Benutzerdefinierter Proxy" @@ -58372,10 +58322,6 @@ msgid "Move Line(s) Down" msgstr "Linie(n) nach unten bewegen" -msgid "Text: ExternalText: Internal" -msgstr "Text: ExternerText: Intern" - - msgid "File: *%s (unsaved)" msgstr "Datei: *%s (nicht gespeichert)" @@ -58907,14 +58853,6 @@ msgid "Save as Studio light" msgstr "Speichere als Studiolicht" -msgid "Color Set %d" -msgstr "Farbset %d" - - -msgid "Color %d" -msgstr "Farbe %d" - - msgid "Player" msgstr "Player" @@ -58943,6 +58881,14 @@ msgid ":" msgstr ":" +msgid "Color Set %d" +msgstr "Farbset %d" + + +msgid "Color %d" +msgstr "Farbe %d" + + msgid "Description:" msgstr "Beschreibung:" @@ -58959,10 +58905,6 @@ msgid "Author:" msgstr "Autor:" -msgid "author" -msgstr "Autor" - - msgid "Version:" msgstr "Version:" @@ -63746,10 +63688,6 @@ msgid "Undefined Socket Type" msgstr "Undefinierter Socket Typ" -msgid "Group Input " -msgstr "Gruppeneingabe " - - msgid " (String)" msgstr " (String)" @@ -64725,22 +64663,6 @@ msgid "Unable to create new strip" msgstr "Neuer Streifen kann nicht erzeugt werden" -msgid "Functions" -msgstr "Funktionen" - - -msgid "Comparison" -msgstr "Vergleich" - - -msgid "Trigonometric" -msgstr "Trigonometrie" - - -msgid "Conversion" -msgstr "Konvertierung" - - msgid "Same input/output direction of sockets" msgstr "Gleiche Eingangs-/Ausgangsrichtung von Sockeln" diff --git a/locale/po/es.po b/locale/po/es.po index 1729b1e75f7..b9e77f72d79 100644 --- a/locale/po/es.po +++ b/locale/po/es.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: \n" "Last-Translator: Gabriel Gazzán \n" "Language-Team: Español \n" @@ -11,7 +11,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 3.2" +"X-Generator: Poedit 3.2.2" msgid "Shader AOV" @@ -686,6 +686,14 @@ msgid "The entire Scene / Preview range" msgstr "El rango completo de la escena" +msgid "Manual Range" +msgstr "Rango manual" + + +msgid "Manually determined frame range" +msgstr "Rango de fotogramas determinado manualmente" + + msgid "Show Frame Numbers" msgstr "Mostrar números fotogramas" @@ -1074,6 +1082,10 @@ msgid "Simple name of the asset's catalog, for debugging and data recovery purpo msgstr "Nombre simple del catálogo de recursos, para propósitos de depuración y recuperación de datos" +msgid "Copyright" +msgstr "Derechos de autor" + + msgid "Description" msgstr "Descripción" @@ -1366,6 +1378,10 @@ msgid "Active Color Attribute" msgstr "Atributo de color activo" +msgid "The name of the active color attribute for display and editing" +msgstr "El nombre del atributo de color activo a ser mostrado y editado" + + msgid "Active Attribute Index" msgstr "Identificador atributo activo" @@ -1374,6 +1390,14 @@ msgid "Active attribute index" msgstr "Identificador del atributo activo" +msgid "Default Color Attribute" +msgstr "Atributo de color predefinido" + + +msgid "The name of the default color attribute used as a fallback for rendering" +msgstr "El nombre del atributo de color predefinido, usado como alternativa durante el procesamiento" + + msgid "Active Render Color Index" msgstr "Identificador color activo en procesamiento" @@ -4625,13 +4649,17 @@ msgstr "Mostrar imagen de fondo" msgid "Show this image as background" -msgstr "Mostrar esta imagen como fondo" +msgstr "Muestra esta imagen como fondo" msgid "Show Expanded" msgstr "Mostrar expandido" +msgid "Show the details in the user interface" +msgstr "Muestra detalles en la interfaz de usuario" + + msgid "Show On Foreground" msgstr "Mostrar en Primer Plano" @@ -5596,6 +5624,10 @@ msgid "Enabled" msgstr "Habilitado" +msgid "Enable this object as a collider for physics systems" +msgstr "Habilitar este objeto como colisionador para los sistemas de dinámicas" + + msgid "Single Sided" msgstr "Un solo lado" @@ -5692,6 +5724,10 @@ msgid "Non-Color" msgstr "No es color" +msgid "Color space used for images which contain non-color data (e.g. normal maps)" +msgstr "Espacio de color usado para imágenes que contienen datos, en vez de colores (p.ej: mapas de normales)" + + msgid "Raw" msgstr "Crudo" @@ -8701,6 +8737,10 @@ msgid "Index" msgstr "Identificador" +msgid "Index of this point" +msgstr "Identificador de este punto" + + msgid "Profile Path editor used to build a profile path" msgstr "Editor de curva de perfil usado para construir una curva de perfil" @@ -12925,10 +12965,22 @@ msgid "Filter Asset Types" msgstr "Filtrar por tipo" +msgid "Import Method" +msgstr "Método de importación" + + msgid "Determine how the asset will be imported" msgstr "Determina cómo será importado el recurso" +msgid "Follow Preferences" +msgstr "Conforme a las preferencias" + + +msgid "Use the import method set in the Preferences for this asset library, don't override it for this Asset Browser" +msgstr "Usar para esta biblioteca de recursos el método de importación definido en las Preferencias, sin redefinirlo en este Explorador de recursos" + + msgid "Link" msgstr "Vincular" @@ -12989,6 +13041,10 @@ msgid "3D vector" msgstr "Vector 3D" +msgid "Read-Only Vector" +msgstr "Vector de sólo lectura" + + msgid "Domain Settings" msgstr "Opciones dominio" @@ -13613,10 +13669,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "Cantidad mínima de partículas por celda (asegura que cada celda contenga al menos esta cantidad de partículas)" -msgid "Number" -msgstr "Cantidad" - - msgid "Particle number factor (higher value results in more particles)" msgstr "Factor de cantidad de partículas (un valor más alto producirá más partículas)" @@ -15693,10 +15745,22 @@ msgid "Auto-Masking Layer" msgstr "Autoenmascarar (capa)" +msgid "Affect only the Active Layer" +msgstr "Afecta sólo a la capa activa" + + +msgid "Affect only strokes below the cursor" +msgstr "Afecta sólo a los trazos bajo el puntero" + + msgid "Auto-Masking Material" msgstr "Autoenmascarar (material)" +msgid "Affect only the Active Material" +msgstr "Afecta sólo al material activo" + + msgid "Auto-Masking Strokes" msgstr "Autoenmascarar (puntero)" @@ -15845,6 +15909,14 @@ msgid "Stroke start extreme cap style" msgstr "Estilo de extremo al final del trazo" +msgid "Init Time" +msgstr "Tiempo inicial" + + +msgid "Initial time of the stroke" +msgstr "Tiempo inicial del trazo" + + msgid "Triangles" msgstr "Triángulos" @@ -15909,6 +15981,10 @@ msgid "Color intensity (alpha factor)" msgstr "Intensidad del color (factor de alfa)" +msgid "Time relative to stroke start" +msgstr "Tiempo relativo al inicio del trazo" + + msgid "UV Fill" msgstr "UV relleno" @@ -16311,6 +16387,10 @@ msgid "Texture Mapping" msgstr "Mapeo de textura" +msgid "Change stroke UV texture values" +msgstr "Cambia los valores de la textura UV del trazo" + + msgid "Time Offset" msgstr "Desplazar tiempo" @@ -16551,6 +16631,10 @@ msgid "Material used for filtering effect" msgstr "Material usado para filtrar el efecto" +msgid "Offset Object" +msgstr "Objeto de desplazamiento" + + msgid "Use the location and rotation of another object to determine the distance and rotational change between arrayed items" msgstr "Utiliza la posición y rotación de otro objeto para determinar la distancia y cambio rotacional entre los elementos de la serie" @@ -16599,6 +16683,10 @@ msgid "Enable offset" msgstr "Habilita el desplazamiento" +msgid "Use Object Offset" +msgstr "Desplazamiento usando objeto" + + msgid "Enable object offset" msgstr "Habilita el desplazamiento usando un objeto" @@ -16631,6 +16719,10 @@ msgid "Time Alignment" msgstr "Alineación de tiempo" +msgid "How should strokes start to appear/disappear" +msgstr "Cómo deberían comenzar a aparecer o desaparecer los trazos" + + msgid "Align Start" msgstr "Alinear inicio" @@ -16683,12 +16775,16 @@ msgid "Maximum number of frames that the build effect can run for (unless anothe msgstr "Cantidad máxima de fotogramas durante la cual se producirá el efecto de construcción (a menos que ocurra otro fotograma clave de lápiz de cera antes de que ese tiempo haya transcurrido)" +msgid "How strokes are being built" +msgstr "Cómo se construirán los trazos" + + msgid "Sequential" msgstr "Secuencial" msgid "Strokes appear/disappear one after the other, but only a single one changes at a time" -msgstr "Los trazos aparecerán/desaparecerán uno a continuación del otro, y sólo uno estará cambiando en un instante dado" +msgstr "Los trazos aparecerán o desaparecerán uno a continuación de otro, y sólo uno estará cambiando en un instante dado" msgid "Concurrent" @@ -16696,7 +16792,7 @@ msgstr "Concurrente" msgid "Multiple strokes appear/disappear at once" -msgstr "Múltiples trazos estarán apareciendo/desapareciendo al mismo tiempo" +msgstr "Múltiples trazos aparecerán o desaparecerán al mismo tiempo" msgid "Builds only new strokes (assuming 'additive' drawing)" @@ -16715,6 +16811,18 @@ msgid "Speed Factor" msgstr "Velocidad" +msgid "Multiply recorded drawing speed by a factor" +msgstr "Multiplica la velocidad grabada de dibujo por un cierto número" + + +msgid "Maximum Gap" +msgstr "Pausa máxima" + + +msgid "The maximum gap between strokes in seconds" +msgstr "La pausa máxima entre un trazo y el siguiente, expresada en segundos" + + msgid "Delay" msgstr "Retardo" @@ -16731,6 +16839,34 @@ msgid "Timing" msgstr "Temporización" +msgid "Use drawing speed, a number of frames, or a manual factor to build strokes" +msgstr "Permite usar una velocidad de dibujo, una cantidad de fotogramas o un factor arbitrario para construir los trazos" + + +msgid "Natural Drawing Speed" +msgstr "Velocidad natural de dibujo" + + +msgid "Use recorded speed multiplied by a factor" +msgstr "Usa la velocidad registrada de dibujo, multiplicada por un valor" + + +msgid "Number of Frames" +msgstr "Cantidad de fotogramas" + + +msgid "Set a fixed number of frames for all build animations" +msgstr "Permite definir una cantidad determinada de fotogramas para el total de las animaciones de construcción" + + +msgid "Percentage Factor" +msgstr "Porcentaje" + + +msgid "Set a manual percentage to build" +msgstr "Permite definir manualmente el porcentaje de construcción visible" + + msgid "Transition" msgstr "Transición" @@ -17253,6 +17389,10 @@ msgid "Shadow Camera Size" msgstr "Cámara sombras Tamaño" +msgid "Represents the \"Orthographic Scale\" of an orthographic camera. If the camera is positioned at the light's location with this scale, it will represent the coverage of the shadow \"camera\"" +msgstr "Este valor representa la \"escala ortográfica\" de una cámara ortogonal. Si la cámara es colocada en la posición de una luz con esta escala, representará la cobertura de la \"cámara\" de sombras" + + msgid "Shadow Region Filtering" msgstr "Filtrado de región de sombras" @@ -17621,6 +17761,10 @@ msgid "Instanced Objects" msgstr "Objetos instanciados" +msgid "Allow particle objects and face/vertex instances to show in line art" +msgstr "Mostrar arte lineal a partir de objetos de partículas e instancias en vértices o caras" + + msgid "Offset Towards Custom Camera" msgstr "Desplazar hacia cámara personalizada" @@ -17757,6 +17901,10 @@ msgid "Amount of noise to apply to thickness" msgstr "Cantidad de ruido a aplicar al grosor" +msgid "Amount of noise to apply to UV rotation" +msgstr "Cantidad de ruido a aplicar a la rotación UV" + + msgid "Noise Offset" msgstr "Desplazar ruido" @@ -17805,10 +17953,34 @@ msgid "Offset Stroke modifier" msgstr "Modificador para desplazar trazos" +msgid "Randomize stroke offset" +msgstr "Aleatorizar desplazamiento del trazo" + + +msgid "Offset layers by the same factor" +msgstr "Desplaza las capas en la misma magnitud" + + +msgid "Offset strokes by the same factor based on stroke draw order" +msgstr "Desplaza los trazos en la misma magnitud, basándose en el orden de dibujo de los mismos" + + +msgid "Offset materials by the same factor" +msgstr "Desplaza los materiales en la misma magnitud" + + msgid "Start Offset" msgstr "Inicio desplazamiento" +msgid "Offset starting point" +msgstr "Punto de inicio del desplazamiento" + + +msgid "Number of elements that will be grouped" +msgstr "Cantidad de elementos que serán agrupados" + + msgid "Opacity Modifier" msgstr "Modificador Opacidad" @@ -19330,30 +19502,6 @@ msgid "Editable falloff curve" msgstr "Curva de decaimiento editable" -msgid "Curve Preset" -msgstr "Ajuste de curva" - - -msgid "Smoother" -msgstr "Más suave" - - -msgid "Root" -msgstr "Raíz" - - -msgid "Sharp" -msgstr "Definido" - - -msgid "Sharper" -msgstr "Muy definido" - - -msgid "Inverse Square" -msgstr "Inverso al cuadrado" - - msgid "Curves Sculpt Settings" msgstr "Opciones de esculpido de curvas" @@ -20794,18 +20942,10 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "Nombre del atributo de Alembic usado para generar datos de desenfoque por movimiento" -msgid "Velocity Unit" -msgstr "Unidades de velocidad" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "Permite definir cómo serán interpretados los vectores de velocidad con respecto al tiempo, 'fotograma' significa que el delta de tiempo será de 1 fotograma, 'segundo' significa que el delta de tiempo será de 1/FPS" -msgid "Second" -msgstr "Segundo" - - msgid "Camera data-block for storing camera settings" msgstr "Bloque de datos de cámara para almacenar las opciones de la cámara" @@ -21446,6 +21586,10 @@ msgid "Distance to move the curve parallel to its normals" msgstr "Distancia a mover la curva en forma paralela a sus normales" +msgid "Path Duration" +msgstr "Duración trayectoria" + + msgid "The number of frames that are needed to traverse the path, defining the maximum value for the 'Evaluation Time' setting" msgstr "La cantidad de fotogramas que se necesitan para recorrer la trayectoria, definiendo el valor máximo para la propiedad 'Tiempo de evaluación'" @@ -21634,6 +21778,14 @@ msgid "Active Text Box" msgstr "Marco de texto activo" +msgid "Horizontal Alignment" +msgstr "Alinear horizontalmente" + + +msgid "Text horizontal alignment from the object center" +msgstr "Alinear el texto horizontalmente con respecto al centro del objeto" + + msgid "Align text to the left" msgstr "Alinear el texto a la izquierda" @@ -21662,6 +21814,14 @@ msgid "Align to the left and the right, with equal character spacing" msgstr "Alinear a izquierda y derecha, con espaciado equidistante entre caracteres" +msgid "Vertical Alignment" +msgstr "Alinear verticalmente" + + +msgid "Text vertical alignment from the object center" +msgstr "Alinear el texto verticalmente con respecto al centro del objeto" + + msgid "Align text to the top" msgstr "Alinear el texto hacia arriba" @@ -21670,6 +21830,10 @@ msgid "Top Baseline" msgstr "Superior (base)" +msgid "Align text to the top line's baseline" +msgstr "Alinear el texto hacia la línea base superior" + + msgid "Middle" msgstr "Centro" @@ -21682,6 +21846,10 @@ msgid "Bottom Baseline" msgstr "Inferior (base)" +msgid "Align text to the bottom line's baseline" +msgstr "Alinear el texto hacia la línea base inferior" + + msgid "Align text to the bottom" msgstr "Alinear el texto hacia abajo" @@ -21874,6 +22042,10 @@ msgid "Normals" msgstr "Normales" +msgid "The curve normal value at each of the curve's control points" +msgstr "El valor de la normal a la curva en cada uno de los puntos de control de la misma" + + msgid "Control points of all curves" msgstr "Puntos de control de todas las curvas" @@ -21906,6 +22078,14 @@ msgid "Enable symmetry in the Z axis" msgstr "Habilita la simetría en el eje Z" +msgid "Use Sculpt Collision" +msgstr "Usar colisiones al esculpir" + + +msgid "Enable collision with the surface while sculpting" +msgstr "Habilita el cálculo de colisiones con la superficie mientras se esculpe" + + msgid "Freestyle Line Style" msgstr "Freestyle - Estilo de línea" @@ -23114,6 +23294,10 @@ msgid "X/Y pixels per meter, for the image buffer" msgstr "Píxeles X/Y por metro, para el buffer de imagen" +msgid "Seam Margin" +msgstr "Margen de costura" + + msgid "Width and height of the image buffer in pixels, zero when image data can't be loaded" msgstr "Ancho y altura en píxeles del buffer de imagen, cero cuando los datos de la imagen no puedan ser cargados" @@ -23541,6 +23725,10 @@ msgid "Inverse Linear" msgstr "Inverso lineal" +msgid "Inverse Square" +msgstr "Inverso al cuadrado" + + msgid "Inverse Coefficients" msgstr "Coeficientes inversos" @@ -26697,6 +26885,10 @@ msgid "Display boid health" msgstr "Mostrar salud del boid" +msgid "Number" +msgstr "Cantidad" + + msgid "Show particle number" msgstr "Mostrar número de partículas" @@ -27090,6 +27282,22 @@ msgid "Linear distance model with clamping" msgstr "Modelo lineal de distancia con límites" +msgid "Exponential" +msgstr "Exponencial" + + +msgid "Exponential distance model" +msgstr "Modelo exponencial de distancia" + + +msgid "Exponential Clamped" +msgstr "Exponencial limitado" + + +msgid "Exponential distance model with clamping" +msgstr "Modelo exponencial de distancia con límites" + + msgid "Doppler Factor" msgstr "Factor Doppler" @@ -27756,10 +27964,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "El archivo de texto en el disco es diferente al que está en memoria" -msgid "Lines" -msgstr "Líneas" - - msgid "Lines of text" msgstr "Líneas de texto" @@ -28430,10 +28634,18 @@ msgid "Use soft marble" msgstr "Usar mármol suave" +msgid "Sharp" +msgstr "Definido" + + msgid "Use more clearly defined marble" msgstr "Usar un mármol más definido" +msgid "Sharper" +msgstr "Muy definido" + + msgid "Use very clearly defined marble" msgstr "Usar un mármol muy definido" @@ -31153,6 +31365,21 @@ msgid "Ndof-" msgstr "Ndof-" +msgctxt "UI_Events_KeyMaps" +msgid "NDOF View 1" +msgstr "NDOF vista 1" + + +msgctxt "UI_Events_KeyMaps" +msgid "NDOF View 2" +msgstr "NDOF vista 2" + + +msgctxt "UI_Events_KeyMaps" +msgid "NDOF View 3" +msgstr "NDOF vista 3" + + msgctxt "UI_Events_KeyMaps" msgid "NDOF Button 1" msgstr "NDOF botón 1" @@ -32047,12 +32274,16 @@ msgid "Layer collection" msgstr "Colección de capas" +msgid "Layer collection children" +msgstr "Subordinada de colección de capas" + + msgid "Collection this layer collection is wrapping" -msgstr "Colección a la que esta colección de capas envuelve" +msgstr "Colección envuelta por esta colección de capas" msgid "Exclude from View Layer" -msgstr "Excluir de la capa de visualización" +msgstr "Excluir de capa de visualización" msgid "Exclude from view layer" @@ -32083,6 +32314,10 @@ msgid "Whether this collection is visible for the view layer, take into account msgstr "Permite definir si esta colección es visible en la capa de visualización, tomando en cuenta al superior de la colección" +msgid "Name of this layer collection (same as its collection one)" +msgstr "Nombre de esta colección de capas (el mismo que el de su colección)" + + msgid "Layer Objects" msgstr "Objetos de la capa" @@ -33460,6 +33695,10 @@ msgid "Asset" msgstr "Recurso" +msgid "Catalog" +msgstr "Catálogo" + + msgid "Assets Context Menu" msgstr "Recursos - menú contextual" @@ -34225,6 +34464,14 @@ msgid "Loose" msgstr "Suelto" +msgid "Edge is not connected to any faces" +msgstr "El borde no se encuentra conectado a ninguna cara" + + +msgid "Sharp edge for shading" +msgstr "Borde definido en el sombreado" + + msgid "Freestyle Edge Mark" msgstr "Borde marcado de Freestyle" @@ -34609,6 +34856,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "Si el vértice tiene varios bordes adyacentes, se envolverá a ellos directamente" +msgid "Root" +msgstr "Raíz" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "El vértice es la base para los cálculos de rotación y la generación del esqueleto, establecer este indicador no elimina a otras bases en la misma isla de la malla" @@ -39257,6 +39508,10 @@ msgid "Line thickness for motion path" msgstr "Grosor de línea al dibujar la trayectoria" +msgid "Lines" +msgstr "Líneas" + + msgid "Use straight lines between keyframe points" msgstr "Dibujar líneas rectas entre los puntos de los fotogramas clave" @@ -53416,10 +53671,6 @@ msgid "Export vertex colors with meshes" msgstr "Exporta colores de los vértices junto con las mallas" -msgid "Copyright" -msgstr "Derechos de autor" - - msgid "Legal rights and conditions for the model" msgstr "Derechos y condiciones legales para el modelo" @@ -70438,10 +70689,6 @@ msgid "Fill Range by Selection" msgstr "Completar rango usando selección" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Completa los valores Rango mín./máx. usando la distancia mín./máx. entre los objetos seleccionados y el objetivo " - - msgid "Name of the modifier to work on" msgstr "Nombre del modificador sobre el cual actuar" @@ -77825,7 +78072,7 @@ msgstr "Incluir animaciones" msgid "Export animations if available (exporting animations will enforce the decomposition of node transforms into and components)" -msgstr "Exportar animaciones, si las hubiera (exportar animaciones forzará la separación de los nodos de transformación en sus componentes and )" +msgstr "Exportar animaciones, si las hubiera (al exportar animaciones, se forzará la separación de las transformaciones de los nodos en componentes de y )" msgid "Include Armatures" @@ -88799,10 +89046,6 @@ msgid "Additional subdivision along the curves" msgstr "Subdivisión adicional a lo largo de las curvas" -msgid "Curves Shape Type" -msgstr "Tipo de forma de las curvas" - - msgid "Curves shape type" msgstr "Tipo de forma de las curvas" @@ -103783,10 +104026,6 @@ msgid "No compatible GPUs found for Cycles" msgstr "No se encontraron GPU compatibles para Cycles" -msgid "(TM)TRADE MARK SIGN(tm)TRADE MARK SIGN(R)REGISTERED SIGN(C)COPYRIGHT SIGN" -msgstr "(TM)SÍMBOLO DE MARCA REGISTRADA(R)SÍMBOLO DE REGISTRADO(C)SÍMBOLO DE DERECHOS RESERVADOS" - - msgid "Requires Intel GPU with Xe-HPG architecture" msgstr "Requiere una GPU de Intel con arquitectura Xe-HPG" @@ -104576,10 +104815,6 @@ msgid "Invert Selection" msgstr "Invertir selección" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Rastreo" @@ -104663,15 +104898,15 @@ msgid "Restore" msgstr "Restablecer" -msgid "%s (Global)" -msgstr "%s (Global)" - - msgctxt "WindowManager" msgid "Add New" msgstr "Agregar nuevo" +msgid "%s (Global)" +msgstr "%s (Global)" + + msgctxt "Operator" msgid "New" msgstr "Nueva" @@ -104986,14 +105221,6 @@ msgid "Current frame not within strip framerange" msgstr "El fotograma actual no se encuentra dentro del rango de fotogramas del clip" -msgid "Remove Add-on: %r?" -msgstr "¿Eliminar complemento: %r?" - - -msgid "Path: %r" -msgstr "Ruta: %r" - - msgid "Reload Start-Up file to restore settings" msgstr "Recargar el archivo de inicio para restablecer las opciones" @@ -105058,6 +105285,14 @@ msgid "Source file is in the add-on search path: %r" msgstr "El archivo fuente se encuentra en la ruta de búsqueda de complementos: %r" +msgid "Remove Add-on: %r?" +msgstr "¿Eliminar complemento: %r?" + + +msgid "Path: %r" +msgstr "Ruta: %r" + + msgid "Active face must be a quad" msgstr "La cara activa debe ser un cuadrilátero" @@ -105078,10 +105313,6 @@ msgid "See OperatorList.txt text block" msgstr "Ver bloque de texto OperatorList.txt" -msgid "Rename %d %s" -msgstr "Renombrar %d %s" - - msgid "Renamed %d of %d %s" msgstr "Se renombró %d de %d %s" @@ -105099,18 +105330,6 @@ msgid "Open..." msgstr "Abrir..." -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "Fecha: %s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "Identificador: %sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "Rama: %sutf-8replace" - - msgid "Blender is free software" msgstr "Blender es software libre" @@ -105175,11 +105394,6 @@ msgid "Spacebar" msgstr "Barra espaciadora" -msgctxt "Operator" -msgid "Load %d.%d SettingsOperator" -msgstr "Cargar opciones %d.%d" - - msgctxt "Operator" msgid "Save New Settings" msgstr "Guardar nuevas opciones" @@ -105204,10 +105418,6 @@ msgid "Development Fund" msgstr "Fondo de desarrollo" -msgid "Windowing Environment: %s" -msgstr "Entorno de ventanas: %s" - - msgctxt "Operator" msgid "Credits" msgstr "Créditos" @@ -105391,6 +105601,10 @@ msgid "Strip From" msgstr "Recortar desde" +msgid "Rename %d %s" +msgstr "Renombrar %d %s" + + msgid "Date: %s %s" msgstr "Fecha: %s %s" @@ -105424,6 +105638,10 @@ msgid "Load %d.%d Settings" msgstr "Cargar opciones %d.%d" +msgid "Windowing Environment: %s" +msgstr "Entorno de ventanas: %s" + + msgid "Type \"%s\" can not be found" msgstr "El tipo \"%s\" no puede ser encontrado" @@ -105934,10 +106152,6 @@ msgid "Apply All Shape Keys" msgstr "Aplicar todas las Formas claves" -msgid "%s ▶ %s" -msgstr "%s ▶ %s" - - msgid "Name collisions: , " msgstr "Colisiones de nombres: , " @@ -106606,22 +106820,10 @@ msgid "Hair dynamics disabled" msgstr "Dinámicas de pelo deshabilitadas" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Iteraciones: %d .. %d (prom. %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Error: %.5f .. %.5f (prom. %.5f)" - - msgid "Multiply Mass with Size" msgstr "Multiplicar masa por tamaño" -msgid "Spacing: %g" -msgstr "Espaciado: %g" - - msgid "Show Emitter" msgstr "Mostrar emisor" @@ -106666,10 +106868,6 @@ msgid "Coordinate System" msgstr "Sistema de coordenadas" -msgid "%d fluid particles for this frame" -msgstr "%d partículas de fluido en este fotograma" - - msgctxt "Operator" msgid "Delete Edit" msgstr "Borrar edición" @@ -106683,6 +106881,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "El porcentaje de visualización hace que las dinámicas sean imprecisas cuando no están capturadas" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Iteraciones: %d .. %d (prom. %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Error: %.5f .. %.5f (prom. %.5f)" + + +msgid "Spacing: %g" +msgstr "Espaciado: %g" + + msgid "Not yet functional" msgstr "No funcional aún" @@ -106697,6 +106907,10 @@ msgid "Disconnect All" msgstr "Desconectar todas" +msgid "%d fluid particles for this frame" +msgstr "%d partículas de fluido en este fotograma" + + msgid "Speed Multiplier" msgstr "Multiplicador de velocidad" @@ -107157,6 +107371,10 @@ msgid "This object is part of a compound shape" msgstr "Este objeto es parte de una forma compuesta" +msgid "Second" +msgstr "Segundo" + + msgid "X Stiffness" msgstr "X Resistencia" @@ -107365,11 +107583,6 @@ msgid "Unknown add-ons" msgstr "Complementos desconocidos" -msgctxt "Operator" -msgid "%s: %s" -msgstr "%s: %s" - - msgid "category" msgstr "categoría" @@ -107645,11 +107858,6 @@ msgid "Tracks for Rotation/Scale" msgstr "Rastros de rotación / escala" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Zoom %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "Ajustar vista" @@ -107670,14 +107878,14 @@ msgid "Frame All Fit" msgstr "Enmarcar todo (ajustado)" -msgid "Solve error: %.2f px" -msgstr "Error de resolución: %.2f px" - - msgid "Zoom %d:%d" msgstr "Zoom %d:%d" +msgid "Solve error: %.2f px" +msgstr "Error de resolución: %.2f px" + + msgctxt "Operator" msgid "Copy as Script" msgstr "Copiar como script" @@ -108994,10 +109202,6 @@ msgid "Default Fade" msgstr "Fundido predefinido" -msgid "Original frame range: %d-%d (%d)" -msgstr "Rango de fot. original: %d-%d (%d)" - - msgid "Strip Offset Start" msgstr "Desplazamiento clip Inicio" @@ -109061,14 +109265,6 @@ msgid "Effect Fader" msgstr "Efecto desvanecimiento" -msgid "%dx%d" -msgstr "%dx%d" - - -msgid "%.2f" -msgstr "%.2f" - - msgid "Original Frame Range" msgstr "Velocidad de fotogramas original" @@ -109093,8 +109289,8 @@ msgid "Pack" msgstr "Empacar" -msgid "%d Hz" -msgstr "%d Hz" +msgid "Original frame range: %d-%d (%d)" +msgstr "Rango de fot. original: %d-%d (%d)" msgid "Source Channel" @@ -109211,10 +109407,6 @@ msgid "Move Line(s) Down" msgstr "Mover líneas abajo" -msgid "Text: ExternalText: Internal" -msgstr "Texto: ExternoTexto: Interno" - - msgid "File: *%s (unsaved)" msgstr "Archivo: *%s (no guardado)" @@ -109539,11 +109731,6 @@ msgid "Load Factory Blender Settings" msgstr "Cargar opciones de fábrica" -msgctxt "Operator" -msgid "Load Factory %s Settings" -msgstr "Cargar opciones de fábrica %s" - - msgctxt "Operator" msgid "Collada (.dae)" msgstr "Collada (.dae)" @@ -109644,6 +109831,11 @@ msgid "NLA Strip Name" msgstr "Nombre de clip ANL" +msgctxt "Operator" +msgid "Load Factory %s Settings" +msgstr "Cargar opciones de fábrica %s" + + msgid "Auto-Save Preferences" msgstr "Auto-guardar preferencias" @@ -109937,19 +110129,6 @@ msgid "Load Factory Blender Preferences" msgstr "Cargar preferencias de fábrica" -msgctxt "Operator" -msgid "Load Factory %s Preferences" -msgstr "Cargar preferencias de fábrica %s" - - -msgid "Color Set %d" -msgstr "Conjunto de colores %d" - - -msgid "Color %d" -msgstr "Color %d" - - msgid "Player" msgstr "Reproductor" @@ -109990,6 +110169,14 @@ msgid "Load Factory %s Preferences" msgstr "Cargar preferencias de fábrica %s" +msgid "Color Set %d" +msgstr "Conjunto de colores %d" + + +msgid "Color %d" +msgstr "Color %d" + + msgid "Description:" msgstr "Descripción:" @@ -110006,10 +110193,6 @@ msgid "Author:" msgstr "Autor:" -msgid "author" -msgstr "autor" - - msgid "Version:" msgstr "Versión:" @@ -111165,10 +111348,6 @@ msgid "Snap To" msgstr "Adherir a" -msgid "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" -msgstr "PINTAR_LCERAEDITAR_LCERAESCULPIR_LCERAINFLUENCIA_LCERAVÉRTICE_LCERAOBJETODibujar Lápiz de ceraEditar Lápiz de ceraEsculpir Lápiz de ceraInfluencia Lápiz de ceraVértice Lápiz de ceraLápiz de cera" - - msgid "Fade Inactive Layers" msgstr "Desvanecer capas inactivas" @@ -118957,10 +119136,6 @@ msgid "Undefined Socket Type" msgstr "Tipo de conector no definido" -msgid "Group Input " -msgstr "Entrada del grupo " - - msgid "Could not determine type of group node" msgstr "No se pudo determinar el tipo del nodo de grupo" @@ -121756,22 +121931,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "Clip de ANL '%s' no encontrado en la pista '%s'" -msgid "Functions" -msgstr "Funciones" - - -msgid "Comparison" -msgstr "Comparación" - - -msgid "Trigonometric" -msgstr "Trigonométrica" - - -msgid "Conversion" -msgstr "Conversión" - - msgid "CustomGroup" msgstr "Grupo_personalizado" diff --git a/locale/po/eu.po b/locale/po/eu.po index cee707660d6..4cd37cd95df 100644 --- a/locale/po/eu.po +++ b/locale/po/eu.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Ainhize & Miriam \n" "Language-Team: Euskara \n" diff --git a/locale/po/fa.po b/locale/po/fa.po index bd94668d12f..8181d8021ea 100644 --- a/locale/po/fa.po +++ b/locale/po/fa.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2012-10-31 17:00-0800\n" "Last-Translator: Amin Babaeipanah \n" "Language-Team: LeoMoon Studios \n" @@ -3821,10 +3821,6 @@ msgid "Author:" msgstr "ﻩﺪﻨﺴﯾﻮﻧ:" -msgid "author" -msgstr "ﻩﺪﻨﺴﯾﻮﻧ" - - msgid "Version:" msgstr "ﻪﺨﺴﻧ:" diff --git a/locale/po/fi.po b/locale/po/fi.po index 6780a0a0f9d..639dc18cd4f 100644 --- a/locale/po/fi.po +++ b/locale/po/fi.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: \n" "Last-Translator: \n" "Language-Team: \n" @@ -10217,10 +10217,6 @@ msgid "No packed file" msgstr "Ei pakattua tiedostoa" -msgid "Group Input " -msgstr "Ryhmäsyöte " - - msgid " (String)" msgstr "(Merkkijono)" @@ -10628,22 +10624,6 @@ msgid "Key" msgstr "Avain" -msgid "Functions" -msgstr "Funktiot" - - -msgid "Comparison" -msgstr "Vertailu" - - -msgid "Trigonometric" -msgstr "Trigonometrinen" - - -msgid "Conversion" -msgstr "Konversio" - - msgid "CustomGroup" msgstr "Mukautettu ryhmä" diff --git a/locale/po/fr.po b/locale/po/fr.po index 01c65abc5d8..31281e4bab7 100644 --- a/locale/po/fr.po +++ b/locale/po/fr.po @@ -1,10 +1,10 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" -"PO-Revision-Date: 2023-02-27 17:30+0100\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" +"PO-Revision-Date: 2023-03-12 17:34+0100\n" "Last-Translator: Damien Picard (pioverfour) \n" "Language-Team: French https://wiki.blender.org/wiki/Process/Translate_Blender/French_Team\n" "Language: fr\n" @@ -719,7 +719,7 @@ msgstr "Intervalle de frames choisi manuellement" msgid "Show Frame Numbers" -msgstr "Afficher numéros de frames" +msgstr "Afficher les numéros de frames" msgid "Show frame numbers on Motion Paths" @@ -743,11 +743,11 @@ msgstr "Accentuer la position des images clés sur les chemins de mouvement" msgid "Show Keyframe Numbers" -msgstr "Afficher numéros d’images clés" +msgstr "Afficher les numéros d’images clés" msgid "Show frame numbers of Keyframes on Motion Paths" -msgstr "Afficher numéros de frames des images clés sur les chemins de mouvement" +msgstr "Afficher les numéros de frames des images clés sur les chemins de mouvement" msgid "Paths Type" @@ -803,7 +803,7 @@ msgstr "Régions en lesquelles cette zone est subdivisée" msgid "Show Menus" -msgstr "Afficher menus" +msgstr "Afficher les menus" msgid "Show menus in the header" @@ -1106,6 +1106,10 @@ msgid "Simple name of the asset's catalog, for debugging and data recovery purpo msgstr "Nom simple du catalogue d’assets, utile pour le débogage et la récupération de données" +msgid "Copyright" +msgstr "Copyright" + + msgid "Description" msgstr "Description" @@ -3273,7 +3277,7 @@ msgstr "Hériter un redimensionnement uniforme représentant le changement globa msgid "Completely ignore parent scaling" -msgstr "Totalement ignorer le redimensionnement du parent" +msgstr "Ignorer totalement le redimensionnement du parent" msgid "None (Legacy)" @@ -3333,7 +3337,7 @@ msgstr "Sélectionner queue" msgid "Display Wire" -msgstr "Afficher fil-de-fer" +msgstr "Afficher le fil-de-fer" msgid "Bone is always displayed in wireframe regardless of viewport shading mode (useful for non-obstructive custom bone shapes)" @@ -3409,7 +3413,7 @@ msgstr "Hériter rotation" msgid "Bone inherits rotation or scale from parent bone" -msgstr "L’os hérite rotation ou taille de son os parent" +msgstr "L’os hérite de la rotation ou de l’échelle de l’os parent" msgid "DEPRECATED: Bone inherits scaling from parent bone" @@ -3869,7 +3873,7 @@ msgstr "Effacer les traits, en atténuant les force et épaisseur de leurs point msgid "Erase stroke points" -msgstr "Effacer points de trait" +msgstr "Effacer les points des traits" msgid "Stroke" @@ -3877,11 +3881,11 @@ msgstr "Trait" msgid "Erase entire strokes" -msgstr "Effacer traits complets" +msgstr "Effacer les traits complets" msgid "Affect Stroke Strength" -msgstr "Affecte force du trait" +msgstr "Affecter la force du trait" msgid "Amount of erasing for strength" @@ -3889,7 +3893,7 @@ msgstr "Quantité d’effacement pour la force" msgid "Affect Stroke Thickness" -msgstr "Affecte épaisseur du trait" +msgstr "Affecter l’épaisseur du trait" msgid "Amount of erasing for thickness" @@ -4137,7 +4141,7 @@ msgstr "Dessiner" msgid "Blur" -msgstr "Flouter" +msgstr "Flou" msgid "Smear" @@ -4250,7 +4254,7 @@ msgstr "Facteur aléatoire de modification de la valeur originale" msgid "Show Fill" -msgstr "Afficher remplissage" +msgstr "Afficher le remplissage" msgid "Show transparent lines to use as boundary for filling" @@ -4673,7 +4677,7 @@ msgstr "Redimensionner l’image d’arrière-plan" msgid "Show Background Image" -msgstr "Afficher image d’arrière-plan" +msgstr "Afficher l’image d’arrière-plan" msgid "Show this image as background" @@ -5652,6 +5656,10 @@ msgid "Enabled" msgstr "Activé" +msgid "Enable this object as a collider for physics systems" +msgstr "Activer cet objet comme collisionneur dans les systèmes physiques" + + msgid "Single Sided" msgstr "Un seul côté" @@ -5685,7 +5693,7 @@ msgstr "Périphérique d’affichage" msgid "Display device name" -msgstr "Afficher nom du périphérique" +msgstr "Afficher le nom du périphérique" msgid "Input color space settings" @@ -6254,7 +6262,7 @@ msgstr "Solveur d’objet" msgid "Copy Location" -msgstr "Copier position" +msgstr "Copier la position" msgid "Copy the location of a target (with an optional offset), so that they move together" @@ -6262,7 +6270,7 @@ msgstr "Copier la position d’une cible (avec un décalage optionnel), de faço msgid "Copy Rotation" -msgstr "Copier rotation" +msgstr "Copier la rotation" msgid "Copy the rotation of a target (with an optional offset), so that they rotate together" @@ -6270,7 +6278,7 @@ msgstr "Copier la rotation d’une cible (avec un décalage optionnel), de faço msgid "Copy Scale" -msgstr "Copier échelle" +msgstr "Copier l’échelle" msgid "Copy the scale factors of a target (with an optional offset), so that they are scaled by the same amount" @@ -6278,7 +6286,7 @@ msgstr "Copier les facteurs d’échelle d’une cible (avec un décalage option msgid "Copy Transforms" -msgstr "Copier transformations" +msgstr "Copier les transformations" msgid "Copy all the transformations of a target, so that they move together" @@ -6598,7 +6606,7 @@ msgstr "Action objet" msgid "Bones only: apply the object's transformation channels of the action to the constrained bone, instead of bone's channels" -msgstr "Os uniquement : appliquer les canaux de transformation objet de l’action à l’os contraint, au lieu de ceux de l’os" +msgstr "Os uniquement : appliquer les canaux de transformation objet de l’action à l’os contraint, au lieu des canaux de l’os" msgid "Use Evaluation Time" @@ -6862,15 +6870,15 @@ msgstr "Copier X" msgid "Copy the target's X location" -msgstr "Copier la position X de la cible" +msgstr "Copier la position en X de la cible" msgid "Copy Y" -msgstr "CopieY" +msgstr "Copier Y" msgid "Copy the target's Y location" -msgstr "Copier la position Y de la cible" +msgstr "Copier la position en Y de la cible" msgid "Copy Z" @@ -6878,7 +6886,7 @@ msgstr "Copier Z" msgid "Copy the target's Z location" -msgstr "Copier la position Z de la cible" +msgstr "Copier la position en Z de la cible" msgid "Copy Rotation Constraint" @@ -6886,7 +6894,7 @@ msgstr "Contrainte Copier rotation" msgid "Copy the rotation of the target" -msgstr "Copier la rotation de la cible" +msgstr "Copier la rotation en de la cible" msgid "Euler Order" @@ -7006,15 +7014,15 @@ msgstr "OBSOLÈTE : Ajouter la rotation originale à la rotation copiée" msgid "Copy the target's X rotation" -msgstr "Copier la rotation X de la cible" +msgstr "Copier la rotation en X de la cible" msgid "Copy the target's Y rotation" -msgstr "Copier la rotation Y de la cible" +msgstr "Copier la rotation en Y de la cible" msgid "Copy the target's Z rotation" -msgstr "Copier la rotation Z de la cible" +msgstr "Copier la rotation en Z de la cible" msgid "Copy Scale Constraint" @@ -7298,7 +7306,7 @@ msgstr "Type d’IK" msgid "Copy Pose" -msgstr "Copier pose" +msgstr "Copier la pose" msgid "Maximum number of solving iterations" @@ -9252,7 +9260,7 @@ msgstr "Chaîne pour filtrage en live" msgid "Display Armature" -msgstr "Afficher armature" +msgstr "Afficher les armatures" msgid "Include visualization of armature related animation data" @@ -9260,15 +9268,15 @@ msgstr "Inclure la visualisation des données d’animation relatives aux armatu msgid "Display Cache Files" -msgstr "Afficher fichiers cache" +msgstr "Afficher les fichiers de cache" msgid "Include visualization of cache file related animation data" -msgstr "Inclure la visualisation des données d’animation relatives au fichier cache" +msgstr "Inclure la visualisation des données d’animation relatives au fichier de cache" msgid "Display Camera" -msgstr "Afficher caméra" +msgstr "Afficher les caméras" msgid "Include visualization of camera related animation data" @@ -9276,7 +9284,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux camér msgid "Display Curve" -msgstr "Afficher courbes" +msgstr "Afficher les courbes" msgid "Include visualization of curve related animation data" @@ -9284,7 +9292,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux courbe msgid "Show Data-Block Filters" -msgstr "Afficher filtres de blocs de données" +msgstr "Afficher les filtres des blocs de données" msgid "Show options for whether channels related to certain types of data are included" @@ -9292,7 +9300,7 @@ msgstr "Afficher les options pour les canaux incluant certains types de données msgid "Collapse Summary" -msgstr "Replier résumé" +msgstr "Replier le résumé" msgid "Collapse summary when shown, so all other channels get hidden (Dope Sheet editors only)" @@ -9300,7 +9308,7 @@ msgstr "Replier le résumé quand il est montré, de façon que tous les autres msgid "Display Grease Pencil" -msgstr "Afficher crayon gras" +msgstr "Afficher les crayons gras" msgid "Include visualization of Grease Pencil related animation data and frames" @@ -9308,7 +9316,7 @@ msgstr "Inclure la visualisation des données d’animation et images relatives msgid "Display Hair" -msgstr "Afficher poils" +msgstr "Afficher les poils" msgid "Include visualization of hair related animation data" @@ -9332,7 +9340,7 @@ msgstr "Inclure la visualisation de données d’animation relatives aux lattice msgid "Display Light" -msgstr "Afficher éclairages" +msgstr "Afficher les éclairages" msgid "Include visualization of light related animation data" @@ -9340,7 +9348,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux éclai msgid "Display Line Style" -msgstr "Afficher style de ligne" +msgstr "Afficher les styles de ligne" msgid "Include visualization of Line Style related Animation data" @@ -9348,7 +9356,7 @@ msgstr "Inclure la visualisation des données d’animation relatives styles de msgid "Display Material" -msgstr "Afficher matériaux" +msgstr "Afficher les matériaux" msgid "Include visualization of material related animation data" @@ -9356,7 +9364,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux matér msgid "Display Meshes" -msgstr "Afficher maillages" +msgstr "Afficher les maillages" msgid "Include visualization of mesh related animation data" @@ -9364,7 +9372,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux mailla msgid "Display Metaball" -msgstr "Afficher méta-balles" +msgstr "Afficher les méta-balles" msgid "Include visualization of metaball related animation data" @@ -9372,7 +9380,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux méta- msgid "Include Missing NLA" -msgstr "Inclure NLA manquant" +msgstr "Inclure les NLA manquants" msgid "Include animation data-blocks with no NLA data (NLA editor only)" @@ -9380,7 +9388,7 @@ msgstr "Inclure les blocs de données animation dépourvus de données NLA (édi msgid "Display Modifier Data" -msgstr "Afficher données de modificateur" +msgstr "Afficher les données de modificateur" msgid "Include visualization of animation data related to data-blocks linked to modifiers" @@ -9388,7 +9396,7 @@ msgstr "Inclure la visualisation des données d’animation liées aux blocs de msgid "Display Movie Clips" -msgstr "Afficher clips vidéo" +msgstr "Afficher les clips vidéo" msgid "Include visualization of movie clip related animation data" @@ -9396,7 +9404,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux clips msgid "Display Node" -msgstr "Afficher nœuds" +msgstr "Afficher les nœuds" msgid "Include visualization of node related animation data" @@ -9404,7 +9412,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux nœuds msgid "Only Show Errors" -msgstr "Afficher erreurs uniquement" +msgstr "Afficher les erreurs uniquement" msgid "Only include F-Curves and drivers that are disabled or have errors" @@ -9412,7 +9420,7 @@ msgstr "N’inclure que les F-courbes et les contrôleurs qui sont désactivés msgid "Only Show Selected" -msgstr "Afficher sélectionnées uniquement" +msgstr "Afficher la sélection uniquement" msgid "Only include channels relating to selected objects and data" @@ -9420,7 +9428,7 @@ msgstr "N’inclure que les canaux relatifs aux objets et données sélectionné msgid "Display Particle" -msgstr "Afficher particules" +msgstr "Afficher les particules" msgid "Include visualization of particle related animation data" @@ -9428,7 +9436,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux partic msgid "Display Point Cloud" -msgstr "Afficher nuage de points" +msgstr "Afficher les nuages de points" msgid "Include visualization of point cloud related animation data" @@ -9436,7 +9444,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux nuages msgid "Display Scene" -msgstr "Afficher scène" +msgstr "Afficher les scènes" msgid "Include visualization of scene related animation data" @@ -9444,7 +9452,7 @@ msgstr "Inclure la visualisation des données d’animation relatives à la scè msgid "Display Shape Keys" -msgstr "Afficher clés de forme" +msgstr "Afficher les clés de forme" msgid "Include visualization of shape key related animation data" @@ -9452,7 +9460,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux clés msgid "Display Speaker" -msgstr "Afficher haut-parleurs" +msgstr "Afficher les haut-parleurs" msgid "Include visualization of speaker related animation data" @@ -9460,7 +9468,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux haut-p msgid "Display Summary" -msgstr "Afficher résumé" +msgstr "Afficher le résumé" msgid "Display an additional 'summary' line (Dope Sheet editors only)" @@ -9468,7 +9476,7 @@ msgstr "Afficher une ligne de « résumé » supplémentaire (éditeur Feuille msgid "Display Texture" -msgstr "Afficher textures" +msgstr "Afficher les textures" msgid "Include visualization of texture related animation data" @@ -9476,7 +9484,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux textur msgid "Display Transforms" -msgstr "Afficher transformations" +msgstr "Afficher les transformations" msgid "Include visualization of object-level animation data (mostly transforms)" @@ -9484,7 +9492,7 @@ msgstr "Inclure la visualisation des données d’animation au niveau objet (pri msgid "Display Volume" -msgstr "Afficher volume" +msgstr "Afficher les volumes" msgid "Include visualization of volume related animation data" @@ -9492,7 +9500,7 @@ msgstr "Inclure la visualisation des données d’animation relatives aux volume msgid "Display World" -msgstr "Afficher monde" +msgstr "Afficher le monde" msgid "Include visualization of world related animation data" @@ -10067,7 +10075,7 @@ msgstr "Inverser l’influence dans le volume" msgid "Erase Paint" -msgstr "Effacer peinture" +msgstr "Effacer la peinture" msgid "Erase / remove paint instead of adding it" @@ -12950,7 +12958,7 @@ msgstr "Filtrer Volume" msgid "Show 3D volume files" -msgstr "Afficher fichiers de volume 3D" +msgstr "Afficher les fichiers de volume 3D" msgid "Library Browser" @@ -13230,7 +13238,7 @@ msgstr "Multiplicateur pour faire tenir le champ sélectionné dans une carte de msgid "Clear In Obstacle" -msgstr "Effacer obstacle intérieur" +msgstr "Effacer dans l’obstacle" msgid "Delete fluid inside obstacles" @@ -13693,10 +13701,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "Nombre minimum de particules par cellules (garantit que chaque cellule a au moins cette quantité de particules)" -msgid "Number" -msgstr "Numéro/Nombre" - - msgid "Particle number factor (higher value results in more particles)" msgstr "Facteur de nombre de particules (des valeurs plus élevées donnent plus de particules)" @@ -15498,7 +15502,7 @@ msgstr "Afficher le calque devant les objets" msgid "Show Points" -msgstr "Afficher points" +msgstr "Afficher les points" msgid "Show the points which make up the strokes (for debugging purposes)" @@ -16119,7 +16123,7 @@ msgstr "Biais de profondeur utilisé pour la sélection" msgid "Show Hover" -msgstr "Afficher survol" +msgstr "Afficher au survol" msgid "Show Active" @@ -16415,6 +16419,10 @@ msgid "Texture Mapping" msgstr "Placage de texture" +msgid "Change stroke UV texture values" +msgstr "Changer les coordonnées UV du trait" + + msgid "Time Offset" msgstr "Décalage temporel" @@ -16548,7 +16556,7 @@ msgstr "Lisser le trait" msgid "Change stroke thickness" -msgstr "Modifier épaisseur du trait" +msgstr "Modifier l’épaisseur du trait" msgid "Hue/Saturation" @@ -16556,7 +16564,7 @@ msgstr "Teinte/saturation" msgid "Apply changes to stroke colors" -msgstr "Appliquer les changements de couleurs de trait" +msgstr "Appliquer les changements aux couleurs des trait" msgid "Opacity of the strokes" @@ -17925,6 +17933,10 @@ msgid "Amount of noise to apply to thickness" msgstr "Quantité de bruit à appliquer à l’épaisseur" +msgid "Amount of noise to apply to UV rotation" +msgstr "Quantité de bruit à appliquer à la rotation UV" + + msgid "Noise Offset" msgstr "Décalage bruit" @@ -18362,7 +18374,7 @@ msgstr "Longueur constante" msgid "Keep the texture at a constant length regardless of the length of each stroke" -msgstr "Conserver la texture à une longueur constante, en ignorant la longueur de chaque tracé" +msgstr "Conserver la texture à une longueur constante, en ignorant la longueur de chaque trait" msgid "Stroke Length" @@ -19059,7 +19071,7 @@ msgstr "Afficher l’armature en état de pose liée (pas de mise en pose possib msgid "Display Axes" -msgstr "Afficher axes" +msgstr "Afficher les axes" msgid "Display bone axes" @@ -19067,7 +19079,7 @@ msgstr "Afficher les axes des os" msgid "Display Custom Bone Shapes" -msgstr "Afficher formes personnalisées d’os" +msgstr "Afficher les formes d’os personnalisées" msgid "Display bones with their custom shapes" @@ -19075,7 +19087,7 @@ msgstr "Afficher les os avec leurs formes personnalisées" msgid "Display Bone Group Colors" -msgstr "Afficher couleurs de groupes d’os" +msgstr "Afficher les couleurs des groupes d’os" msgid "Display bone group colors" @@ -19083,7 +19095,7 @@ msgstr "Afficher les couleurs des groupes d’os" msgid "Display Names" -msgstr "Afficher noms" +msgstr "Afficher les noms" msgid "Display bone names" @@ -19267,7 +19279,7 @@ msgstr "Utiliser le mode de fusion « teinte » pendant la peinture" msgid "Erase Alpha" -msgstr "Effacer alpha" +msgstr "Effacer l’alpha" msgid "Erase alpha while painting" @@ -19530,30 +19542,6 @@ msgid "Editable falloff curve" msgstr "Courbe d’atténuation éditable" -msgid "Curve Preset" -msgstr "Préréglage de courbe" - - -msgid "Smoother" -msgstr "Plus doux" - - -msgid "Root" -msgstr "Racine" - - -msgid "Sharp" -msgstr "Dure" - - -msgid "Sharper" -msgstr "Plus dur" - - -msgid "Inverse Square" -msgstr "Quadratique inverse" - - msgid "Curves Sculpt Settings" msgstr "Réglages de peinture de courbes" @@ -20107,7 +20095,7 @@ msgstr "Outil de sculpture" msgid "Draw Sharp" -msgstr "Afficher dureté" +msgstr "Afficher la dureté" msgid "Clay" @@ -20191,7 +20179,7 @@ msgstr "Seuil en-dessous duquel aucun « durcissement » n’est effectué" msgid "Show Cursor Preview" -msgstr "Afficher prévisualisation curseur" +msgstr "Afficher la prévisualisation curseur" msgid "Preview the scrape planes in the cursor during the stroke" @@ -20998,18 +20986,10 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "Nom de l’attribut Alembic utilisé pour générer les données de flou cinétique" -msgid "Velocity Unit" -msgstr "Unité de vélocité" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "Définir comment les vecteurs vélocité sont interprétés par rapport au temps, « frame » signifie que le différentiel de temps est de 1 image, « seconde » que le différentiel de temps est de 1 / FPS" -msgid "Second" -msgstr "Seconde" - - msgid "Camera data-block for storing camera settings" msgstr "Bloc de données caméra pour stocker les réglages de caméra" @@ -21175,7 +21155,7 @@ msgstr "Décentrement vertical de la caméra" msgid "Display Background Images" -msgstr "Afficher images d’arrière-plan" +msgstr "Afficher les images d’arrière-plan" msgid "Display reference images behind objects in the 3D View" @@ -21251,7 +21231,7 @@ msgstr "Afficher l’intervalle de découpage et la mise au point sur la caméra msgid "Show Mist" -msgstr "Afficher brume" +msgstr "Afficher la brume" msgid "Display a line from the Camera to indicate the mist area" @@ -21259,7 +21239,7 @@ msgstr "Afficher une ligne depuis la caméra pour indiquer la zone de brume" msgid "Show Name" -msgstr "Afficher nom" +msgstr "Afficher le nom" msgid "Show the active Camera's name in Camera view" @@ -21267,7 +21247,7 @@ msgstr "Afficher le nom de la caméra active, en vue caméra" msgid "Show Passepartout" -msgstr "Afficher passe-partout" +msgstr "Afficher le passe-partout" msgid "Show a darkened overlay outside the image area in Camera view" @@ -21275,7 +21255,7 @@ msgstr "Assombrir l’image en-dehors de la zone d’image, en vue caméra" msgid "Show Safe Areas" -msgstr "Afficher zones de sécurité" +msgstr "Afficher les zones de sécurité" msgid "Show TV title safe and action safe areas in Camera view" @@ -21283,7 +21263,7 @@ msgstr "Afficher les zones de sécurité TV de titre et d’action, en vue camé msgid "Show Center-Cut Safe Areas" -msgstr "Afficher zones de sécurité coupe centrale" +msgstr "Afficher les zones de sécurité coupe centrale" msgid "Show safe areas to fit content in a different aspect ratio" @@ -21291,7 +21271,7 @@ msgstr "Afficher les zones de sécurité pour insérer du contenu dans des propo msgid "Show Sensor Size" -msgstr "Afficher taille de capteur" +msgstr "Afficher la taille de capteur" msgid "Show sensor size (film gate) in Camera view" @@ -22251,11 +22231,11 @@ msgstr "Sélectionner comment les traits caractéristiques sont joints pour form msgid "Plain" -msgstr "Continu" +msgstr "Simple" msgid "Plain chaining" -msgstr "Chaînage complet" +msgstr "Chaînage simple" msgid "Sketchy" @@ -22619,7 +22599,7 @@ msgstr "Position d’épaisseur" msgid "Thickness position of silhouettes and border edges (applicable when plain chaining is used with the Same Object option)" -msgstr "Position d’épaisseur des arêtes de silhouettes et de bord (applicable quand le chaînage complet est utilisé avec l’option Même objet)" +msgstr "Position d’épaisseur des arêtes de silhouettes et de bord (applicable quand le chaînage simple est utilisé avec l’option Même objet)" msgid "Silhouettes and border edges are centered along stroke geometry" @@ -22987,7 +22967,7 @@ msgstr "Afficher les images clés en pelure d’oignon avec un dégradé de tran msgid "Show Start Frame" -msgstr "Afficher frame de début" +msgstr "Afficher la frame de début" msgid "Display onion keyframes for looping animations" @@ -23793,6 +23773,10 @@ msgid "Inverse Linear" msgstr "Linéaire inverse" +msgid "Inverse Square" +msgstr "Quadratique inverse" + + msgid "Inverse Coefficients" msgstr "Inverser coefficients" @@ -23942,7 +23926,7 @@ msgstr "L’énergie que cet éclairage émettrait sur toute sa surface s’il n msgid "Show Cone" -msgstr "Afficher cône" +msgstr "Afficher le cône" msgid "Display transparent cone in 3D view to visualize which objects are contained in it" @@ -24102,7 +24086,7 @@ msgstr "Afficher les distances de découpage dans la vue 3D" msgid "Show Preview Plane" -msgstr "Afficher plan de prévisualisation" +msgstr "Afficher le plan de prévisualisation" msgid "Show captured lighting data into the 3D view for debugging purpose" @@ -24410,7 +24394,7 @@ msgstr "Utiliser du bruit pour diffuser la visibilité binaire, et un filtre pou msgid "Show Backface" -msgstr "Afficher face arrière" +msgstr "Afficher la face arrière" msgid "Render multiple transparent layers (may introduce transparency sorting problems)" @@ -24594,7 +24578,7 @@ msgstr "Polygones du maillage" msgid "Remesh Mode" -msgstr "Modificateur Remesh" +msgstr "Modificateur remaillage" msgid "Voxel" @@ -24602,7 +24586,7 @@ msgstr "Voxel" msgid "Use the voxel remesher" -msgstr "Utiliser le remesher voxel" +msgstr "Utiliser le remailleur par voxels" msgid "Quad" @@ -24610,7 +24594,7 @@ msgstr "Quad" msgid "Use the quad remesher" -msgstr "Utiliser le remesher quad" +msgstr "Utiliser le remailleur quad" msgid "Adaptivity" @@ -24758,7 +24742,7 @@ msgstr "Conserver l’ensemble de faces actuel sur le nouveau maillage" msgid "Preserve Vertex Colors" -msgstr "Préserver couleurs de sommets" +msgstr "Préserver les couleurs de sommets" msgid "Keep the current vertex colors on the new mesh" @@ -25226,7 +25210,7 @@ msgstr "Région pour le visualiseur" msgid "Use boundaries for viewer nodes and composite backdrop" -msgstr "Utiliser des limites pour les nœuds visualiseurs et l’image de fond de compositing" +msgstr "Utiliser des limites pour les nœuds visualiseurs et l’image de fond du compositing" msgid "Geometry Node Tree" @@ -25958,7 +25942,7 @@ msgstr "Rendre l’instanciateur visible au rendu" msgid "Display Instancer" -msgstr "Afficher instanciateur" +msgstr "Afficher l’instanciateur" msgid "Make instancer visible in the viewport" @@ -25966,7 +25950,7 @@ msgstr "Rendre l’instanciateur visible dans la vue 3D" msgid "Display Name" -msgstr "Afficher nom" +msgstr "Afficher le nom" msgid "Display the object's name" @@ -25982,7 +25966,7 @@ msgstr "Toujours afficher la forme actuelle pour cet objet" msgid "Display Texture Space" -msgstr "Afficher espace de texture" +msgstr "Afficher l’espace de texture" msgid "Display the object's texture space" @@ -25994,7 +25978,7 @@ msgstr "Afficher transparent" msgid "Display material transparency in the object" -msgstr "Afficher la transparence de matériau dans l’objet" +msgstr "Afficher la transparence du matériau dans l’objet" msgid "Display the object's wireframe over solid shading" @@ -26949,6 +26933,10 @@ msgid "Display boid health" msgstr "Afficher la santé des boids" +msgid "Number" +msgstr "Numéro/Nombre" + + msgid "Show particle number" msgstr "Afficher le numéro de particule" @@ -27563,7 +27551,7 @@ msgstr "Ne prendre en compte que les images clés de l’objet actif et/ou de se msgid "Show Subframe" -msgstr "Afficher sous-frame" +msgstr "Afficher la sous-frame" msgid "Show current scene subframe and allow set it using interface tools" @@ -28024,10 +28012,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "Le fichier texte sur le disque est différent de celui en mémoire" -msgid "Lines" -msgstr "Lignes" - - msgid "Lines of text" msgstr "Lignes de texte" @@ -28181,7 +28165,7 @@ msgstr "En faire une texture basée sur les nœuds" msgid "Show Alpha" -msgstr "Afficher alpha" +msgstr "Afficher l’alpha" msgid "Show Alpha in Preview Render" @@ -28698,10 +28682,18 @@ msgid "Use soft marble" msgstr "Utiliser du marbre doux" +msgid "Sharp" +msgstr "Dure" + + msgid "Use more clearly defined marble" msgstr "Utiliser du marbre plus clairement défini" +msgid "Sharper" +msgstr "Plus dur" + + msgid "Use very clearly defined marble" msgstr "Utiliser du marbre très clairement défini" @@ -33677,11 +33669,11 @@ msgstr "Afficher les remplissages de traits de ce matériau" msgid "Show Stroke" -msgstr "Afficher trait" +msgstr "Afficher le trait" msgid "Show stroke lines of this material" -msgstr "Afficher les lignes de ce matériau" +msgstr "Afficher les traits de ce matériau" msgid "Stroke Style" @@ -34931,6 +34923,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "Si le sommet a plusieurs arêtes adjacentes, elles forment directement la coque" +msgid "Root" +msgstr "Racine" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "Le sommet est une racine pour les calculs de rotation et la génération d’armature, définir cette option ne retire pas les autres racines de l’îlot de maillage" @@ -35059,6 +35055,10 @@ msgid "UV Pin" msgstr "Épinglage UV" +msgid "UV pinned state in the UV editor" +msgstr "État de l’épinglage dans l’éditeur d’UV" + + msgid "UV coordinates on face corners" msgstr "Coordonnées UV sur les coins de faces" @@ -35408,7 +35408,7 @@ msgstr "Subdiviser le maillage de telle manière à pouvoir modifier des niveaux msgid "Remesh" -msgstr "Remesh" +msgstr "Remaillage" msgid "Generate new mesh topology based on the current shape" @@ -38225,7 +38225,7 @@ msgstr "Système de particules contrôlé par ce modificateur" msgid "Remesh Modifier" -msgstr "Modificateur Remesh" +msgstr "Modificateur Remaillage" msgid "Generate a new surface with regular topology that follows the shape of the input mesh" @@ -38892,6 +38892,10 @@ msgid "UVWarp Modifier" msgstr "Modificateur déformer (gauchir) les UV" +msgid "Add target position to UV coordinates" +msgstr "Ajouter la position de la cible aux coordonnées UV" + + msgid "U-Axis" msgstr "Axe U" @@ -39675,6 +39679,10 @@ msgid "Line thickness for motion path" msgstr "Épaisseur de ligne pour le chemin de mouvement" +msgid "Lines" +msgstr "Lignes" + + msgid "Use straight lines between keyframe points" msgstr "Dessiner des lignes droites entre les points d’images clés" @@ -40781,7 +40789,7 @@ msgstr "Limiter la quantité de redimensionnement automatique" msgid "Show Tracks" -msgstr "Afficher pistes" +msgstr "Afficher les pistes" msgid "Show UI list of tracks participating in stabilization" @@ -41282,15 +41290,15 @@ msgstr "État de sélection de nœud" msgid "Show Options" -msgstr "Afficher options" +msgstr "Afficher les options" msgid "Show Preview" -msgstr "Afficher prévisualisation" +msgstr "Afficher la prévisualisation" msgid "Show Texture" -msgstr "Afficher texture" +msgstr "Afficher la texture" msgid "Display node in viewport textured shading mode" @@ -43935,7 +43943,7 @@ msgstr "Taille du domaine" msgid "Retrieve the number of elements in a geometry for each attribute domain" -msgstr "Récupérer le nombre d’éléments dans une géométrie pour chaque domaine d’attribut" +msgstr "Obtenir le nombre d’éléments dans une géométrie pour chaque domaine d’attribut" msgid "Component" @@ -44003,7 +44011,7 @@ msgstr "Infos collection" msgid "Retrieve geometry instances from a collection" -msgstr "Récupérer les instances de géométrie depuis une collection" +msgstr "Obtenir les instances de géométrie depuis une collection" msgid "The transformation of the instances output. Does not affect the internal geometry" @@ -44035,7 +44043,7 @@ msgstr "Coins de la face" msgid "Retrieve corners that make up a face" -msgstr "Récupérer les coins qui constituent une face" +msgstr "Obtenir les coins qui constituent une face" msgid "Corners of Vertex" @@ -44043,7 +44051,7 @@ msgstr "Coins du sommet" msgid "Retrieve face corners connected to vertices" -msgstr "Récupérer les coins de faces connectés aux sommets" +msgstr "Obtenir les coins de faces connectés aux sommets" msgid "Generate a poly spline arc" @@ -44107,7 +44115,7 @@ msgstr "Utiliser les poignées de droite" msgid "Retrieve the length of all splines added together" -msgstr "Récupérer la longueur totale de toutes les splines additionnées" +msgstr "Obtenir la longueur totale de toutes les splines additionnées" msgid "Curve of Point" @@ -44115,7 +44123,7 @@ msgstr "Courbe du point" msgid "Retrieve the curve a control point is part of" -msgstr "Récupérer la courbe dont un point fait partie" +msgstr "Obtenir la courbe dont un point fait partie" msgid "Bezier Segment" @@ -44219,7 +44227,7 @@ msgstr "Générer une spline polygonale de forme parabolique avec les positions msgid "Set Handle Type" -msgstr "Définir type de poignée" +msgstr "Définir le type de poignée" msgid "Set the handle type for the control points of a Bézier curve" @@ -44239,7 +44247,7 @@ msgstr "Générer une spline polygonale en forme de spirale" msgid "Set Spline Type" -msgstr "Définir type de spline" +msgstr "Définir le type de spline" msgid "Change the type of curves" @@ -44319,11 +44327,11 @@ msgstr "Déplacer et tourner les courbes d’après les changements entre le mai msgid "Delete Geometry" -msgstr "Effacer géométrie" +msgstr "Supprimer la géométrie" msgid "Remove selected elements of a geometry" -msgstr "Enlever les éléments séléctionnés d’une géométrie" +msgstr "Enlever les éléments sélectionnés d’une géométrie" msgid "Which domain to delete in" @@ -44427,7 +44435,7 @@ msgstr "Arêtes du coin" msgid "Retrieve the edges on both sides of a face corner" -msgstr "Récupérer les arêtes de part et d’autre d’un coin de face" +msgstr "Obtenir les arêtes de part et d’autre d’un coin de face" msgid "Edges of Vertex" @@ -44435,7 +44443,7 @@ msgstr "Arêtes du sommet" msgid "Retrieve the edges connected to each vertex" -msgstr "Récupérer les arêtes connectées à chaque sommet" +msgstr "Obtenir les arêtes connectées à chaque sommet" msgid "Edges to Face Groups" @@ -44459,7 +44467,7 @@ msgstr "Face du coin" msgid "Retrieve the face each face corner is part of" -msgstr "Récupérer la face dont chaque coin de face fait partie" +msgstr "Obtenir la face dont chaque coin de face fait partie" msgid "Evaluate at Index" @@ -44467,7 +44475,7 @@ msgstr "Évaluer à l’indice" msgid "Retrieve data of other elements in the context's geometry" -msgstr "Récupérer les données d’autres éléments dans la géométrie du contexte" +msgstr "Obtenir les données d’autres éléments dans la géométrie du contexte" msgid "Domain the field is evaluated in" @@ -44479,7 +44487,7 @@ msgstr "Évaluer dans le domaine" msgid "Retrieve values from a field on a different domain besides the domain from the context" -msgstr "Récupérer les données d’un champ dans un domaine différent du domaine du contexte" +msgstr "Obtenir les données d’un champ dans un domaine différent du domaine du contexte" msgid "Fill Curve" @@ -44535,7 +44543,7 @@ msgstr "Infos image" msgid "Retrieve information about an image" -msgstr "Récupérer des informations sur une image" +msgstr "Obtenir des informations sur une image" msgid "Sample values from an image texture" @@ -44572,7 +44580,7 @@ msgstr "Positions des poignées de courbe" msgid "Retrieve the position of each Bézier control point's handles" -msgstr "Récupérer les positions des poignées de chaque point de contrôle de Bézier" +msgstr "Obtenir les positions des poignées de chaque point de contrôle de Bézier" msgid "Curve Tilt" @@ -44580,11 +44588,11 @@ msgstr "Inclinaison de courbe" msgid "Retrieve the angle at each control point used to twist the curve's normal around its tangent" -msgstr "Récupérer l’angle utilisé pour incliner la normale de la courbe autour de sa tangente à chaque point de contrôle" +msgstr "Obtenir l’angle utilisé pour incliner la normale de la courbe autour de sa tangente à chaque point de contrôle" msgid "Retrieve a stable random identifier value from the \"id\" attribute on the point domain, or the index if the attribute does not exist" -msgstr "Récupérer un identifiant aléatoire et stable de l’attribut « id » sur le domaine point, ou l’indice si l’attribut n’existe pas" +msgstr "Obtenir un identifiant aléatoire et stable de l’attribut « id » sur le domaine point, ou l’indice si l’attribut n’existe pas" msgid "Input image" @@ -44592,7 +44600,7 @@ msgstr "Entrée image" msgid "Retrieve an integer value indicating the position of each element in the list, starting at zero" -msgstr "Récupérer une valeur entière indiquant la position de chaque élément dans la liste, commençant à zéro" +msgstr "Obtenir une valeur entière indiquant la position de chaque élément dans la liste, commençant à zéro" msgid "Instance Rotation" @@ -44600,7 +44608,7 @@ msgstr "Rotation de l’instance" msgid "Retrieve the rotation of each instance in the geometry" -msgstr "Récupérer la rotation de chaque instance dans la géométrie" +msgstr "Obtenir la rotation de chaque instance dans la géométrie" msgid "Instance Scale" @@ -44608,7 +44616,7 @@ msgstr "Échelle de l’instance" msgid "Retrieve the scale of each instance in the geometry" -msgstr "Récupérer l’échelle de chaque instance dans la géométrie" +msgstr "Obtenir l’échelle de chaque instance dans la géométrie" msgid "Output a single material" @@ -44616,7 +44624,7 @@ msgstr "Sortir un seul matériau" msgid "Retrieve the index of the material used for each element in the geometry's list of materials" -msgstr "Récupérer l’indice de matériau utilisé pour chaque élément dans la liste de matériaux de la géométrie" +msgstr "Obtenir l’indice du matériau utilisé pour chaque élément dans la liste de matériaux de la géométrie" msgid "Edge Angle" @@ -44632,7 +44640,7 @@ msgstr "Voisins d’arête" msgid "Retrieve the number of faces that use each edge as one of their sides" -msgstr "Récupérer le nombre de faces utilisant chaque arête comme côté de la face" +msgstr "Obtenir le nombre de faces utilisant chaque arête comme côté de la face" msgid "Edge Vertices" @@ -44640,7 +44648,7 @@ msgstr "Sommets d’arêtes" msgid "Retrieve topology information relating to each edge of a mesh" -msgstr "Récupérer des informations de topologie à propos de chaque arête d’un maillage" +msgstr "Obtenir des informations de topologie à propos de chaque arête d’un maillage" msgid "Calculate the surface area of a mesh's faces" @@ -44652,7 +44660,7 @@ msgstr "La face est plane" msgid "Retrieve whether all triangles in a face are on the same plane, i.e. whether have the same normal" -msgstr "Récupérer si tous les triangles d’une face sont sur le même plan, c-à-d s’ils ont la même normale" +msgstr "Savoir si tous les triangles d’une face sont sur le même plan, c-à-d s’ils ont la même normale" msgid "Face Neighbors" @@ -44660,7 +44668,7 @@ msgstr "Voisins de face" msgid "Retrieve topology information relating to each face of a mesh" -msgstr "Récupérer des informations de topologie à propos de chaque face d’un maillage" +msgstr "Obtenir des informations de topologie à propos de chaque face d’un maillage" msgid "Mesh Island" @@ -44668,7 +44676,7 @@ msgstr "Îlot de maillage" msgid "Retrieve information about separate connected regions in a mesh" -msgstr "Récupérer des informations sur les régions connectées distinctes dans un maillage" +msgstr "Obtenir des informations sur les régions connectées distinctes dans un maillage" msgid "Vertex Neighbors" @@ -44676,7 +44684,7 @@ msgstr "Voisins de sommet" msgid "Retrieve topology information relating to each vertex of a mesh" -msgstr "Récupérer des informations de topologie à propos de chaque sommet d’un maillage" +msgstr "Obtenir des informations de topologie à propos de chaque sommet d’un maillage" msgid "Named Attribute" @@ -44684,7 +44692,7 @@ msgstr "Attribut nommé" msgid "Retrieve the data of a specified attribute" -msgstr "Récupérer les données de l’attribut spécifié" +msgstr "Obtenir les données de l’attribut spécifié" msgid "The data type used to read the attribute values" @@ -44692,19 +44700,19 @@ msgstr "Le type de données utilisé pour lire les valeurs d’attribut" msgid "Retrieve a unit length vector indicating the direction pointing away from the geometry at each element" -msgstr "Récupérer un vecteur de longueur unitaire pointant vers la direction opposée de la géométrie pour chaque élément" +msgstr "Obtenir un vecteur de longueur unitaire s’éloignant de la géométrie pour chaque élément" msgid "Retrieve a vector indicating the location of each element" -msgstr "Récupérer un vecteur indiquant la position de chaque élément" +msgstr "Obtenir un vecteur indiquant la position de chaque élément" msgid "Retrieve the radius at each point on curve or point cloud geometry" -msgstr "Récupérer le rayon de chaque point de la courbe ou de la géométrie de nuage de point" +msgstr "Obtenir le rayon de chaque point de la géométrie de courbe ou de nuage de points" msgid "Retrieve the current time in the scene's animation in units of seconds or frames" -msgstr "Récupérér le temps actuel dans l’animation de la scène, avec des unités en secondes ou en frames" +msgstr "Obtenir le temps actuel dans l’animation de la scène, avec des unités en secondes ou en frames" msgid "Is Shade Smooth" @@ -44712,7 +44720,7 @@ msgstr "Est ombrage lissé" msgid "Retrieve whether each face is marked for smooth shading" -msgstr "Récupérer si chaque face est marquée comme ombrage lissé" +msgstr "Savoir si chaque face est marquée comme ombrage lissé" msgid "Shortest Edge Paths" @@ -44776,7 +44784,7 @@ msgstr "Est vue 3D" msgid "Retrieve whether the nodes are being evaluated for the viewport rather than the final render" -msgstr "Récupère si les nœud sont évalués pour la vue 3D plutôt que pour le rendu final" +msgstr "Savoir si les nœuds sont évalués pour la vue 3D plutôt que pour le rendu final" msgid "Join Geometry" @@ -44952,7 +44960,7 @@ msgstr "Infos objet" msgid "Retrieve information from an object" -msgstr "Récupérer des informations sur un objet" +msgstr "Obtenir des informations sur un objet" msgid "The transformation of the vector and geometry outputs" @@ -44972,7 +44980,7 @@ msgstr "Décaler coin dans face" msgid "Retrieve corners in the same face as another" -msgstr "Récupérer les coins dans la même face qu’un autre" +msgstr "Obtenir les coins dans la même face qu’un autre" msgid "Offset Point in Curve" @@ -44992,7 +45000,7 @@ msgstr "Points de la courbe" msgid "Retrieve a point index within a curve" -msgstr "Récupérer un indice de point de la courbe" +msgstr "Obtenir un indice de point de la courbe" msgid "Points to Vertices" @@ -45052,7 +45060,7 @@ msgstr "Lancer de rayon" msgid "Cast rays from the context geometry onto a target geometry, and retrieve information from each hit point" -msgstr "Lancer des rayons depuis la géométrie du contexte vers une géométrie source, et récupérer des informations de chaque point d’impact" +msgstr "Lancer des rayons depuis la géométrie du contexte vers une géométrie source, et obtenir des informations de chaque point d’impact" msgid "Mapping from the target geometry to hit points" @@ -45144,7 +45152,7 @@ msgstr "Échantillonner courbe" msgid "Retrieve data from a point on a curve at a certain distance from its start" -msgstr "Récupérer les données d’un point sur une courbe à une certaine distance de son début" +msgstr "Obtenir les données d’un point sur une courbe à une certaine distance de son début" msgid "Method for sampling input" @@ -45172,7 +45180,7 @@ msgstr "Échantillonner indice" msgid "Retrieve values from specific geometry elements" -msgstr "Récupérer les valeurs d’éléments de géométrie spécifiques" +msgstr "Obtenir les valeurs d’éléments de géométrie spécifiques" msgid "Clamp the indices to the size of the attribute domain instead of outputting a default value for invalid indices" @@ -45248,7 +45256,7 @@ msgstr "Cet objet" msgid "Retrieve the object that contains the geometry nodes modifier currently being executed" -msgstr "Récupérer l’objet qui contient le modificateur Nœuds de géométrie en cours d’exécution" +msgstr "Obtenir l’objet qui contient le modificateur Nœuds de géométrie en cours d’exécution" msgid "Separate Components" @@ -45392,7 +45400,7 @@ msgstr "Longueur spline" msgid "Retrieve the total length of each spline, as a distance or as a number of points" -msgstr "Récupérer la longueur totale de chaque spline, en tant que distance ou que nombre de points" +msgstr "Obtenir la longueur totale de chaque spline, en tant que distance ou que nombre de points" msgid "Spline Parameter" @@ -45400,7 +45408,7 @@ msgstr "Paramètre de spline" msgid "Retrieve how far along each spline a control point is" -msgstr "Récupérer la distance où se trouve chaque point depuis le début de la spline" +msgstr "Obtenir la distance où se trouve chaque point depuis le début de la spline" msgid "Split Edges" @@ -45596,7 +45604,7 @@ msgstr "Sommet du coin" msgid "Retrieve the vertex each face corner is attached to" -msgstr "Récupérer le sommet auquel chaque coin de face s’attache" +msgstr "Obtenir le sommet auquel chaque coin de face s’attache" msgid "Display the input data in the Spreadsheet Editor" @@ -45713,7 +45721,7 @@ msgstr "Nombre de rayons à tracer par évaluation du shader" msgid "Retrieve attributes attached to objects or geometry" -msgstr "Récupérer des attributs attachés aux objets ou à leur géométrie" +msgstr "Obtenir des attributs attachés aux objets ou à leur géométrie" msgid "Attribute Name" @@ -46021,7 +46029,7 @@ msgstr "Données caméra" msgid "Retrieve information about the camera and how it relates to the current shading point's position" -msgstr "Récupérer des informations sur la caméra et sa relation avec la position du point à shader" +msgstr "Obtenir des informations sur la caméra et sa relation avec la position du point à shader" msgid "Clamp a value between a minimum and a maximum" @@ -46141,7 +46149,7 @@ msgstr "Infos courbes" msgid "Retrieve hair curve information" -msgstr "Récupérer les infos de la courbe de cheveux" +msgstr "Obtenir les infos de la courbe de cheveux" msgid "" @@ -46188,7 +46196,7 @@ msgid "" "Retrieve the type of incoming ray for which the shader is being executed.\n" "Typically used for non-physically-based tricks" msgstr "" -"Récupérer le type du rayon incident pour lequel le shader est en cours d’exécution.\n" +"Obtenir le type du rayon incident pour lequel le shader est en cours d’exécution.\n" "Typiquement utilisé pour des astuces sans base physique" @@ -46313,7 +46321,7 @@ msgstr "Mélanger deux shaders. Typiquement utilisé pour superposer des matéri msgid "Retrieve geometric information about the current shading point" -msgstr "Récupérer des infos de géométrie sur le point en cours de shading" +msgstr "Obtenir des infos de géométrie sur le point en cours de shading" msgid "Generate a normal vector and a dot product" @@ -46365,7 +46373,7 @@ msgstr "Carte UV pour les cartes en espace tangent" msgid "Retrieve information about the object instance" -msgstr "Récupérer des informations sur l’instance d’objet" +msgstr "Obtenir des informations sur l’instance d’objet" msgid "AOV Output" @@ -46441,7 +46449,7 @@ msgstr "Infos de particules" msgid "Retrieve the data of the particle that spawned the object instance, for example to give variation to multiple instances of an object" -msgstr "Récupérer les données de la particule qui a instancié l’objet, par exemple pour donner des variations à différentes instances d’un objet" +msgstr "Obtenir les données de la particule qui a instancié l’objet, par exemple pour donner des variations à différentes instances d’un objet" msgid "Point Info" @@ -46449,7 +46457,7 @@ msgstr "Infos de point" msgid "Retrieve information about points in a point cloud" -msgstr "Récupérer des infos sur les points dans un nuage de points" +msgstr "Obtenir des infos sur les points dans un nuage de points" msgid "A color picker" @@ -46648,7 +46656,7 @@ msgid "" "Retrieve multiple types of texture coordinates.\n" "Typically used as inputs for texture nodes" msgstr "" -"Récupérer différents types de coordonnées de textures.\n" +"Obtiner différents types de coordonnées de textures.\n" "Typiquement utilisé pour les entrées des nœuds de textures" @@ -46845,7 +46853,7 @@ msgstr "Générer un point volumétrique pour chaque particule ou sommet d’un msgid "Object to take point data from" -msgstr "Objet d’où récupérer les données de point" +msgstr "Objet d’où obtenir les données de point" msgid "Color Source" @@ -47245,7 +47253,7 @@ msgstr "La moitié inférieure des textures est pour les extrémités des traits msgid "Retrieve a UV map from the geometry, or the default fallback if none is specified" -msgstr "Récupérer une carte UV dans la géométrie, ou se replier sur la carte par défaut si aucune n’est spécifiée" +msgstr "Obtenir une carte UV dans la géométrie, ou se replier sur la carte par défaut si aucune n’est spécifiée" msgid "UV coordinates to be used for mapping" @@ -47498,7 +47506,7 @@ msgstr "Attribut de couleur" msgid "Retrieve a color attribute, or the default fallback if none is specified" -msgstr "Récupérer un attribut de couleur, ou la valeur par défaut si aucun n’est spécifié" +msgstr "Obtenir un attribut de couleur, ou la valeur par défaut si aucun n’est spécifié" msgid "Volume Absorption" @@ -47541,7 +47549,7 @@ msgid "" "Retrieve the edges of an object as it appears to Cycles.\n" "Note: as meshes are triangulated before being processed by Cycles, topology will always appear triangulated" msgstr "" -"Récupérer les arêtes d’un objet tels qu’il apparaît à Cycles.\n" +"Obtenir les arêtes d’un objet tels qu’il apparaît à Cycles.\n" "Note : puisque les maillages sont triangulés avant d’être traités par Cycles, la topologie apparaîtra toujours triangulée" @@ -48309,7 +48317,7 @@ msgstr "Attendre pour désélectionner les autres" msgctxt "Operator" msgid "Copy Keyframes" -msgstr "Copier images clés" +msgstr "Copier les images clés" msgid "Copy selected keyframes to the copy/paste buffer" @@ -48361,7 +48369,7 @@ msgstr "Transformer les éléments sélectionnés par type de mode" msgctxt "Operator" msgid "Set Keyframe Easing Type" -msgstr "Définir type d’amorti de l’image clé" +msgstr "Définir le type d’amorti de l’image clé" msgid "Set easing type for the F-Curve segments starting from the selected keyframes" @@ -48420,7 +48428,7 @@ msgstr "Définir la frame actuelle à la frame moyenne des images clés sélecti msgctxt "Operator" msgid "Set Keyframe Handle Type" -msgstr "Définir type de poignée des images clés" +msgstr "Définir le type de poignée des images clés" msgid "Set type of handle for selected keyframes" @@ -48459,7 +48467,7 @@ msgstr "Dans le groupe actif" msgctxt "Operator" msgid "Set Keyframe Type" -msgstr "Définir type des images clés" +msgstr "Définir le type des images clés" msgid "Set type of keyframe for the selected keyframes" @@ -48537,7 +48545,7 @@ msgstr "Créer une nouvelle action" msgctxt "Operator" msgid "Paste Keyframes" -msgstr "Coller images clés" +msgstr "Coller les images clés" msgid "Paste keyframes from copy/paste buffer for the selected channels, starting on the current frame" @@ -48585,7 +48593,7 @@ msgstr "Réécrire les clés dans l’intervalle collé, en utilisant l’interv msgid "Paste time offset of keys" -msgstr "Coller décalage temporel des clés" +msgstr "Décalage temporel des clés collées" msgid "Paste keys starting at current frame" @@ -48597,7 +48605,7 @@ msgstr "Finir à la frame" msgid "Paste keys ending at current frame" -msgstr "Coller les clé en finissant à la frame actuelle" +msgstr "Coller les clés en finissant à la frame actuelle" msgid "Frame Relative" @@ -49132,7 +49140,7 @@ msgstr "Enlever les F-courbes sélectionnées de leurs groupes actuels" msgctxt "Operator" msgid "Clear Useless Actions" -msgstr "Effacer actions inutilisées" +msgstr "Effacer les actions inutilisées" msgid "Mark actions with no F-Curves for deletion after save and reload of file preserving \"action libraries\"" @@ -49149,7 +49157,7 @@ msgstr "Seules les actions inutilisées (« utilisateur factice » uniquement) msgctxt "Operator" msgid "Copy Driver" -msgstr "Copier contrôleur" +msgstr "Copier le contrôleur" msgid "Copy the driver for the highlighted button" @@ -49198,7 +49206,7 @@ msgstr "Définir la frame actuelle comme la frame de fin de la scène ou de pré msgctxt "Operator" msgid "Clear Keyframe (Buttons)" -msgstr "Effacer image clé (boutons)" +msgstr "Effacer les images clés (boutons)" msgid "Clear all keyframes on the currently active property" @@ -49303,12 +49311,12 @@ msgstr "Insérer des images clés pour l’ensemble de clés spécifié, avec un msgid "Always Show Menu" -msgstr "Toujours afficher menu" +msgstr "Toujours afficher le menu" msgctxt "Operator" msgid "Set Active Keying Set" -msgstr "Définir ensemble de clés actif" +msgstr "Définir l’ensemble de clés actif" msgid "Set a new active keying set" @@ -49396,7 +49404,7 @@ msgstr "Enlever la propriété active de l’interface de l’ensemble de clés msgctxt "Operator" msgid "Paste Driver" -msgstr "Coller contrôleur" +msgstr "Coller le contrôleur" msgid "Paste the driver in the clipboard to the highlighted button" @@ -49405,7 +49413,7 @@ msgstr "Coller le contrôleur depuis le presse-papier pour le bouton surligné" msgctxt "Operator" msgid "Clear Preview Range" -msgstr "Effacer intervalle de prévisualisation" +msgstr "Effacer l’intervalle de prévisualisation" msgid "Clear preview range" @@ -49534,7 +49542,7 @@ msgstr "Nom de l’os nouvellement créé" msgctxt "Operator" msgid "Recalculate Roll" -msgstr "Recalculer roulis" +msgstr "Recalculer le roulis" msgid "Automatically fix alignment of select bones' axes" @@ -49741,7 +49749,7 @@ msgstr "Active tous les calques, ou juste les 16 premiers (ligne supérieure)" msgctxt "Operator" msgid "Clear Parent" -msgstr "Effacer parentage" +msgstr "Effacer le parentage" msgid "Remove the parent-child relationship between selected bones and their parents" @@ -49757,16 +49765,16 @@ msgstr "Comment effacer le parentage" msgid "Clear Parent" -msgstr "Effacer parentage" +msgstr "Effacer le parentage" msgid "Disconnect Bone" -msgstr "Déconnecter os" +msgstr "Déconnecter l’os" msgctxt "Operator" msgid "Make Parent" -msgstr "Rendre parent" +msgstr "Parenter" msgid "Set the active bone as the parent of the selected bones" @@ -49946,7 +49954,7 @@ msgstr "Nombre de coupes" msgctxt "Operator" msgid "Switch Direction" -msgstr "Inverser direction" +msgstr "Inverser la direction" msgid "Change the direction that a chain of bones points in (head and tail swap)" @@ -50172,7 +50180,7 @@ msgstr "Rendre toutes les modifications de catalogues permanentes en enregistran msgctxt "Operator" msgid "Clear Asset" -msgstr "Effacer asset" +msgstr "Effacer l’asset" msgid "Delete all asset metadata and turn the selected asset data-blocks back into normal data-blocks" @@ -50710,7 +50718,7 @@ msgstr "Effet sur les pistes qui sont trackées sur moins que le nombre spécifi msgctxt "Operator" msgid "Clear Solution" -msgstr "Effacer solution" +msgstr "Effacer la solution" msgid "Clear all calculated data" @@ -50719,7 +50727,7 @@ msgstr "Effacer toutes les données calculées" msgctxt "Operator" msgid "Clear Track Path" -msgstr "Effacer chemin des pistes" +msgstr "Effacer le chemin des pistes" msgid "Clear tracks after/before current position or clear the whole track" @@ -50773,7 +50781,7 @@ msgstr "Créer des F-courbes pour l’objet, qui copieront le mouvement de l’o msgctxt "Operator" msgid "Copy Tracks" -msgstr "Copier pistes" +msgstr "Copier les pistes" msgid "Copy selected tracks to clipboard" @@ -51167,7 +51175,7 @@ msgstr "Activer multivues" msgctxt "Operator" msgid "Paste Tracks" -msgstr "Coller pistes" +msgstr "Coller les pistes" msgid "Paste tracks from clipboard" @@ -51529,7 +51537,7 @@ msgstr "Ajouter ou supprimer un préréglage de couleur de piste de clip" msgctxt "Operator" msgid "Copy Color" -msgstr "Copier couleur" +msgstr "Copier la couleur" msgid "Copy color to all selected tracks" @@ -51630,11 +51638,11 @@ msgstr "Ajuster la frame à la vue" msgctxt "Operator" msgid "Center View to Cursor" -msgstr "Centrer vue sur curseur" +msgstr "Centrer la vue sur le curseur" msgid "Center the view so that the cursor is in the middle of the view" -msgstr "Centrer la vue de façon que le curseur soit au milieu de la vue" +msgstr "Centrer la vue de façon à ce que le curseur soit au milieu de la vue" msgctxt "Operator" @@ -51813,7 +51821,7 @@ msgstr "Tout effacer" msgid "Clear text by type" -msgstr "Effacer texte par type" +msgstr "Effacer le texte par type" msgid "History" @@ -52428,7 +52436,7 @@ msgstr "Supprimer les points de contrôle sélectionnés, en corrigeant les vois msgctxt "Operator" msgid "Draw Curve" -msgstr "Afficher courbe" +msgstr "Dessiner une courbe" msgid "Draw a freehand spline" @@ -52560,7 +52568,7 @@ msgstr "Extruder la courbe et déplacer le résultat" msgctxt "Operator" msgid "Set Handle Type" -msgstr "Définir type de poignée" +msgstr "Définir le type de poignée" msgid "Set type of handles for selected control points" @@ -52599,7 +52607,7 @@ msgstr "Faire correspondre l’espace texture à la boîte englobante de l’obj msgctxt "Operator" msgid "Recalculate Handles" -msgstr "Recalculer poignées" +msgstr "Recalculer les poignées" msgid "Recalculate the direction of selected handles" @@ -52607,7 +52615,7 @@ msgstr "Recalculer la direction des poignées sélectionnées" msgid "Recalculate handle length" -msgstr "Recalculer les longueur des poignées" +msgstr "Recalculer la longueur des poignées" msgctxt "Operator" @@ -52842,7 +52850,7 @@ msgstr "Sélectionner tous les points de contrôle liés à la sélection actuel msgid "Select all control points linked to already selected ones" -msgstr "Sélectionner tous les points de contrôle liés à ceux déjà sélectionnés" +msgstr "Sélectionner tous les points de contrôle liés aux points déjà sélectionnés" msgid "Deselect linked control points rather than selecting them" @@ -53015,7 +53023,7 @@ msgstr "Centrer dans l’espace de vue global" msgctxt "Operator" msgid "Set Spline Type" -msgstr "Définir type de courbe" +msgstr "Définir le type de courbe" msgid "Set type of active spline" @@ -54031,14 +54039,18 @@ msgid "Export vertex colors with meshes" msgstr "Exporter les couleurs de sommets avec les maillages" -msgid "Copyright" -msgstr "Copyright" - - msgid "Legal rights and conditions for the model" msgstr "Termes et conditions légales attachées au modèle" +msgid "Use Current Frame" +msgstr "Utiliser la frame actuelle" + + +msgid "Export the scene in the current animation frame" +msgstr "Exporter la scène à la frame d’animation actuelle" + + msgid "Export Deformation Bones Only" msgstr "Exporter uniquement les os de déformation" @@ -54235,6 +54247,14 @@ msgid "Export vertex tangents with shape keys (morph targets)" msgstr "Exporter les tangentes des sommets avec des clés de forme (morph targets)" +msgid "Group by NLA Track" +msgstr "Regrouper par piste NLA" + + +msgid "When on, multiple actions become part of the same glTF animation if they're pushed onto NLA tracks with the same name. When off, all the currently assigned actions become one glTF animation" +msgstr "Si activé, plusieurs actions seront combinées en une même animation glTF si elles sont poussées sur les pistes NLA du même nom. Si désactivé, toutes les actions actuellement assignées deviendront une même animation glTF" + + msgid "Merged Animation Name" msgstr "Nom de l’animation combinée" @@ -55321,12 +55341,12 @@ msgstr "(Dés)activer le style de police" msgctxt "Operator" msgid "Copy Text" -msgstr "Copier texte" +msgstr "Copier le texte" msgctxt "Operator" msgid "Cut Text" -msgstr "Couper texte" +msgstr "Couper le texte" msgid "Cut selected text to clipboard" @@ -55335,7 +55355,7 @@ msgstr "Couper le texte sélectionné dans le presse-papier" msgctxt "Operator" msgid "Insert Text" -msgstr "Insérer texte" +msgstr "Insérer du texte" msgid "Accent Mode" @@ -55348,16 +55368,16 @@ msgstr "Le prochain caractère tapé sera superposé au précédent, pour les ca msgctxt "Operator" msgid "Paste Text" -msgstr "Coller texte" +msgstr "Coller le texte" msgctxt "Operator" msgid "Paste File" -msgstr "Coller fichier" +msgstr "Coller le fichier" msgid "Paste contents from file" -msgstr "Coller du contenu depuis un fichier" +msgstr "Coller le contenu d’un fichier" msgctxt "Operator" @@ -55952,7 +55972,7 @@ msgstr "Convertir en annotations" msgctxt "Operator" msgid "Copy Strokes" -msgstr "Copier trait" +msgstr "Copier le trait" msgid "Copy selected Grease Pencil points and strokes" @@ -56808,7 +56828,7 @@ msgstr "Entrer/sortir du mode de peinture pour les traits de crayon gras" msgctxt "Operator" msgid "Paste Strokes" -msgstr "Coller traits" +msgstr "Coller les traits" msgid "Paste previously copied strokes to active layer or to original layer" @@ -57132,7 +57152,7 @@ msgstr "Sélectionner couleurs de sommets" msgid "Select all points with similar vertex color of current selected" -msgstr "Sélectionner tous les points dont les couleurs de sommets sont similaire à ceux de la sélection" +msgstr "Sélectionner tous les points dont les couleurs de sommets sont similaire à celles de la sélection" msgid "Tolerance of the selection. Higher values select a wider range of similar colors" @@ -57304,7 +57324,7 @@ msgstr "Tout ouvrir" msgctxt "Operator" msgid "Set handle type" -msgstr "Définir type de poignée" +msgstr "Définir le type de poignée" msgid "Set the type of an edit curve handle" @@ -58058,7 +58078,7 @@ msgstr "Supprimer tous les contrôleurs considérés comme invalides" msgctxt "Operator" msgid "Copy Driver Variables" -msgstr "Copier variables de contrôleur" +msgstr "Copier les variables de contrôleur" msgid "Copy the driver variables of the active driver" @@ -58067,7 +58087,7 @@ msgstr "Copier les variables de contrôleur du contrôleur actif" msgctxt "Operator" msgid "Paste Driver Variables" -msgstr "Coller variables de contrôleur" +msgstr "Coller les variables de contrôleur" msgid "Add copied driver variables to the active driver" @@ -58164,7 +58184,7 @@ msgstr "N’ajouter un F-modificateur qu’à la F-courbe active" msgctxt "Operator" msgid "Copy F-Modifiers" -msgstr "Copier F-modificateurs" +msgstr "Copier les F-modificateurs" msgid "Copy the F-Modifier(s) of the active F-Curve" @@ -58173,7 +58193,7 @@ msgstr "Copier les F-modificateurs de la F-courbe active" msgctxt "Operator" msgid "Paste F-Modifiers" -msgstr "Coller F-modificateurs" +msgstr "Coller les F-modificateurs" msgid "Add copied F-Modifiers to the selected F-Curves" @@ -58194,7 +58214,7 @@ msgstr "Placer le curseur au point médian des images clés sélectionnées" msgctxt "Operator" msgid "Clear Ghost Curves" -msgstr "Effacer courbes fantômes" +msgstr "Effacer les courbes fantômes" msgid "Clear F-Curve snapshots (Ghosts) for active Graph Editor" @@ -58436,7 +58456,7 @@ msgstr "Effacer les limites de la région de rendu et désactiver celle-ci" msgctxt "Operator" msgid "Clear Render Slot" -msgstr "Effacer emplacement de rendu" +msgstr "Effacer l’emplacement de rendu" msgid "Clear the currently selected render slot" @@ -59565,7 +59585,7 @@ msgstr "Frame de début pour insérer l’animation" msgctxt "Operator" msgid "Copy Reports to Clipboard" -msgstr "Copier rapports dans presse-papier" +msgstr "Copier les rapports dans le presse-papier" msgid "Copy selected reports to clipboard" @@ -59671,7 +59691,7 @@ msgstr "Sélectionner en miroir les points de lattice" msgid "Select vertex directly linked to already selected ones" -msgstr "Sélectionner les sommets directement liés à ceux déjà sélectionnés" +msgstr "Sélectionner les sommets directement liés aux sommets déjà sélectionnés" msgid "Randomly select UVW control points" @@ -59852,7 +59872,7 @@ msgstr "Ajouter sommet" msgctxt "Operator" msgid "Copy Splines" -msgstr "Copier courbes" +msgstr "Copier les courbes" msgid "Copy selected splines to clipboard" @@ -59886,11 +59906,11 @@ msgstr "Dupliquer masque" msgctxt "Operator" msgid "Clear Feather Weight" -msgstr "Réinitialiser poids de plume" +msgstr "Réinitialiser les poids de plume" msgid "Reset the feather weight to zero" -msgstr "Réinitialiser les poids de plume à zéro" +msgstr "Remettre les poids de plume à zéro" msgctxt "Operator" @@ -59899,7 +59919,7 @@ msgstr "Annuler cacher dans la vue" msgid "Reveal the layer by setting the hide flag" -msgstr "Afficher le calque en définissant le drapeau « caché »" +msgstr "Afficher les calques de masque temporairement cachés" msgctxt "Operator" @@ -59908,7 +59928,7 @@ msgstr "Définir cacher dans la vue" msgid "Hide the layer by setting the hide flag" -msgstr "Cacher le calque en réglant le drapeau « caché »" +msgstr "Cacher temporairement les calques de masque" msgctxt "Operator" @@ -59964,7 +59984,7 @@ msgstr "Définir le parentage du masque" msgctxt "Operator" msgid "Paste Splines" -msgstr "Coller courbes" +msgstr "Coller les courbes" msgid "Paste splines from clipboard" @@ -60018,7 +60038,7 @@ msgstr "Désélectionner les points de courbe aux bords de chacune des régions msgid "Select all curve points linked to already selected ones" -msgstr "Sélectionner tous les points de courbe liés à ceux déjà sélectionnés" +msgstr "Sélectionner tous les points de courbe liés aux points déjà sélectionnés" msgid "(De)select all points linked to the curve under the mouse cursor" @@ -60026,7 +60046,7 @@ msgstr "(Dé)sélectionner tous les points liés à la courbe sous le curseur de msgid "Select more spline points connected to initial selection" -msgstr "Sélectionner plus de point de courbe connectés à la sélection initiale" +msgstr "Sélectionner plus de points de courbe connectés à la sélection initiale" msgctxt "Operator" @@ -60097,7 +60117,7 @@ msgstr "Faire glisser un point sur la spline pour définir sa courbure" msgctxt "Operator" msgid "Copy Material" -msgstr "Copier matériau" +msgstr "Copier le matériau" msgid "Copy the material settings and nodes" @@ -60115,7 +60135,7 @@ msgstr "Ajouter un nouveau matériau" msgctxt "Operator" msgid "Paste Material" -msgstr "Coller matériau" +msgstr "Coller le matériau" msgid "Paste the material settings and nodes" @@ -60142,7 +60162,7 @@ msgstr "Supprimer la variable dans la console" msgctxt "Operator" msgid "Show BBox" -msgstr "Afficher boîte englobante" +msgstr "Afficher la boîte englobante" msgid "Show/Hide the BBox of Matrix items" @@ -60646,7 +60666,7 @@ msgstr "Ajouter une couche de données de normales divisées personnalisées, s msgctxt "Operator" msgid "Clear Custom Split Normals Data" -msgstr "Effacer données de normales divisées personnalisées" +msgstr "Effacer les données de normales divisées personnalisées" msgid "Remove the custom split normals layer, if it exists" @@ -60655,7 +60675,7 @@ msgstr "Enlever la couche de données de normales divisées personnalisées, si msgctxt "Operator" msgid "Clear Sculpt Mask Data" -msgstr "Effacer données de masque de sculpture" +msgstr "Effacer les données de masque de sculpture" msgid "Clear vertex sculpt masking data from the mesh" @@ -60673,11 +60693,11 @@ msgstr "Ajouter un calque de peau de sommet" msgctxt "Operator" msgid "Clear Skin Data" -msgstr "Effacer données de peau" +msgstr "Effacer les données de peau" msgid "Clear vertex skin layer" -msgstr "Effacer calque de peau de sommet" +msgstr "Effacer le calque de peau de sommet" msgctxt "Operator" @@ -61135,7 +61155,7 @@ msgstr "Souder les arêtes isolées sur des faces (en les divisant pour créer d msgctxt "Operator" msgid "Copy Mirrored UV Coords" -msgstr "Copier coordonnées UV en miroir" +msgstr "Copier les coordonnées UV en miroir" msgid "Copy mirror UV coordinates on the X axis based on a mirrored mesh" @@ -61692,7 +61712,7 @@ msgstr "Définir la valeur des faces" msgctxt "Operator" msgid "Recalculate Normals" -msgstr "Recalculer normales" +msgstr "Recalculer les normales" msgid "Make face and vertex normals point either outside or inside the mesh" @@ -61721,7 +61741,7 @@ msgstr "Mode des outils utilisant des entrées depuis l’interface" msgid "Copy Normal" -msgstr "Copier normale" +msgstr "Copier la normale" msgid "Copy normal to buffer" @@ -61729,7 +61749,7 @@ msgstr "Copier la normale vers le tampon" msgid "Paste Normal" -msgstr "Coller normale" +msgstr "Coller la normale" msgid "Paste normal from buffer" @@ -63124,7 +63144,7 @@ msgstr "Forcer la symétrie (à la fois de forme et topologique) le long d’un msgid "Which sides to copy from and to" -msgstr "Quels côtés d’où et vers lequel copier" +msgstr "Depuis quel côté copier, et vers lequel" msgid "-Y to +Y" @@ -63418,15 +63438,15 @@ msgstr "Après précalcul des courbes, supprimer les clés redondantes" msgid "Clear Constraints" -msgstr "Effacer contraintes" +msgstr "Effacer les contraintes" msgid "Remove all constraints from keyed object/bones, and do 'visual' keying" -msgstr "Enlever toutes les contraintes des objets/os cléés, et effectuer un cléage « visuel »" +msgstr "Enlever toutes les contraintes des objets/os avec clés, et ajouter des clés de manière « visuelle »" msgid "Clear Parents" -msgstr "Effacer parents" +msgstr "Effacer les parents" msgid "Bake animation onto the object then clear parents (objects only)" @@ -63877,11 +63897,11 @@ msgstr "Ajuster l’image d’arrière-plan à la vue" msgctxt "Operator" msgid "Background Image Move" -msgstr "Déplacer image d’arrière-plan" +msgstr "Déplacer l’image d’arrière-plan" msgid "Move node backdrop" -msgstr "Déplacer l’arrière-plan des nœuds" +msgstr "Déplacer l’image de fond des nœuds" msgctxt "Operator" @@ -63904,7 +63924,7 @@ msgstr "(Dé)zoomer l’image d’arrière-plan" msgctxt "Operator" msgid "Clear Viewer Region" -msgstr "Effacer région de visualisation" +msgstr "Effacer la région de visualisation" msgid "Clear the boundaries for viewer operations" @@ -64418,7 +64438,7 @@ msgstr "Sélectionner le nœud sous le curseur" msgid "Clear Viewer" -msgstr "Effacer visualiseur" +msgstr "Effacer le visualiseur" msgid "Deactivate geometry nodes viewer when clicking in empty space" @@ -64472,7 +64492,7 @@ msgstr "Sélectionner liés depuis" msgid "Select nodes linked from the selected ones" -msgstr "Sélectionner les nœuds liés en entrée à ceux sélectionnés" +msgstr "Sélectionner les nœuds liés en entrée aux nœuds sélectionnés" msgctxt "Operator" @@ -64481,7 +64501,7 @@ msgstr "Sélectionner liés à" msgid "Select nodes linked to the selected ones" -msgstr "Sélectionner les nœuds liés en sortie à ceux sélectionnés" +msgstr "Sélectionner les nœuds liés en sortie aux nœuds sélectionnés" msgctxt "Operator" @@ -64775,7 +64795,7 @@ msgstr "Ajouter un objet caméra à la scène" msgctxt "Operator" msgid "Clear Library Override" -msgstr "Effacer redéfinition bibliothèque" +msgstr "Effacer les redéfinitions de bibliothèque" msgid "Delete the selected local overrides and relink their usages to the linked data-blocks if possible, else reset them and mark them as non editable" @@ -64882,7 +64902,7 @@ msgstr "Supprimer toutes les contraintes pour l’objet actif uniquement" msgctxt "Operator" msgid "Copy Constraints to Selected Objects" -msgstr "Copier contraintes vers objets sélectionnés" +msgstr "Copier les contraintes vers les objets sélectionnés" msgid "Copy constraints to other selected objects" @@ -64937,7 +64957,7 @@ msgstr "Courbes depuis les données évaluées" msgctxt "Operator" msgid "Copy Global Transform" -msgstr "Copier transformations globales" +msgstr "Copier les transformations globales" msgid "Copies the matrix of the currently active object or pose bone to the clipboard. Uses world-space matrices" @@ -65265,7 +65285,7 @@ msgstr "(Dés)activer le champ de force de l’objet" msgctxt "Operator" msgid "Copy Geometry Node Group" -msgstr "Copier groupe de nœuds de géométrie" +msgstr "Copier le groupe de nœuds de géométrie" msgid "Copy the active geometry node group and assign it to the active modifier" @@ -65399,7 +65419,7 @@ msgstr "Appliquer un modificateur (déformant uniquement) à une nouvelle clé d msgctxt "Operator" msgid "Copy Modifier" -msgstr "Copier modificateur" +msgstr "Copier le modificateur" msgid "Duplicate modifier at the same position in the stack" @@ -65408,7 +65428,7 @@ msgstr "Dupliquer un modificateur, à la même position dans la pile" msgctxt "Operator" msgid "Copy Modifier to Selected" -msgstr "Copier modificateur vers sélectionnés" +msgstr "Copier le modificateur vers sélectionnés" msgid "Copy the modifier from the active object to all selected objects" @@ -65529,6 +65549,10 @@ msgid "Hook selected vertices to the first selected object" msgstr "Accrocher les sommets sélectionnés au premier objet sélectionné" +msgid "Assign the hook to the hook object's active bone" +msgstr "Assigner le crochet à l’os actif de l’objet crochet" + + msgctxt "Operator" msgid "Assign to Hook" msgstr "Assigner à crochet" @@ -65842,7 +65866,7 @@ msgstr "Remplacer les polices des objets de texte" msgid "Copy Modifiers" -msgstr "Copier modificateurs" +msgstr "Copier les modificateurs" msgid "Replace Modifiers" @@ -65952,7 +65976,7 @@ msgstr "Assigner l’emplacement de matériau actif à la sélection" msgctxt "Operator" msgid "Copy Material to Selected" -msgstr "Copier matériau vers sélectionnés" +msgstr "Copier le matériau vers sélectionnés" msgid "Copy material to selected objects" @@ -66300,11 +66324,11 @@ msgstr "Effacer et garder transformations" msgid "As 'Clear Parent', but keep the current visual transformations of the object" -msgstr "Comme « Supprimer parenté », mais conserve les transformations visuelles actuelles de l’objet" +msgstr "Comme « Effacer le parentage », mais conserve les transformations visuelles actuelles de l’objet" msgid "Clear Parent Inverse" -msgstr "Effacer inverse du parentage" +msgstr "Effacer l’inverse du parentage" msgid "Reset the transform corrections applied to the parenting relationship, does not remove parenting itself" @@ -66409,7 +66433,7 @@ msgstr "Enlever le système de particules sélectionné" msgctxt "Operator" msgid "Paste Global Transform" -msgstr "Coller transformation globale" +msgstr "Coller la transformation globale" msgid "Pastes the matrix from the clipboard to the currently active pose bone or object. Uses world-space matrices" @@ -66467,7 +66491,7 @@ msgstr "Intervalle de calcul" msgctxt "Operator" msgid "Clear Object Paths" -msgstr "Effacer chemins d’objets" +msgstr "Effacer les chemins d’objets" msgid "Only clear motion paths of selected objects" @@ -66512,7 +66536,7 @@ msgstr "(Dés)activer la pose/sélection des os" msgctxt "Operator" msgid "QuadriFlow Remesh" -msgstr "Remesh QuadrFlow" +msgstr "Remailler avec QuadriFlow" msgid "Create a new quad based mesh using the surface data of the current mesh. All data layers will be lost" @@ -66540,11 +66564,11 @@ msgstr "Longueurs d’arêtes" msgid "Input target edge length in the new mesh" -msgstr "Entrée la longueur d’arête cible pour le nouveau maillage" +msgstr "Longueur d’arête cible pour le nouveau maillage" msgid "Input target number of faces in the new mesh" -msgstr "Entrée le nombre de faces cible pour le nouveau maillage" +msgstr "Nombre de faces cible pour le nouveau maillage" msgid "Reproject the paint mask onto the new mesh" @@ -66552,7 +66576,7 @@ msgstr "Reprojeter le masque de peinture sur le nouveau maillage" msgid "Random seed to use with the solver. Different seeds will cause the remesher to come up with different quad layouts on the mesh" -msgstr "Graine aléatoire à utiliser pour le solveur. Le remesher utilisera des graines différentes pour trouver des dispositions de quads différentes sur le maillage" +msgstr "Graine aléatoire à utiliser pour le solveur. Le remailleur utilisera des graines différentes pour trouver des dispositions de quads différentes sur le maillage" msgid "Smooth Normals" @@ -67291,7 +67315,7 @@ msgstr "Ajouter un objet texte à la scène" msgctxt "Operator" msgid "Clear Track" -msgstr "Effacer suivi" +msgstr "Effacer le suivi" msgid "Clear tracking constraint or flag from object" @@ -67299,7 +67323,7 @@ msgstr "Supprimer la contrainte ou le drapeau de tracking de l’objet" msgid "Clear Track" -msgstr "Effacer suivi" +msgstr "Effacer le suivi" msgid "Clear and Keep Transformation (Clear Track)" @@ -67481,7 +67505,7 @@ msgstr "Enlever les sommets dont le poids est inférieur ou égal à cette limit msgctxt "Operator" msgid "Copy Vertex Group" -msgstr "Copier groupe de sommets" +msgstr "Copier le groupe de sommets" msgid "Make a copy of the active vertex group" @@ -67490,7 +67514,7 @@ msgstr "Faire une copie du groupe de sommets actif" msgctxt "Operator" msgid "Copy Vertex Group to Selected" -msgstr "Copier groupes de sommets vers sélectionnés" +msgstr "Copier les groupes de sommets vers sélectionnés" msgid "Replace vertex groups of selected objects by vertex groups of active object" @@ -67819,7 +67843,7 @@ msgstr "Normaliser les poids du sommet actif" msgctxt "Operator" msgid "Paste Weight to Selected" -msgstr "Coller poids vers sélectionnés" +msgstr "Coller le poids vers sélectionnés" msgid "Copy this group's weight to other selected vertices (disabled if vertex group is locked)" @@ -67868,7 +67892,7 @@ msgstr "Détecter automatiquement les séquences animées dans les fichiers volu msgctxt "Operator" msgid "Voxel Remesh" -msgstr "Remesh par voxels" +msgstr "Remailler par voxels" msgid "Calculates a new manifold mesh based on the volume of the current mesh. All data layers will be lost" @@ -67881,7 +67905,7 @@ msgstr "Éditer taille voxel" msgid "Modify the mesh voxel size interactively used in the voxel remesher" -msgstr "Modifier la taille des voxels de maillage utilisée interactivement dans le remesher par voxels" +msgstr "Modifier la taille des voxels de maillage utilisée interactivement dans le remailleur par voxels" msgctxt "Operator" @@ -67903,7 +67927,7 @@ msgstr "Opération d’animation" msgid "Clear Animation Data" -msgstr "Supprimer données d’animation" +msgstr "Supprimer les données d’animation" msgid "Remove this animation data container" @@ -67911,19 +67935,19 @@ msgstr "Supprimer ce conteneur de données d’animation" msgid "Set Action" -msgstr "Définir action" +msgstr "Définir l’action" msgid "Unlink Action" -msgstr "Délier action" +msgstr "Délier l’action" msgid "Refresh Drivers" -msgstr "Rafraîchir contrôleurs" +msgstr "Rafraîchir les contrôleurs" msgid "Clear Drivers" -msgstr "Effacer contrôleurs" +msgstr "Effacer les contrôleurs" msgctxt "Operator" @@ -68141,16 +68165,16 @@ msgstr "Sélectionner les objets dans la collection" msgctxt "Operator" msgid "Show Collection" -msgstr "Afficher collection" +msgstr "Afficher la collection" msgid "Show the collection in this view layer" -msgstr "Afficher les collections dans ce calque de vue" +msgstr "Afficher la collection dans ce calque de vue" msgctxt "Operator" msgid "Show Inside Collection" -msgstr "Afficher dans collection" +msgstr "Afficher dans la collection" msgid "Show all the objects and collections inside the collection" @@ -68407,6 +68431,14 @@ msgid "Library Operation" msgstr "Opération de bibliothèque" +msgid "" +"Delete this library and all its items.\n" +"Warning: No undo" +msgstr "" +"Supprimer cette bibliothèque et tous ses éléments.\n" +"Attention : pas d’annulation possible" + + msgid "Relocate" msgstr "Relocaliser" @@ -68691,7 +68723,7 @@ msgstr "Ouvrir ou fermer la hiérarchie" msgctxt "Operator" msgid "Show Active" -msgstr "Afficher actif" +msgstr "Afficher l’actif" msgid "Open up the tree and adjust the view so that the active object is shown centered" @@ -68700,7 +68732,7 @@ msgstr "Ouvrir l’arbre et ajuster la vue de façon que l’objet actif y soit msgctxt "Operator" msgid "Show Hierarchy" -msgstr "Afficher hiérarchie" +msgstr "Afficher la hiérarchie" msgid "Open all object entries and close all others" @@ -68825,6 +68857,10 @@ msgid "Add Simple UVs" msgstr "Ajouter UV simples" +msgid "Add cube map UVs on mesh" +msgstr "Ajouter une carte UV cubique au maillage" + + msgctxt "Operator" msgid "Add Paint Slot" msgstr "Ajouter emplacement de peinture" @@ -68958,7 +68994,7 @@ msgstr "Afficher" msgid "Show vertices" -msgstr "Afficher sommets" +msgstr "Afficher les sommets" msgid "Which vertices to hide or show" @@ -69456,7 +69492,7 @@ msgstr "Connecter tous les systèmes de cheveux au maillage émetteur" msgctxt "Operator" msgid "Copy Particle Systems" -msgstr "Copier systèmes de particules" +msgstr "Copier les systèmes de particules" msgid "Copy particle systems from the active object to selected objects" @@ -69527,7 +69563,7 @@ msgstr "Dupliquer également les réglages, afin que le nouveau système de part msgctxt "Operator" msgid "Copy Particle Instance Object" -msgstr "Copier objet instancié sur particule" +msgstr "Copier l’objet instancié sur particule" msgid "Duplicate the current instance object" @@ -69572,7 +69608,7 @@ msgstr "Enlever l’objet instancié sélectionné" msgctxt "Operator" msgid "Clear Edited" -msgstr "Effacer éditions" +msgstr "Effacer les éditions" msgid "Undo all edition performed on the particle system" @@ -69820,7 +69856,7 @@ msgstr "Créer un asset de pose pour chaque marqueur de pose dans l’action act msgctxt "Operator" msgid "Copy Pose as Asset" -msgstr "Copier pose en tant qu’asset" +msgstr "Copier la pose en tant qu’asset" msgid "Create a new pose asset on the clipboard, to be pasted into an Asset Browser" @@ -69991,7 +70027,7 @@ msgstr "Ajouter une contrainte à l’os actif, avec pour cibles (si nécessaire msgctxt "Operator" msgid "Clear Pose Constraints" -msgstr "Effacer contraintes de pose" +msgstr "Effacer les contraintes de pose" msgid "Clear all the constraints for the selected bones" @@ -70000,7 +70036,7 @@ msgstr "Effacer toutes les contraintes des os sélectionnés" msgctxt "Operator" msgid "Copy Constraints to Selected Bones" -msgstr "Copier contraintes vers os sélectionnés" +msgstr "Copier les contraintes vers les os sélectionnés" msgid "Copy constraints to other selected bones" @@ -70009,7 +70045,7 @@ msgstr "Copier les contraintes vers les autres os sélectionnés" msgctxt "Operator" msgid "Copy Pose" -msgstr "Copier pose" +msgstr "Copier la pose" msgid "Copies the current pose of the selected bones to copy/paste buffer" @@ -70128,7 +70164,7 @@ msgstr "Enlever toutes les contraintes IK des os sélectionnés" msgctxt "Operator" msgid "Clear Pose Location" -msgstr "Effacer position pose" +msgstr "Effacer la position de pose" msgid "Reset locations of selected bones to their default values" @@ -70137,7 +70173,7 @@ msgstr "Réinitialiser les positions des os sélectionnés à leurs valeurs par msgctxt "Operator" msgid "Paste Pose" -msgstr "Coller pose" +msgstr "Coller la pose" msgid "Paste the stored pose on to the current pose" @@ -70175,7 +70211,7 @@ msgstr "Quel point des os est utilisé lors du calcul des chemins" msgctxt "Operator" msgid "Clear Bone Paths" -msgstr "Effacer chemins d’os" +msgstr "Effacer les chemins d’os" msgid "Only clear motion paths of selected bones" @@ -70317,7 +70353,7 @@ msgstr "Afficher tous les os cachés en mode Pose" msgctxt "Operator" msgid "Clear Pose Rotation" -msgstr "Effacer rotation pose" +msgstr "Effacer la rotation de pose" msgid "Reset rotations of selected bones to their default values" @@ -70335,7 +70371,7 @@ msgstr "Définir la représentation de rotation utilisée par les os sélectionn msgctxt "Operator" msgid "Clear Pose Scale" -msgstr "Effacer taille de pose" +msgstr "Effacer la taille de pose" msgid "Reset scaling of selected bones to their default values" @@ -70378,12 +70414,12 @@ msgstr "Sélectionner os parent" msgid "Select bones that are parents of the currently selected bones" -msgstr "Sélectionner les os parents de ceux actuellement sélectionnés" +msgstr "Sélectionner les os parents des os actuellement sélectionnés" msgctxt "Operator" msgid "Clear Pose Transforms" -msgstr "Effacer transformations pose" +msgstr "Effacer les transformations pose" msgid "Reset location, rotation, and scaling of selected bones to their default values" @@ -70392,7 +70428,7 @@ msgstr "Réinitialiser les positions, rotations et tailles des os sélectionnés msgctxt "Operator" msgid "Clear User Transforms" -msgstr "Effacer transformations utilisateur" +msgstr "Effacer les transformations utilisateur" msgid "Reset pose bone transforms to keyframed state" @@ -70549,7 +70585,7 @@ msgstr "Supprimer un chemin à exclure de l’exécution auto" msgctxt "Operator" msgid "Copy Previous Settings" -msgstr "Copier réglages précédents" +msgstr "Copier les réglages précédents" msgid "Copy settings from previous version" @@ -70676,7 +70712,7 @@ msgstr "Réinitialiser aux couleurs du thème par défaut" msgctxt "Operator" msgid "Copy Studio Light Settings" -msgstr "Copier paramètres d’éclairage studio" +msgstr "Copier les paramètres d’éclairage studio" msgid "Copy Studio Light settings to the Studio Light editor" @@ -71162,7 +71198,7 @@ msgstr "Supprimer les réglages de corps rigide de l’objet" msgctxt "Operator" msgid "Copy Rigid Body Settings" -msgstr "Copier réglages de corps rigide" +msgstr "Copier les réglages de corps rigide" msgid "Copy Rigid Body settings from active object to selected" @@ -71288,8 +71324,8 @@ msgid "Fill Range by Selection" msgstr "Définir intervalle d’après sélection" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Définir les entrées min/max de l’intervalle d’après les distances min/max entre les objets sélectionnés et l’objet source " +msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object (either a user-specified object or the active camera)" +msgstr "Définir les entrées min/max de l’intervalle d’après les distances min/max entre les objets sélectionnés et l’objet source (soit un objet choisi par l’utilisateur, soit la caméra active)" msgid "Name of the modifier to work on" @@ -71332,7 +71368,7 @@ msgstr "Ajouter un ensemble de lignes à la liste des ensembles de lignes" msgctxt "Operator" msgid "Copy Line Set" -msgstr "Copier ensemble de lignes" +msgstr "Copier l’ensemble de lignes" msgid "Copy the active line set to a buffer" @@ -71354,7 +71390,7 @@ msgstr "Direction dans laquelle déplacer l’ensemble de lignes actif" msgctxt "Operator" msgid "Paste Line Set" -msgstr "Coller ensemble de lignes" +msgstr "Coller l’ensemble de lignes" msgid "Paste the buffer content to the active line set" @@ -71559,7 +71595,7 @@ msgstr "Ajouter une nouvelle scène vide avec les paramètres par défaut" msgctxt "Scene" msgid "Copy Settings" -msgstr "Copier réglages" +msgstr "Copier les réglages" msgid "Add a new, empty scene, and copy settings from the current scene" @@ -71589,7 +71625,7 @@ msgstr "Ajouter une nouvelle scène par type dans l’éditeur de séquences, et msgid "Copy Settings" -msgstr "Copier réglages" +msgstr "Copier les réglages" msgid "Linked Copy" @@ -72079,7 +72115,7 @@ msgstr "Direction dans laquelle alterner" msgctxt "Operator" msgid "Cycle Space Type Set" -msgstr "Alterner ou définir type d’espace" +msgstr "Alterner ou définir le type d’espace" msgid "Set the space type or cycle subtype" @@ -73519,7 +73555,7 @@ msgstr "Désentrelacer toutes les sources vidéo sélectionnées" msgctxt "Operator" msgid "Erase Strips" -msgstr "Effacer bandes" +msgstr "Effacer les bandes" msgid "Erase selected strips from the sequencer" @@ -73676,7 +73712,7 @@ msgstr "Fondu depuis le début des séquences situées sous le curseur de temps msgctxt "Operator" msgid "Clear Fades" -msgstr "Effacer fondus" +msgstr "Effacer les fondus" msgid "Removes fade animation from selected sequences" @@ -74326,7 +74362,7 @@ msgstr "Balance des blancs" msgctxt "Operator" msgid "Copy to Selected Strips" -msgstr "Copier vers bandes sélectionnées" +msgstr "Copier vers les bandes sélectionnées" msgid "Copy modifiers of the active strip to all selected strips" @@ -74796,7 +74832,7 @@ msgstr "Ajouter une nouvelle texture" msgctxt "Operator" msgid "Copy Texture Slot Settings" -msgstr "Copier réglages d’emplacement texture" +msgstr "Copier les réglages d’emplacement de texture" msgid "Copy the material texture settings and nodes" @@ -74814,7 +74850,7 @@ msgstr "Déplacer des emplacements de texture vers le haut/le bas" msgctxt "Operator" msgid "Paste Texture Slot Settings" -msgstr "Coller réglages d’emplacement texture" +msgstr "Coller les réglages d’emplacement de texture" msgid "Copy the texture settings and nodes" @@ -74996,7 +75032,7 @@ msgstr "(Dés)activer l’écrasement quand on tape" msgid "Paste text selected elsewhere rather than copied (X11 only)" -msgstr "Coller le texte sélectionné quelque part, plutôt que copié (X11 seulement)" +msgstr "Coller le texte sélectionné ailleurs, plutôt que le texte copié (X11 seulement)" msgctxt "Operator" @@ -75681,7 +75717,7 @@ msgstr "Ignorer relâchement" msgctxt "Operator" msgid "Clear Button String" -msgstr "Effacer texte bouton" +msgstr "Effacer le texte du bouton" msgid "Unsets the text of the active button" @@ -75694,7 +75730,7 @@ msgstr "Copier en tant que nouveau contrôleur" msgid "Create a new driver with this property as input, and copy it to the clipboard. Use Paste Driver to add it to the target property, or Paste Driver Variables to extend an existing driver" -msgstr "Créer un nouveau contrôleur avec cette propriété en entrée, et le copier dans le presse-papier. Utiliser Coller contrôleur pour l’ajouter à la propriété cible, ou Coller variables de contrôleur pour étendre un contrôleur existant" +msgstr "Créer un nouveau contrôleur avec cette propriété en entrée, et le copier dans le presse-papier. Utiliser Coller le contrôleur pour l’ajouter à la propriété cible, ou Coller les variables de contrôleur pour étendre un contrôleur existant" msgctxt "Operator" @@ -75712,7 +75748,7 @@ msgstr "Copier le chemin complet des données" msgctxt "Operator" msgid "Copy Python Command" -msgstr "Copier commande Python" +msgstr "Copier la commande Python" msgid "Copy the Python command matching this button" @@ -76253,7 +76289,7 @@ msgstr "Réinitialiser tous les éléments du tableau à leurs valeurs par défa msgctxt "Operator" msgid "Define Override Type" -msgstr "Définir type redéfinition" +msgstr "Définir le type de redéfinition" msgid "Create an override operation, or set the type of an existing one" @@ -76395,6 +76431,10 @@ msgid "Align Rotation" msgstr "Aligner la rotation" +msgid "Align the UV island's rotation" +msgstr "Aligner la rotation de l’îlot UV" + + msgid "Axis to align to" msgstr "Axis sur lequel aligner" @@ -76434,7 +76474,7 @@ msgstr "Réduire le cisaillement dans les îlots" msgctxt "Operator" msgid "Copy UVs" -msgstr "Copier UV" +msgstr "Copier les UV" msgid "Copy selected UV vertices" @@ -76715,7 +76755,7 @@ msgstr "Marquer les arêtes UV sélectionnées comme coutures" msgid "Clear Seams" -msgstr "Effacer coutures" +msgstr "Effacer les coutures" msgid "Clear instead of marking seams" @@ -76802,7 +76842,7 @@ msgstr "Empaqueter les îlots dans la tuile UDIM active, ou dans la tuile UDIM d msgctxt "Operator" msgid "Paste UVs" -msgstr "Coller UV" +msgstr "Coller les UV" msgid "Paste selected UV vertices" @@ -76843,6 +76883,10 @@ msgid "Use orthographic projection" msgstr "Utiliser une projection orthogonale" +msgid "Randomize the UV island's location, rotation, and scale" +msgstr "Randomiser la position, la rotation et l’échelle de l’îlot UV" + + msgid "Maximum rotation" msgstr "Rotation maximum" @@ -77139,7 +77183,7 @@ msgstr "Compteur de sélection d’objets" msgid "Snap Islands" -msgstr "Coller îlots" +msgstr "Coller les îlots" msgid "Snap islands together (on edge stitch mode, rotates the islands too)" @@ -77375,7 +77419,7 @@ msgstr "Définir la région de découpage" msgctxt "Operator" msgid "Copy Objects" -msgstr "Copier objets" +msgstr "Copier les objets" msgid "Selected objects are copied to the clipboard" @@ -77683,7 +77727,7 @@ msgstr "Menu mode objet" msgctxt "Operator" msgid "Paste Objects" -msgstr "Coller objet" +msgstr "Coller les objets" msgid "Objects from the clipboard are pasted" @@ -78531,7 +78575,7 @@ msgstr "Sélectionner nouveaux objets" msgid "Clear Asset Data" -msgstr "Effacer données d’asset" +msgstr "Effacer les données d’asset" msgid "Don't add asset meta-data or tags from the original data-block" @@ -79265,7 +79309,7 @@ msgstr "Créer un script de démo, et optionnellement l’exécuter" msgid "Number of times to play the animation" -msgstr "Nombres de fois où lire/jouer l’animation" +msgstr "Combien de fois lire/jouer l’animation" msgid "Render Anim" @@ -79273,7 +79317,7 @@ msgstr "Rendre animation" msgid "Render entire animation (render mode only)" -msgstr "Rendre une animation complète (mode de rendu uniquement)" +msgstr "Rendre toute l’animation (mode rendu uniquement)" msgid "Screen Switch" @@ -79727,7 +79771,7 @@ msgstr "Ouvrir un fichier Blender" msgid "Display File Selector" -msgstr "Afficher sélecteur de fichiers" +msgstr "Afficher le sélecteur de fichiers" msgid "Load UI" @@ -79808,7 +79852,7 @@ msgstr "Ouvrir un chemin dans un navigateur de fichiers" msgctxt "Operator" msgid "Batch-Clear Previews" -msgstr "Effacer prévisualisation en masse" +msgstr "Effacer les prévisualisations en masse" msgid "Clear selected .blend file's previews" @@ -79898,7 +79942,7 @@ msgstr "Générer les prévisualisations des scènes" msgctxt "Operator" msgid "Clear Data-Block Previews" -msgstr "Effacer prévisualisations des blocs de données" +msgstr "Effacer les prévisualisations des blocs de données" msgid "Clear data-block previews (only for some types like objects, materials, textures, etc.)" @@ -80337,15 +80381,15 @@ msgstr "Dessiner la région" msgid "Draw Region & Swap" -msgstr "Afficher région et intervertir" +msgstr "Dessiner la région et intervertir" msgid "Draw region and swap" -msgstr "Afficher la région et intervertir" +msgstr "Dessiner la région et intervertir" msgid "Draw Window" -msgstr "Dessiner fenêtre" +msgstr "Dessiner la fenêtre" msgid "Draw window" @@ -80353,7 +80397,7 @@ msgstr "Dessiner la fenêtre" msgid "Draw Window & Swap" -msgstr "Afficher fenêtre et intervertir" +msgstr "Dessiner la fenêtre et intervertir" msgid "Draw window and swap" @@ -81372,7 +81416,7 @@ msgstr "Palette active" msgid "Show Brush" -msgstr "Afficher brosse" +msgstr "Afficher la brosse" msgid "Show Brush On Surface" @@ -81788,7 +81832,7 @@ msgstr "Nombre de symétries radiales sur l’axe X" msgid "Number of times to copy strokes across the surface" -msgstr "Nombres de fois où copier les traits à travers la surface" +msgstr "Combien de fois copier les traits à travers la surface" msgid "Source and destination for symmetrize operator" @@ -82466,7 +82510,7 @@ msgstr "Visualisation des maths de la console" msgid "Backdrop" -msgstr "Fond" +msgstr "Image de fond" msgid "Slot" @@ -83947,7 +83991,7 @@ msgstr "Forme englobante à utiliser pour les outils" msgid "Display Particles" -msgstr "Afficher particules" +msgstr "Afficher les particules" msgid "Display actual particles" @@ -83955,7 +83999,7 @@ msgstr "Afficher les vraies particules" msgid "Comb" -msgstr "Coiffer" +msgstr "Peigner" msgid "Comb hairs" @@ -83963,23 +84007,23 @@ msgstr "Peigner les cheveux" msgid "Smooth hairs" -msgstr "Adoucir cheveux" +msgstr "Adoucir les cheveux" msgid "Add hairs" -msgstr "Ajouter cheveux" +msgstr "Ajouter des cheveux" msgid "Make hairs longer or shorter" -msgstr "Rendre les cheveux plus longs ou plus courts" +msgstr "Rallonger ou raccourcir les cheveux" msgid "Puff" -msgstr "Bouffée" +msgstr "Bouffer" msgid "Make hairs stand up" -msgstr "Rendre les cheveux « rigides »" +msgstr "Faire dresser les cheveux" msgid "Cut hairs" @@ -85668,7 +85712,7 @@ msgstr "Chemin de l’exécutable du lecteur d’animation personnalisé" msgid "Auto Save Time" -msgstr "Fréquence de sauvegarde auto" +msgstr "Intervalle de la sauvegarde auto" msgid "The time (in minutes) to wait between automatic temporary saves" @@ -85780,7 +85824,7 @@ msgstr "Afficher les fichiers et les blocs de données qui sont habituellement m msgid "Show Recent Locations" -msgstr "Afficher destinations récentes" +msgstr "Afficher les destinations récentes" msgid "Show Recent locations list in the File Browser" @@ -85788,7 +85832,7 @@ msgstr "Afficher la liste des emplacements récents dans le navigateur de fichie msgid "Show System Locations" -msgstr "Afficher emplacements système" +msgstr "Afficher les emplacements système" msgid "Show System locations list in the File Browser" @@ -85884,7 +85928,7 @@ msgstr "Nombre de pixels à glisser avant qu’un évènement « glisser » ne msgid "Invert Zoom Direction" -msgstr "Inverser direction du zoom" +msgstr "Inverser la direction du zoom" msgid "Invert the axis of mouse movement for zooming" @@ -87004,15 +87048,15 @@ msgstr "Taille de l’icône des axes" msgid "Mini Axes Type" -msgstr "Type de mini axes" +msgstr "Type des mini axes" msgid "Show a small rotating 3D axes in the top right corner of the 3D viewport" -msgstr "Afficher de petits axes 3D tournants dans le coin supérieur droit de la vue 3D" +msgstr "Afficher des petits axes 3D tournants dans le coin supérieur droit de la vue 3D" msgid "Simple Axis" -msgstr "Axe simple" +msgstr "Axes simples" msgid "Interactive Navigation" @@ -87144,7 +87188,7 @@ msgstr "Afficher les commandes permettant la navigation dans les vues 2D et 3D q msgid "Display Object Info" -msgstr "Afficher infos objet" +msgstr "Afficher les infos d’objet" msgid "Include the name of the active object and the current frame number in the text info overlay" @@ -87160,7 +87204,7 @@ msgstr "Inclure le nombre de frames affichées par seconde dans le texte d’inf msgid "Show Splash" -msgstr "Afficher écran d’accueil" +msgstr "Afficher l’écran d’accueil" msgid "Display splash screen on startup" @@ -87168,7 +87212,7 @@ msgstr "Afficher l’écran d’accueil au démarrage" msgid "Show Memory" -msgstr "Afficher mémoire" +msgstr "Afficher la mémoire" msgid "Show Blender memory usage" @@ -87184,7 +87228,7 @@ msgstr "Afficher les statistiques de la scène" msgid "Show Version" -msgstr "Afficher version" +msgstr "Afficher la version" msgid "Show Blender version string" @@ -87192,7 +87236,7 @@ msgstr "Afficher la version de Blender" msgid "Show VRAM" -msgstr "Afficher VRAM" +msgstr "Afficher la VRAM" msgid "Show GPU video memory usage" @@ -87216,7 +87260,7 @@ msgstr "Afficher les références Python dans les infobulles" msgid "Display View Name" -msgstr "Afficher nom de la vue" +msgstr "Afficher le nom de la vue" msgid "Include the name of the view orientation in the text info overlay" @@ -88128,7 +88172,7 @@ msgstr "BVH statique" msgid "Any object modification requires a complete BVH rebuild, but renders faster" -msgstr "Tout modification d’objet requiert une reconstruction complète de la BVH, mais le rendu est plus rapide" +msgstr "Toute modification d’objet requiert une reconstruction complète de la BVH, mais le rendu est plus rapide" msgid "Use Compact BVH" @@ -88348,7 +88392,7 @@ msgstr "N’utiliser que les fonctionnalités finies et prise en charge" msgid "Use experimental and incomplete features that might be broken or change in the future" -msgstr "Utiliser les fonctionnalités expérimentales et incomplètes, qui pourraient casser ou être modifiées à l’avenir" +msgstr "Utiliser les fonctionnalités expérimentales et inachevées, qui pourraient casser ou être modifiées à l’avenir" msgid "Image brightness scale" @@ -88452,7 +88496,7 @@ msgstr "Rebonds min lumière" msgid "Minimum number of light bounces. Setting this higher reduces noise in the first bounces, but can also be less efficient for more complex geometry like curves and volumes" -msgstr "Nombre minimum de rebonds de lumière. Un plus haute valeur réduit le bruit dans les premiers rebonds, mais peut être moins efficient pour des géométries complexes comme des courbes ou des volumes" +msgstr "Nombre minimum de rebonds de lumière. Une plus haute valeur réduit le bruit dans les premiers rebonds, mais peut être moins efficiente pour des géométries complexes comme des courbes ou des volumes" msgid "Min Transparent Bounces" @@ -88460,7 +88504,7 @@ msgstr "Rebonds min transparence" msgid "Minimum number of transparent bounces. Setting this higher reduces noise in the first bounces, but can also be less efficient for more complex geometry like curves and volumes" -msgstr "Nombre minimum de rebonds transparetns. Un plus haute valeur réduit le bruit dans les premiers rebonds, mais peut être moins efficient pour des géométries complexes comme des courbes ou des volumes" +msgstr "Nombre minimum de rebonds transparents. Une plus haute valeur réduit le bruit dans les premiers rebonds, mais peut être moins efficiente pour des géométries complexes comme des courbes ou des volumes" msgid "Motion Blur Position" @@ -89060,7 +89104,7 @@ msgstr "Nombre d’échantillons par pixel" msgid "Show Active Pixels" -msgstr "Afficher pixels actifs" +msgstr "Afficher les pixels actifs" msgid "When using adaptive sampling highlight pixels which are being sampled" @@ -89468,7 +89512,7 @@ msgstr "Exporter les normales, UV, couleurs de sommets et matériaux pour les fo msgid "Copy Textures" -msgstr "Copier textures" +msgstr "Copier les textures" msgid "Copy textures on export to the output path" @@ -90020,10 +90064,6 @@ msgid "Additional subdivision along the curves" msgstr "Subdivision supplémentaire le long des courbes" -msgid "Curves Shape Type" -msgstr "Type de forme des courbes" - - msgid "Curves shape type" msgstr "Type de forme des courbes" @@ -90201,7 +90241,7 @@ msgstr "Utiliser un anticrénelage pour adoucir les bords des traits" msgid "Display modifiers" -msgstr "Afficher modificateur" +msgstr "Afficher les modificateurs" msgid "Playback Only" @@ -90409,7 +90449,7 @@ msgstr "Réserver les emplacements avec des fichiers vides pendant le rendu des msgid "Cache Result" -msgstr "Cache du résultat" +msgstr "Résultat en cache" msgid "Save render cache to EXR files (useful for heavy compositing, Note: affects indirectly rendered scenes)" @@ -90421,7 +90461,7 @@ msgstr "Faire passer le résultat du rendu (et du compositing) dans le pipeline msgid "Override Scene Settings" -msgstr "Remplacer réglages de rendu" +msgstr "Remplacer les réglages de rendu" msgid "Use workbench render settings from the sequencer scene, instead of each individual scene used in the strip" @@ -90429,7 +90469,7 @@ msgstr "Utiliser les réglages de rendu workbench de la scène du séquenceur, a msgid "Use Simplify" -msgstr "Utiliser simplification" +msgstr "Utiliser la simplification" msgid "Enable simplification of scene for quicker preview renders" @@ -90437,7 +90477,7 @@ msgstr "Activer la simplification de la scène, pour des rendus de prévisualisa msgid "Render Single Layer" -msgstr "Rendre calque seul" +msgstr "Rendre ce seul calque" msgid "Only render the active layer. Only affects rendering from the interface, ignored for rendering from command line" @@ -90445,7 +90485,7 @@ msgstr "Ne rendre que le calque actif. N’affecte que le rendu depuis l’inter msgid "Use Spherical Stereo" -msgstr "Utiliser stéréo sphérique" +msgstr "Utiliser la stéréo sphérique" msgid "Active render engine supports spherical stereo rendering" @@ -90485,7 +90525,7 @@ msgstr "Inclure le nom du fichier .blend dans les métadonnées de l’image" msgid "Stamp Frame" -msgstr "Étiqueter frame" +msgstr "Étiquette frame" msgid "Include the frame number in image metadata" @@ -90497,7 +90537,7 @@ msgstr "Inclure l’intervalle de frames rendu dans les métadonnées de l’ima msgid "Stamp Hostname" -msgstr "Étiqueter nom d’hôte" +msgstr "Étiquette nom d’hôte" msgid "Include the hostname of the machine that rendered the frame" @@ -90505,7 +90545,7 @@ msgstr "Inclure le nom d’hôte de la machine qui a rendu cette image" msgid "Stamp Labels" -msgstr "Noms d’étiquette" +msgstr "Noms des étiquettes" msgid "Display stamp labels (\"Camera\" in front of camera name, etc.)" @@ -91601,7 +91641,7 @@ msgstr "Interpolation plus douce de l’irradiance, mais peut introduire des bav msgid "Show Cubemap Cache" -msgstr "Afficher cache de cubemap" +msgstr "Afficher le cache de cubemap" msgid "Display captured cubemaps in the viewport" @@ -91609,7 +91649,7 @@ msgstr "Afficher les cubemaps capturées dans la vue 3D" msgid "Show Irradiance Cache" -msgstr "Afficher cache d’irradiance" +msgstr "Afficher le cache d’irradiance" msgid "Display irradiance samples in the viewport" @@ -92929,7 +92969,7 @@ msgstr "Panoramique du son lors de la lecture (uniquement pour les sources mono) msgid "Display Waveform" -msgstr "Afficher forme d’onde" +msgstr "Afficher la forme d’onde" msgid "Display the audio waveform inside the strip" @@ -93120,7 +93160,7 @@ msgstr "Toutes les bandes, incluant récursivement celles dans les méta-bandes" msgid "Show Cache" -msgstr "Afficher cache" +msgstr "Afficher le cache" msgid "Visualize cached images on the timeline" @@ -93160,7 +93200,7 @@ msgstr "Visualiser les images brutes en cache" msgid "Show Overlay" -msgstr "Afficher frame superposée" +msgstr "Afficher la frame superposée" msgid "Partial overlay on top of the sequencer with a frame offset" @@ -93468,7 +93508,7 @@ msgstr "Réglages de surimpression pour prévisualisation" msgid "Show Annotation" -msgstr "Afficher annotation" +msgstr "Afficher les annotations" msgid "Show annotations for this view" @@ -93480,7 +93520,7 @@ msgstr "Contour de l’image" msgid "Show Metadata" -msgstr "Afficher métadonnées" +msgstr "Afficher les métadonnées" msgid "Show metadata of first visible strip" @@ -93496,7 +93536,7 @@ msgstr "Réglages de surimpression dans la timeline" msgid "Show F-Curves" -msgstr "Afficher F-courbes" +msgstr "Afficher les F-courbes" msgid "Display strip opacity/volume curve" @@ -93504,7 +93544,7 @@ msgstr "Afficher la courbe d’opacité ou de volume de la bande" msgid "Show Grid" -msgstr "Afficher grille" +msgstr "Afficher la grille" msgid "Show vertical grid lines" @@ -93512,11 +93552,11 @@ msgstr "Afficher des lignes de grille verticales" msgid "Show Duration" -msgstr "Afficher durée" +msgstr "Afficher la durée" msgid "Show Offsets" -msgstr "Afficher décalages" +msgstr "Afficher les décalages" msgid "Display strip in/out offsets" @@ -93524,7 +93564,7 @@ msgstr "Afficher les décalages d’entrée et de sortie de la bande" msgid "Show Source" -msgstr "Afficher source" +msgstr "Afficher la source" msgid "Display path to source file, or name of source datablock" @@ -93532,7 +93572,7 @@ msgstr "Afficher le chemin vers le fichier source, ou le nom du bloc de données msgid "Show Color Tags" -msgstr "Afficher étiquettes de couleur" +msgstr "Afficher les étiquettes de couleur" msgid "Display the strip color tags in the sequencer" @@ -93540,7 +93580,7 @@ msgstr "Afficher les étiquettes de couleur des bandes dans le séquenceur" msgid "Show Thumbnails" -msgstr "Afficher miniatures" +msgstr "Afficher les miniatures" msgid "Show strip thumbnails" @@ -94518,7 +94558,7 @@ msgstr "Graphiques pour visualiser les statistiques du clip vidéo" msgid "Show Blue Channel" -msgstr "Afficher canal bleu" +msgstr "Afficher le canal bleu" msgid "Show blue channel in the frame" @@ -94526,7 +94566,7 @@ msgstr "Afficher le canal bleu de la frame" msgid "Show Bundles" -msgstr "Afficher faisceaux" +msgstr "Afficher les faisceaux" msgid "Show projection of 3D markers into footage" @@ -94534,7 +94574,7 @@ msgstr "Afficher la projection des marqueurs 3D dans le métrage" msgid "Show Disabled" -msgstr "Afficher désactivés" +msgstr "Afficher désactivées" msgid "Show disabled tracks from the footage" @@ -94542,7 +94582,7 @@ msgstr "Afficher les pistes désactivées dans le métrage" msgid "Show Filters" -msgstr "Afficher filtres" +msgstr "Afficher les filtres" msgid "Show filters for graph editor" @@ -94550,7 +94590,7 @@ msgstr "Afficher les filtres pour l’éditeur de graphes" msgid "Show Gizmo" -msgstr "Afficher gizmos" +msgstr "Afficher les gizmos" msgid "Show gizmos of all types" @@ -94566,15 +94606,15 @@ msgstr "Gizmo de navigation dans la vue" msgid "Show Frames" -msgstr "Afficher frames" +msgstr "Afficher les frames" msgid "Show curve for per-frame average error (camera motion should be solved first)" -msgstr "Afficher la courbe de l’erreur moyenne par frame (le mouvement de la caméra devrait d’abord être résolu)" +msgstr "Afficher la courbe de l’erreur moyenne par frame (le mouvement de la caméra doit d’abord être résolu)" msgid "Show Tracks Error" -msgstr "Afficher erreur des pistes" +msgstr "Afficher l’erreur des pistes" msgid "Display the reprojection error curve for selected tracks" @@ -94582,7 +94622,7 @@ msgstr "Afficher la courbe d’erreur de reprojection pour les pistes sélection msgid "Show Tracks Motion" -msgstr "Afficher mouvement des pistes" +msgstr "Afficher le mouvement des pistes" msgid "Display the speed curves (in \"x\" direction red, in \"y\" direction green) for the selected tracks" @@ -94590,7 +94630,7 @@ msgstr "Afficher les courbes de vitesse (en rouge pour la direction « x », e msgid "Show Green Channel" -msgstr "Afficher canal vert" +msgstr "Afficher le canal vert" msgid "Show green channel in the frame" @@ -94602,7 +94642,7 @@ msgstr "Afficher la grille montrant la distorsion optique" msgid "Show Marker Pattern" -msgstr "Afficher motif de marqueur" +msgstr "Afficher le motif de marqueur" msgid "Show pattern boundbox for markers" @@ -94610,7 +94650,7 @@ msgstr "Afficher la boîte englobante de motif pour les marqueurs" msgid "Show Marker Search" -msgstr "Afficher recherche de marqueur" +msgstr "Afficher la recherche de marqueur" msgid "Show search boundbox for markers" @@ -94618,19 +94658,19 @@ msgstr "Afficher la boîte englobante de recherche pour le marqueurs" msgid "Show Mask Overlay" -msgstr "Afficher masque par superposition" +msgstr "Afficher le masque en superposition" msgid "Show Mask Spline" -msgstr "Afficher splines des masques" +msgstr "Afficher les splines des masques" msgid "Show metadata of clip" -msgstr "Afficher métadonnées du clip" +msgstr "Afficher lesmétadonnées du clip" msgid "Show Names" -msgstr "Afficher noms" +msgstr "Afficher les noms" msgid "Show track names and status" @@ -94638,7 +94678,7 @@ msgstr "Afficher les noms et statuts des pistes" msgid "Show Red Channel" -msgstr "Afficher canal rouge" +msgstr "Afficher le canal rouge" msgid "Show red channel in the frame" @@ -94658,7 +94698,7 @@ msgstr "Barre latérale" msgid "Show Seconds" -msgstr "Afficher secondes" +msgstr "Afficher les secondes" msgid "Show timing in seconds not frames" @@ -94674,7 +94714,7 @@ msgstr "Afficher le métrage stabilisé dans l’éditeur (si la stabilisation e msgid "Show Tiny Markers" -msgstr "Afficher petits marqueurs" +msgstr "Afficher des petits marqueurs" msgid "Show markers in a more compact manner" @@ -94682,7 +94722,7 @@ msgstr "Afficher les marqueurs d’une manière plus compacte" msgid "Show Track Path" -msgstr "Afficher chemin de piste" +msgstr "Afficher la trajectoire de la piste" msgid "Show path of how track moves" @@ -94913,7 +94953,7 @@ msgstr "Marquer les images clés auxquelles la courbe des valeurs change de dire msgid "Show Handles and Interpolation" -msgstr "Afficher poignées et interpolation" +msgstr "Afficher les poignées et l’interpolation" msgid "Display keyframe handle types and non-bezier interpolation modes" @@ -94921,7 +94961,7 @@ msgstr "Afficher les types de poignées des images clés et leurs modes d’inte msgid "Show Markers" -msgstr "Afficher marqueurs" +msgstr "Afficher les marqueurs" msgid "If any exists, show markers in a separate row at the bottom of the editor" @@ -94929,7 +94969,7 @@ msgstr "S’ils existent, afficher les marqueurs sur une ligne séparée en bas msgid "Show Pose Markers" -msgstr "Afficher marqueurs de pose" +msgstr "Afficher les marqueurs de pose" msgid "Show markers belonging to the active action instead of Scene markers (Action and Shape Key Editors only)" @@ -94937,7 +94977,7 @@ msgstr "Afficher les marqueurs appartenant à l’action active, au lieu des mar msgid "Show Sliders" -msgstr "Afficher potards" +msgstr "Afficher les potards" msgid "Show sliders beside F-Curve channels" @@ -95101,7 +95141,7 @@ msgstr "Centres individuels" msgid "Show Cursor" -msgstr "Afficher curseur" +msgstr "Afficher le curseur" msgid "Show 2D cursor" @@ -95113,7 +95153,7 @@ msgstr "Afficher l’extrapolation" msgid "Show Handles" -msgstr "Afficher poignées" +msgstr "Afficher les poignées" msgid "Show handles of Bezier control points" @@ -95169,7 +95209,7 @@ msgstr "Données de l’espace éditeur d’image et d’UV" msgid "Display Channels" -msgstr "Afficher canaux" +msgstr "Afficher les canaux" msgid "Channels of the image to display" @@ -95257,7 +95297,7 @@ msgstr "Graphiques pour visualiser des statistiques de l’image" msgid "Show Mask Editor" -msgstr "Afficher éditeur de masques" +msgstr "Afficher l’éditeur de masques" msgid "Show Mask editing related properties" @@ -95265,7 +95305,7 @@ msgstr "Afficher les propriétés relatives à l’édition de masque" msgid "Show Paint" -msgstr "Afficher peinture" +msgstr "Afficher la peinture" msgid "Show paint related properties" @@ -95273,7 +95313,7 @@ msgstr "Afficher les propriétés relative à la peinture" msgid "Show Render" -msgstr "Afficher rendu" +msgstr "Afficher le rendu" msgid "Show render related properties" @@ -95281,7 +95321,7 @@ msgstr "Afficher les propriétés relatives au rendu" msgid "Display Repeated" -msgstr "Afficher répétition" +msgstr "Afficher la répétition" msgid "Display the image repeated outside of the main view" @@ -95289,7 +95329,7 @@ msgstr "Afficher l’image répétée en dehors de la vue principale" msgid "Show Stereo" -msgstr "Afficher stéréo" +msgstr "Afficher la stéréo" msgid "Display the image in Stereo 3D" @@ -95337,7 +95377,7 @@ msgstr "Données de l’espace infos" msgid "Show Debug" -msgstr "Afficher débug" +msgstr "Afficher le débug" msgid "Display debug reporting info" @@ -95345,7 +95385,7 @@ msgstr "Afficher les infos des rapports de débugage" msgid "Show Error" -msgstr "Afficher erreurs" +msgstr "Afficher les erreurs" msgid "Display error text" @@ -95353,7 +95393,7 @@ msgstr "Afficher les textes d’erreur" msgid "Show Info" -msgstr "Afficher infos" +msgstr "Afficher les infos" msgid "Display general information" @@ -95361,7 +95401,7 @@ msgstr "Afficher des informations générales" msgid "Show Operator" -msgstr "Afficher opérateurs" +msgstr "Afficher les opérateurs" msgid "Display the operator log" @@ -95369,7 +95409,7 @@ msgstr "Afficher le log des opérateurs" msgid "Show Warn" -msgstr "Afficher avertissements" +msgstr "Afficher les avertissements" msgid "Display warnings" @@ -95385,7 +95425,7 @@ msgstr "Données de l’espace éditeur NLA" msgid "Show Local Markers" -msgstr "Afficher marqueurs locaux" +msgstr "Afficher les marqueurs locaux" msgid "Show action-local markers on the strips, useful when synchronizing timing across strips" @@ -95486,7 +95526,7 @@ msgstr "Type de shader" msgid "Type of data to take shader from" -msgstr "Type de données d’où récupérer le shader" +msgstr "Type de données d’où obtenir le shader" msgid "Edit shader nodes from Object" @@ -95511,7 +95551,7 @@ msgstr "Type de texture" msgid "Type of data to take texture from" -msgstr "Type de données d’où récupérer la texture" +msgstr "Type de données d’où obtenir la texture" msgid "Edit texture nodes from World" @@ -95527,7 +95567,7 @@ msgstr "Éditer les nœuds de texture du style de ligne" msgid "Node tree type to display and edit" -msgstr "Type d’arborescence de nœuds à afficher et éditer" +msgstr "Type d’arborescence de nœuds à afficher et à éditer" msgid "Auto Render" @@ -95668,7 +95708,7 @@ msgstr "Afficher les relations de redéfinitions de bibliothèques" msgid "Show Mode Column" -msgstr "Afficher colonne de mode" +msgstr "Afficher la colonne de mode" msgid "Show the mode column for mode toggle and activation" @@ -95696,7 +95736,7 @@ msgstr "Afficher les enfants" msgid "Show Collections" -msgstr "Afficher collections" +msgstr "Afficher les collections" msgid "Show collections" @@ -95704,11 +95744,11 @@ msgstr "Afficher les collections" msgid "Complete Matches Only" -msgstr "Correspondances complètes uniquement" +msgstr "Correspondances exactes uniquement" msgid "Only use complete matches of search string" -msgstr "N’utiliser que les correspondances à la recherche complètes" +msgstr "N’utiliser que les correspondances exactes à la recherche" msgid "Show only data-blocks of one type" @@ -95716,7 +95756,7 @@ msgstr "Afficher seulement les blocs de données d’un type" msgid "Show System Overrides" -msgstr "Afficher redéfinitions système" +msgstr "Afficher les redéfinitions système" msgid "For libraries with overrides created, show the overridden values that are defined/controlled automatically (e.g. to make users of an overridden data-block point to the override data, not the original linked data)" @@ -95756,7 +95796,7 @@ msgstr "Afficher ce qui se trouve dans les éléments des objets" msgid "Show Empties" -msgstr "Afficher objets vides" +msgstr "Afficher les objets vides" msgid "Show empty objects" @@ -95764,7 +95804,7 @@ msgstr "Afficher les objets vides" msgid "Show Lights" -msgstr "Afficher éclairages" +msgstr "Afficher les éclairages" msgid "Show light objects" @@ -95772,7 +95812,7 @@ msgstr "Afficher les objets éclairage" msgid "Show Meshes" -msgstr "Afficher maillages" +msgstr "Afficher les maillages" msgid "Show mesh objects" @@ -95780,7 +95820,7 @@ msgstr "Afficher les objets maillages" msgid "Show Other Objects" -msgstr "Afficher autres objets" +msgstr "Afficher les autres objets" msgid "Show curves, lattices, light probes, fonts, ..." @@ -96016,7 +96056,7 @@ msgstr "Données de l’espace éditeur de séquences" msgid "Display Channel" -msgstr "Afficher canal" +msgstr "Afficher le canal" msgid "The channel number shown in the image preview. 0 is the result of all strips combined" @@ -96084,7 +96124,7 @@ msgstr "Taille de la scène" msgid "Use Backdrop" -msgstr "Utiliser fond" +msgstr "Utiliser le fond" msgid "Display result under strips" @@ -96092,7 +96132,7 @@ msgstr "Afficher le résultat en-dessous des bandes" msgid "Display Frames" -msgstr "Afficher frames" +msgstr "Afficher les frames" msgid "Display frames rather than seconds" @@ -96124,7 +96164,7 @@ msgstr "Montrer les zones surexposées avec les bandes zebra" msgid "Show Overlays" -msgstr "Afficher surimpressions" +msgstr "Afficher les surimpressions" msgid "Separate Colors" @@ -96204,7 +96244,7 @@ msgstr "Données persistantes associées aux colonnes du tableur" msgid "Display Context Path Collapsed" -msgstr "Afficher chemin de contexte replié" +msgstr "Afficher le chemin de contexte replié" msgid "Geometry Component" @@ -96252,7 +96292,7 @@ msgstr "Filtres utilisés pour retirer des lignes des données affichées" msgid "Show Only Selected" -msgstr "Afficher sélectionnés seulement" +msgstr "Afficher la sélection seulement" msgid "Only include rows that correspond to selected elements" @@ -96320,7 +96360,7 @@ msgstr "Afficher les numéros de ligne à côté du texte" msgid "Show Margin" -msgstr "Afficher marge" +msgstr "Afficher la marge" msgid "Show right margin" @@ -96500,7 +96540,7 @@ msgstr "Réglages d’ombrage dans la vue 3D" msgid "Show 3D Marker Names" -msgstr "Afficher noms des marqueurs 3D" +msgstr "Afficher les noms des marqueurs 3D" msgid "Show names for reconstructed tracks objects" @@ -96508,15 +96548,15 @@ msgstr "Afficher les noms des objets pistes reconstitués" msgid "Show Camera Path" -msgstr "Afficher chemin caméra" +msgstr "Afficher la trajectoire de la caméra" msgid "Show reconstructed camera path" -msgstr "Afficher le chemin reconstitué de la caméra" +msgstr "Afficher la trajectoire reconstituée de la caméra" msgid "Show Camera Focus Distance" -msgstr "Afficher distance mise au point de la caméra" +msgstr "Afficher la distance mise au point de la caméra" msgid "Gizmo to adjust camera focus distance (depends on limits display)" @@ -96524,7 +96564,7 @@ msgstr "Gizmo permettant d’ajuster la distance de mise au point de la caméra msgid "Show Camera Lens" -msgstr "Afficher focale caméra" +msgstr "Afficher la focale de la caméra" msgid "Gizmo to adjust camera focal length or orthographic scale" @@ -96532,7 +96572,7 @@ msgstr "Gizmo permettant d’ajuster la focale ou l’échelle orthogonale de la msgid "Show Empty Force Field" -msgstr "Afficher objet vide avec champ de force" +msgstr "Afficher l’objet vide avec champ de force" msgid "Gizmo to adjust the force field" @@ -96540,7 +96580,7 @@ msgstr "Gizmo permettant d’ajuster le champ de force" msgid "Show Empty Image" -msgstr "Afficher objet vide image" +msgstr "Afficher l’objet vide image" msgid "Gizmo to adjust image size and position" @@ -96548,7 +96588,7 @@ msgstr "Gizmo permettant d’ajuster la taille et la position d’une image" msgid "Show Light Look-At" -msgstr "Afficher direction éclairage" +msgstr "Afficher la direction de l’éclairage" msgid "Gizmo to adjust the direction of the light" @@ -96556,7 +96596,7 @@ msgstr "Gizmo permettant d’ajuster la direction de l’éclairage" msgid "Show Light Size" -msgstr "Afficher taille éclairage" +msgstr "Afficher la taille de l’éclairage" msgid "Gizmo to adjust spot and area size" @@ -96564,7 +96604,7 @@ msgstr "Gizmo permettant d’ajuster la taille des éclairages de zone et spots" msgid "Show Object Rotation" -msgstr "Afficher rotation d’objet" +msgstr "Afficher la rotation de l’objet" msgid "Gizmo to adjust rotation" @@ -96572,7 +96612,7 @@ msgstr "Gizmo permettant d’ajuster la rotation" msgid "Show Object Scale" -msgstr "Afficher échelle d’objet" +msgstr "Afficher l’échelle de l’objet" msgid "Gizmo to adjust scale" @@ -96580,7 +96620,7 @@ msgstr "Gizmo permettant d’ajuster l’échelle" msgid "Show Object Location" -msgstr "Afficher position d’objet" +msgstr "Afficher la position de l’objet" msgid "Gizmo to adjust location" @@ -96592,7 +96632,7 @@ msgstr "Haut-parleur" msgid "Show Reconstruction" -msgstr "Afficher reconstitution" +msgstr "Afficher la reconstitution" msgid "Display reconstruction data from active movie clip" @@ -96612,7 +96652,7 @@ msgstr "Afficher le volume de la pyramide de vue pour la 3D stéréo" msgid "Show Viewer" -msgstr "Afficher visualiseur" +msgstr "Afficher le visualiseur" msgid "Display non-final geometry from viewer nodes" @@ -96692,7 +96732,7 @@ msgstr "Utiliser une région à l’intérieur du cadre pour le rendu dans la vu msgid "Display Background" -msgstr "Afficher arrière-plan" +msgstr "Afficher l’arrière-plan" msgid "Show the grid background and borders" @@ -96708,7 +96748,7 @@ msgstr "Obtenir le chemin d’arborescence du nœud dans une chaîne de caractè msgid "Show Tree Path" -msgstr "Afficher chemin de l’arborescence" +msgstr "Afficher le chemin de l’arborescence" msgid "Display breadcrumbs for the editor's context" @@ -96716,7 +96756,7 @@ msgstr "Afficher le fil d’Ariane pour le contexte de l’éditeur" msgid "Show Named Attributes" -msgstr "Afficher attributs nommés" +msgstr "Afficher les attributs nommés" msgid "Show when nodes are using named attributes" @@ -96728,7 +96768,7 @@ msgstr "Afficher les surimpressions, comme les liens colorés ou en pointillés" msgid "Show Timing" -msgstr "Afficher timing" +msgstr "Afficher le timing" msgid "Display each node's last execution time" @@ -96736,7 +96776,7 @@ msgstr "Afficher le temps d’exécution de chaque nœud" msgid "Show Wire Colors" -msgstr "Afficher couleurs des liens" +msgstr "Afficher les couleurs des liens" msgid "Color node links based on their connected sockets" @@ -96838,7 +96878,7 @@ msgstr "Arrondir aux centres des pixels" msgid "Display Faces" -msgstr "Afficher faces" +msgstr "Afficher les faces" msgid "Display faces over the image" @@ -96858,7 +96898,7 @@ msgstr "Afficher les propriétés de métadonnées de l’image" msgid "Display Modified Edges" -msgstr "Afficher arêtes modifiées" +msgstr "Afficher les arêtes modifiées" msgid "Display edges after modifiers are applied" @@ -96874,7 +96914,7 @@ msgstr "Afficher les coordonnées en pixels, plutôt qu’entre 0.0 et 1.0" msgid "Display Stretch" -msgstr "Afficher étirement" +msgstr "Afficher l’étirement" msgid "Display faces colored according to the difference in shape between UVs and their 3D coordinates (blue for low distortion, red for high distortion)" @@ -96885,6 +96925,10 @@ msgid "Display Texture Paint UVs" msgstr "Afficher les UV de peinture de texture" +msgid "Display overlay of texture paint UV layer" +msgstr "Afficher le calque UV de la texture peinte en surimpression" + + msgid "Tile Grid Shape" msgstr "Forme de la grille de tuiles" @@ -97797,7 +97841,7 @@ msgstr "Couleur de marqueur verrouillé" msgid "Color of marker" -msgstr "Effacer de marqueur" +msgstr "Couleur de marqueur" msgid "Marker Outline" @@ -99045,7 +99089,7 @@ msgstr "Couleurs de fond des menus" msgid "Menu Item Colors" -msgstr "Couleurs des élément de menu" +msgstr "Couleurs des éléments de menu" msgid "Number Widget Colors" @@ -99053,7 +99097,7 @@ msgstr "Couleurs des widgets numériques" msgid "Slider Widget Colors" -msgstr "Couleurs des widgets curseurs" +msgstr "Couleurs des widgets de potards" msgid "Option Widget Colors" @@ -99169,7 +99213,7 @@ msgstr "Passe-partout de caméra" msgid "Camera Path" -msgstr "Chemin de caméra" +msgstr "Trajectoire de la caméra" msgid "Clipping Border" @@ -100282,7 +100326,7 @@ msgstr "Inverser le filtrage (afficher les éléments cachés, et vice versa)" msgid "Show Filter" -msgstr "Afficher filtre" +msgstr "Afficher le filtre" msgid "Show filtering options" @@ -100610,7 +100654,7 @@ msgstr "Opacité maximum des os en mode d’affichage filaire" msgid "Display Handles" -msgstr "Afficher poignées" +msgstr "Afficher les poignées" msgid "Limit the display of curve handles in edit mode" @@ -100690,7 +100734,7 @@ msgstr "Opacité masque de sculpture" msgid "Display X Axis" -msgstr "Afficher axe X" +msgstr "Afficher l’axe X" msgid "Show the X axis line" @@ -100698,7 +100742,7 @@ msgstr "Afficher la ligne de l’axe X" msgid "Display Y Axis" -msgstr "Afficher axe Y" +msgstr "Afficher l’axe Y" msgid "Show the Y axis line" @@ -100706,7 +100750,7 @@ msgstr "Afficher la ligne de l’axe Y" msgid "Display Z Axis" -msgstr "Afficher axe Z" +msgstr "Afficher l’axe Z" msgid "Show the Z axis line" @@ -100714,7 +100758,7 @@ msgstr "Afficher la ligne de l’axe Z" msgid "Show Bones" -msgstr "Afficher os" +msgstr "Afficher les os" msgid "Display bones (disable to show motion paths only)" @@ -100730,7 +100774,7 @@ msgstr "Afficher le curseur 3D en surimpression" msgid "Draw Normals" -msgstr "Afficher normales" +msgstr "Afficher les normales" msgid "Display 3D curve normals in editmode" @@ -100814,7 +100858,7 @@ msgstr "Détails d’objets, y compris filaire vide, caméras et autres guides v msgid "Display Face Center" -msgstr "Afficher centre de la face" +msgstr "Afficher le centre de la face" msgid "Display face center when face selection is enabled in solid shading modes" @@ -100822,7 +100866,7 @@ msgstr "Afficher le centre de la face quand la sélection de face est activée d msgid "Display Normals" -msgstr "Afficher normales" +msgstr "Afficher les normales" msgid "Display face normals as lines" @@ -100850,7 +100894,7 @@ msgstr "Atténuer la géométrie inactive en utilisant la couleur d’arrière-p msgid "Display Grid Floor" -msgstr "Afficher grille du sol" +msgstr "Afficher la grille du sol" msgid "Show the ground plane grid" @@ -100858,7 +100902,7 @@ msgstr "Afficher la grille du plan au sol" msgid "Display Freestyle Edge Marks" -msgstr "Afficher marques d’arêtes Freestyle" +msgstr "Afficher les marques d’arêtes Freestyle" msgid "Display Freestyle edge marks, used with the Freestyle renderer" @@ -100866,7 +100910,7 @@ msgstr "Afficher les marques d’arêtes Freestyle, utilisées par le moteur de msgid "Display Freestyle Face Marks" -msgstr "Afficher marques de faces Freestyle" +msgstr "Afficher les marques de faces Freestyle" msgid "Display Freestyle face marks, used with the Freestyle renderer" @@ -100934,7 +100978,7 @@ msgstr "Afficher les surimpressions, comme les gizmos et les contours" msgid "Show Wire" -msgstr "Afficher filaire" +msgstr "Afficher le filaire" msgid "Use wireframe display in painting modes" @@ -100958,15 +101002,15 @@ msgstr "Afficher les courbes originales en cours d’édition" msgid "Sculpt Show Face Sets" -msgstr "Afficher ensembles de faces de sculpture" +msgstr "Afficher les ensembles de faces de sculpture" msgid "Sculpt Show Mask" -msgstr "Afficher masque de sculpture" +msgstr "Afficher le masque de sculpture" msgid "Display Split Normals" -msgstr "Afficher normales divisées" +msgstr "Afficher les normales divisées" msgid "Display vertex-per-face normals as lines" @@ -100986,7 +101030,7 @@ msgstr "Afficher des statistiques à propos du maillage" msgid "Show Text" -msgstr "Afficher texte" +msgstr "Afficher le texte" msgid "Display overlay text" @@ -100994,7 +101038,7 @@ msgstr "Afficher le texte en surimpression" msgid "Display Vertex Normals" -msgstr "Afficher normales des sommets" +msgstr "Afficher les normales des sommets" msgid "Display vertex normals as lines" @@ -101006,7 +101050,7 @@ msgstr "Afficher l’attribut en surimpression pour le nœud visualiseur actif" msgid "Show Weights" -msgstr "Afficher poids" +msgstr "Afficher les poids" msgid "Display weights in editmode" @@ -101018,7 +101062,7 @@ msgstr "Afficher les filaires des arêtes" msgid "Show Weight Contours" -msgstr "Afficher poids" +msgstr "Afficher les niveaux des poids" msgid "Show contour lines formed by points with the same interpolated weight" @@ -101026,7 +101070,7 @@ msgstr "Afficher des courbes de niveaux formées par les points ayant le même p msgid "Show Bone X-Ray" -msgstr "Afficher rayons X d’os" +msgstr "Afficher les rayons X d’os" msgid "Show the bone selection overlay" @@ -101277,7 +101321,7 @@ msgstr "Facteur pour les vallées de cavité" msgid "Show material color" -msgstr "Afficher couleur de matériau" +msgstr "Afficher la couleur du matériau" msgid "Show scene in a single color" @@ -101393,7 +101437,7 @@ msgstr "Cavité" msgid "Show Cavity" -msgstr "Afficher cavité" +msgstr "Afficher la cavité" msgid "Show Object Outline" @@ -101413,7 +101457,7 @@ msgstr "Rendre les reflets spéculaires" msgid "Show X-Ray" -msgstr "Afficher rayons X" +msgstr "Afficher les rayons X" msgid "Show whole scene transparent" @@ -101513,15 +101557,15 @@ msgstr "L’éclairage est fixe et ne suit pas la caméra" msgid "Show VR Controllers" -msgstr "Afficher contrôleurs VR" +msgstr "Afficher les contrôleurs VR" msgid "Show Landmarks" -msgstr "Afficher points de référence" +msgstr "Afficher les points de référence" msgid "Show VR Camera" -msgstr "Afficher caméra VR" +msgstr "Afficher la caméra VR" msgid "X-Ray Alpha" @@ -102650,7 +102694,7 @@ msgstr "Afficher un contrôleur clair avec un rayon de visée" msgid "Show Controllers" -msgstr "Afficher contrôleurs" +msgstr "Afficher les contrôleurs" msgid "Show VR controllers (requires VR actions for controller poses)" @@ -102658,7 +102702,7 @@ msgstr "Afficher les contrôleurs VR (nécessite les actions VR pour les poses d msgid "Show Custom Overlays" -msgstr "Afficher surimpressions personnalisées" +msgstr "Afficher les surimpressions personnalisées" msgid "Show custom VR overlays" @@ -102666,15 +102710,15 @@ msgstr "Afficher des surimpressions personnalisées en VR" msgid "Show Object Extras" -msgstr "Afficher objets supplémentaires" +msgstr "Afficher les objets supplémentaires" msgid "Show object extras, including empties, lights, and cameras" -msgstr "Afficher objets supplémentaires, dont les vides, les éclairages et les caméras" +msgstr "Afficher les objets supplémentaires, dont les vides, les éclairages et les caméras" msgid "Show Selection" -msgstr "Afficher sélection" +msgstr "Afficher la sélection" msgid "Show selection outlines" @@ -105042,7 +105086,7 @@ msgstr "Plan Z" msgctxt "WindowManager" msgid "Clear Constraints" -msgstr "Effacer contraintes" +msgstr "Effacer les contraintes" msgctxt "WindowManager" @@ -105253,12 +105297,24 @@ msgid "Requires NVIDIA GPU with compute capability %s" msgstr "GPU NVIDIA avec capacité de calcul %s" +msgid "Requires AMD GPU with Vega or RDNA architecture" +msgstr "GPU AMD avec architecture Vega ou RDNA" + + msgid "and NVIDIA driver version %s or newer" msgstr "et pilote NVIDIA en version %s ou plus nécessaires" -msgid "Requires AMD GPU with Vega or RDNA architecture" -msgstr "GPU AMD avec architecture Vega ou RDNA" +msgid "Requires Intel GPU with Xe-HPG architecture" +msgstr "GPU Intel avec architecture Xe-HPG" + + +msgid "Requires Intel GPU with Xe-HPG architecture and" +msgstr "GPU Intel nécessaire avec architecture Xe-HPG et" + + +msgid " - oneAPI Level-Zero Loader" +msgstr " - chargeur oneAPI Level-Zero" msgid "and AMD Radeon Pro %s driver or newer" @@ -105269,10 +105325,6 @@ msgid "and AMD driver version %s or newer" msgstr "et pilote AMD en version %s ou plus nécessaires" -msgid "Requires Intel GPU with Xe-HPG architecture" -msgstr "GPU Intel avec architecture Xe-HPG" - - msgid "and Windows driver version %s or newer" msgstr "et pilote Windows en version %s ou plus nécessaires" @@ -105285,18 +105337,10 @@ msgid "or AMD with macOS %s or newer" msgstr "ou AMD avec macOS %s ou plus nécessaire" -msgid "Requires Intel GPU with Xe-HPG architecture and" -msgstr "GPU Intel nécessaire avec architecture Xe-HPG et" - - msgid " - intel-level-zero-gpu version %s or newer" msgstr " - intel-level-zero-gpu version %s ou plus" -msgid " - oneAPI Level-Zero Loader" -msgstr " - chargeur oneAPI Level-Zero" - - msgid "Noise Threshold" msgstr "Seuil de bruit" @@ -105611,7 +105655,7 @@ msgstr "Impossible d’ouvrir le fichier %r (%s)" msgctxt "Operator" msgid "Display Variant" -msgstr "Afficher variante" +msgstr "Afficher une variante" msgctxt "Operator" @@ -106083,10 +106127,6 @@ msgid "Invert Selection" msgstr "Inverser sélection" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}] : \"{}\" ({})" - - msgid "Tracking" msgstr "Suivi" @@ -106178,15 +106218,15 @@ msgid "Restore" msgstr "Restaurer" -msgid "%s (Global)" -msgstr "%s (Global)" - - msgctxt "WindowManager" msgid "Add New" msgstr "Ajouter nouveau" +msgid "%s (Global)" +msgstr "%s (Global)" + + msgctxt "Operator" msgid "New" msgstr "Nouvelle" @@ -106394,7 +106434,7 @@ msgstr "« %s » ignoré, pas le même nombre de sommets" msgid "Expected one other selected mesh object to copy from" -msgstr "Un autre objet duquel copier est censé être sélectionné" +msgstr "Un autre objet à partir duquel copier est censé être sélectionné" msgid "No animation data to convert on object: %r" @@ -106501,14 +106541,6 @@ msgid "Current frame not within strip framerange" msgstr "La frame actuelle n’est pas dans l’intervalle de frames de la bande" -msgid "Remove Add-on: %r?" -msgstr "Enlever add-on : %r ?" - - -msgid "Path: %r" -msgstr "Chemin : %r" - - msgid "Reload Start-Up file to restore settings" msgstr "Recharger le fichier de démarrage pour restaurer les réglages" @@ -106573,6 +106605,14 @@ msgid "Source file is in the add-on search path: %r" msgstr "Le fichier source est dans le chemin de recherche d’add-ons : %r" +msgid "Remove Add-on: %r?" +msgstr "Enlever add-on : %r ?" + + +msgid "Path: %r" +msgstr "Chemin : %r" + + msgid "Active face must be a quad" msgstr "La face active doit être un quadrilatère" @@ -106593,10 +106633,6 @@ msgid "See OperatorList.txt text block" msgstr "Voir le bloc de texte OperatorList.txt" -msgid "Rename %d %s" -msgstr "Renommer %d %s" - - msgid "Renamed %d of %d %s" msgstr "%d sur %d %s renommé(es)" @@ -106614,18 +106650,6 @@ msgid "Open..." msgstr "Ouvrir…" -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "Date : %s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "Hash : %sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "Branche : %sutf-8replace" - - msgid "Blender is free software" msgstr "Blender est un logiciel libre" @@ -106690,11 +106714,6 @@ msgid "Spacebar" msgstr "Barre d’espace" -msgctxt "Operator" -msgid "Load %d.%d SettingsOperator" -msgstr "Récupérer les paramètres de %d.%d" - - msgctxt "Operator" msgid "Save New Settings" msgstr "Enregistrer les nouveaux paramètres" @@ -106719,10 +106738,6 @@ msgid "Development Fund" msgstr "Fonds de développement" -msgid "Windowing Environment: %s" -msgstr "Système de fenêtrage : %s" - - msgctxt "Operator" msgid "Credits" msgstr "Crédits" @@ -106906,6 +106921,10 @@ msgid "Strip From" msgstr "Retirer depuis" +msgid "Rename %d %s" +msgstr "Renommer %d %s" + + msgid "Date: %s %s" msgstr "Date : %s %s" @@ -106936,7 +106955,11 @@ msgstr "Expression régulière invalide (chercher) : " msgctxt "Operator" msgid "Load %d.%d Settings" -msgstr "Récupérer les paramètres de %d.%d" +msgstr "Charger les paramètres de %d.%d" + + +msgid "Windowing Environment: %s" +msgstr "Système de fenêtrage : %s" msgid "Type \"%s\" can not be found" @@ -107372,7 +107395,7 @@ msgstr "Tout fusionner" msgctxt "Operator" msgid "Copy Layer to Selected" -msgstr "Copier calque vers sélectionnés" +msgstr "Copier le calque vers sélectionnés" msgctxt "Operator" @@ -107458,10 +107481,6 @@ msgid "Apply All Shape Keys" msgstr "Appliquer toutes les clés de forme" -msgid "%s ▶ %s" -msgstr "%s ▶ %s" - - msgid "Name collisions: , " msgstr "Collision de noms : " @@ -107709,11 +107728,11 @@ msgstr "Les couleurs de canaux sont désactivées dans les préférences d’ani msgid "Display Cursor" -msgstr "Afficher curseur" +msgstr "Afficher le curseur" msgid "Show Fill Color While Drawing" -msgstr "Afficher couleur de remplissage durant le dessin" +msgstr "Afficher la couleur de remplissage durant le dessin" msgid "Cursor Color" @@ -108033,12 +108052,12 @@ msgstr "Inverser pour gratter" msgctxt "Operator" msgid "Copy Active to Selected Objects" -msgstr "Copier actif vers objets sélectionnés" +msgstr "Copier l’actif vers les objets sélectionnés" msgctxt "Operator" msgid "Copy All to Selected Objects" -msgstr "Copier tous vers objets sélectionnés" +msgstr "Copier tous vers les objets sélectionnés" msgid "Quality Steps" @@ -108130,24 +108149,12 @@ msgid "Hair dynamics disabled" msgstr "Dynamique de poils désactivée" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Itérations : %d … %d (moy. %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Erreur : %.5f … %.5f (moy. %.5f)" - - msgid "Multiply Mass with Size" msgstr "Multiplier masse par taille" -msgid "Spacing: %g" -msgstr "Espacement : %g" - - msgid "Show Emitter" -msgstr "Afficher émetteur" +msgstr "Afficher l’émetteur" msgid "Fade Distance" @@ -108190,10 +108197,6 @@ msgid "Coordinate System" msgstr "Système de coordonnées" -msgid "%d fluid particles for this frame" -msgstr "%d particules fluides pour cette frame" - - msgctxt "Operator" msgid "Delete Edit" msgstr "Supprimer édition" @@ -108207,6 +108210,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "Le pourcentage d’affichage rend les dynamiques imprécises, sans précalcul" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Itérations : %d … %d (moy. %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Erreur : %.5f … %.5f (moy. %.5f)" + + +msgid "Spacing: %g" +msgstr "Espacement : %g" + + msgid "Not yet functional" msgstr "Pas encore fonctionnel" @@ -108221,6 +108236,10 @@ msgid "Disconnect All" msgstr "Tout déconnecter" +msgid "%d fluid particles for this frame" +msgstr "%d particules fluides pour cette frame" + + msgid "Speed Multiplier" msgstr "Multiplicateur de vélocité" @@ -108681,6 +108700,10 @@ msgid "This object is part of a compound shape" msgstr "Cet objet fait partie d’une forme combinée" +msgid "Second" +msgstr "Seconde" + + msgid "X Stiffness" msgstr "Raideur en X" @@ -108897,11 +108920,6 @@ msgid "Unknown add-ons" msgstr "Add-ons inconnus" -msgctxt "Operator" -msgid "%s: %s" -msgstr "%s : %s" - - msgid "category" msgstr "catégorie" @@ -109138,7 +109156,7 @@ msgstr "Inverser" msgctxt "Operator" msgid "Show Tracks" -msgstr "Afficher pistes" +msgstr "Afficher les pistes" msgid "Normalization" @@ -109181,11 +109199,6 @@ msgid "Tracks for Rotation/Scale" msgstr "Pistes pour rotation/échelle" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Zoom %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "Ajuster vue" @@ -109206,14 +109219,14 @@ msgid "Frame All Fit" msgstr "Cadrer sur tout, remplir" -msgid "Solve error: %.2f px" -msgstr "Erreur de solution : %.2f px" - - msgid "Zoom %d:%d" msgstr "Zoom %d:%d" +msgid "Solve error: %.2f px" +msgstr "Erreur de solution : %.2f px" + + msgctxt "Operator" msgid "Copy as Script" msgstr "Copier en tant que script" @@ -109527,7 +109540,7 @@ msgstr "Aucun asset actif" msgctxt "Operator" msgid "Clear Asset (Set Fake User)" -msgstr "Effacer asset (définir utilisateur factice)" +msgstr "Effacer l’asset (définir utilisateur factice)" msgid "Asset Catalog:" @@ -109657,7 +109670,7 @@ msgstr "Arêtes modifiées" msgid "Show Same Material" -msgstr "Afficher même matériau" +msgstr "Afficher le même matériau" msgctxt "Operator" @@ -109762,7 +109775,7 @@ msgstr "Désépingler" msgctxt "Operator" msgid "Clear Seam" -msgstr "Effacer couture UV" +msgstr "Effacer la couture UV" msgctxt "Operator" @@ -109987,12 +110000,12 @@ msgstr "Rechercher…" msgctxt "Operator" msgid "Backdrop Move" -msgstr "Déplacer fond" +msgstr "Déplacer le fond" msgctxt "Operator" msgid "Fit Backdrop to Available Space" -msgstr "Adapter la vue de fond à l’espace disponible" +msgstr "Adapter l’image de fond à l’espace disponible" msgctxt "Operator" @@ -110068,7 +110081,7 @@ msgstr "Éditer" msgctxt "Operator" msgid "Clear Viewer" -msgstr "Effacer visualiseur" +msgstr "Effacer le visualiseur" msgctxt "Operator" @@ -110599,10 +110612,6 @@ msgid "Default Fade" msgstr "Fondu par défaut" -msgid "Original frame range: %d-%d (%d)" -msgstr "Intervalle de frame original : %d–%d (%d)" - - msgid "Strip Offset Start" msgstr "Décalage début de bande" @@ -110624,7 +110633,7 @@ msgstr "Zoom fractionnel de prévis." msgid "Show Separate Color Channels" -msgstr "Afficher canaux de couleurs séparés" +msgstr "Afficher les canaux de couleurs séparés" msgctxt "Operator" @@ -110649,12 +110658,12 @@ msgstr "Supprimer bande et données" msgctxt "Operator" msgid "Copy Modifiers to Selection" -msgstr "Copier modificateurs vers la sélection" +msgstr "Copier les modificateurs vers la sélection" msgctxt "Operator" msgid "Clear Fade" -msgstr "Effacer fondu" +msgstr "Effacer le fondu" msgctxt "Operator" @@ -110666,14 +110675,6 @@ msgid "Effect Fader" msgstr "Effet de fondu" -msgid "%dx%d" -msgstr "%d×%d" - - -msgid "%.2f" -msgstr "%.2f" - - msgid "Original Frame Range" msgstr "Intervalle de frames original" @@ -110698,8 +110699,8 @@ msgid "Pack" msgstr "Empaqueter" -msgid "%d Hz" -msgstr "%d Hz" +msgid "Original frame range: %d-%d (%d)" +msgstr "Intervalle de frame original : %d–%d (%d)" msgid "Source Channel" @@ -111140,11 +111141,6 @@ msgid "Load Factory Blender Settings" msgstr "Charger les réglages d’usine de Blender" -msgctxt "Operator" -msgid "Load Factory %s Settings" -msgstr "Charger les réglages d’usine pour %s" - - msgctxt "Operator" msgid "Collada (.dae)" msgstr "Collada (.dae)" @@ -111250,6 +111246,11 @@ msgid "NLA Strip Name" msgstr "Nom de la bande NLA" +msgctxt "Operator" +msgid "Load Factory %s Settings" +msgstr "Charger les réglages d’usine pour %s" + + msgid "Auto-Save Preferences" msgstr "Enregistrer les préférences automatiquement" @@ -111417,7 +111418,7 @@ msgstr "Texte d’infos en surimpression" msgid "View Name" -msgstr "Afficher nom" +msgstr "Afficher le nom" msgid "Playback Frame Rate (FPS)" @@ -111486,11 +111487,11 @@ msgstr "Par défaut" msgid "Timer (Minutes)" -msgstr "Fréquence (minutes)" +msgstr "Intervalle (minutes)" msgid "Show Locations" -msgstr "Afficher emplacements" +msgstr "Afficher les emplacements" msgid "Double Click Speed" @@ -111543,23 +111544,10 @@ msgid "Load Factory Blender Preferences" msgstr "Charger les préférences d’usine de Blender" -msgctxt "Operator" -msgid "Load Factory %s Preferences" -msgstr "Charger les préférences d’usine de %s" - - msgid "Requires a restart of Blender to take effect" msgstr "Nécessite un redémarrage de Blender pour prendre effet" -msgid "Color Set %d" -msgstr "Ensemble de couleurs %d" - - -msgid "Color %d" -msgstr "Couleur %d" - - msgid "Player" msgstr "Lecteur" @@ -111569,7 +111557,7 @@ msgstr "Molette" msgid "Invert Wheel Zoom Direction" -msgstr "Inverser direction du zoom" +msgstr "Inverser la direction du zoom" msgid "Fly/Walk" @@ -111600,6 +111588,14 @@ msgid "Load Factory %s Preferences" msgstr "Charger les préférences d’usine de %s" +msgid "Color Set %d" +msgstr "Ensemble de couleurs %d" + + +msgid "Color %d" +msgstr "Couleur %d" + + msgid "Description:" msgstr "Description :" @@ -111616,10 +111612,6 @@ msgid "Author:" msgstr "Auteur :" -msgid "author" -msgstr "auteur" - - msgid "Version:" msgstr "Version :" @@ -112015,7 +112007,7 @@ msgstr "Supprimer images clés…" msgctxt "Operator" msgid "Clear Keyframes..." -msgstr "Effacer images clés…" +msgstr "Effacer les images clés…" msgctxt "Operator" @@ -112118,7 +112110,7 @@ msgstr "Animation des données de l’objet" msgctxt "Operator" msgid "Copy UV Maps" -msgstr "Copier cartes UV" +msgstr "Copier les cartes UV" msgid "Sculpt Curves" @@ -112196,7 +112188,7 @@ msgstr "Verrouillages" msgctxt "Operator" msgid "Box Show" -msgstr "Afficher dans rectangle" +msgstr "Afficher dans un rectangle" msgctxt "Operator" @@ -112230,7 +112222,7 @@ msgstr "Remplir masque" msgctxt "Operator" msgid "Clear Mask" -msgstr "Effacer masque" +msgstr "Effacer le masque" msgctxt "Operator" @@ -112468,7 +112460,7 @@ msgstr "Calculer chemins de mouvement" msgctxt "Operator" msgid "Clear Motion Paths" -msgstr "Effacer chemins de mouvement" +msgstr "Effacer les chemins de mouvement" msgctxt "Operator" @@ -112696,7 +112688,7 @@ msgstr "Voir sélectionné(e)s" msgid "Show Gizmos" -msgstr "Afficher gizmos" +msgstr "Afficher les gizmos" msgid "Toggle Overlays" @@ -112978,7 +112970,7 @@ msgstr "Aimanter à la surface la plus proche" msgctxt "Operator" msgid "Paste Pose Flipped" -msgstr "Coller pose inversée" +msgstr "Coller la pose inversée" msgctxt "Operator" @@ -113023,7 +113015,7 @@ msgstr "Appliquer sélectionnés comme pose de repos" msgctxt "Operator" msgid "Paste X-Flipped Pose" -msgstr "Coller poses X-inversées" +msgstr "Coller les poses inversées en X" msgid "Vertex Context Menu" @@ -113077,7 +113069,7 @@ msgstr "Tourner arête à gauche" msgctxt "Operator" msgid "Clear Sharp" -msgstr "Effacer dureté" +msgstr "Effacer la dureté" msgctxt "Operator" @@ -113112,22 +113104,22 @@ msgstr "Recalculer à l’intérieur" msgctxt "Operator" msgid "Copy Vectors" -msgstr "Copier vecteurs" +msgstr "Copier les vecteurs" msgctxt "Operator" msgid "Paste Vectors" -msgstr "Coller vecteurs" +msgstr "Coller les vecteurs" msgctxt "Operator" msgid "Reset Vectors" -msgstr "Réinitialiser vecteurs" +msgstr "Réinitialiser les vecteurs" msgctxt "Operator" msgid "Smooth Edges" -msgstr "Adoucir arêtes" +msgstr "Adoucir les arêtes" msgctxt "Operator" @@ -113137,12 +113129,12 @@ msgstr "Sommets pointus" msgctxt "Operator" msgid "Delete Segment" -msgstr "Supprimer segment" +msgstr "Supprimer le segment" msgctxt "Operator" msgid "Delete Point" -msgstr "Supprimer point" +msgstr "Supprimer le point" msgctxt "Operator" @@ -113162,7 +113154,7 @@ msgstr "Degré" msgctxt "Operator" msgid "Multiplication Sign" -msgstr "Multiplication" +msgstr "Signe multiplication" msgctxt "Operator" @@ -113440,12 +113432,12 @@ msgstr "Supprimer faces" msgctxt "Operator" msgid "Clear Freestyle Edge" -msgstr "Effacer arête Freestyle" +msgstr "Effacer l’arête Freestyle" msgctxt "Operator" msgid "Clear Freestyle Face" -msgstr "Effacer face Freestyle" +msgstr "Effacer la face Freestyle" msgid "Specular Lighting" @@ -113719,7 +113711,7 @@ msgstr "Détails" msgctxt "Operator" msgid "Remesh" -msgstr "Remesh" +msgstr "Remailler" msgid "Tile Offset" @@ -113890,6 +113882,10 @@ msgid "File written by newer Blender binary (%d.%d), expect loss of data!" msgstr "Fichier écrit par un binaire Blender plus récent (%d.%d), attendez-vous à des pertes de données !" +msgid "File could not be read, critical data corruption detected" +msgstr "Le fichier n’a pas pu être lu, une corruption critique des données a été détectée" + + msgid "Loading failed: " msgstr "Le chargement a échoué : " @@ -115242,7 +115238,7 @@ msgstr "Zone d’animation active attendue" msgid "Paste driver: no driver to paste" -msgstr "Coller contrôleur : pas de contrôleur à coller" +msgstr "Coller le contrôleur : pas de contrôleur à coller" msgid "No driver to copy variables from" @@ -115314,7 +115310,7 @@ msgstr "" msgid "No RNA pointer available to retrieve values for this fcurve" -msgstr "Aucun pointeur RNA disponible pour y récupérer des valeurs pour cette F-courbe" +msgstr "Aucun pointeur RNA disponible duquel obtenir des valeurs pour cette F-courbe" msgid "No F-Curve to add keyframes to" @@ -115322,7 +115318,7 @@ msgstr "Pas de F-courbe à laquelle ajouter des images clés" msgid "No RNA pointer available to retrieve values for keyframing from" -msgstr "Pas de pointeur RNA de disponible pour y récupérer des valeurs pour la création d’images clés" +msgstr "Pas de pointeur RNA de disponible duquel obtenir des valeurs pour la création d’images clés" msgid "No ID block and/or AnimData to delete keyframe from" @@ -115662,7 +115658,7 @@ msgstr "Les actions de cette armature seront détruites par cette nouvelle pose msgid "No pose to copy" -msgstr "Pas de pose à copier" +msgstr "Aucune pose à copier" msgid "Copied pose to buffer" @@ -116143,7 +116139,7 @@ msgstr "Pas implémenté !" msgid "No strokes to paste, select and copy some points before trying again" -msgstr "Pas de traits à coller, sélectionner et copier des points avant de réessayer" +msgstr "Aucune trait à coller, sélectionner et copier des points avant de réessayer" msgid "Can not paste strokes when active layer is hidden or locked" @@ -116492,12 +116488,12 @@ msgstr "Insérer une seule image clé" msgctxt "Operator" msgid "Clear Keyframes" -msgstr "Effacer images clés" +msgstr "Effacer les images clés" msgctxt "Operator" msgid "Clear Single Keyframes" -msgstr "Effacer images clés d’une seule propriété" +msgstr "Effacer les images clés d’une seule propriété" msgctxt "Operator" @@ -116577,7 +116573,7 @@ msgstr "Copier une seule vers sélectionnés" msgctxt "Operator" msgid "Copy Full Data Path" -msgstr "Copier chemin de données complet" +msgstr "Copier le chemin de données complet" msgctxt "Operator" @@ -116822,7 +116818,7 @@ msgstr "Placer en dernier" msgid "Flip Color Ramp" -msgstr "Inverser dégradé de couleur" +msgstr "Inverser le dégradé de couleur" msgid "Distribute Stops from Left" @@ -118503,7 +118499,7 @@ msgstr "Le changement de forme ne peut fonctionner qu’avec de plus hauts nivea msgid "Second selected mesh object required to copy shape from" -msgstr "Un second objet maillage sélectionné est requis, d’où copier la forme" +msgstr "Un second objet maillage doit être sélectionné, d’où copier la forme" msgid "Objects do not have the same number of vertices" @@ -118683,27 +118679,27 @@ msgstr "Déplacer la souris pour changer la taille de voxel. Ctrl : Échelle re msgid "Voxel remesher cannot run with a voxel size of 0.0" -msgstr "Le remesher voxel ne peut être utilisé avec une taille de voxel de 0.0" +msgstr "Le remailleur par voxels ne peut être utilisé avec une taille de voxel de 0.0" msgid "Voxel remesher failed to create mesh" -msgstr "Le remesher voxel n’a pas pu créer le maillage" +msgstr "Le remailleur par voxels n’a pas pu créer le maillage" msgid "The remesher cannot work on linked or override data" -msgstr "Le remesher ne fonctionne pas sur des données liées ou redéfinies" +msgstr "Le remailleur ne fonctionne pas sur des données liées ou redéfinies" msgid "The remesher cannot run from edit mode" -msgstr "Le remesher ne fonctionne pas en mode édition" +msgstr "Le remailleur ne fonctionne pas en mode édition" msgid "The remesher cannot run with dyntopo activated" -msgstr "Le remesher ne fonctionne pas quand la topologie dynamique est activée" +msgstr "Le remailleur ne fonctionne pas quand la topologie dynamique est activée" msgid "The remesher cannot run with a Multires modifier in the modifier stack" -msgstr "Le remesher ne fonctionne pas avec un modificateur multirésolutions dans la pile de modificateurs" +msgstr "Le remailleur ne fonctionne pas si un modificateur Multirésolutions se trouve dans la pile de modificateurs" msgid "Select Collection" @@ -118895,7 +118891,7 @@ msgstr "%d poids de sommet limités" msgid "Copy vertex groups to selected: %d done, %d failed (object data must support vertex groups and have matching indices)" -msgstr "Copier groupes de sommets vers sélection : %d effectués, %d ont échoué (les données d’objet doivent prendre en charge les groupes de sommets et avoir des indices correspondants)" +msgstr "Copier les groupes de sommets vers la sélection : %d effectués, %d ont échoué (les données d’objet doivent prendre en charge les groupes de sommets et avoir des indices correspondants)" msgid "No active editable object" @@ -119375,7 +119371,7 @@ msgstr "Afficher les paramètres de l’outil" msgid "Show Footer" -msgstr "Afficher pied de page" +msgstr "Afficher le pied de page" msgid "Flip to Right" @@ -120397,7 +120393,7 @@ msgstr "Impossible d’ajouter le modificateur (voir la console pour les détail msgid "No F-Modifiers available to be copied" -msgstr "Pas de F-modificateurs à copier" +msgstr "Aucun F-modificateur à copier" msgid "No F-Modifiers to paste" @@ -120820,10 +120816,6 @@ msgid "Undefined Socket Type" msgstr "Type de prise non-défini" -msgid "Group Input " -msgstr "Entrée groupe " - - msgid "Could not determine type of group node" msgstr "Impossible de déterminer le type de groupe de nœuds" @@ -121358,7 +121350,7 @@ msgstr "Aucun élément actif à renommer" msgid "No selected data-blocks to copy" -msgstr "Pas de blocs de donnée sélectionnés à copier" +msgstr "Aucun bloc de données sélectionné à copier" msgid "No data to paste" @@ -122146,7 +122138,7 @@ msgstr "Profondeur trop grande" msgid "No objects to paste" -msgstr "Pas d’objet à coller" +msgstr "Aucun objet à coller" msgid "Copied %d selected object(s)" @@ -123116,6 +123108,14 @@ msgid "Driver not found in this animation data" msgstr "Le contrôleur est introuvable dans les données d’animation" +msgid "%s '%s' is too long, maximum length is %d" +msgstr "%s « %s » est trop long, la longueur maximale est %d" + + +msgid "%s '%s', bl_idname '%s' %s" +msgstr "%s '%s', bl_idname '%s' %s" + + msgid "NlaTrack '%s' cannot be removed" msgstr "Impossible d’enlever la piste NLA « %s »" @@ -123691,22 +123691,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "La bande NLA « %s » est introuvable dans la piste « %s »" -msgid "Functions" -msgstr "Fonctions" - - -msgid "Comparison" -msgstr "Comparaison" - - -msgid "Trigonometric" -msgstr "Trigonométrique" - - -msgid "Conversion" -msgstr "Conversion" - - msgid "CustomGroup" msgstr "GroupePersonnalisé" @@ -123747,6 +123731,10 @@ msgid "Unable to move sockets in built-in node" msgstr "Impossible de déplacer des prises d’un nœud intégré" +msgid "%s '%s', bl_idname '%s' could not be unregistered" +msgstr "%s '%s', bl_idname '%s' n’a pas pu être déchargé" + + msgid "Node tree '%s' has undefined type %s" msgstr "L’arborescence de nœuds « %s » a un type indéfini %s" @@ -124092,6 +124080,14 @@ msgid "Region not found in space type" msgstr "La région est introuvable dans le type d’espace" +msgid "%s '%s' has category '%s' " +msgstr "%s '%s' a la catégorie '%s'" + + +msgid "%s parent '%s' for '%s' not found" +msgstr "%s parent '%s' introuvable pour '%s'" + + msgid "Add-on is no longer valid" msgstr "L’add-on n’est plus valide" @@ -124172,6 +124168,10 @@ msgid "GizmoType '%s' is for a 3D gizmo-group. The 'draw_select' callback is set msgstr "Le type de gizmo « %s » est pour un groupe de gizmos 3D. Le callback 'draw_select' est défini mais seul 'test_select' sera utilisé" +msgid "%s area type does not support gizmos" +msgstr "Le type de zone %s ne prend pas en charge les gizmos" + + msgid "Gizmo target property '%s.%s' not found" msgstr "La propriété cible « %s.%s » du gizmo est introuvable" @@ -124571,7 +124571,7 @@ msgstr "Convertir en maillage" msgid "Built without Remesh modifier" -msgstr "Compilé sans le modificateur Remesh" +msgstr "Compilé sans le modificateur Remaillage" msgid "Axis Object" @@ -124587,7 +124587,7 @@ msgstr "Étirer UV" msgid "SimpleDeform" -msgstr "DéformerSimple" +msgstr "DéformationSimple" msgid "Create Armature" @@ -125414,7 +125414,7 @@ msgstr "Si la spline de profil est cyclique, remplir les extrémités du maillag msgid "The control point to retrieve data from" -msgstr "Le point de contrôle duquel récupérer les données" +msgstr "Le point de contrôle duquel obtenir les données" msgid "The curve the control point is part of" @@ -125430,7 +125430,7 @@ msgstr "L’avancée du point le long de sa courbe" msgid "The curve to retrieve data from. Defaults to the curve from the context" -msgstr "La courbe de laquelle récupérer les données. Utilise la courbe à partir du contexte par défaut" +msgstr "La courbe de laquelle obtenir les données. Utilise la courbe à partir du contexte par défaut" msgid "Values used to sort the curve's points. Uses indices by default" @@ -125486,15 +125486,15 @@ msgstr "La surface n’a pas de maillage" msgid "Evaluated surface missing UV map: \"%s\"" -msgstr "Il manque une carte UV à la surface évaluée : \"%s\"" +msgstr "Il manque une carte UV à la surface évaluée : \"%s\"" msgid "Original surface missing UV map: \"%s\"" -msgstr "Il manque une carte UV à la surface originale : \"%s\"" +msgstr "Il manque une carte UV à la surface originale : \"%s\"" msgid "Evaluated surface missing attribute: \"rest_position\"" -msgstr "Il manque un attribut à la surface évaluée : \"rest_position\"" +msgstr "Il manque un attribut à la surface évaluée : \"rest_position\"" msgid "Curves are not attached to any UV map" @@ -125998,7 +125998,7 @@ msgstr "Désactivé, Blender a été compilé sans OpenSubdiv" msgid "The face to retrieve data from. Defaults to the face from the context" -msgstr "La face de laquelle récupérer les données. Utilise la face à partir du contexte par défaut" +msgstr "La face de laquelle obtenir les données. Utilise la face à partir du contexte par défaut" msgid "Values used to sort the face's corners. Uses indices by default" @@ -126026,7 +126026,7 @@ msgstr "Indice sommet" msgid "The vertex to retrieve data from. Defaults to the vertex from the context" -msgstr "Le sommet duquel récupérer les données. Utilise le sommet à partir du contexte par défaut" +msgstr "Le sommet duquel obtenir les données. Utilise le sommet à partir du contexte par défaut" msgid "Values used to sort corners attached to the vertex. Uses indices by default" @@ -126042,7 +126042,7 @@ msgstr "Nombre de faces ou de coins connectés à chaque sommet" msgid "The corner to retrieve data from. Defaults to the corner from the context" -msgstr "Le coin duquel récupérer les données. Utilise le coin à partir du contexte par défaut" +msgstr "Le coin duquel obtenir les données. Utilise le coin à partir du contexte par défaut" msgid "Next Edge Index" @@ -126182,7 +126182,7 @@ msgstr "Impossible de supprimer l’attribut prédéfini nommé \"" msgid "Which element to retrieve a value from on the geometry" -msgstr "Depuis quel élément récupérer une valeur sur la géométrie" +msgstr "Depuis quel élément obtenir une valeur sur la géométrie" msgid "The source geometry must contain a mesh or a point cloud" @@ -127828,7 +127828,7 @@ msgstr "Voir la vue 3D avec des lunettes de réalité virtuelle (visiocasques)" msgid "Copy Global Transform" -msgstr "Copier transformations globales" +msgstr "Copier les transformations globales" msgid "N-panel in the 3D Viewport" @@ -128240,7 +128240,7 @@ msgstr "Abkhaz (Аԥсуа бызшәа)" msgid "Thai (ภาษาไทย)" -msgstr "Thai (ภาษาไทย)" +msgstr "Thaï (ภาษาไทย)" msgid "Slovak (Slovenčina)" @@ -128252,7 +128252,7 @@ msgstr "Géorgien (ქართული)" msgid "Complete" -msgstr "Complètes" +msgstr "Achevées" msgid "In Progress" diff --git a/locale/po/ha.po b/locale/po/ha.po index 23188eb24c1..e0442f3f2bf 100644 --- a/locale/po/ha.po +++ b/locale/po/ha.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2017-12-25 14:01+0100\n" "Last-Translator: UMAR HARUNA ABDULLAHI \n" "Language-Team: BlenderNigeria \n" diff --git a/locale/po/he.po b/locale/po/he.po index 03c1ed7a607..424f42927aa 100644 --- a/locale/po/he.po +++ b/locale/po/he.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2012-10-07 13:56+0300\n" "Last-Translator: Barak Itkin \n" "Language-Team: LANGUAGE \n" diff --git a/locale/po/hi.po b/locale/po/hi.po index 9cba1770f99..ea25519b0ca 100644 --- a/locale/po/hi.po +++ b/locale/po/hi.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2015-03-03 16:21+0530\n" "Last-Translator: Roshan Lal Gumasta \n" "Language-Team: Hindi \n" @@ -1541,10 +1541,6 @@ msgid "Time" msgstr "समय" -msgid "Number" -msgstr "संख्या" - - msgid "Delete" msgstr "मिटाएँ" @@ -1854,14 +1850,6 @@ msgid "Add Color" msgstr "रंग जोड़ें" -msgid "Root" -msgstr "मूल" - - -msgid "Sharp" -msgstr "पैना" - - msgid "Repeat" msgstr "दोहराएँ" @@ -2478,6 +2466,10 @@ msgid "Roughness 2" msgstr "खुरदरापन २" +msgid "Number" +msgstr "संख्या" + + msgid "Show particle number" msgstr "कण संख्या दिखाएँ" @@ -2567,10 +2559,6 @@ msgid "Modified" msgstr "संशोधित" -msgid "Lines" -msgstr "लाइनों" - - msgid "Register" msgstr "पंजीकृत करें" @@ -2623,6 +2611,10 @@ msgid "Calculate Alpha" msgstr "पारदर्शिता गणना" +msgid "Sharp" +msgstr "पैना" + + msgid "Sin" msgstr "ज्या" @@ -3025,6 +3017,10 @@ msgid "Seam" msgstr "सीवन" +msgid "Root" +msgstr "मूल" + + msgid "Ball" msgstr "गेंद" @@ -3146,6 +3142,10 @@ msgid "Use distance between affected object's vertices and target object, or tar msgstr "प्रभावित ऑब्जेक्ट सकें और लक्ष्य ऑब्जेक्ट के बीच दूरी का उपयोग करें, या लक्ष्य वस्तु की ज्यामिति" +msgid "Lines" +msgstr "लाइनों" + + msgid "Tracks" msgstr "पटरियां" @@ -5542,10 +5542,6 @@ msgid "Update Trunk" msgstr "अद्यतन ट्रंक" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgctxt "Operator" msgid "New" msgstr "नई" @@ -5698,6 +5694,10 @@ msgid "Roughness End" msgstr "खुरदरापन समाप्त" +msgid "Use Timing" +msgstr "समय का उपयोग करें" + + msgid "Spacing: %g" msgstr "रिक्ति: %g" @@ -5706,10 +5706,6 @@ msgid "%d fluid particles for this frame" msgstr "इस गठन के लिए %d तरल पदार्थ कणों" -msgid "Use Timing" -msgstr "समय का उपयोग करें" - - msgid "Structural" msgstr "संरचनात्मक" @@ -6021,10 +6017,6 @@ msgid "Author:" msgstr "लेखक:" -msgid "author" -msgstr "लेखक" - - msgid "Version:" msgstr "संस्करण:" diff --git a/locale/po/hu.po b/locale/po/hu.po index 6b0979fe90b..538df7249b8 100644 --- a/locale/po/hu.po +++ b/locale/po/hu.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2015-02-21 19:17+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -13,9 +13,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.7.4\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -25,9 +25,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -37,9 +37,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -49,9 +49,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -61,9 +61,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -73,9 +73,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -85,9 +85,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -97,9 +97,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -109,9 +109,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -121,9 +121,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -133,9 +133,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -145,9 +145,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -157,9 +157,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -169,9 +169,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -181,9 +181,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -193,9 +193,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -205,9 +205,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -217,9 +217,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -229,9 +229,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -241,9 +241,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -253,9 +253,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -265,9 +265,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -277,9 +277,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -289,9 +289,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -301,9 +301,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -313,9 +313,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -325,9 +325,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -337,9 +337,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -349,9 +349,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -361,9 +361,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-12-27 18:52+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -373,9 +373,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.7.1\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -385,9 +385,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -397,9 +397,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -409,9 +409,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -421,9 +421,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -433,9 +433,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -445,9 +445,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -457,9 +457,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -469,9 +469,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -481,9 +481,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -493,9 +493,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -505,9 +505,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -517,9 +517,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -529,9 +529,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -541,9 +541,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -553,9 +553,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -565,9 +565,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -577,9 +577,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -589,9 +589,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -601,9 +601,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -613,9 +613,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -625,9 +625,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -637,9 +637,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -649,9 +649,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -661,9 +661,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -673,9 +673,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -685,9 +685,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -697,9 +697,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -709,9 +709,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -721,9 +721,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 17:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -733,9 +733,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -745,9 +745,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -757,9 +757,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -769,9 +769,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -781,9 +781,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -793,9 +793,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -805,9 +805,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -817,9 +817,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -829,9 +829,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -841,9 +841,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -853,9 +853,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -865,9 +865,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -877,9 +877,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -889,9 +889,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -901,9 +901,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -913,9 +913,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -925,9 +925,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -937,9 +937,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -949,9 +949,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -961,9 +961,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -973,9 +973,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -985,9 +985,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -997,9 +997,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1009,9 +1009,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1021,9 +1021,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1033,9 +1033,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1045,9 +1045,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1057,9 +1057,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1069,9 +1069,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1081,9 +1081,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2015-01-10 20:46+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1093,9 +1093,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.7.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1105,9 +1105,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1117,9 +1117,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1129,9 +1129,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1141,9 +1141,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1153,9 +1153,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1165,9 +1165,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1177,9 +1177,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1189,9 +1189,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1201,9 +1201,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1213,9 +1213,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1225,9 +1225,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1237,9 +1237,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1249,9 +1249,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1261,9 +1261,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1273,9 +1273,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1285,9 +1285,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1297,9 +1297,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1309,9 +1309,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1321,9 +1321,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1333,9 +1333,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1345,9 +1345,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1357,9 +1357,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1369,9 +1369,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1381,9 +1381,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1393,9 +1393,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1405,9 +1405,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1417,9 +1417,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1429,9 +1429,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1441,9 +1441,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-12-27 18:52+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1453,9 +1453,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.7.1\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1465,9 +1465,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1477,9 +1477,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1489,9 +1489,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1501,9 +1501,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1513,9 +1513,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1525,9 +1525,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1537,9 +1537,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1549,9 +1549,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1561,9 +1561,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1573,9 +1573,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1585,9 +1585,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1597,9 +1597,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1609,9 +1609,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1621,9 +1621,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1633,9 +1633,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1645,9 +1645,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1657,9 +1657,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1669,9 +1669,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1681,9 +1681,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1693,9 +1693,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1705,9 +1705,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1717,9 +1717,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1729,9 +1729,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1741,9 +1741,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1753,9 +1753,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1765,9 +1765,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1777,9 +1777,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1789,9 +1789,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1801,9 +1801,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 17:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1813,9 +1813,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1825,9 +1825,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1837,9 +1837,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1849,9 +1849,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1861,9 +1861,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1873,9 +1873,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1885,9 +1885,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1897,9 +1897,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1909,9 +1909,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1921,9 +1921,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1933,9 +1933,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1945,9 +1945,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1957,9 +1957,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1969,9 +1969,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -1981,9 +1981,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -1993,9 +1993,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2005,9 +2005,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2017,9 +2017,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2029,9 +2029,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2041,9 +2041,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2053,9 +2053,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2065,9 +2065,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2077,9 +2077,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2089,9 +2089,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2101,9 +2101,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2113,9 +2113,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2125,9 +2125,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2137,9 +2137,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2149,9 +2149,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2161,9 +2161,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2015-01-30 16:20+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2173,9 +2173,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.7.4\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2185,9 +2185,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2197,9 +2197,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2209,9 +2209,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2221,9 +2221,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2233,9 +2233,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2245,9 +2245,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2257,9 +2257,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2269,9 +2269,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2281,9 +2281,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2293,9 +2293,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2305,9 +2305,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2317,9 +2317,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2329,9 +2329,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2341,9 +2341,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2353,9 +2353,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2365,9 +2365,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2377,9 +2377,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2389,9 +2389,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2401,9 +2401,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2413,9 +2413,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2425,9 +2425,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2437,9 +2437,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2449,9 +2449,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2461,9 +2461,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2473,9 +2473,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2485,9 +2485,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2497,9 +2497,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2509,9 +2509,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2521,9 +2521,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-12-27 18:52+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2533,9 +2533,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.7.1\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2545,9 +2545,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2557,9 +2557,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2569,9 +2569,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2581,9 +2581,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2593,9 +2593,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2605,9 +2605,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2617,9 +2617,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2629,9 +2629,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2641,9 +2641,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2653,9 +2653,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2665,9 +2665,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2677,9 +2677,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2689,9 +2689,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2701,9 +2701,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2713,9 +2713,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2725,9 +2725,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2737,9 +2737,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2749,9 +2749,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2761,9 +2761,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2773,9 +2773,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2785,9 +2785,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2797,9 +2797,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2809,9 +2809,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2821,9 +2821,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2833,9 +2833,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2845,9 +2845,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2857,9 +2857,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2869,9 +2869,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2881,9 +2881,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 17:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2893,9 +2893,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2905,9 +2905,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2917,9 +2917,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2929,9 +2929,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2941,9 +2941,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -2953,9 +2953,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2965,9 +2965,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2977,9 +2977,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -2989,9 +2989,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3001,9 +3001,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3013,9 +3013,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3025,9 +3025,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3037,9 +3037,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3049,9 +3049,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3061,9 +3061,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3073,9 +3073,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3085,9 +3085,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3097,9 +3097,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3109,9 +3109,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3121,9 +3121,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3133,9 +3133,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3145,9 +3145,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3157,9 +3157,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3169,9 +3169,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3181,9 +3181,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3193,9 +3193,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3205,9 +3205,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3217,9 +3217,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3229,9 +3229,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3241,9 +3241,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2015-01-10 20:46+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3253,9 +3253,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.7.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3265,9 +3265,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3277,9 +3277,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3289,9 +3289,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3301,9 +3301,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3313,9 +3313,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3325,9 +3325,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3337,9 +3337,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3349,9 +3349,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3361,9 +3361,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3373,9 +3373,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3385,9 +3385,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3397,9 +3397,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3409,9 +3409,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3421,9 +3421,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3433,9 +3433,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3445,9 +3445,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3457,9 +3457,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3469,9 +3469,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3481,9 +3481,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3493,9 +3493,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3505,9 +3505,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3517,9 +3517,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3529,9 +3529,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3541,9 +3541,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3553,9 +3553,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3565,9 +3565,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3577,9 +3577,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3589,9 +3589,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3601,9 +3601,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-12-27 18:52+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3613,9 +3613,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.7.1\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3625,9 +3625,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3637,9 +3637,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3649,9 +3649,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3661,9 +3661,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3673,9 +3673,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3685,9 +3685,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3697,9 +3697,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3709,9 +3709,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3721,9 +3721,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3733,9 +3733,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3745,9 +3745,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3757,9 +3757,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3769,9 +3769,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3781,9 +3781,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3793,9 +3793,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3805,9 +3805,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3817,9 +3817,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3829,9 +3829,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3841,9 +3841,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3853,9 +3853,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3865,9 +3865,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3877,9 +3877,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3889,9 +3889,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3901,9 +3901,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3913,9 +3913,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3925,9 +3925,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3937,9 +3937,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3949,9 +3949,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3961,9 +3961,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 17:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -3973,9 +3973,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3985,9 +3985,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -3997,9 +3997,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4009,9 +4009,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4021,9 +4021,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -4033,9 +4033,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4045,9 +4045,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4057,9 +4057,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4069,9 +4069,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4081,9 +4081,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -4093,9 +4093,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4105,9 +4105,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4117,9 +4117,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4129,9 +4129,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4141,9 +4141,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-11-05 16:47+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -4153,9 +4153,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.10\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4165,9 +4165,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4177,9 +4177,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4189,9 +4189,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4201,9 +4201,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-09-08 18:25+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -4213,9 +4213,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.9\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4225,9 +4225,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4237,9 +4237,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4249,9 +4249,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4261,9 +4261,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2014-02-06 23:05+0100\n" "Last-Translator: Pomsár Miklós \n" "Language-Team: MagyarBlender \n" @@ -4273,9 +4273,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.6.3\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:27+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4285,9 +4285,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-03 20:47+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4297,9 +4297,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-09 21:29+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -4309,9 +4309,9 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Basepath: .\n" "X-Generator: Poedit 1.5.5\n" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-08-19 16:10+0100\n" "Last-Translator: Pomsár András \n" "Language-Team: MagyarBlender \n" @@ -8311,10 +8311,6 @@ msgid "Dynamic" msgstr "Dinamikus" -msgid "Sharp" -msgstr "Éles" - - msgid "Repeat" msgstr "Ismétlés" @@ -9611,10 +9607,6 @@ msgid "Memory" msgstr "Memória" -msgid "Lines" -msgstr "Vonalak" - - msgid "Register" msgstr "Regisztrálás" @@ -9647,6 +9639,10 @@ msgid "Repeat Y" msgstr "Y ismétlés" +msgid "Sharp" +msgstr "Éles" + + msgid "Octaves" msgstr "Oktávok" @@ -12925,6 +12921,10 @@ msgid "Line Thickness" msgstr "Vonalvastagság" +msgid "Lines" +msgstr "Vonalak" + + msgid "Units" msgstr "Egységek" @@ -15528,10 +15528,6 @@ msgid "Fill Range by Selection" msgstr "Terjedelem kitöltése a kijelölés alapján" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "A Terjedelem Min/Max mezők kitöltése a kijelölt térháló objektumok és a forrás objektum min/max távolsága alapján" - - msgid "Name of the modifier to work on" msgstr "Az aktuális módosító neve" diff --git a/locale/po/id.po b/locale/po/id.po index ae6db63d48c..a73aa43394b 100644 --- a/locale/po/id.po +++ b/locale/po/id.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2021-12-25 23:57-0800\n" "Last-Translator: Adriel Tristanputra \n" "Language-Team: Indonesian <>\n" @@ -9219,22 +9219,6 @@ msgid "Add Color" msgstr "Tambahkan Warna" -msgid "Smoother" -msgstr "Lebih halus" - - -msgid "Root" -msgstr "Akar" - - -msgid "Sharp" -msgstr "Tajam" - - -msgid "Sharper" -msgstr "Lebih Tajam" - - msgid "Dash Ratio" msgstr "Rasio Garis" @@ -9383,14 +9367,6 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "Nama atribut Alembic digunakan untuk generasi data blur gerakan" -msgid "Velocity Unit" -msgstr "Unit Kecepatan" - - -msgid "Second" -msgstr "Kedua" - - msgid "Field of View" msgstr "Bidang pandang" @@ -10443,6 +10419,14 @@ msgid "Use soft marble" msgstr "Gunakan marmer halus" +msgid "Sharp" +msgstr "Tajam" + + +msgid "Sharper" +msgstr "Lebih Tajam" + + msgid "Noise Texture" msgstr "Tekstur" @@ -12028,6 +12012,10 @@ msgid "Skin Vertex" msgstr "Warna Standar" +msgid "Root" +msgstr "Akar" + + msgid "Mesh Skin Vertex Layer" msgstr "Warna Standar" @@ -22939,10 +22927,6 @@ msgid "No mesh object" msgstr "Tidak ada objek mesh" -msgid "Rename %d %s" -msgstr "Ganti nama %d %s" - - msgctxt "Operator" msgid "Open..." msgstr "Buka..." @@ -23016,6 +23000,10 @@ msgid "Characters" msgstr "Karakter" +msgid "Rename %d %s" +msgstr "Ganti nama %d %s" + + msgid "Date: %s %s" msgstr "Tanggal: %s %s" @@ -23249,10 +23237,6 @@ msgid "Delete All Shape Keys" msgstr "Hapus Semua Kunci Bentuk" -msgid "%s ▶ %s" -msgstr "%s ▶ %s" - - msgctxt "Operator" msgid "Sort by Name" msgstr "Urut dari Nama" @@ -23632,18 +23616,6 @@ msgid "Strand Shape" msgstr "Partikel" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Iterations: %d .. %d (rata-rata. %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Error: %.5f .. %.5f (rata-rata. %.5f)" - - -msgid "Spacing: %g" -msgstr "Spasi: %g" - - msgid "Randomize Amplitude" msgstr "Acak Amplitudo" @@ -23660,15 +23632,23 @@ msgid "Coordinate System" msgstr "Sistem Koordinasi" -msgid "%d fluid particles for this frame" -msgstr "%d partikel cair untuk frame ini" - - msgctxt "Operator" msgid "Delete Edit" msgstr "Hapus Edit" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Iterations: %d .. %d (rata-rata. %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Error: %.5f .. %.5f (rata-rata. %.5f)" + + +msgid "Spacing: %g" +msgstr "Spasi: %g" + + msgid "Not yet functional" msgstr "Belum fungsional" @@ -23683,6 +23663,10 @@ msgid "Disconnect All" msgstr "Putuskan Semua" +msgid "%d fluid particles for this frame" +msgstr "%d partikel cair untuk frame ini" + + msgid "Speed Multiplier" msgstr "Pengali Kecepatan" @@ -23835,6 +23819,10 @@ msgid "Guide Mode" msgstr "Mode Panduan" +msgid "Second" +msgstr "Kedua" + + msgid "X Stiffness" msgstr "Kekakuan X" @@ -24048,11 +24036,6 @@ msgid "Set Keyframe B" msgstr "Set Keyframe B" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Perbesar %d:%d" - - msgctxt "Operator" msgid "Enable Markers" msgstr "Gunakan Tanda" @@ -24063,14 +24046,14 @@ msgid "Frame All Fit" msgstr "Semua Frame Cukup/Fit" -msgid "Solve error: %.2f px" -msgstr "Memecahkan error: %.2f px" - - msgid "Zoom %d:%d" msgstr "Perbesar %d:%d" +msgid "Solve error: %.2f px" +msgstr "Memecahkan error: %.2f px" + + msgctxt "Operator" msgid "Copy as Script" msgstr "Salin sebagai Skrip" @@ -24771,10 +24754,6 @@ msgid "Clip" msgstr "Klip" -msgid "%dx%d" -msgstr "%dx%d" - - msgid "Source Channel" msgstr "Saluran Sumber" @@ -24918,14 +24897,6 @@ msgid "Save as Studio light" msgstr "Simpan sebagai cahaya Studio" -msgid "Color Set %d" -msgstr "Set Warna %d" - - -msgid "Color %d" -msgstr "Warna %d" - - msgid "Player" msgstr "Pemain" @@ -24958,6 +24929,14 @@ msgid ":" msgstr ":" +msgid "Color Set %d" +msgstr "Set Warna %d" + + +msgid "Color %d" +msgstr "Warna %d" + + msgid "Description:" msgstr "Deskripsi:" @@ -24974,10 +24953,6 @@ msgid "Author:" msgstr "Pembuat:" -msgid "author" -msgstr "pembuat" - - msgid "Version:" msgstr "Versi:" @@ -26717,18 +26692,6 @@ msgid "Unable to create new strip" msgstr "Tidak dapat membuka dokumen" -msgid "Functions" -msgstr "Fungsi" - - -msgid "Comparison" -msgstr "Perbandingan" - - -msgid "Conversion" -msgstr "Konversi" - - msgid "Vertex not in group" msgstr "Warna Standar" diff --git a/locale/po/it.po b/locale/po/it.po index 58e63d8eb3b..268d6543e15 100644 --- a/locale/po/it.po +++ b/locale/po/it.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2022-01-21 16:08+0100\n" "Last-Translator: MT\n" "Language-Team: blend-it \n" @@ -8926,10 +8926,6 @@ msgid "Data Depth" msgstr "Profondità Dati" -msgid "Number" -msgstr "Numero" - - msgid "Randomness" msgstr "Casualità" @@ -10661,22 +10657,6 @@ msgid "Color of cursor when subtracting" msgstr "Colore del cursore quando sottrae" -msgid "Root" -msgstr "Radice" - - -msgid "Sharp" -msgstr "Nitido" - - -msgid "Sharper" -msgstr "Più Nitido" - - -msgid "Inverse Square" -msgstr "Quadratico Inverso" - - msgid "Falloff Angle" msgstr "Angolo Decadimento" @@ -11137,14 +11117,6 @@ msgid "Up" msgstr "Su" -msgid "Velocity Unit" -msgstr "Unità Velocità" - - -msgid "Second" -msgstr "Secondi" - - msgid "Camera data-block for storing camera settings" msgstr "Blocco-dati Camera per i dati le impostazioni della camera" @@ -12599,6 +12571,10 @@ msgid "Inverse Linear" msgstr "Lineare Inverso" +msgid "Inverse Square" +msgstr "Quadratico Inverso" + + msgid "Inverse Coefficients" msgstr "Coefficienti Inversi" @@ -14454,6 +14430,10 @@ msgid "Show hair simulation grid" msgstr "Mostra griglia simulazione capelli" +msgid "Number" +msgstr "Numero" + + msgid "Show particle number" msgstr "Mostra il numero delle particelle" @@ -15104,10 +15084,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "Il file di testo sul disco è differente da quello in memoria" -msgid "Lines" -msgstr "Linee" - - msgid "Lines of text" msgstr "Linee di testo" @@ -15704,10 +15680,18 @@ msgid "Use soft marble" msgstr "Utilizza marmo morbido" +msgid "Sharp" +msgstr "Nitido" + + msgid "Use more clearly defined marble" msgstr "Usa un marmo definito più chiaramente" +msgid "Sharper" +msgstr "Più Nitido" + + msgid "Use very clearly defined marble" msgstr "Usa un marmo molto ben definito" @@ -19056,6 +19040,10 @@ msgid "Radius of the skin" msgstr "Raggio della pelle" +msgid "Root" +msgstr "Radice" + + msgid "Name of skin layer" msgstr "Nome del livello pelle" @@ -21931,6 +21919,10 @@ msgid "Line Thickness" msgstr "Spessore Linea" +msgid "Lines" +msgstr "Linee" + + msgid "Motion Path Points" msgstr "Punti Percorso del Movimento" @@ -52615,10 +52607,6 @@ msgid "Invert Selection" msgstr "Inverti Selezione" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Tracciamento" @@ -53134,22 +53122,10 @@ msgid "Strand Shape" msgstr "Forma Fibra" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Ripetizioni: %d .. %d (med. %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Errore: %.5f .. %.5f (med. %.5f)" - - msgid "Multiply Mass with Size" msgstr "Moltiplica la Massa per la Dimensione" -msgid "Spacing: %g" -msgstr "Spaziatura: %g" - - msgid "Show Emitter" msgstr "Mostra Emettitore" @@ -53178,14 +53154,22 @@ msgid "Coordinate System" msgstr "Sistema di Coordinate" -msgid "%d fluid particles for this frame" -msgstr "%d particelle fluide per questo frame" - - msgid "Use Timing" msgstr "Usa Tempistica" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Ripetizioni: %d .. %d (med. %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Errore: %.5f .. %.5f (med. %.5f)" + + +msgid "Spacing: %g" +msgstr "Spaziatura: %g" + + msgid "Not yet functional" msgstr "Non ancora funzionale" @@ -53200,6 +53184,10 @@ msgid "Disconnect All" msgstr "Disconnetti Tutto" +msgid "%d fluid particles for this frame" +msgstr "%d particelle fluide per questo frame" + + msgid "Dynamic Mesh" msgstr "Mesh Dinamica" @@ -53283,6 +53271,10 @@ msgid "Fuel" msgstr "Combustibile" +msgid "Second" +msgstr "Secondi" + + msgid "Upper" msgstr "Maiuscolo" @@ -54210,10 +54202,6 @@ msgid "Rotation" msgstr "Rotazione" -msgid "Original frame range: %d-%d (%d)" -msgstr "Intervallo fotogrammi originale: %d-%d (%d)" - - msgctxt "Operator" msgid "Clip" msgstr "Filmato" @@ -54235,6 +54223,10 @@ msgid "Pack" msgstr "Comprimi" +msgid "Original frame range: %d-%d (%d)" +msgstr "Intervallo fotogrammi originale: %d-%d (%d)" + + msgid "Source Channel" msgstr "Canale Sorgente" @@ -54692,10 +54684,6 @@ msgid "Author:" msgstr "Autore:" -msgid "author" -msgstr "autore" - - msgid "Version:" msgstr "Versione:" @@ -58672,10 +58660,6 @@ msgid "Frame: %d" msgstr "Fotogramma: %d" -msgid "Group Input " -msgstr "Ingresso Gruppo " - - msgid " (String)" msgstr "(Stringa)" @@ -59707,14 +59691,6 @@ msgid "Unable to create new strip" msgstr "Impossibile creare un nuovo spezzone" -msgid "Functions" -msgstr "Funzioni" - - -msgid "Comparison" -msgstr "Confronto" - - msgid "Unable to create socket" msgstr "Impossibile creare il connettore" diff --git a/locale/po/ja.po b/locale/po/ja.po index 2e97522b51c..59b7801f46b 100644 --- a/locale/po/ja.po +++ b/locale/po/ja.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2016-10-13 03:05+0900\n" "Last-Translator: \n" "Language-Team: Japanese Translation Team (https://sites.google.com/site/blugjp/blender-translators)\n" @@ -715,8 +715,12 @@ msgid "The entire Scene / Preview range" msgstr "シーン/プレビュー範囲すべて" +msgid "Manual Range" +msgstr "手動で指定" + + msgid "Manually determined frame range" -msgstr "手動でフレーム範囲を設定します" +msgstr "手動で指定したフレーム範囲" msgid "Show Frame Numbers" @@ -1107,6 +1111,10 @@ msgid "Simple name of the asset's catalog, for debugging and data recovery purpo msgstr "アセットのカタログのシンプルな名前。デバッグとデータリカバリ用" +msgid "Copyright" +msgstr "コピーライト" + + msgid "Description" msgstr "詳細" @@ -5694,6 +5702,10 @@ msgid "Enabled" msgstr "有効" +msgid "Enable this object as a collider for physics systems" +msgstr "このオブジェクトを物理演算システムのコライダーにします" + + msgid "Single Sided" msgstr "片面" @@ -6013,7 +6025,7 @@ msgstr "色の補間方法を設定します" msgid "Near" -msgstr "接近" +msgstr "近接" msgid "Far" @@ -6048,6 +6060,10 @@ msgid "B-Spline" msgstr "Bスプライン" +msgid "Constant" +msgstr "一定" + + msgid "Color Ramp Element" msgstr "カラーランプ要素" @@ -10881,7 +10897,7 @@ msgstr "列挙アイテム定義" msgid "Definition of a choice in an RNA enum property" -msgstr "RNAのenumプロパティ内の選択の定義" +msgstr "RNAの列挙(Enum)プロパティ内の選択の定義" msgid "Description of the item's purpose" @@ -13857,10 +13873,6 @@ msgstr "" "(各セルは少なくともこのパーティクル数を持つようになります)" -msgid "Number" -msgstr "数" - - msgid "Particle number factor (higher value results in more particles)" msgstr "パーティクル係数(大きな値でパーティクルが増加)" @@ -16153,8 +16165,12 @@ msgid "Stroke start extreme cap style" msgstr "ストロークの始端を閉じるスタイル" +msgid "Init Time" +msgstr "開始時間" + + msgid "Initial time of the stroke" -msgstr "ストロークの開始の時間" +msgstr "ストローク開始の時間" msgid "Triangles" @@ -16631,6 +16647,10 @@ msgid "Texture Mapping" msgstr "テクスチャマッピング" +msgid "Change stroke UV texture values" +msgstr "ストロークの UV テクスチャ値を変更します" + + msgid "Time Offset" msgstr "タイムオフセット" @@ -18145,6 +18165,10 @@ msgid "Amount of noise to apply to thickness" msgstr "幅に適用するノイズの量" +msgid "Amount of noise to apply to UV rotation" +msgstr "UV 回転に適用するノイズの量" + + msgid "Noise Offset" msgstr "ノイズオフセット" @@ -19770,30 +19794,6 @@ msgid "Editable falloff curve" msgstr "減衰曲線を有効化します" -msgid "Curve Preset" -msgstr "カーブプリセット" - - -msgid "Smoother" -msgstr "スムーザー" - - -msgid "Root" -msgstr "ルート" - - -msgid "Sharp" -msgstr "シャープ" - - -msgid "Sharper" -msgstr "よりシャープ" - - -msgid "Inverse Square" -msgstr "逆二乗式" - - msgid "Curves Sculpt Settings" msgstr "ヘアーカーブスカルプト設定" @@ -21263,10 +21263,6 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "モーションブラーデータの生成に使用される Alembic の属性の名前" -msgid "Velocity Unit" -msgstr "速度の単位" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "" "時間に対する速度ベクトルの解釈方法\n" @@ -21274,10 +21270,6 @@ msgstr "" "「秒数」はデルタタイムが 1/FPS" -msgid "Second" -msgstr "秒数" - - msgid "Camera data-block for storing camera settings" msgstr "カメラ設定を格納するカメラデータブロック" @@ -24078,6 +24070,10 @@ msgid "Inverse Linear" msgstr "逆線形" +msgid "Inverse Square" +msgstr "逆二乗式" + + msgid "Inverse Coefficients" msgstr "逆係数" @@ -27268,6 +27264,10 @@ msgid "Display boid health" msgstr "ボイドのヘルスを表示します" +msgid "Number" +msgstr "数" + + msgid "Show particle number" msgstr "パーティクルの番号を表示します" @@ -28351,10 +28351,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "ディスク上のテキストファイルはメモリ内のものと異なります" -msgid "Lines" -msgstr "ライン" - - msgid "Lines of text" msgstr "テキストの行" @@ -28495,6 +28491,10 @@ msgid "Procedural - wave generated bands or rings, with optional noise" msgstr "手続き型 - オプションのノイズと共に、帯状もしくはリング状の波型を生成します" +msgid "Set negative texture RGB and intensity values to zero, for some uses like displacement this option can be disabled to get the full range" +msgstr "負のテクスチャ RGB 値と明るさを0にします。ディスプレイスメントのように全範囲を使用する場合、このオプションは OFF にしてください" + + msgid "Map the texture intensity to the color ramp. Note that the alpha value is used for image textures, enable \"Calculate Alpha\" for images without an alpha channel" msgstr "" "テクスチャの明るさをカラーランプにマップします\n" @@ -29024,10 +29024,18 @@ msgid "Use soft marble" msgstr "ソフトマーブルを使用" +msgid "Sharp" +msgstr "シャープ" + + msgid "Use more clearly defined marble" msgstr "よりクリアに設定されたマーブルを使用" +msgid "Sharper" +msgstr "よりシャープ" + + msgid "Use very clearly defined marble" msgstr "更にクリアに設定されたマーブルを使用" @@ -29292,6 +29300,10 @@ msgid "Minkowski exponent" msgstr "ミンコフスキーの指数" +msgid "Scales the intensity of the noise" +msgstr "ノイズの明るさをスケーリングします" + + msgid "Weight 1" msgstr "ウェイト 1" @@ -29844,6 +29856,10 @@ msgid "Insert Before" msgstr "前に挿入" +msgid "Insert a new item into collection before the one referenced in subitem_reference_name or _index (NOT USED)" +msgstr "コレクションの subitem_reference_name または _index(未使用)で参照されるアイテムの後に新しいアイテムを挿入します" + + msgid "Subitem Local Index" msgstr "サブアイテムローカルインデックス" @@ -35279,6 +35295,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "頂点が隣接する複数のエッジを持っている場合、エッジ間を緩く結びます" +msgid "Root" +msgstr "ルート" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "頂点を回転の計算とアーマチュア生成用のルートにします。このフラグ設定は同じメッシュアイランドの他のルートをクリアしません" @@ -35407,6 +35427,10 @@ msgid "UV Pin" msgstr "UVピン止め" +msgid "UV pinned state in the UV editor" +msgstr "UV エディター内での UV のピン止め状態" + + msgid "UV coordinates on face corners" msgstr "面コーナーの UV 座標" @@ -36649,10 +36673,18 @@ msgid "Original Coords" msgstr "元の座標" +msgid "Use base mesh vertex coordinates as the rest position" +msgstr "ベースメッシュの頂点座標をレスト位置として使用します" + + msgid "Bind Coords" msgstr "バインド座標" +msgid "Use bind vertex coordinates for rest position" +msgstr "バインド頂点座標をレスト位置として使用します" + + msgid "Compensate for scale applied by other modifiers" msgstr "他のモディファイアーにより適用されたスケールの補正" @@ -37297,28 +37329,36 @@ msgid "Displacement modifier" msgstr "ディスプレイスモディファイアー" +msgid "Use the texture's intensity value to displace in the X direction" +msgstr "テクスチャの明度を X 方向のディスプレイスに使用します" + + msgid "Use the texture's intensity value to displace in the Y direction" -msgstr "テクスチャの輝度をY方向のディスプレイスに使用します" +msgstr "テクスチャの明度を Y 方向のディスプレイスに使用します" msgid "Use the texture's intensity value to displace in the Z direction" -msgstr "テクスチャの輝度をZ方向のディスプレイスに使用します" +msgstr "テクスチャの明度を Z 方向のディスプレイスに使用します" msgid "Use the texture's intensity value to displace along the vertex normal" -msgstr "テクスチャの輝度を頂点の法線に沿ったディスプレイスに使用します" +msgstr "テクスチャの明度を頂点の法線に沿ったディスプレイスに使用します" msgid "Custom Normal" msgstr "カスタム法線" +msgid "Use the texture's intensity value to displace along the (averaged) custom normal (falls back to vertex)" +msgstr "テクスチャの明度値を(頂点の代わりに)カスタム法線(の平均)に沿ったディスプレイスに使用します" + + msgid "RGB to XYZ" msgstr "RGBのXYZ化" msgid "Use the texture's RGB values to displace the mesh in the XYZ direction" -msgstr "テクスチャのRGB 値をXYZ 方向のディスプレイスに使用します" +msgstr "テクスチャの RGB 値を XYZ 方向のディスプレイスに使用します" msgid "Midlevel" @@ -38335,15 +38375,19 @@ msgstr "泡のある荒れた海洋を使用します" msgid "Established Ocean" -msgstr "従来の海洋" +msgstr "規定の海洋" msgid "Use for a large area, established ocean (Pierson-Moskowitz method)" -msgstr "大きな領域用の、従来の海洋(Pierson-Moskowitz 法)" +msgstr "大きな領域用の、規定の海洋(Pierson-Moskowitz 法)" msgid "Established Ocean (Sharp Peaks)" -msgstr "従来の海洋(尖ったピーク)" +msgstr "規定の海洋(尖ったピーク)" + + +msgid "Use for established oceans ('JONSWAP', Pierson-Moskowitz method) with peak sharpening" +msgstr "規定の海洋(「JONSWAP」、Pierson-Moskowitz 法)と、シャープ化による尖ったピークを使用します" msgid "Shallow Water" @@ -39248,6 +39292,10 @@ msgid "UVWarp Modifier" msgstr "UVワープモディファイアー" +msgid "Add target position to UV coordinates" +msgstr "UV座標にターゲットの位置を加算します" + + msgid "U-Axis" msgstr "U軸" @@ -40035,6 +40083,10 @@ msgid "Line thickness for motion path" msgstr "モーションパスのラインの太さ" +msgid "Lines" +msgstr "ライン" + + msgid "Use straight lines between keyframe points" msgstr "キーフレームポイント間を直線で表示します" @@ -43780,6 +43832,10 @@ msgid "Adaptation" msgstr "適応" +msgid "If 0, global; if 1, based on pixel intensity" +msgstr "0でグローバル、1でピクセル明度" + + msgid "Set to 0 to use estimate from input image" msgstr "0で入力画像からの概算を使用" @@ -43800,6 +43856,10 @@ msgid "The value the average luminance is mapped to" msgstr "マップされる平均ルミナンスの値" +msgid "Normally always 1, but can be used as an extra control to alter the brightness curve" +msgstr "通常は常に1ですが、さらに明度曲線を操作するのに使用できます" + + msgid "Tonemap Type" msgstr "トーンマップタイプ" @@ -44370,18 +44430,22 @@ msgid "Retrieve geometry instances from a collection" msgstr "コレクションからジオメトリインスタンスを取得します" +msgid "The transformation of the instances output. Does not affect the internal geometry" +msgstr "インスタンス出力のトランスフォーム空間。内部ジオメトリには影響しません" + + msgid "Original" msgstr "オリジナル" msgid "Output the geometry relative to the collection offset" -msgstr "コレクションのオフセットに対してジオメトリを出力します" +msgstr "コレクションのオフセットでジオメトリを出力します" msgid "Bring the input collection geometry into the modified object, maintaining the relative position between the objects in the scene" msgstr "" -"入力コレクションのジオメトリを変形するオブジェクトに渡し\n" -"シーン内での各オブジェクトの相対的な位置を維持します" +"シーン内での各オブジェクト間の相対的な位置を維持しながら\n" +"入力コレクションのジオメトリを変形オブジェクトに渡します" msgid "Convex Hull" @@ -54121,12 +54185,16 @@ msgstr "" "別々の AnimStack としてエクスポートします" +msgid "Apply Transform" +msgstr "トランスフォームを適用" + + msgid "Bake space transform into object data, avoids getting unwanted rotations to objects when target space is not aligned with Blender's space (WARNING! experimental option, use at own risk, known to be broken with armatures/animations)" msgstr "" -"空間の変換をオブジェクトデータにベイクし、ターゲットの空間が\n" -"Blender の空間と合致しない時の、望ましくない回転を回避します\n" -"(注意:実験的オプションであるため自己責任で使用してください\n" -" アーマチュアやアニメーションが壊れる既知の問題があります)" +"トランスフォームをオブジェクトデータにベイクし、ターゲット空間が\n" +"Blender の空間と合致しない時に起こる望ましくない回転を回避します\n" +"(注意:実験的なオプションであるため、自己責任で使用してください\n" +" アーマチュアやアニメーションが壊れる問題があります)" msgid "Active scene to file" @@ -54476,14 +54544,18 @@ msgid "Export vertex colors with meshes" msgstr "頂点カラーをメッシュと共にエクスポートします" -msgid "Copyright" -msgstr "コピーライト" - - msgid "Legal rights and conditions for the model" msgstr "モデルの法的な権利と条件" +msgid "Use Current Frame" +msgstr "現在のフレームを使用" + + +msgid "Export the scene in the current animation frame" +msgstr "シーンを現在のアニメーションフレームでエクスポートします" + + msgid "Export Deformation Bones Only" msgstr "変形ボーンのみ" @@ -54701,6 +54773,17 @@ msgid "Export vertex tangents with shape keys (morph targets)" msgstr "頂点のタンジェントをシェイプキー(モーフターゲット)と共にエクスポートします" +msgid "Group by NLA Track" +msgstr "NLAトラックでグループ化" + + +msgid "When on, multiple actions become part of the same glTF animation if they're pushed onto NLA tracks with the same name. When off, all the currently assigned actions become one glTF animation" +msgstr "" +"有効時、もし複数のアクションが同じ名前の NLA トラック上にストリップ化されていれば\n" +"同じ glTF アニメーションの一部になります\n" +"無効時、現在割り当て中の全アクションが一つの glTF アニメーションになります" + + msgid "Merged Animation Name" msgstr "アニメーション名を統合" @@ -66049,6 +66132,10 @@ msgid "Hook selected vertices to the first selected object" msgstr "選択した頂点を始めに選択したオブジェクトにフックします" +msgid "Assign the hook to the hook object's active bone" +msgstr "フックをフックオブジェクトのアクティブボーンに割り当てます" + + msgctxt "Operator" msgid "Assign to Hook" msgstr "フックに割り当て" @@ -68947,6 +69034,14 @@ msgid "Library Operation" msgstr "ライブラリ操作" +msgid "" +"Delete this library and all its items.\n" +"Warning: No undo" +msgstr "" +"このライブラリとその全アイテムを削除します\n" +"(注:元に戻せません)" + + msgid "Relocate" msgstr "リロケート" @@ -69375,6 +69470,10 @@ msgid "Add Simple UVs" msgstr "シンプルなUVを追加" +msgid "Add cube map UVs on mesh" +msgstr "キューブマップの UV をメッシュに追加します" + + msgctxt "Operator" msgid "Add Paint Slot" msgstr "ペイントスロットを追加" @@ -71848,8 +71947,11 @@ msgid "Fill Range by Selection" msgstr "選択から範囲設定" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "選択中のメッシュオブジェクトとソースオブジェクト間の最小/最大距離により、最小/最大範囲を設定します" +msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object (either a user-specified object or the active camera)" +msgstr "" +"選択中のメッシュオブジェクトと、ソースオブジェクト\n" +"(ユーザー指定のオブジェクトまたはアクティブカメラ)\n" +"間の最小/最大距離により、最小/最大範囲を設定します" msgid "Name of the modifier to work on" @@ -76975,6 +77077,10 @@ msgid "Align Rotation" msgstr "回転を揃える" +msgid "Align the UV island's rotation" +msgstr "UV アイランドの回転を揃えます" + + msgid "Axis to align to" msgstr "揃える対象の軸" @@ -77423,6 +77529,10 @@ msgid "Use orthographic projection" msgstr "平行投影を使用" +msgid "Randomize the UV island's location, rotation, and scale" +msgstr "UV アイランドの位置、回転、スケールをランダム化します" + + msgid "Maximum rotation" msgstr "回転の最大角度" @@ -79773,7 +79883,7 @@ msgstr "適用する値" msgctxt "Operator" msgid "Context Set Enum" -msgstr "Enum設定コンテクスト" +msgstr "列挙設定コンテクスト" msgid "Assignment value (as a string)" @@ -90762,10 +90872,6 @@ msgid "Additional subdivision along the curves" msgstr "カーブに沿ってさらに細分化します" -msgid "Curves Shape Type" -msgstr "カーブの形状タイプ" - - msgid "Curves shape type" msgstr "カーブの形状タイプ" @@ -97657,6 +97763,10 @@ msgid "Display Texture Paint UVs" msgstr "テクスチャペイントUVを表示" +msgid "Display overlay of texture paint UV layer" +msgstr "テクスチャペイント UV レイヤーをオーバーレイ表示します" + + msgid "Tile Grid Shape" msgstr "タイルグリッド形状" @@ -102563,6 +102673,11 @@ msgid "Data type of voxel values" msgstr "ボクセル値のデータタイプ" +msgctxt "Volume" +msgid "Boolean" +msgstr "ブーリアン" + + msgctxt "Volume" msgid "Float" msgstr "単精度" @@ -104439,6 +104554,11 @@ msgid "Curve" msgstr "カーブ" +msgctxt "WindowManager" +msgid "Curves" +msgstr "新カーブ" + + msgctxt "WindowManager" msgid "Armature" msgstr "アーマチュア" @@ -106038,20 +106158,28 @@ msgid "No compatible GPUs found for Cycles" msgstr "Cycles 用の互換性のある GPU がありません" -msgid "(TM)TRADE MARK SIGN(tm)TRADE MARK SIGN(R)REGISTERED SIGN(C)COPYRIGHT SIGN" -msgstr "(TM)登録商標サイン(tm)登録商標サイン(R)登録済みサイン(C)著作権サイン" - - msgid "Requires NVIDIA GPU with compute capability %s" msgstr "Compute Capability %s の NVIDIA GPU が必要です" +msgid "Requires AMD GPU with Vega or RDNA architecture" +msgstr "Vega や RDNA アーキテクチャの AMD GPU カードと" + + msgid "and NVIDIA driver version %s or newer" msgstr "NVIDIA ドライバー Ver.%s 以降が必要です" -msgid "Requires AMD GPU with Vega or RDNA architecture" -msgstr "Vega や RDNA アーキテクチャの AMD GPU カードと" +msgid "Requires Intel GPU with Xe-HPG architecture" +msgstr "Xe-HPG アーキテクチャの Intel GPU カードと" + + +msgid "Requires Intel GPU with Xe-HPG architecture and" +msgstr "Xe-HPG アーキテクチャの Intel GPU カードと以下が必要です" + + +msgid " - oneAPI Level-Zero Loader" +msgstr " ・oneAPI Level-Zeroローダー" msgid "and AMD Radeon Pro %s driver or newer" @@ -106062,10 +106190,6 @@ msgid "and AMD driver version %s or newer" msgstr "AMD ドライバー Ver.%s 以降が必要です" -msgid "Requires Intel GPU with Xe-HPG architecture" -msgstr "Xe-HPG アーキテクチャの Intel GPU カードと" - - msgid "and Windows driver version %s or newer" msgstr "Windows ドライバー Ver.%s 以降が必要です" @@ -106078,18 +106202,10 @@ msgid "or AMD with macOS %s or newer" msgstr "または AMD と macOS %s 以降が必要です" -msgid "Requires Intel GPU with Xe-HPG architecture and" -msgstr "Xe-HPG アーキテクチャの Intel GPU カードと以下が必要です" - - msgid " - intel-level-zero-gpu version %s or newer" msgstr " ・intel-level-zero-gpu ver.%s 以降" -msgid " - oneAPI Level-Zero Loader" -msgstr " ・oneAPI Level-Zeroローダー" - - msgid "Noise Threshold" msgstr "ノイズしきい値" @@ -106761,7 +106877,7 @@ msgstr "RNAラベル:" msgid "Enum Item Label:" -msgstr "Enumアイテムラベル:" +msgstr "列挙アイテムラベル:" msgid "Button Tip:" @@ -106773,7 +106889,7 @@ msgstr "RNAチップ:" msgid "Enum Item Tip:" -msgstr "Enumアイテムチップ:" +msgstr "列挙アイテムチップ:" msgid "Could not write to po file ({})" @@ -106884,10 +107000,6 @@ msgid "Invert Selection" msgstr "選択を反転" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "トラッキング" @@ -106979,15 +107091,15 @@ msgid "Restore" msgstr "リストア" -msgid "%s (Global)" -msgstr "%s(グローバル)" - - msgctxt "WindowManager" msgid "Add New" msgstr "新規作成" +msgid "%s (Global)" +msgstr "%s(グローバル)" + + msgctxt "Operator" msgid "New" msgstr "新規" @@ -107302,14 +107414,6 @@ msgid "Current frame not within strip framerange" msgstr "現在のフレームはストリップのフレーム範囲内ではありません" -msgid "Remove Add-on: %r?" -msgstr "アドオンを削除: %r?" - - -msgid "Path: %r" -msgstr "パス: %r" - - msgid "Reload Start-Up file to restore settings" msgstr "設定を戻すにはスタートアップファイルを再読み込みしてください" @@ -107374,6 +107478,14 @@ msgid "Source file is in the add-on search path: %r" msgstr "アドオン検索パスにソースファイルがあります: %r" +msgid "Remove Add-on: %r?" +msgstr "アドオンを削除: %r?" + + +msgid "Path: %r" +msgstr "パス: %r" + + msgid "Active face must be a quad" msgstr "アクティブな面は四角形でないといけません" @@ -107394,10 +107506,6 @@ msgid "See OperatorList.txt text block" msgstr "OperatorList.txt テキストブロックを参照してください" -msgid "Rename %d %s" -msgstr "リネーム %d %s" - - msgid "Renamed %d of %d %s" msgstr "リネームしました(%d/%d)%s" @@ -107415,18 +107523,6 @@ msgid "Open..." msgstr "開く..." -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "日付:%s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "ハッシュ:%sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "ブランチ:%sutf-8replace" - - msgid "Blender is free software" msgstr "Blender はフリーソフトウェアです" @@ -107491,11 +107587,6 @@ msgid "Spacebar" msgstr "[スペース]" -msgctxt "Operator" -msgid "Load %d.%d SettingsOperator" -msgstr "%d.%dの設定オペレーター読み込み" - - msgctxt "Operator" msgid "Save New Settings" msgstr "新しい設定を保存" @@ -107520,10 +107611,6 @@ msgid "Development Fund" msgstr "開発ファンド" -msgid "Windowing Environment: %s" -msgstr "ウインドウ環境: %s" - - msgctxt "Operator" msgid "Credits" msgstr "クレジット" @@ -107707,6 +107794,10 @@ msgid "Strip From" msgstr "除去の始点" +msgid "Rename %d %s" +msgstr "リネーム %d %s" + + msgid "Date: %s %s" msgstr "日付: %s %s" @@ -107740,6 +107831,10 @@ msgid "Load %d.%d Settings" msgstr "%d.%dの設定を読み込む" +msgid "Windowing Environment: %s" +msgstr "ウインドウ環境: %s" + + msgid "Type \"%s\" can not be found" msgstr "タイプ「%s」がありません" @@ -108259,10 +108354,6 @@ msgid "Apply All Shape Keys" msgstr "全シェイプキーを適用" -msgid "%s ▶ %s" -msgstr "%s . %s" - - msgid "Name collisions: , " msgstr "名前の衝突: , " @@ -108931,22 +109022,10 @@ msgid "Hair dynamics disabled" msgstr "ヘアーの物理演算を無効にします" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "ソルブ回数: %d .. %d (平均 %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "誤差: %.5f .. %.5f (平均 %.5f)" - - msgid "Multiply Mass with Size" msgstr "質量×サイズ" -msgid "Spacing: %g" -msgstr "間隔: %g" - - msgid "Show Emitter" msgstr "エミッターを表示" @@ -108991,10 +109070,6 @@ msgid "Coordinate System" msgstr "座標系" -msgid "%d fluid particles for this frame" -msgstr "%d 個の流体パーティクルがこのフレームにあります" - - msgctxt "Operator" msgid "Delete Edit" msgstr "編集を削除" @@ -109008,6 +109083,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "表示割合を変更するとベイクなしでの物理演算の精度が下がります" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "ソルブ回数: %d .. %d (平均 %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "誤差: %.5f .. %.5f (平均 %.5f)" + + +msgid "Spacing: %g" +msgstr "間隔: %g" + + msgid "Not yet functional" msgstr "まだ機能していません" @@ -109022,6 +109109,10 @@ msgid "Disconnect All" msgstr "すべて接続解除" +msgid "%d fluid particles for this frame" +msgstr "%d 個の流体パーティクルがこのフレームにあります" + + msgid "Speed Multiplier" msgstr "速度の乗数" @@ -109482,6 +109573,10 @@ msgid "This object is part of a compound shape" msgstr "このオブジェクトは複合形状の一部です" +msgid "Second" +msgstr "秒数" + + msgid "X Stiffness" msgstr "剛性 X" @@ -109698,11 +109793,6 @@ msgid "Unknown add-ons" msgstr "未知のアドオン" -msgctxt "Operator" -msgid "%s: %s" -msgstr "%s: %s" - - msgid "category" msgstr "カテゴリ" @@ -109982,11 +110072,6 @@ msgid "Tracks for Rotation/Scale" msgstr "回転・スケール用トラック" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "ズーム %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "全体表示" @@ -110007,14 +110092,14 @@ msgid "Frame All Fit" msgstr "枠全体に表示" -msgid "Solve error: %.2f px" -msgstr "解析エラー: %.2f px" - - msgid "Zoom %d:%d" msgstr "ズーム %d:%d" +msgid "Solve error: %.2f px" +msgstr "解析エラー: %.2f px" + + msgctxt "Operator" msgid "Copy as Script" msgstr "スクリプトとしてコピー" @@ -111400,10 +111485,6 @@ msgid "Default Fade" msgstr "デフォルトフェード" -msgid "Original frame range: %d-%d (%d)" -msgstr "元のフレーム範囲: %d-%d (%d)" - - msgid "Strip Offset Start" msgstr "ストリップオフセット開始" @@ -111467,14 +111548,6 @@ msgid "Effect Fader" msgstr "エフェクトフェーダー" -msgid "%dx%d" -msgstr "%d×%d" - - -msgid "%.2f" -msgstr "%.2f" - - msgid "Original Frame Range" msgstr "元のフレーム範囲" @@ -111499,8 +111572,8 @@ msgid "Pack" msgstr "パック" -msgid "%d Hz" -msgstr "%d Hz" +msgid "Original frame range: %d-%d (%d)" +msgstr "元のフレーム範囲: %d-%d (%d)" msgid "Source Channel" @@ -111617,10 +111690,6 @@ msgid "Move Line(s) Down" msgstr "行を下に移動" -msgid "Text: ExternalText: Internal" -msgstr "テキスト: 外部テキスト: 内部" - - msgid "File: *%s (unsaved)" msgstr "ファイル: *%s(未保存)" @@ -111945,11 +112014,6 @@ msgid "Load Factory Blender Settings" msgstr "Blenderの初期設定を読み込む" -msgctxt "Operator" -msgid "Load Factory %s Settings" -msgstr "%sの初期設定を読み込む" - - msgctxt "Operator" msgid "Collada (.dae)" msgstr "Collada (.dae)" @@ -112055,6 +112119,11 @@ msgid "NLA Strip Name" msgstr "NLAストリップ名" +msgctxt "Operator" +msgid "Load Factory %s Settings" +msgstr "%sの初期設定を読み込む" + + msgid "Auto-Save Preferences" msgstr "プリファレンスを自動保存" @@ -112348,23 +112417,10 @@ msgid "Load Factory Blender Preferences" msgstr "Blenderの初期プリファレンスを読み込む" -msgctxt "Operator" -msgid "Load Factory %s Preferences" -msgstr "%sの初期プリファレンスを読み込む" - - msgid "Requires a restart of Blender to take effect" msgstr "Blender の再起動が必要です" -msgid "Color Set %d" -msgstr "カラーセット %d" - - -msgid "Color %d" -msgstr "カラー %d" - - msgid "Player" msgstr "プレイヤー" @@ -112405,6 +112461,14 @@ msgid "Load Factory %s Preferences" msgstr "%sの初期プリファレンスを読み込む" +msgid "Color Set %d" +msgstr "カラーセット %d" + + +msgid "Color %d" +msgstr "カラー %d" + + msgid "Description:" msgstr "詳細:" @@ -112421,10 +112485,6 @@ msgid "Author:" msgstr "作者:" -msgid "author" -msgstr "作者" - - msgid "Version:" msgstr "バージョン:" @@ -113599,10 +113659,6 @@ msgid "Snap To" msgstr "スナップ先" -msgid "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" -msgstr "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" - - msgid "Fade Inactive Layers" msgstr "非アクティブレイヤーをフェード" @@ -114699,6 +114755,10 @@ msgid "File written by newer Blender binary (%d.%d), expect loss of data!" msgstr "新しいBlenderバイナリ(%d.%d)で保存されたファイル。データが欠けている可能性があります!" +msgid "File could not be read, critical data corruption detected" +msgstr "ファイルが読み込みできません。重大なデータ破損が検出されました" + + msgid "Loading failed: " msgstr "読み込み失敗: " @@ -120997,7 +121057,7 @@ msgstr "補間:" msgid "None for Enum/Boolean" -msgstr "なし(Enum/Boolean時)" +msgstr "なし(列挙/ブーリアン時)" msgid "Key Frame" @@ -121643,10 +121703,6 @@ msgid "Undefined Socket Type" msgstr "未定義ソケットタイプ" -msgid "Group Input " -msgstr "グループ入力 " - - msgid "Could not determine type of group node" msgstr "グループノードのタイプが決められません" @@ -123851,8 +123907,12 @@ msgid "Can't edit this property from a system override data-block" msgstr "システムオーバーライドデータブロックのプロパティは編集できません" +msgid "Only boolean, int, float, and enum properties supported" +msgstr "ブーリアン、整数、Float、列挙プロパティのみ対応" + + msgid "Only boolean, int, and float properties supported" -msgstr "boolean、int、float のみ対応" +msgstr "ブーリアン、整数、Float のみ対応" msgid "'%s' does not contain '%s' with prefix and suffix" @@ -123935,6 +123995,14 @@ msgid "Driver not found in this animation data" msgstr "このアニメーションデータにドライバーがありません" +msgid "%s '%s' is too long, maximum length is %d" +msgstr "%s「%s」は長すぎです(最大長:%d)" + + +msgid "%s '%s', bl_idname '%s' %s" +msgstr "%s「%s」、bl_idname「%s」%s" + + msgid "NlaTrack '%s' cannot be removed" msgstr "NLAトラック「%s」が削除できません" @@ -124510,22 +124578,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "NLAストリップ「%s」がトラック「%s」にありません" -msgid "Functions" -msgstr "関数" - - -msgid "Comparison" -msgstr "比較" - - -msgid "Trigonometric" -msgstr "三角関数" - - -msgid "Conversion" -msgstr "変換" - - msgid "CustomGroup" msgstr "カスタムグループ" @@ -124566,6 +124618,10 @@ msgid "Unable to move sockets in built-in node" msgstr "ビルトインノードにはソケットを移動できません" +msgid "%s '%s', bl_idname '%s' could not be unregistered" +msgstr "%s「%s」、bl_idname「%s」は登録解除できませんでした" + + msgid "Node tree '%s' has undefined type %s" msgstr "ノードツリー「%s」に未定義タイプ %s があります" @@ -124911,8 +124967,16 @@ msgid "Region not found in space type" msgstr "空間タイプに領域がありません" +msgid "%s '%s' has category '%s' " +msgstr "%s「%s」にカテゴリ「%s」があります " + + +msgid "%s parent '%s' for '%s' not found" +msgstr "%s 「%s」(「%s」の親)が見つかりません" + + msgid "Add-on is no longer valid" -msgstr "アドオンがもう有効ではありません" +msgstr "もう有効なアドオンではありません" msgid "Excluded path is no longer valid" @@ -124991,12 +125055,16 @@ msgid "GizmoType '%s' is for a 3D gizmo-group. The 'draw_select' callback is set msgstr "ギズモタイプ「%s」は3Dギズモグループ用です。「draw_select」コールバックは「test_select」が使用される所のみセットされます" +msgid "%s area type does not support gizmos" +msgstr "「%s」エリアタイプはギズモに未対応です" + + msgid "Gizmo target property '%s.%s' not found" -msgstr "ギズモターゲットプロパティ '%s.%s' がありません" +msgstr "ギズモターゲットプロパティ「%s.%s」がありません" msgid "Property '%s.%s' not found" -msgstr "プロパティ '%s.%s' がありません" +msgstr "プロパティ「%s.%s」がありません" msgid "Gizmo target '%s.%s' expects '%s', '%s.%s' is '%s'" @@ -126608,12 +126676,16 @@ msgid "The curve group to interpolate in" msgstr "補間するカーブグループ" +msgid "Max Neighbors" +msgstr "最大隣接数" + + msgid "Maximum amount of close guide curves that are taken into account for interpolation" -msgstr "補間時に考慮する近くのガイドカーブの最大数" +msgstr "補間時に考慮する近隣のガイドカーブの最大数" msgid "Closest Index" -msgstr "最接近インデックス" +msgstr "最近接インデックス" msgid "Index of the closest guide curve for each generated curve" @@ -126621,7 +126693,7 @@ msgstr "各生成カーブに一番近いガイドカーブのインデックス msgid "Closest Weight" -msgstr "最接近ウェイト" +msgstr "最近接ウェイト" msgid "Weight of the closest guide curve for each generated curve" @@ -128038,15 +128110,15 @@ msgstr "コンテクスト内にオペレーターがありません" msgid "Property cannot be both boolean and float" -msgstr "プロパティはbooleanとfloatの両方にはなれません" +msgstr "プロパティはブーリアンと Float の両方にはなれません" msgid "Pointer from path image_id is not an ID" -msgstr "パスimage_idのポインタがIDではありません" +msgstr "パス image_id のポインタが ID ではありません" msgid "Property must be an integer or a float" -msgstr "プロパティはintegerまたはfloatのみです" +msgstr "プロパティは整数または Float のみです" msgid "Property must be a none, distance, factor, percentage, angle, or pixel" diff --git a/locale/po/ka.po b/locale/po/ka.po index f4d4f3ec47c..513287cf0e8 100644 --- a/locale/po/ka.po +++ b/locale/po/ka.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Tamar Mebonia , 2023\n" "Language-Team: LANGUAGE \n" @@ -1101,6 +1101,10 @@ msgid "Simple name of the asset's catalog, for debugging and data recovery purpo msgstr "აქტივების კატალოგის მარტივი სახელი, ხარვეზების აღმოფხვრისა და მონაცემთა აღდგენისათვის" +msgid "Copyright" +msgstr "კოპირაითი" + + msgid "Description" msgstr "აღწერა" @@ -2362,11 +2366,11 @@ msgstr "ვიდეო კლიპების კოლექცია" msgid "Main Node Trees" -msgstr "მთავარი კვანძოვანი ხეები" +msgstr "მთავარი კვანძური ხეები" msgid "Collection of node trees" -msgstr "კვანძოვანი ხეების კოლექცია" +msgstr "კვანძური ხეების კოლექცია" msgid "Main Objects" @@ -5368,11 +5372,11 @@ msgstr "მოშვებულ ნაპირებს ერთმანე msgid "Bending Stiffness Vertex Group" -msgstr "დრეკვის გახევების წვეროთა ჯგუფი" +msgstr "დრეკისას გახევების წვეროთა ჯგუფი" msgid "Vertex group for fine control over bending stiffness" -msgstr "წვეროთა ჯგუფი დრეკვის გახევების ზედმიწევნით კონტროლისათვის" +msgstr "წვეროთა ჯგუფი დრეკისას გახევების ზედმიწევნით კონტროლისათვის" msgid "Internal Springs Vertex Group" @@ -13655,10 +13659,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "ნაწილაკების მინიმალური რიცხვი თითო უჯრედზე (უზრუნველყოფს თითოეული უჯრედის მიერ მინიმუმ ამ რაოდენობის ნაწილაკების ქონას)" -msgid "Number" -msgstr "რიცხვი" - - msgid "Particle number factor (higher value results in more particles)" msgstr "ნაწილაკების რიცხვის კოეფიციენტი (რაც მაღალია მნიშვნელობა, მით მეტია ნაწილაკი)" @@ -19480,30 +19480,6 @@ msgid "Editable falloff curve" msgstr "მილევის რედაქტირებადი წირი" -msgid "Curve Preset" -msgstr "წინასწარ დაყენებული წირი" - - -msgid "Smoother" -msgstr "უფრო გლუვი" - - -msgid "Root" -msgstr "ფესვი" - - -msgid "Sharp" -msgstr "მკვეთრი" - - -msgid "Sharper" -msgstr "უფრო მკვეთრი" - - -msgid "Inverse Square" -msgstr "ინვერსიული კვადრატი" - - msgid "Curves Sculpt Settings" msgstr "წირების ძერწვის პარამეტრები" @@ -20948,18 +20924,10 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "იმ Alembic ატრიბუტის სახელი, რომელიც მოძრაობის გადღაბნის მონაცემების წარმოსაქმნელად გამოიყენება" -msgid "Velocity Unit" -msgstr "სისწრაფის ერთეული" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "განსაზღვრე, თუ როგორ ინტერპრეტირდება სისწრაფის ვექტორები დროსთან მიმართებაში, 'კადრი' ნიშნავს, რომ დელტა დრო 1 კადრია, 'მეორე' ნიშნავს, რომ დელტა დრო არის 1 / FPS" -msgid "Second" -msgstr "მეორე" - - msgid "Camera data-block for storing camera settings" msgstr "კამერის მონაცემთა ბლოკი კამერის პარამეტრების შესანახად" @@ -23308,30 +23276,74 @@ msgid "Seam Margin" msgstr "ნაკერის მინდორი" +msgid "Width and height of the image buffer in pixels, zero when image data can't be loaded" +msgstr "გამოსახულების ბუფერის სიგანე და სიმაღლე პიქსელებში, ნული, როცა გამოსახულების მონაცემები ვერ იტვირთება" + + +msgid "Where the image comes from" +msgstr "საიდან მოდის გამოსახულება" + + msgid "Single Image" msgstr "ერთი გამოსახულება" +msgid "Single image file" +msgstr "გამოსახულების ერთი ფაილი" + + +msgid "Multiple image files, as a sequence" +msgstr "გამოსახულების რამდენიმე ფაილი, სეკვენციად" + + msgid "Movie" msgstr "ვიდეო" +msgid "Movie file" +msgstr "ვიდეო ფაილი" + + +msgid "Generated image" +msgstr "წარმოქმნილი გამოსახულება" + + msgid "Viewer" msgstr "მაჩვენებელი" +msgid "Compositing node viewer" +msgstr "კომპოზიტინგის კვანძის მაჩვენებელი" + + msgid "UDIM Tiles" msgstr "UDIM ფილები" +msgid "Tiled UDIM image texture" +msgstr "გამოსახულების მიჯრილი UDIM ტექსტურა" + + msgid "Stereo 3D Format" msgstr "სტერეო 3გ ფორმატი" +msgid "Settings for stereo 3d" +msgstr "პარამეტრები სტერეო 3გ ფორმატისთვის" + + msgid "Image Tiles" msgstr "გამოსახულების ფილები" +msgid "Tiles of the image" +msgstr "გამოსახულების ფილები" + + +msgid "How to generate the image" +msgstr "როგორ წარმოიქმნას ფაილი" + + msgid "Multilayer" msgstr "მრავალშრიანი" @@ -23352,18 +23364,34 @@ msgid "Deinterlace" msgstr "მონაცვლეობის გაუქმება" +msgid "Deinterlace movie file on load" +msgstr "მონაცვლეობის გაუქმება ვიდეო ფაილის ჩატვირთვისას" + + msgid "Float Buffer" msgstr "ათწილადების ბუფერი" +msgid "Generate floating-point buffer" +msgstr "ათწილადი ბუფერის წარმოქმნა" + + msgid "Half Float Precision" msgstr "ნახევრად ზუსტი ათწილადი" +msgid "Use 16 bits per channel to lower the memory usage during rendering" +msgstr "გამოიყენე ყოველ არხზე 16 ბიტი რენდერისას მეხსიერების დასაზოგად" + + msgid "Use Multi-View" msgstr "მრავალხედის გამოყენება" +msgid "Use Multiple Views (when available)" +msgstr "რამოდენიმე ხედის გამოყენება (როცა ხელმისაწვდომია)" + + msgid "View as Render" msgstr "რენდერად ნახვა" @@ -23372,26 +23400,58 @@ msgid "Views Format" msgstr "ხედების ფორმატი" +msgid "Mode to load image views" +msgstr "გამოსახულების ხედების ჩასატვირთი რეჟიმი" + + msgid "Individual" msgstr "ინდივიდუალური" +msgid "Individual files for each view with the prefix as defined by the scene views" +msgstr "ინდივიდუალური ფაილები ყოველი პრეფიქსიანი ხედისთვის, როგორც განსაზღვრულია სცენის ხედების მიერ" + + +msgid "Single file with an encoded stereo pair" +msgstr "ერთი ფაილი კოდირებული სტერეო წყვილით" + + +msgid "Shape keys data-block containing different shapes of geometric data-blocks" +msgstr "ფორმის სოლების მონაცემთა ბლოკები, რომლებიც შეიცავენ გეომეტრიულ მონაცემთა ბლოკების სხვადასხვა ფორმებს" + + +msgid "Evaluation time for absolute shape keys" +msgstr "შეფასების დრო აბსოლუტური ფორმის სოლებისთვის" + + msgid "Key Blocks" -msgstr "გასაღებთა ბლოკები" +msgstr "სოლების ბლოკები" msgid "Shape keys" -msgstr "ფორმათა გასაღებები" +msgstr "ფორმის სოლები" msgid "Reference Key" -msgstr "მითითების გასაღები" +msgstr "მითითების სოლი" + + +msgid "Make shape keys relative, otherwise play through shapes as a sequence using the evaluation time" +msgstr "აქციე ფორმის სოლები შეფარდებითად, სხვა მხრივ ფორმებში გადასვლა აქციე სეკვენციად შეფასების დროის გამოყენებით" msgid "User" msgstr "მომხმარებელი" +msgid "Data-block using these shape keys" +msgstr "მონაცემთია ბლოკი, რომელიც ამ ფორმის სოლებს იყენებს" + + +msgid "Lattice data-block defining a grid for deforming other objects" +msgstr "გისოსების მონაცემთა ბლოკი, რომელიც ადგენს ცხრილს სხვა ობიექტების დეფორმირებისთვის" + + msgid "Interpolation Type U" msgstr "ინტერპოლაციის ტიპი U" @@ -23401,7 +23461,7 @@ msgstr "ქეთმულ-რომი" msgid "BSpline" -msgstr "B-სპლაინი" +msgstr "B-სფლაინი" msgid "Interpolation Type V" @@ -23412,23 +23472,63 @@ msgid "Interpolation Type W" msgstr "ინტერპოლაციის ტიპი W" +msgid "Points of the lattice" +msgstr "გისოსების წერტილები" + + msgid "U" msgstr "U" +msgid "Point in U direction (can't be changed when there are shape keys)" +msgstr "წერტილები U მიმართულებით (ვერ შეიცვლება, როცა არსებობს ფორმის სოლები)" + + msgid "V" msgstr "V" +msgid "Point in V direction (can't be changed when there are shape keys)" +msgstr "წერტილები V მიმართულებით (ვერ შეიცვლება, როცა არსებობს ფორმის სოლები)" + + msgid "W" msgstr "W" +msgid "Point in W direction (can't be changed when there are shape keys)" +msgstr "წერტილები W მიმართულებით (ვერ შეიცვლება, როცა არსებობს ფორმის სოლები)" + + +msgid "Only display and take into account the outer vertices" +msgstr "ასახე და გაითვალისწინე მხოლოდ გარეთა წვეროები" + + +msgid "Vertex group to apply the influence of the lattice" +msgstr "წვეროთა ჯგუფი, რომელზეც გისოსებს ზეგავლენა უნდა ჰქონდეს" + + +msgid "External .blend file from which data is linked" +msgstr "გარე .blend ფაილი, რომლიდანაც მონაცემები ბმულითაა დაკავშირებული" + + +msgid "Path to the library .blend file" +msgstr "ბიბლიოთეკის .blend ფაილის მისამართი" + + +msgid "Version of Blender the library .blend was saved with" +msgstr "ბლენდერის ვერსია, რომლითაც .blend ბიბლიოთეკა იქნა შენახული" + + msgctxt "Light" msgid "Light" msgstr "სინათლე" +msgid "Light data-block for lighting a scene" +msgstr "სინათლის მონაცემთა ბლოკი სცენის განათებისთვის" + + msgid "Light color" msgstr "სინათლის ფერი" @@ -23437,18 +23537,42 @@ msgid "Cutoff Distance" msgstr "მოჭრის მანძილი" +msgid "Distance at which the light influence will be set to 0" +msgstr "მანძილი, რომელზეც სინათლის ზეგავლენა 0-ზე დაყენდება" + + msgid "Cycles Light Settings" msgstr "Cycles-ის სინათლის პარამეტრები" +msgid "Cycles light settings" +msgstr "Cycles-ის სინათლის პარამეტრები" + + msgid "Diffuse Factor" msgstr "დიფუზიის კოეფიციენტი" +msgid "Diffuse reflection multiplier" +msgstr "დიფუზიური ანარეკლის მამრავლი" + + +msgid "Falloff distance - the light is at half the original intensity at this point" +msgstr "მილევის მანძილი - ამ ადგილთან სინათლე თავისი თავდაპირველი ინტენსივობის ნახევარზეა" + + +msgid "Node tree for node based lights" +msgstr "კვანძური ხე კვანძებზე დაფუძნებული სინათლეებისთვის" + + msgid "Specular Factor" msgstr "სპეკულარობის კოეფიციენტი" +msgid "Specular reflection multiplier" +msgstr "სპეკულარული ანარეკლის მამრავლი" + + msgctxt "Light" msgid "Type" msgstr "ტიპი" @@ -23498,10 +23622,22 @@ msgid "Custom Attenuation" msgstr "მორგებული შესუსტება" +msgid "Use custom attenuation distance instead of global light threshold" +msgstr "გამოიყენე მორგებული შესუსტების მანძილი და არა გლობალური სინათლის ზღვარი" + + +msgid "Use shader nodes to render the light" +msgstr "გამოიყენე იერფერის კვანძები სინათლის დასარენდერებლად" + + msgid "Volume Factor" msgstr "მოცულობის კოეფიციენტი" +msgid "Volume light multiplier" +msgstr "მოცულობითი სინათლის მამრავლი" + + msgid "Area Light" msgstr "არეალური სინათლე" @@ -23514,26 +23650,59 @@ msgid "Constant Coefficient" msgstr "მუდმივი კოეფიციენტი" +msgid "Constant distance attenuation coefficient" +msgstr "მუდმივი მანძილისმიერი შესუსტების კოეფიციენტი" + + msgid "Contact Shadow Bias" msgstr "კონტაქტური ჩრდილების მიკერძოება" +msgid "Bias to avoid self shadowing" +msgstr "მიკერძოება თვითდაჩრდილვის თავიდან ასარიდებლად" + + msgid "Contact Shadow Distance" msgstr "კონტაქტური ჩრდილების მანძილი" +msgid "World space distance in which to search for screen space occluder" +msgstr "სამყაროს სივრცისეული მანძილი, რომელზეც უნდა მოიძებნოს ეკრანის სივრცის დამხშობი" + + msgid "Contact Shadow Thickness" msgstr "კონტაქტური ჩრდილების სისქე" +msgid "Pixel thickness used to detect occlusion" +msgstr "დახშობის აღმოსაჩენი პიქსელური სისქე" + + +msgctxt "Light" +msgid "Power" +msgstr "ხარისხი" + + +msgid "Light energy emitted over the entire area of the light in all directions" +msgstr "სინათლის მთელი არეალიდან ყველა მიმართულებით გამოცემული შუქის ენერგია" + + msgid "Falloff Type" msgstr "მილევის ტიპი" +msgid "Intensity Decay with distance" +msgstr "ინტენსივობის დავარდნა დაშორებასთან ერთად" + + msgid "Inverse Linear" msgstr "ინვერსიული წრფივი" +msgid "Inverse Square" +msgstr "ინვერსიული კვადრატი" + + msgid "Inverse Coefficients" msgstr "ინვერსიული კოეფიციენტები" @@ -23546,42 +23715,86 @@ msgid "Linear Attenuation" msgstr "წრფივი შესუსტება" +msgid "Linear distance attenuation" +msgstr "წრფივი მანძილისმიერი შესუსტები" + + msgid "Linear Coefficient" msgstr "წრფივი კოეფიციენტი" +msgid "Linear distance attenuation coefficient" +msgstr "წრფივი მანძილისმიერი შესუსტების კოეფიციენტი" + + msgid "Quadratic Attenuation" msgstr "კვადრატული შესუსტება" +msgid "Quadratic distance attenuation" +msgstr "კვადრატული მანძილისმიერი შესუსტება" + + msgid "Quadratic Coefficient" msgstr "კვადრატული კოეფიციენტი" +msgid "Quadratic distance attenuation coefficient" +msgstr "კვადრატული მანძილისმიერი შესუსტების კოეფიციენტი" + + msgid "Shadow Buffer Bias" msgstr "ჩრდილის ბუფერის მიკერძოება" +msgid "Bias for reducing self shadowing" +msgstr "მიკერძოება თვითდაჩრდილვის თავიდან ასაცილებლად" + + msgid "Shadow Buffer Clip Start" -msgstr "რდილის ბუფერის ჩამოჭრის დასაწყისი" +msgstr "ჩრდილის ბუფერის ჩამოჭრის დასაწყისი" + + +msgid "Shadow map clip start, below which objects will not generate shadows" +msgstr "ჩრდილის რუკის ჩამოჭრის დასაწყისი, რომლის ქვემოთაც ობიექტები ჩრდილს არ წარმოქმნიან" msgid "Samples" msgstr "სემპლები" +msgid "Number of shadow buffer samples" +msgstr "რდილის ბუფერის სემპლების რიცხვი" + + msgid "Shadow Buffer Size" msgstr "ჩრდილის ბუფერის ზომა" +msgid "Resolution of the shadow buffer, higher values give crisper shadows but use more memory" +msgstr "ჩრდილის ბუფერის გარჩევადობა, უფრო მაღალი მნიშვნელობები უფრო მკვეთრ ჩრდილებს იძლევა, მაგრამ მეტ მეხსიერებას იყენებს" + + msgid "Shadow Color" msgstr "ჩრდილის ფერი" +msgid "Color of shadows cast by the light" +msgstr "სინათლის მიერ წარმოქმნილი ჩრდილის ფერი" + + msgid "Shadow Soft Size" msgstr "ჩრდილის სირბილის ზომა" +msgid "Light size for ray shadow sampling (Raytraced shadows)" +msgstr "სინათლის ზომა სხივური ჩრდილის სემპლინგისთვის (სხივების მიდევნებით შექმნილი ჩრდილები)" + + +msgid "Shape of the area Light" +msgstr "არეალური სინათლის ფორმა" + + msgid "Rectangle" msgstr "მართკუთხედი" @@ -23594,14 +23807,30 @@ msgid "Ellipse" msgstr "ელიფსი" +msgid "Size of the area of the area light, X direction size for rectangle shapes" +msgstr "არეალური სინათლის არეალის ზომა, X მიმართულების ზომა მართკუთხა ფორმებისთვის" + + msgid "Size Y" msgstr "ზომა Y" +msgid "Size of the area of the area light in the Y direction for rectangle shapes" +msgstr "არეალური სინათლის არეალის ზომა Y მიმართულებით მართკუთხა ფორმებისთვის" + + +msgid "How widely the emitted light fans out, as in the case of a gridded softbox" +msgstr "რამდენად ფართოდ იშლება გამოცემული სინათლე, როგორც ცხაურიანი სოფთბოქსის შემთხვევაში" + + msgid "Contact Shadow" msgstr "კონტაქტური ჩრდილი" +msgid "Use screen space ray-tracing to have correct shadowing near occluder, or for small features that does not appear in shadow maps" +msgstr "გამოიყენე ეკრანული სივრცის სხივების მიდევნება, რომ მომჩრდილველის მახლობლად სწორი მოჩრდილვა მოხდეს, ან პატარა შტრიხებისთვის, რომლებიც ჩრდილის რუკებში არ ჩნდება" + + msgid "Point Light" msgstr "წერტილოვანი სინათლე" @@ -23618,74 +23847,194 @@ msgid "Directional cone Light" msgstr "მიმართული კონუსური სინათლე" +msgid "The energy this light would emit over its entire area if it wasn't limited by the spot angle" +msgstr "ენერგია, რომელსაც ეს სინათლე გამოსცემს" + + msgid "Show Cone" msgstr "კონუსის ჩვენება" +msgid "Display transparent cone in 3D view to visualize which objects are contained in it" +msgstr "ასახე გამჭვირვალე კონუსი 3გ ხედში იმის ვიზუალიზაციისთვის, თუ რომელ ობიექტებს მოიცავს იგი" + + msgid "Spot Blend" msgstr "ლაქის შერევა" +msgid "The softness of the spotlight edge" +msgstr "პროჟექტორის კიდის სირბილე" + + msgid "Spot Size" msgstr "ლაქის ზომა" +msgid "Angle of the spotlight beam" +msgstr "პროჟექტორის სვეტის კუთხე" + + +msgid "Cast a square spot light shape" +msgstr "დაუშვი კვადრატული პროჟექტორის ფორმა" + + msgid "Sun Light" msgstr "მზის სინათლე" +msgid "Constant direction parallel ray Light" +msgstr "მუდმივი მიმართულების მქონე პარალელურ სხივებიანი სინათლე" + + +msgid "Angular diameter of the Sun as seen from the Earth" +msgstr "მზის კუთხოვანი დიამეტრი, დანახული დედამიწიდან" + + +msgid "Sunlight strength in watts per meter squared (W/m^2)" +msgstr "მზის სინათლის სიძლიერე ვატებში ყოველ კვადრატულ მეტრზე (ვტ/მ^2)" + + msgid "Cascade Count" -msgstr "კასკადების რაოდენობა" +msgstr "კასკადების რიცხვი" + + +msgid "Number of texture used by the cascaded shadow map" +msgstr "კასკადურ ჩრდილთა რუკის მიერ გამოყენებული ტექსტურების რიცხვი" msgid "Exponential Distribution" msgstr "ექსპონენტური განაწილება" +msgid "Higher value increase resolution towards the viewpoint" +msgstr "უფრო მაღალი მნიშვნელობა ზრდის გარჩევადობას თვალთახედვის წერტილის მიმართ" + + msgid "Cascade Fade" msgstr "კასკადების მილევა" +msgid "How smooth is the transition between each cascade" +msgstr "რამდენად თანაბარია გარდასვლა კასკადებს შორის" + + msgid "Cascade Max Distance" msgstr "კასკადების მაქსიმალური დაშორება" +msgid "End distance of the cascaded shadow map (only in perspective view)" +msgstr "კასკადური ჩრდილის რუკის დასრულების მანძილი (მხოლოდ პერსპექტიულ ხედში)" + + +msgid "Light Probe data-block for lighting capture objects" +msgstr "სინათლის ზონდის მონაცემთა ბლოკი დასაფიქსირებელი ობიექტების განათებისთვის" + + +msgid "Probe clip end, beyond which objects will not appear in reflections" +msgstr "დასასრული ზონდის ჩამოჭრისა, რომლის მიღმაც ობიექტები ანარეკლებში აღარ გამოჩნდება" + + +msgid "Probe clip start, below which objects will not appear in reflections" +msgstr "დასაწყისი ზონდის ჩამოჭრისა, რომლის მიღმაც ობიექტები ანარეკლებში აღარ გამოჩნდება" + + +msgid "Control how fast the probe influence decreases" +msgstr "აკონტროლე, რამდენად სწრაფად მცირდება ზონდის ზეგავლენა" + + msgid "Resolution X" msgstr "გარჩევადობა X" +msgid "Number of sample along the x axis of the volume" +msgstr "სემპლების რაოდენობა ამ მოცულობის x ღერძის გაყოლებაზე" + + msgid "Resolution Y" msgstr "გარჩევადობა Y" +msgid "Number of sample along the y axis of the volume" +msgstr "სემპლების რაოდენობა ამ მოცულობის y ღერძის გაყოლებაზე" + + msgid "Resolution Z" msgstr "გარჩევადობა Z" +msgid "Number of sample along the z axis of the volume" +msgstr "სემპლების რაოდენობა ამ მოცულობის z ღერძის გაყოლებაზე" + + msgid "Influence Distance" msgstr "გავლენის მანძილი" +msgid "Influence distance of the probe" +msgstr "ზონდის ზეგავლენის მანძილი" + + +msgid "Type of influence volume" +msgstr "ზეგავლენის მოცულობის ტიპი" + + msgid "Intensity" msgstr "ინტენსივობა" +msgid "Modify the intensity of the lighting captured by this probe" +msgstr "დაამოდიფიცირე ამ ზონდის მიერ დაფიქსირებული განათების ინტენსივობა" + + msgid "Invert Collection" -msgstr "კოლექციის ინვერტირება" +msgstr "კოლექციის შექცევა" + + +msgid "Invert visibility collection" +msgstr "ხილვადობის კოლექციის შექცევა" msgid "Parallax Radius" msgstr "პარალაქსის რადიუსი" +msgid "Lowest corner of the parallax bounding box" +msgstr "პარალაქსის ზღუდის კოლოფის ყველაზე ქვემო კუთხე" + + +msgid "Type of parallax volume" +msgstr "პარალაქსის მოცულობის ტიპი" + + +msgid "Show the clipping distances in the 3D view" +msgstr "აჩვენე ჩამოჭრის მანძილები 3გ ხედში" + + msgid "Show Preview Plane" msgstr "წინასწარი ხედის სიბრტყის ჩვენება" +msgid "Show captured lighting data into the 3D view for debugging purpose" +msgstr "აჩვენე დაფიქსირებული განათების მონაცემები 3გ ხედში ხარვეზების აღმოფხვრისთვის" + + +msgid "Show the influence volume in the 3D view" +msgstr "აჩვენე ზეგავლენის მოცულობა 3გ ხედში" + + msgid "Parallax" msgstr "პარალაქსი" +msgid "Show the parallax correction volume in the 3D view" +msgstr "აჩვენე პარალაქსის შემასწორებელი მოცულობა 3გ ხედში" + + +msgid "Type of light probe" +msgstr "სინათლის ზონდის ტიპი" + + msgid "Reflection Cubemap" msgstr "ანარეკლის კუბური ზონდი" @@ -23710,14 +24059,26 @@ msgid "Use Custom Parallax" msgstr "მორგებული პარალაქსის გამოყენება" +msgid "Enable custom settings for the parallax correction volume" +msgstr "ჩაურთე პარალაქსის შემასწორებელ მოცულობას მორგებული პარამეტრები" + + msgid "Visibility Bleed Bias" msgstr "ხილულობის ჟონვის მიკერძოება" +msgid "Bias for reducing light-bleed on variance shadow maps" +msgstr "მიკერძოება, რომელიც ამცირებს სინათლის ჟონვას დისპერსიულ ჩრდილების რუკებზე" + + msgid "Visibility Blur" msgstr "ხილულობის გადღაბნა" +msgid "Filter size of the visibility blur" +msgstr "ხილულობის გადღაბნის ფილტრის ზომა" + + msgid "Visibility Bias" msgstr "ხილულობის მიკერძოება" @@ -23726,30 +24087,82 @@ msgid "Visibility Collection" msgstr "ხილულობის კოლექცია" +msgid "Restrict objects visible for this probe" +msgstr "შეზღუდე ამ ზონდისთვის ხილული ობიექტები" + + +msgid "Mask data-block defining mask for compositing" +msgstr "კომპოზიტინგისთვის ნიღბის განსასაზღვრი ნიღბის მონაცემთა ბლოკი" + + msgid "Active Shape Index" msgstr "აქტიური ფორმის ინდექსი" +msgid "Index of active layer in list of all mask's layers" +msgstr "აქტიური შრის ინდექსი ნიღბის ყველა შრის სიაში" + + +msgid "Final frame of the mask (used for sequencer)" +msgstr "ნიღბის ბოლო კადრი (სეკვენსერისთვის)" + + +msgid "First frame of the mask (used for sequencer)" +msgstr "ნიღბის პირველი კადრი (სეკვენსერისთვის)" + + +msgid "Collection of layers which defines this mask" +msgstr "ამნიღბის განმსაზღვრელი შრეების კოლექცია" + + +msgid "Material data-block to define the appearance of geometric objects for rendering" +msgstr "მასალის მონაცემთა ბლოკი, რომელიც რენდერისას გეომეტრიული ობიექტების გარეგნობას განსაზღვრავს" + + msgid "Clip Threshold" msgstr "ჩამოჭრის ზღვარი" +msgid "A pixel is rendered only if its alpha value is above this threshold" +msgstr "პიქსელი დარენდერდება მხოლოდ იმ შემთხვევაში, თუ მისი ალფა მნიშვნელობა ამ ზღვარს ზემოთაა" + + +msgid "Blend Mode for Transparent Faces" +msgstr "შერევის რეჟიმი გამჭვირვალე წახნაგებისთვის" + + msgid "Opaque" msgstr "გაუმჭვირვალი" +msgid "Render surface without transparency" +msgstr "დაარენდერე ზედაპირი გამჭვირვალობის გარეშე" + + msgid "Alpha Clip" msgstr "ალფა ჩამოჭრა" +msgid "Use the alpha threshold to clip the visibility (binary visibility)" +msgstr "გამოიყენე ალფა ზღვარი ხილვადობის ჩამოსაჭრელად (ბინარული ხილვადობა)" + + msgid "Alpha Hashed" msgstr "ალფა ჰეშირებული" +msgid "Use noise to dither the binary visibility (works well with multi-samples)" +msgstr "გამოიყენე ხმაური ბინარულ ხილვადობაში გაფანტული ხმაურის დასამატებლად (კარგად მუშაობს მრავალსემპლთან)" + + msgid "Alpha Blend" msgstr "ალფა შერევა" +msgid "Render polygon transparent, depending on alpha channel of the texture" +msgstr "ტექსტურის ალფა არხის მიხედვით დაარენდერე მრავალკუთხედები გამჭვირვალედ" + + msgid "Cycles Material Settings" msgstr "Cycles-ის მასალის პარამეტრები" @@ -23778,34 +24191,74 @@ msgid "Is Grease Pencil" msgstr "ცვილის ფანქარია" +msgid "True if this material has grease pencil data" +msgstr "ჭეშმარიტია, თუ ამ მასალას გააჩნია ცვილის ფანქრის მონაცემები" + + msgid "Line Color" msgstr "ხაზის ფერი" +msgid "Line color used for Freestyle line rendering" +msgstr "თავისუფალი სტილის ხაზის რენდერისთვის გამოყენებული ხაზის ფერი" + + msgid "Line Priority" msgstr "ხაზის პრიორიტეტულობა" +msgid "The line color of a higher priority is used at material boundaries" +msgstr "მასალების საზღვრებთან გამოიყენება ხაზის შედარებით მაღალი პრიორიტეტის ფერი" + + msgid "Line Art Settings" msgstr "მოხაზულობის პარამეტრები" +msgid "Line art settings for material" +msgstr "მოხაზულობის პარამეტრები მასალისთვის" + + msgid "Metallic" -msgstr "ლითონისებური" +msgstr "ლითონური" + + +msgid "Amount of mirror reflection for raytrace" +msgstr "სარკის მიერ არეკლვის ოდენობა სხივების მიდევნებისთვის" + + +msgid "Node tree for node based materials" +msgstr "კვანძური ხე კვანძოვანი მასალებისთვის" msgid "Active Paint Texture Index" msgstr "აქტიური სახატი ტექსტურის ინდექსი" +msgid "Index of active texture paint slot" +msgstr "აქტიური სახატი ტექსტურის სლოტის ინდექსი" + + msgid "Clone Paint Texture Index" msgstr "კლონირებადი სახატი ტექსტურის ინდექსი" +msgid "Index of clone texture paint slot" +msgstr "კლონირებადი სახატი ტექსტურის ინდექსი" + + +msgid "Index number for the \"Material Index\" render pass" +msgstr "ინდექსის ნომერია სარენდერო გავლისთვის \"Material Index\"" + + msgid "Preview Render Type" msgstr "რენდერის წინასწარი ხედის ტიპი" +msgid "Type of preview render" +msgstr "წინასწარი ხედით რენდერის ტიპი" + + msgid "Flat XY plane" msgstr "ბრტყელი XY სიბრტყე" @@ -23834,14 +24287,46 @@ msgid "Refraction Depth" msgstr "გარდატეხის სიღრმე" +msgid "Approximate the thickness of the object to compute two refraction events (0 is disabled)" +msgstr "გარდატეხის ორი მოვლენის გამოსათვლელად დაადგინე ობიექტის მიახლოებითი სისქე (0 ნიშნავს გათიშვას)" + + msgid "Roughness" msgstr "ხეშეშობა" +msgid "Roughness of the material" +msgstr "მასალის ხეშეშობა" + + msgid "Shadow Mode" msgstr "ჩრდილის რეჟიმი" +msgid "Shadow mapping method" +msgstr "ჩრდილის გადანაწილების მეთოდი" + + +msgid "Material will cast no shadow" +msgstr "მასალას არ ექნება ჩრდილი" + + +msgid "Material will cast shadows without transparency" +msgstr "მასალისგან დაცემულ ჩრდილებს არ ექნება გამჭვირვალობა" + + +msgid "Use noise to dither the binary visibility and use filtering to reduce the noise" +msgstr "გამოიყენე ხმაური ბინარულ ხილვადობაში გაფანტული ხმაურის დასამატებლად, ხოლო ხმაურის შესამცირებლად გამოიყენე გაფილტრვა" + + +msgid "Show Backface" +msgstr "უკუმხრის ჩვენებ" + + +msgid "Render multiple transparent layers (may introduce transparency sorting problems)" +msgstr "დაარენდერე რამდენიმე გამჭვირვალე შრე (შეიძლება წარმოშვას გამჭვირვალების დახარისხებასთან დაკავშირებული პრობლემები)" + + msgid "Specular Color" msgstr "სპეკულარული ფერი" @@ -23862,6 +24347,10 @@ msgid "Texture Slot Images" msgstr "ტექსტურის სლოტის გამოსახულებები" +msgid "Texture images used for texture painting" +msgstr "ტექსტურული გამოსახულებები ტექსტურული ხატვისთვის" + + msgid "Texture Slots" msgstr "ტექსტურების სლოტები" @@ -23874,22 +24363,54 @@ msgid "Use back face culling to hide the back side of faces" msgstr "წახნაგების უკანა მხრის დასამალად გამოიყენე უკუმხრის წახნაგების გამოხშირვა" +msgid "Use shader nodes to render the material" +msgstr "მასალების დასარენდერებლად გამოიყენე იერფერების კვანძები" + + msgid "Preview World" msgstr "წინასწარი ხედის სამყარო" +msgid "Use the current world background to light the preview render" +msgstr "რენდერის წინასწარი ხედის გასანათებლად გამოიყენე ამჟამინდელი სამყაროს ფონი" + + msgid "Screen Space Refraction" msgstr "ეკრანის სივრცის გარდატეხა" +msgid "Use raytraced screen space refractions" +msgstr "გამოიყენე ეკრანული სივრცის მიდევნებულ სხივებიანი გარდატეხები" + + msgid "Subsurface Translucency" msgstr "ზედაპირქვეშა გაშუქებადობა" +msgid "Add translucency effect to subsurface" +msgstr "დაამატე გაშუქებადობის ეფექტი " + + +msgid "Mesh data-block defining geometric surfaces" +msgstr "მეშის მონაცემთა ბლოკები, რომლებიც გეომეტრიულ ზედაპირებს განსაზღვრავენ" + + msgid "Auto Smooth Angle" msgstr "ავტომატური სიგლუვის კუთხე" +msgid "Maximum angle between face normals that will be considered as smooth (unused if custom split normals data are available)" +msgstr "მაქსიმალური დახრილობის კუთხე წახნაგის ნორმალებს შორის, რომელიც გლუვად ჩაითვლება (გამოუყენებელია, თუკი მორგებული გახლეჩილი ნორმალების მონაცემები ხელმისაწვდომია)" + + +msgid "Edge Creases" +msgstr "წიბოს ნაკეცები" + + +msgid "Sharpness of the edges for subdivision" +msgstr "წიბოების წამახულობა დაყოფისთვის" + + msgid "Edges" msgstr "წიბოები" @@ -23898,22 +24419,62 @@ msgid "Edges of the mesh" msgstr "მეშის წიბოები" +msgid "Has Edge Bevel Weight" +msgstr "აქვს წიბოს დაცერობების წონა" + + +msgid "True if the mesh has an edge bevel weight layer" +msgstr "ჭეშმარიტია, თუ მეშს აქვს წიბოს დაცერობების წონის შრე" + + msgid "Has Vertex Bevel Weight" msgstr "აქვს წვეროს დაცერობების წონა" +msgid "True if the mesh has an vertex bevel weight layer" +msgstr "ჭეშმარიტია, თუ მეშს აქვს წვეროს დაცერობების წონის შრე" + + +msgid "Has Edge Crease" +msgstr "აქვს წიბოს ნაკეცი" + + +msgid "True if the mesh has an edge crease layer" +msgstr "ჭეშმარიტია, თუ მეშს აქვს წიბოს ნაკეცის შრე" + + +msgid "Has Vertex Crease" +msgstr "აქვს წვეროს ნაკეცი" + + +msgid "True if the mesh has an vertex crease layer" +msgstr "ჭეშმარიტია, თუ მეშს აქვს წვეროს ნაკეცის შრე" + + msgid "Has Custom Normals" msgstr "აქვს მორგებული ნორმალები" +msgid "True if there are custom split normals data in this mesh" +msgstr "ჭეშმარიტია, თუ ამ მეშში არსებობს მორგებული გახლეჩილი ნორმალების მონაცემები" + + msgid "Loop Triangles" msgstr "მარყუჟის სამკუთხედები" +msgid "Tessellation of mesh polygons into triangles" +msgstr "მეშის მრავალკუთხედების სამკუთხედებით მოკირწყვლა" + + msgid "Loops" msgstr "მარყუჟები" +msgid "Loops of the mesh (polygon corners)" +msgstr "მეშის მარყუჟები (მრავალკუთხედის კუთხეები)" + + msgid "Float Property Layers" msgstr "ათწილადი თვისებების შრეები" @@ -23930,10 +24491,18 @@ msgid "Polygon Normals" msgstr "მრავალკუთხედის ნორმალები" +msgid "The normal direction of each polygon, defined by the winding order and position of its vertices" +msgstr "თითოეული მრავალკუთხედის ნორმალის მიმართულება, მისი წვეროების წრიული თანმიმდევრობისა და პოზიციების მიხედვით" + + msgid "Polygons" msgstr "მრავალკუთხედები" +msgid "Polygons of the mesh" +msgstr "მეშის მრავალკუთხედები" + + msgid "Remesh Mode" msgstr "მეშის გარდასახვის რეჟიმი" @@ -23942,50 +24511,106 @@ msgid "Voxel" msgstr "ვოქსელი" +msgid "Use the voxel remesher" +msgstr "გამოიყენე მეშის ვოქსელური გარდამქმნელი" + + msgid "Quad" msgstr "ოთხკუთხა" +msgid "Use the quad remesher" +msgstr "გამოიყენე ოთხკუთხა მეშის გარდამსახველი" + + msgid "Adaptivity" msgstr "ადაპტირებადობა" +msgid "Reduces the final face count by simplifying geometry where detail is not needed, generating triangles. A value greater than 0 disables Fix Poles" +msgstr "ამცირებს წახნაგების საბოლოო რიცხვს გეომეტრიის გამარტივებით იქ, სადაც დეტალები არაა საჭირო, წარმოქმნის სამკუთხედებს. 0-ზე დიდი მნიშვნელობა თიშავს პოლუსების შესწორებას" + + msgid "Voxel Size" msgstr "ვოქსელების ზომა" +msgid "Size of the voxel in object space used for volume evaluation. Lower values preserve finer details" +msgstr "მოცულობის შეფასებისთვის გამოყენებული ვოქსელის ზომა ობიექტის სივრცეში. უფრო მცირე მნიშვნელობები უფრო წვრილმან დეტალებს ინარჩუნებენ." + + +msgid "Sculpt Vertex Colors" +msgstr "წვეროთა ფერების ძერწვა" + + +msgid "Sculpt vertex color layers. Deprecated, use color attributes instead" +msgstr "წვეროთა ფერების ძერწვის შრე. მოძველებულია, ამის მაგივრად ფერის ატრიბუტები გამოიყენე" + + msgid "Skin Vertices" msgstr "გარეკანის წვეროები" +msgid "All skin vertices" +msgstr "გარეკანის ყველა წვერო" + + msgid "Texture Space Mesh" msgstr "ტექსტურული სივრცის მეში" +msgid "Derive texture coordinates from another mesh" +msgstr "გამოიტანე ტექსტურული კოორდინატები სხვა მეშიდან" + + msgid "Texture space location" msgstr "ტექსტურული სივრცის მდებარეობა" +msgid "Texture space size" +msgstr "ტექსტურული სივრცის ზომა" + + msgid "Texture Mesh" msgstr "ტექსტურის მეში" +msgid "Use another mesh for texture indices (vertex indices must be aligned)" +msgstr "გამოიყენე სხვა მეში ტექსტურის ინდექსებისთვის (წვეროთა ინდექსები გამწკრივებული უნდა იყოს)" + + msgid "Selected Edge Total" msgstr "მონიშნული გვერდების ჯამი" +msgid "Selected edge count in editmode" +msgstr "მონიშნული წიბოების რაოდენობა რედაქტირების რეჟიმში" + + msgid "Selected Face Total" msgstr "მონიშნული წახნაგების ჯამი" +msgid "Selected face count in editmode" +msgstr "მონიშნული წახნაგების რაოდენობა რედაქტირების რეჟიმში" + + msgid "Selected Vertex Total" msgstr "მონიშნულ წვეროთა ჯამი" +msgid "Selected vertex count in editmode" +msgstr "მონიშნული წვეროების რაოდენობა რედაქტირების რეჟიმში" + + msgid "Auto Smooth" msgstr "ავტომატური დაგლუვება" +msgid "Auto smooth (based on smooth/sharp faces/edges and angle between faces), or use custom split normals data if available" +msgstr "ავტომატურად დააგლუვე (გლუვი/მკვეთრი წახნაგების/წიბოების და წახნაგთა შორის დახრილობის კუთხის მიხედვით), ან გამოიყენე მორგებული გახლეჩილი ნორმალების მონაცემები, თუ ხელმისაწვდომია" + + msgid "Topology Mirror" msgstr "ტოპოლოგიური სარკე" @@ -23998,34 +24623,70 @@ msgid "Mirror Vertex Groups" msgstr "წვეროთა ჯგუფების სარკისებური არეკლვა" +msgid "Mirror the left/right vertex groups when painting. The symmetry axis is determined by the symmetry settings" +msgstr "ხატვისას გაასარკისებურე მარცხენა/მარჯვენა წვეროთა ჯგუფები. სიმეტრიის ღერძი დგინდება სიმეტრიის პარამეტრებით" + + msgid "Paint Mask" -msgstr "დახატული ნიღაბი" +msgstr "ხატვის ნიღაბი" + + +msgid "Face selection masking for painting" +msgstr "წახნაგების მონიშნვის შენიღბვა ხატვისთვის" msgid "Vertex Selection" msgstr "წვეროთა მონიშნვა" +msgid "Vertex selection masking for painting" +msgstr "წვეროთა მონიშნვის შენიღბვა ხატვისთვის" + + msgid "Fix Poles" -msgstr "გაასწორე პოლუსები" +msgstr "პოლუსები გასწორება" + + +msgid "Produces less poles and a better topology flow" +msgstr "ჰქმნის ნაკლებ პოლუსს და უფრო მწყობრ ტოპოლოგიას" msgid "Preserve Paint Mask" -msgstr "შეინარჩუნე დახატული ნიღაბი" +msgstr "ხატვის ნიღბის შენარჩუნება" + + +msgid "Keep the current mask on the new mesh" +msgstr "შეინარჩუნე ამჟამინდელი ნიღაბი ახალ მეშზე" msgid "Preserve Face Sets" msgstr "წახნაგთა ნაკრებების შენარჩუნება" +msgid "Keep the current Face Sets on the new mesh" +msgstr "შეინარჩუნე წახნაგთა ამჟამინდელი ნაკრები ახალ მეშზე" + + msgid "Preserve Vertex Colors" msgstr "წვეროთა ფერების შენარჩუნება" +msgid "Keep the current vertex colors on the new mesh" +msgstr "შეინარჩუნე ამჟამინდელი წვეროთა ფერები ახალ მეშზე" + + +msgid "Projects the mesh to preserve the volume and details of the original mesh" +msgstr "აპროექცირებს მეშს მოცულობისა და ორიგინალი მეშის დეტალების შესანარჩუნებლად" + + msgid "Clone UV Loop Layer" msgstr "UV მარყუჟის შრის კლონირება" +msgid "UV loop layer to be used as cloning source" +msgstr "კლონირების წყაროდ გამოსაყენებელი UV მარყუჟის შრე" + + msgid "Clone UV Loop Layer Index" msgstr "UV მარყუჟის შრის ინდექსის კლონირება" @@ -24054,18 +24715,34 @@ msgid "Vertex Colors" msgstr "წვეროს ფერები" +msgid "Legacy vertex color layers. Deprecated, use color attributes instead" +msgstr "წვეროთა ფერების ძველებური შრეები. მოძველებულია, ამის ნაცვლად გამოიყენე ფერის ატრიბუტი" + + msgid "Vertex Creases" msgstr "წვეროთა ნაკეცები" +msgid "Sharpness of the vertices" +msgstr "წვეროთა წამახულობა" + + msgid "Vertex Normals" msgstr "წვეროთა ნორმალები" +msgid "The normal direction of each vertex, defined as the average of the surrounding face normals" +msgstr "თითოეული წვეროს ნორმალის მიმართულება, განსაზღვრული გარშემომყოფი წახნაგების ნორმალების საშუალოდ" + + msgid "Vertex Paint Mask" msgstr "წვეროებზე ხატვის ნიღაბი" +msgid "Vertex paint mask" +msgstr "წვეროებზე ხატვის ნიღაბი" + + msgid "Vertices" msgstr "წვეროები" @@ -24074,6 +24751,10 @@ msgid "Vertices of the mesh" msgstr "მეშის წვეროები" +msgid "Metaball data-block to defined blobby surfaces" +msgstr "მეტაბურთის მონაცემთა ბლოკი დაბუშტული ზედაპირების გამოსაკვეთად" + + msgid "Metaball elements" msgstr "მეტაბურთის ელემენტები" @@ -24082,42 +24763,138 @@ msgid "Render Size" msgstr "რენდერის ზომა" +msgid "Polygonization resolution in rendering" +msgstr "გამრავალკუთხედების გარჩევადობა რენდერში" + + msgid "Wire Size" msgstr "მავთულის ზომა" +msgid "Polygonization resolution in the 3D viewport" +msgstr "გამრავალკუთხედების გარჩევადობა 3გ სარკმელში" + + +msgid "Influence of metaball elements" +msgstr "მეტაბურთის ელემენტების ზეგავლენა" + + msgid "Update" msgstr "განახლება" +msgid "Metaball edit update behavior" +msgstr "მეტაბურთის განახლებასთან დაკავშირებული ქცევა რედაქტირების დროს" + + +msgid "While editing, update metaball always" +msgstr "რედაქტირების განმავლობაში მუდმივად განაახლე მეტაბურთი" + + +msgid "While editing, update metaball in half resolution" +msgstr "რედაქტირების განმავლობაში განაახლე მეტაბურთი განახევრებული გარჩევადობით" + + msgid "Fast" msgstr "სწრაფი" +msgid "While editing, update metaball without polygonization" +msgstr "რედაქტირების განმავლობაში განაახლე მეტაბურთი გამრავალკუთხედების გარეშე" + + msgid "Never" msgstr "არასდროს" +msgid "While editing, don't update metaball at all" +msgstr "რედაქტირების განმავლობაში საერთოდ ნუ განაახლებ მეტაბურთს" + + +msgid "MovieClip data-block referencing an external movie file" +msgstr "ვიდეო კლიპის მონაცემთა ბლოკი, რომელიც გარეგან ვიდეო ფაილზე მიუთითებს" + + +msgid "Display Aspect for this clip, does not affect rendering" +msgstr "ასახვის პროპორცია ამ კლიპისთვის, რენდერზე ზემოქმედება არა აქვს" + + +msgid "Filename of the movie or sequence file" +msgstr "ვიდეოს ფაილის, ან ნაწილის ფაილის სახელი " + + msgid "Frame Rate" msgstr "კადრების სიხშირე" +msgid "Detected frame rate of the movie clip in frames per second" +msgstr "ვიდეო კლიპის კადრების აღმოჩენილი სიხშირე წამ კადრში" + + +msgid "Detected duration of movie clip in frames" +msgstr "ვიდეო კლიპის აღმოჩენილი ხანგრძლივობა კადრებში" + + +msgid "Offset of footage first frame relative to its file name (affects only how footage is loading, does not change data associated with a clip)" +msgstr "ჩანაწერის პირველი კადრის აცდენა ფაილის სახელთან მიმართებაში (მხოლოდ ჩანაწერის ჩატვირთვაზე ზემოქმედებს, კლიპთან ასოცირებულ მონაცემებს არ ცვლის)" + + +msgid "Global scene frame number at which this movie starts playing (affects all data associated with a clip)" +msgstr "გლობალური სცენის იმ კადრის ნომერი, რომელზეც ეს ვიდეო იწყებს დაკვრას (ზემოქმედებს კლიპთან ასოცირებულ მონაცემებზე)" + + +msgid "Grease pencil data for this movie clip" +msgstr "ცვილის ფანქრის მონაცემები ამ ვიდეო კლიპისთვის" + + +msgid "Width and height in pixels, zero when image data can't be loaded" +msgstr "სიგანე და სიმაღლე პიქსელებში, ნულია, როცა გამოსახულების ჩატვირთვა ვერ ხერხდება" + + +msgid "Where the clip comes from" +msgstr "საიდან მოდის კლიპი" + + msgid "Movie File" msgstr "ვიდეო ფაილი" +msgid "Use Proxy / Timecode" +msgstr "გამოიყენე პროქსი / დროის კოდირება" + + +msgid "Use a preview proxy and/or timecode index for this clip" +msgstr "გამოიყენე წინასწარი ხედის პროქსი და/ან დროის კოდირების ინდექსი ამ კლიპისთვის" + + msgid "Proxy Custom Directory" msgstr "პროქსის მორგებული საქაღალდე" +msgid "Create proxy images in a custom directory (default is movie location)" +msgstr "შექმენი პროქსი გამოსახულებები მორგებულ საქაღალდეში (ნაგულისხმები საქაღალდეა ვიდეოს მდებარეობა)" + + +msgid "Node tree consisting of linked nodes used for shading, textures and compositing" +msgstr "კვანძური ხე, რომელიც შედგება შეფერადებისთვის, ტექსტურებისა და კომპოზიტინგისთვის გამოყენებული ურთიერთდაკავშირებული კვანძებისგან" + + msgid "Active Input" msgstr "აქტიური შემავალი" +msgid "Index of the active input" +msgstr "აქტიური შემავლის ინდექსი" + + msgid "Active Output" msgstr "აქტიური გამომავალი" +msgid "Index of the active output" +msgstr "აქტიური გამომაცლის ინდექსი" + + msgid "ID Name" msgstr "ID სახელი" @@ -24126,26 +24903,54 @@ msgid "Label" msgstr "იარლიყი" +msgid "The node tree label" +msgstr "კვანძური ხის იარლიყი" + + msgid "Grease Pencil Data" msgstr "ცვილის ფანქრის მონაცემები" +msgid "Grease Pencil data-block" +msgstr "ცვილის ფანქრის მონაცემთა ბლოკი" + + msgid "Inputs" msgstr "შემავლები" +msgid "Node tree inputs" +msgstr "კვანძური ხის შემავლები" + + msgid "Links" msgstr "ბმულები" +msgid "Nodes" +msgstr "კვანძები" + + msgid "Outputs" msgstr "გამომავლები" +msgid "Node tree outputs" +msgstr "კვანძური ხის გამომავლები" + + +msgid "Node Tree type (deprecated, bl_idname is the actual node tree type identifier)" +msgstr "კვანძური ხის ტიპი (მოძველებულია, bl_idname არის თავად კვანძური ხის ტიპის იდენტიფიკატორი)" + + msgid "Undefined" msgstr "განუსაზღვრელი" +msgid "Undefined type of nodes (can happen e.g. when a linked node tree goes missing)" +msgstr "კვანძების განუსაზღვრელი ტიპი (შეიძლება მოხდეს, მაგ. როცა დაკავშირებული კვანძური ხე არ იძებნება)" + + msgid "Shader" msgstr "იერფერი" @@ -24159,47 +24964,87 @@ msgstr "ტექსტურის კვანძები" msgid "Compositing nodes" -msgstr "კვანძები კომპოზიტინგისთვის" +msgstr "კომპოზიტინგის კვანძები" msgid "Geometry nodes" -msgstr "კვანძები გეომეტრიისთვის" +msgstr "გეომეტრიის კვანძები" + + +msgid "The current location (offset) of the view for this Node Tree" +msgstr "ხედის ამჟამინდელი მდებარეობა (აცდენა) ამ კვანძური ხისთვის" msgid "Compositor Node Tree" msgstr "კომპოზიტორ კვანძთა ხე" +msgid "Node tree consisting of linked nodes used for compositing" +msgstr "კვანძური ხე, რომელიც შედგება დაკავშირებული კვანძებისგან, რომლებიც კომპოზიტინგისთვის გამოიყენება" + + msgid "Chunksize" msgstr "ნატეხის ზომა" +msgid "Max size of a tile (smaller values gives better distribution of multiple threads, but more overhead)" +msgstr "ფილის მაქსიმალური ზომა (რაც უფრო მცირეა მნიშვნელობები, მით უკეთესია მრავალ ნაკადთა დისტრიბუცია, მაგრამ იმატებს ოვერჰედი)" + + msgid "32x32" msgstr "32x32" +msgid "Chunksize of 32x32" +msgstr "ნაჭრის ზომა 32x32" + + msgid "64x64" msgstr "64x64" +msgid "Chunksize of 64x64" +msgstr "ნაჭრის ზომა 64x64" + + msgid "128x128" msgstr "128x128" +msgid "Chunksize of 128x128" +msgstr "ნაჭრის ზომა 128x128" + + msgid "256x256" msgstr "256x256" +msgid "Chunksize of 256x256" +msgstr "ნაჭრის ზომა 256x256" + + msgid "512x512" msgstr "512x512" +msgid "Chunksize of 512x512" +msgstr "ნაჭრის ზომა 512x512" + + msgid "1024x1024" msgstr "1024x1024" +msgid "Chunksize of 1024x1024" +msgstr "ნაჭრის ზომა 1024x1024" + + msgid "Edit Quality" -msgstr "Edit Quality" +msgstr "რედაქტირების ხარისხი" + + +msgid "Quality when editing" +msgstr "ხარისხი რედაქტირების დროს" msgid "High" @@ -24210,78 +25055,174 @@ msgid "High quality" msgstr "მაღალი ხარისხი" +msgid "Medium quality" +msgstr "საშუალო ხარისხი" + + msgid "Low" msgstr "დაბალი" +msgid "Low quality" +msgstr "დაბალი ხარისხი" + + msgid "Execution Mode" msgstr "გაშვების რეჟიმი" +msgid "Set how compositing is executed" +msgstr "დააყენე, როგორ გაეშვას კომპოზიტინგი" + + msgid "Tiled" msgstr "მიჯრილი" +msgid "Compositing is tiled, having as priority to display first tiles as fast as possible" +msgstr "კომპოზიტინგი მოზაიკურია, პრიორიტეტად აქვს პირველი ფილების რაც შეიძლება მალე ასახვა" + + msgid "Full Frame" -msgstr "მთელი ჩარჩო" +msgstr "მთელი კადრი" + + +msgid "Composites full image result as fast as possible" +msgstr "რაც შეიძლება მალე აკომპოზიტირებს მთლიან გამოსახულებას" msgid "Render Quality" msgstr "რენდერის ხარისხი" +msgid "Quality when rendering" +msgstr "ხარისხი რენდერის დროს" + + msgid "Buffer Groups" -msgstr "ბაფერის ჯგუფები" +msgstr "ბუფერის ჯგუფები" + + +msgid "Enable buffering of group nodes" +msgstr "ჩართე ჯგუფის კვანძების ბუფერიზება" msgid "OpenCL" msgstr "OpenCL" +msgid "Enable GPU calculations" +msgstr "ჩართე GPU გამოთვლები" + + msgid "Two Pass" msgstr "ორი გავლა" +msgid "Use two pass execution during editing: first calculate fast nodes, second pass calculate all nodes" +msgstr "რედაქტირებისას გამოიყენე ორ გავლიანი გაშვება: პირველ რიგში გამოთვალე სწრაფი კვანძები, მეორე გავლით გამოთვალე ყველა კვანძი" + + msgid "Viewer Region" msgstr "მაჩვენებლის მონაკვეთი" +msgid "Use boundaries for viewer nodes and composite backdrop" +msgstr "გამოიყენე ზღუდეები მაჩვენებლის კვანძებისა და კომპოზიტის ფონისთვის" + + msgid "Geometry Node Tree" msgstr "გეომეტრიის კვანძური ხე" +msgid "Node tree consisting of linked nodes used for geometries" +msgstr "კვანძური ხე, რომელიც შედგება გეომეტრიებისთვის გამოყენებული ურთიერთდაკავშირებული კვანძებისგან" + + msgid "Shader Node Tree" msgstr "იერფერის კვანძური ხე" +msgid "Node tree consisting of linked nodes used for materials (and other shading data-blocks)" +msgstr "კვანძური ხე, რომელიც შედგება მასალებისთვის (და შეფერადების სხვა მონაცემთა ბლოკებისთვის) გამოყენებული ურთიერთდაკავშირებული კვანძებისგან" + + msgid "Texture Node Tree" msgstr "ტექსტურის კვანძური ხე" +msgid "Node tree consisting of linked nodes used for textures" +msgstr "კვანძური ხე, რომელიც შედგება ტექსტურებისთვის გამოყენებული ურთიერთდაკავშირებული კვანძებისგან" + + +msgid "Object data-block defining an object in a scene" +msgstr "ობიექტის მონაცემთა ბლოკი, რომელიც განსაზღვრავს ობიექტს სცენაში" + + msgid "Active Material" msgstr "აქტიური მასალა" +msgid "Active material being displayed" +msgstr "ასახული აქტიური მასალა" + + msgid "Active Material Index" msgstr "აქტიური მასალის ინდექსი" +msgid "Index of active material slot" +msgstr "აქტიური მასალის სლოტის ინდექსი" + + msgid "Active Shape Key" -msgstr "აქტიური ფორმის საკვანძო ფაზა" +msgstr "აქტიური ფორმის სოლი" + + +msgid "Current shape key" +msgstr "მიმდინარე ფორმის სოლი" msgid "Active Shape Key Index" -msgstr "აქტიური ფორმის საკვანძო ფაზის ინდექსი" +msgstr "აქტიური ფორმის სოლის ინდექსი" + + +msgid "Current shape key index" +msgstr "მიმდინარე ფორმის სოლის ინდექსი" + + +msgid "Add Rest Position" +msgstr "მოსვენებული პოზიციის დამატება" + + +msgid "Add a \"rest_position\" attribute that is a copy of the position attribute before shape keys and modifiers are evaluated" +msgstr "დაამატე \"მოსვენებული პოზიციის\" ატრიბუტი, რომელიც ფორმის სოლებისა და მოდიფიკატორების შეფასებამდე არსებული პოზიციის ატრიბუტის ასლია" msgid "Bounding Box" -msgstr "მზღუდავი ყუთი" +msgstr "მზღუდავი კოლოფი" + + +msgid "Object's bounding box in object-space coordinates, all values are -1.0 when not available" +msgstr "ობიექტის მზღუდავი კოლოფი ობიექტის სივრცის კოორდინატებში, როცა მიუწვდომელია, ყველა მნიშვნელობა -1.0-ს უდრის" + + +msgid "Settings for using the object as a collider in physics simulation" +msgstr "ფიზიკის სიმულაციაში ობიექტის შემჯახებლად გამოყენების პარამეტრები" + + +msgid "Object color and alpha, used when faces have the ObColor mode enabled" +msgstr "ობიექტის ფერი და ალფა, გამოყენებული, როცა წახნაგებს ObColor რეჟიმი ჩართული აქვს" msgid "Constraints" msgstr "შეზღუდვები" +msgid "Constraints affecting the transformation of the object" +msgstr "ბორკილები, რომლებიც ობიექტის გარდაქმნებზე მოქმედებს" + + msgid "Cycles Object Settings" msgstr "Cycles-ის ობიექტის პარამეტრები" @@ -24302,28 +25243,60 @@ msgid "Delta Location" msgstr "დელტა მდებარეობა" +msgid "Extra translation added to the location of the object" +msgstr "ობიექტის მდებარეობას მიმატებული დამატებითი გადაადგილება" + + msgid "Delta Rotation (Euler)" msgstr "დელტა ბრუნვა (ეილერი)" +msgid "Extra rotation added to the rotation of the object (when using Euler rotations)" +msgstr "ობიექტის ბრუნვას მიმატებული დამატებითი ბრუნვა (როცა ეილერის ბრუნვები გამოიყენება)" + + msgid "Delta Rotation (Quaternion)" msgstr "დელტა ბრუნვა (კვატერნიონი)" +msgid "Extra rotation added to the rotation of the object (when using Quaternion rotations)" +msgstr "ობიექტის ბრუნვას მიმატებული დამატებითი ბრუნვა (როცა კვატერნიონის ბრუნვები გამოიყენება)" + + msgid "Delta Scale" msgstr "დელტა მასშტაბირება" +msgid "Extra scaling added to the scale of the object" +msgstr "ობიექტის მასშტაბს მიმატებული დამატებითი მასშტაბირება" + + +msgid "" +"Absolute bounding box dimensions of the object.\n" +"Warning: Assigning to it or its members multiple consecutive times will not work correctly, as this needs up-to-date evaluated data" +msgstr "" +"ობიექტის მზღუდავი კოლოფის აბსოლუტური ზომები\n" +"ფრთხილად: მისთვის, ან მისი წევრებისთვის რამდენიმეჯერ მიყოლებით მიკუთვნება სწორად არ იმუშავებს, რადგან ამას განახლებული შეფასებული მონაცემები სჭირდება" + + msgid "Object Display" msgstr "ობიექტის ასახვა" +msgid "Object display settings for 3D viewport" +msgstr "ობიექტის ასახვის პარამეტრები 3გ სარკმლისთვის" + + msgid "Display Bounds Type" -msgstr "ზღუდის ასახვის ტიპი" +msgstr "ზღუდეების ასახვის ტიპი" + + +msgid "Object boundary display type" +msgstr "ობიექტის ზღუდის ასახვის ტიპი" msgid "Display bounds as box" -msgstr "ზღუდეების ასახვა ყუთად" +msgstr "ზღუდეების ასახვა კოლოფად" msgid "Display bounds as sphere" @@ -24354,22 +25327,46 @@ msgid "Display As" msgstr "ასახე, როგორც" +msgid "How to display object in viewport" +msgstr "როგორ აისახოს ობიექტი სარკმელში" + + msgid "Bounds" msgstr "ზღუდეები" +msgid "Display the bounds of the object" +msgstr "ასახე ობიექტის ზღუდეები" + + +msgid "Display the object as a wireframe" +msgstr "ასახე ობიექი ბადედ" + + msgid "Solid" msgstr "მყარი" +msgid "Display the object as a solid (if solid drawing is enabled in the viewport)" +msgstr "ასახე ობიექტი მყარად (თუ მყარი ასახვა სარკმელში ნებადართულია)" + + msgid "Textured" msgstr "ტექსტურირებული" +msgid "Display the object with textures (if textures are enabled in the viewport)" +msgstr "ასახე ობიექტი ტექსტურებიანად (თუ ტექსტურები ნებადართულია სარკმელში)" + + msgid "Empty Display Size" msgstr "ცარიელის ასახვის ზომა" +msgid "Size of display for empties in the viewport" +msgstr "ცარიელების სარკმელში ასახვის ზომა" + + msgid "Empty Display Type" msgstr "ცარიელის ასახვის ტიპი" @@ -24398,12 +25395,20 @@ msgid "Empty Image Depth" msgstr "ცარიელი გამოსახულების სიღრმე" +msgid "Determine which other objects will occlude the image" +msgstr "განსაზღვრე სხვა რომელი ობიექტები გადაეღობება გამოსახულებას" + + msgid "Origin Offset" msgstr "ამოსავალი წერტილის აცდენა" +msgid "Origin offset distance" +msgstr "ამოსავალი წერტილის აცდენის მანძილი" + + msgid "Empty Image Side" -msgstr "ცარიელი გამოსახულების გვერდი" +msgstr "ცარიელი გამოსახულების მხარე" msgid "Show front/back side" @@ -24414,44 +25419,108 @@ msgid "Both" msgstr "ორივე" +msgid "Maps of faces of the object" +msgstr "ობიექტის წახნაგების რუკები" + + +msgid "Settings for using the object as a field in physics simulation" +msgstr "პარამეტრები ფიზიკის სიმულაციაში ობიექტის ველად გამოყენებისთვის" + + msgid "Grease Pencil Modifiers" -msgstr "ხვილის ფანქრის მოდიფიკატორები" +msgstr "ცვილის ფანქრის მოდიფიკატორები" + + +msgid "Modifiers affecting the data of the grease pencil object" +msgstr "მოდიფიკატორები, რომლებიც ცვილის ფანქრის ობიექტის მონაცემებზე ზემოქმედებენ" msgid "Instance Collection" -msgstr "კოლექციის ინსტანცია" +msgstr "ინსტანციების კოლექცია" + + +msgid "Instance an existing collection" +msgstr "არსებული კოლექციის ინსტანცირება" msgid "Instance Faces Scale" msgstr "ინსტანცირებული წახნაგების მასშტაბი" +msgid "Scale the face instance objects" +msgstr "წახნაგის ინსტანციის ობიექტის მასშტაბირება" + + msgid "Instance Type" msgstr "ინსტანციის ტიპი" +msgid "If not None, object instancing method to use" +msgstr "ობიექტის ინსტანცირების მეთოდი, თუ არცერთი-ზე არაა დაყენებული" + + +msgid "Instantiate child objects on all vertices" +msgstr "დააინსტანცირე შვილი ობიექტები ყველა წვეროზე" + + msgid "Faces" msgstr "წახნაგები" +msgid "Instantiate child objects on all faces" +msgstr "დააინსტანცირე შვილი ობიექტები ყველა წახნაგზე" + + +msgid "Enable collection instancing" +msgstr "ჩართე კოლექციის ინსტანცირება" + + msgid "Base from Instancer" msgstr "ბაზა ინსტანსერიდან" +msgid "Object comes from a instancer" +msgstr "ობიექტი მოდის ინსტანსერიდან" + + msgid "Base from Set" msgstr "ბაზა ნაკრებიდან" +msgid "Object comes from a background set" +msgstr "ობიექტი მოდის ფონური ნაკრებიდან" + + msgid "Holdout" msgstr "ალაგმული" +msgid "Render objects as a holdout or matte, creating a hole in the image with zero alpha, to fill out in compositing with real footage or another render" +msgstr "დაარენდერე ობიექტები ალაგმულად, ან მქრქალად, გამოსახულებაში ნული ალფათი ხვრელის შექმნით, რომელიც კომპოზიტინგში შეივსება ნამდვილი ჩანაწერით, ან სხვა რენდერით" + + msgid "Shadow Catcher" msgstr "ჩრდილის დამჭერი" +msgid "Only render shadows and reflections on this object, for compositing renders into real footage. Objects with this setting are considered to already exist in the footage, objects without it are synthetic objects being composited into it" +msgstr "დაარენდერე ჩრდილები და ანარეკლები მხოლოდ ამ ობიექტზე, რენდერების რეალურ ჩანაწერად კომპოზიტირებისთვის. ამ პარამეტრიანი ობიექტები ითვლება ჩანაწერში უკვე არსებულად, ობიექტები მის გარეშე კი სინთეტიკური ობიექტებია, რომლებიც მასში კომპოზიტინგით ჩაემატება" + + msgid "Lightgroup" -msgstr "შუქჯგუფი" +msgstr "სინათლის ჯგუფი" + + +msgid "Lightgroup that the object belongs to" +msgstr "სინათლის ჯგუფი, რომელსაც ობიექტი მიეკუთვნება" + + +msgid "Line art settings for the object" +msgstr "მოხაზულობის პარამეტრები ობიექტისთვის" + + +msgid "Location of the object" +msgstr "ობიექტის მდებარეობა" msgid "Lock Location" @@ -24459,7 +25528,7 @@ msgstr "მდებარეობის ჩაკეტვა" msgid "Lock editing of location when transforming" -msgstr "ჩაკეტე ადგილმდებარეობის რედაქტირება გარდაქმნისას" +msgstr "დაბლოკე ადგილმდებარეობის რედაქტირება გარდაქმნისას" msgid "Lock Rotation" @@ -24467,23 +25536,31 @@ msgstr "ბრუნვის ჩაკეტვა" msgid "Lock editing of rotation when transforming" -msgstr "ჩაკეტე ბრუნვის რედაქტირება გარდაქმნისას" +msgstr "დაბლოკე ბრუნვის რედაქტირება გარდაქმნისას" msgid "Lock Rotation (4D Angle)" msgstr "ბრუნვის ჩაკეტვა (4გ კუთხე)" +msgid "Lock editing of 'angle' component of four-component rotations when transforming" +msgstr "დაბლოკე ოთხ კომპონენტიანი ბრუნვის კომპონენტ 'კუთხე'-ს რედაქტირება გარდაქმნისას" + + msgid "Lock Rotations (4D)" msgstr "ბრუნვების ჩაკეტვა (4D)" +msgid "Lock editing of four component rotations by components (instead of as Eulers)" +msgstr "დაბლოკე ოთხ კომპონენტიანი ბრუნვების რედაქტირება კომპონენტების მიერ (ეილერის მაგივრად)" + + msgid "Lock Scale" msgstr "მასშტაბის ჩაკეტვა" msgid "Lock editing of scale when transforming" -msgstr "ჩაკეტე მასშტაბის რედაქტირება გარდაქმნისას" +msgstr "დაბლოკე მასშტაბის რედაქტირება გარდაქმნისას" msgid "Material Slots" @@ -24498,18 +25575,42 @@ msgid "Input Matrix" msgstr "შემავალი მატრიცა" +msgid "Matrix access to location, rotation and scale (including deltas), before constraints and parenting are applied" +msgstr "მატრიცა მდებარეობაზე, ბრუნვასა და მასშტაბზე წვდომისთვის (დელტების ჩათვლით), ბორკილებისა და დაქვემდებარების გამოყენებამდე" + + msgid "Local Matrix" msgstr "ლოკალური მატრიცა" +msgid "" +"Parent relative transformation matrix.\n" +"Warning: Only takes into account object parenting, so e.g. in case of bone parenting you get a matrix relative to the Armature object, not to the actual parent bone" +msgstr "" +"მშობლისადმი მიმართებითი გარდაქმნის მატრიცა.\n" +"ფრთხილად: მხოლოდ ობიექტის დაქვემდებარებას ითვალისწინებს, ასე რომ, მაგ. ძვლის დაქვემდებარების შემთხვევაში იღებ არმატურის ობიექტისადმი მიმართებით მატრიცას, და არა უშუალოდ მშობელ ძვალს" + + msgid "Parent Inverse Matrix" -msgstr "მშობელი ინვერსიული მატრიცა" +msgstr "მშობელი შექცეული მატრიცა" + + +msgid "Inverse of object's parent matrix at time of parenting" +msgstr "ობიექტის მშობელი მატრიცის დაქვემდებარების დროინდელი ვერსიის შექცევა" msgid "Matrix World" msgstr "სამყაროს მატრიცა" +msgid "Worldspace transformation matrix" +msgstr "სამყაროს სივრცეში გარდაქმნის მატრიცა" + + +msgid "Object interaction mode" +msgstr "ობიექტის ურთიერთქმედების რეჟიმი" + + msgid "Object Mode" msgstr "ობიექტის რეჟიმი" @@ -24562,30 +25663,78 @@ msgid "Grease Pencil Vertex Paint Strokes" msgstr "ცვილის ფანქრის წვეროებზე ხატვის მონასმები" +msgid "Modifiers affecting the geometric data of the object" +msgstr "მოდიფიკატორები, რომლებიც ობიექტის გეომეტრიულ მონაცემებზე მოქმედებენ" + + msgid "Motion Path" msgstr "მოძრაობის ტრაექტორია" +msgid "Motion Path for this element" +msgstr "მოძრაობის ტრაექტორია ამ ელემენტისთვის" + + +msgid "The object is parented to an object" +msgstr "ობიექტი ექვემდებარება სხვა ობიექტს" + + +msgid "The object is parented to a lattice" +msgstr "ობიექტი ექვემდებარება გისოსებს" + + +msgid "The object is parented to a vertex" +msgstr "ობიექტი ექვემდებარება წვეროს" + + msgid "3 Vertices" msgstr "3 წვერო" +msgid "The object is parented to a bone" +msgstr "ობიექტი ექვემდებარება ძვალს" + + msgid "Parent Vertices" msgstr "მშობელი წვეროები" +msgid "Indices of vertices in case of a vertex parenting relation" +msgstr "წვეროთა ინდექსები წვეროს დაქვემდებარების შემთხვევაში" + + +msgid "Index number for the \"Object Index\" render pass" +msgstr "ინდექსის ნომერი სარენდერო გავლა \"ობიექტის ინდექსი\"-სთვის " + + +msgid "Current pose for armatures" +msgstr "ამჟამინდელი პოზა არმატურებისთვის" + + msgid "Rigid Body Settings" msgstr "უდრეკი სხეულის პარამეტრები" +msgid "Settings for rigid body simulation" +msgstr "პარამეტრები უდრეკი სხეულის სიმულაციისთვის" + + msgid "Rigid Body Constraint" msgstr "უდრეკი სხეულის ბორკილი" +msgid "Constraint constraining rigid bodies" +msgstr "უდრეკი სხეულების დამბორკავი ბორკილი" + + msgid "Axis-Angle Rotation" msgstr "ღერძის კუთხის ბრუნვა" +msgid "Angle of Rotation for Axis-Angle rotation representation" +msgstr "ბრუნვის კუთხე ღერძის კუთხის ბრუნვის რეპრეზენტაციისთვის" + + msgid "Euler Rotation" msgstr "ეილერული ბრუნვა" @@ -24602,66 +25751,166 @@ msgid "No Gimbal Lock" msgstr "გიმბალური ჩაკეტვის გარეშე" +msgid "XYZ Rotation Order - prone to Gimbal Lock (default)" +msgstr "ბრუნვის XYZ თანმიმდევრობა - გიმბალური ჩაკეტვისკენაა მიდრეკილი (ნაგულისხმები)" + + +msgid "XZY Rotation Order - prone to Gimbal Lock" +msgstr "ბრუნვის XZY თანმიმდევრობა - გიმბალური ჩაკეტვისკენაა მიდრეკილი" + + +msgid "YXZ Rotation Order - prone to Gimbal Lock" +msgstr "ბრუნვის YXZ თანმიმდევრობა - გიმბალური ჩაკეტვისკენაა მიდრეკილი" + + +msgid "YZX Rotation Order - prone to Gimbal Lock" +msgstr "ბრუნვის YZX თანმიმდევრობა - გიმბალური ჩაკეტვისკენაა მიდრეკილი" + + +msgid "ZXY Rotation Order - prone to Gimbal Lock" +msgstr "ბრუნვის ZXY თანმიმდევრობა - გიმბალური ჩაკეტვისკენაა მიდრეკილი" + + +msgid "ZYX Rotation Order - prone to Gimbal Lock" +msgstr "ბრუნვის ZYX თანმიმდევრობა - გიმბალური ჩაკეტვისკენაა მიდრეკილი" + + msgid "Axis Angle" msgstr "ღერძის კუთხე" +msgid "Axis Angle (W+XYZ), defines a rotation around some axis defined by 3D-Vector" +msgstr "ღერძის კუთხე (W+XYZ), განსაზღვრავს ბრუნვას 3გ ვექტორით განსაზღვრული რომელიმე ღერძის გარშემო" + + msgid "Quaternion Rotation" msgstr "კვატერნიონული ბრუნვა" +msgid "Rotation in Quaternions" +msgstr "ბრუნვა კვატერნიონებში" + + +msgid "Scaling of the object" +msgstr "ობიექტის მასშტაბირება" + + msgid "Shader Effects" msgstr "იერფერის ეფექტები" +msgid "Effects affecting display of object" +msgstr "ობიექტის ასახვაზე მოქმედი ეფექტები" + + msgid "Display All Edges" -msgstr "ყველა გვერდის ასახვა" +msgstr "ყველა წიბოს ასახვა" + + +msgid "Display all edges for mesh objects" +msgstr "ასახე ყველა წიბო მეშის ობიექტებისთვის" + + +msgid "Display the object's origin and axes" +msgstr "ასახე ობიექტის ამოსავალი წერტილი და ღერძები" msgid "Display Bounds" msgstr "ზღუდეების ასახვა" +msgid "Display the object's bounds" +msgstr "ასახე ობიექტის ზღუდეები" + + msgid "Display Only Axis Aligned" msgstr "მხოლოდ ღერძზე გასწორებულის ასახვა" +msgid "Only display the image when it is aligned with the view axis" +msgstr "გამოსახულება მხოლოდ მაშინ ასახე, როცა ხედის ღერძთან გასწორებულია" + + msgid "Display in Orthographic Mode" msgstr "ორთოგრაფიულ რეჟიმში ასახვა" +msgid "Display image in orthographic mode" +msgstr "ასახე გამოსახულება ორთოგრაფიულ რეჟიმში" + + msgid "Display in Perspective Mode" msgstr "პერსპექტივის რეჟიმში ასახვა" +msgid "Display image in perspective mode" +msgstr "ასახე გამოსახულება პერსპექტივის რეჟიმში" + + +msgid "Make the object display in front of others" +msgstr "აიძულე ობიექტი, გამოჩნდეს დანარჩენების წინ" + + msgid "Render Instancer" msgstr "ინსტანსერის დარენდერება" +msgid "Make instancer visible when rendering" +msgstr "გამოაჩინე ინსტანსერი რენდერის დროს" + + msgid "Display Instancer" msgstr "ინსტანსერის ასახვა" +msgid "Make instancer visible in the viewport" +msgstr "გამოაჩინე ინსტანსერი სარკმელში" + + msgid "Display Name" msgstr "სახელის ასახვა" +msgid "Display the object's name" +msgstr "ასახე ობიექტის სახელი" + + msgid "Shape Key Lock" -msgstr "ფორმის საკვანძო ფაზის საკეტი" +msgstr "ფორმის სოლის საკეტი" + + +msgid "Always show the current shape for this object" +msgstr "ყოველთვის აჩვენე ამ ობიექტის ამჟამინდელი ფორმა" msgid "Display Texture Space" msgstr "ტექსტურული სივრცის ასახვა" +msgid "Display the object's texture space" +msgstr "ასახე ობიექტის ტექსტურული სივრცე" + + msgid "Display Transparent" msgstr "გამჭვირვალობის ასახვა" +msgid "Display material transparency in the object" +msgstr "ასახე მასალის გამჭვირვალობა ობიექტში" + + +msgid "Display the object's wireframe over solid shading" +msgstr "ასახე ობიექტის ბადე მყარი შეფერადების ზემოდან" + + msgid "Soft Body Settings" msgstr "რბილი სხეულის პარამეტრები" +msgid "Settings for soft body simulation" +msgstr "პარამეტრები რბილი სხეულის სიმულაციისთვის" + + msgctxt "ID" msgid "Type" msgstr "ტიპი" @@ -24676,6 +25925,11 @@ msgid "Surface" msgstr "ზედაპირი" +msgctxt "ID" +msgid "Hair Curves" +msgstr "თმის წირები" + + msgctxt "ID" msgid "Empty" msgstr "ცარიელი" @@ -24685,6 +25939,10 @@ msgid "Camera Parent Lock" msgstr "კამერის მშობლის საკეტი" +msgid "View Lock 3D viewport camera transformation affects the object's parent instead" +msgstr "3გ სარკმლის კამერის გარდაქმნის ჩაკეტვა ხედში ზემოქმედებს ობიექტის მშობელზე" + + msgid "Dynamic Topology Sculpting" msgstr "დინამიური ტოპოლოგიური ძერწვა" @@ -24693,50 +25951,114 @@ msgid "Use Alpha" msgstr "ალფას გამოყენება" +msgid "Use alpha blending instead of alpha test (can produce sorting artifacts)" +msgstr "გამოიყენე ალფა შერევა ალფა ტესტის მაგივრად (შეიძლება დახარისხების არტეფაქტები წარმოშვას)" + + +msgid "Lights affect grease pencil object" +msgstr "სინათლეები ზემოქმედებს ცვილის ფანქრის ობიექტზე" + + msgid "Scale to Face Sizes" msgstr "მასშტაბირება წახნაგთა ზომებით" +msgid "Scale instance based on face size" +msgstr "დაამასშტაბირე ინსტანცია წახნაგის ზომის მიხედვით" + + msgid "Orient with Normals" msgstr "ორიენტირება ნორმალებით" +msgid "Rotate instance according to vertex normal" +msgstr "აბრუნე ინსტანცია წვეროს ნორმალის მიხედვით" + + +msgid "Enable mesh symmetry in the X axis" +msgstr "ჩართე მეშის სიმეტრია X ღერძზე" + + +msgid "Enable mesh symmetry in the Y axis" +msgstr "ჩართე მეშის სიმეტრია Y ღერძზე" + + +msgid "Enable mesh symmetry in the Z axis" +msgstr "ჩართე მეშის სიმეტრია Z ღერძზე" + + msgid "Shape Key Edit Mode" -msgstr "ფორმის საკვანძო ფაზის რედაქტირების რეჟიმი" +msgstr "ფორმის სოლის რედაქტირების რეჟიმი" + + +msgid "Apply shape keys in edit mode (for meshes only)" +msgstr "გამოიყენე ფორმის სოლები რედაქტირების რეჟიმში (მხოლოდ მეშებისთვის)" msgid "Vertex Groups" msgstr "წვეროთა ჯგუფები" +msgid "Vertex groups of the object" +msgstr "ობიექტის წვეროთა ჯგუფები" + + msgid "Camera Visibility" -msgstr "კამერის ხილულობა" +msgstr "ხილულობა კამერისთვის" + + +msgid "Object visibility to camera rays" +msgstr "ობიექტის ხილულობა კამერის სხივებისთვის" msgid "Diffuse Visibility" -msgstr "დიფუზიის ხილულობა" +msgstr "ხილულობა დიფუზიისთვის" + + +msgid "Object visibility to diffuse rays" +msgstr "ობიექტის ხილულობა დიფუზიის სხივებისთვის" msgid "Glossy Visibility" -msgstr "პრიალის ხილულობა" +msgstr "ხილულობა პრიალისთვის" + + +msgid "Object visibility to glossy rays" +msgstr "ობიექტის ხილულობა პრიალის სხივებისთვის" msgid "Shadow Visibility" -msgstr "ჩრდილის ხილვადობა" +msgstr "ხილულობა ჩრდილისთვის" + + +msgid "Object visibility to shadow rays" +msgstr "ობიექტის ხილულობა ჩრდილის სხივებისთვის" msgid "Transmission Visibility" -msgstr "ტრანსმისიის ხილულობა" +msgstr "ხილულობა ტრანსმისიისთვის" + + +msgid "Object visibility to transmission rays" +msgstr "ობიექტის ხილულობა ტრანსმისიის სხივებისთვის" msgid "Volume Scatter Visibility" -msgstr "მოცულობის გაფანტულობის ხილულობა" +msgstr "ხილულობა მოცულობის გაფანტულობისთვის" + + +msgid "Object visibility to volume scattering rays" +msgstr "ობიექტის ხილულობა მოცულობის გაფანტულობის სხივებისთვის" msgid "Particle Settings" msgstr "ნაწილაკთა პარამეტრები" +msgid "Particle settings, reusable by multiple particle systems" +msgstr "ნაწილაკთა პარამეტრები, გამოყენებადია ნაწილაკთა მრავალი სისტემისთვის" + + msgid "Active Instance Object" msgstr "აქტიური ინსტანციური ობიექტი" @@ -24749,18 +26071,34 @@ msgid "Degrees" msgstr "გრადუსი" +msgid "How many degrees path has to curve to make another render segment" +msgstr "რამდენი გრადუსით უნდა მოუხვიოს ბილიკმა, რომ ახალი სარენდერო სეგმენტი შექმნას" + + msgid "Pixel" msgstr "პიქსელი" +msgid "How many pixels path has to cover to make another render segment" +msgstr "რამდენი პიქსელი უნდა დაფაროს ბილიკმა, რომ ახალი სარენდერო სეგმენტი შექმნას" + + msgid "Angular Velocity" msgstr "კუთხოვანი სისწრაფე" +msgid "Angular velocity amount (in radians per second)" +msgstr "კუთხოვანი სისწრაფის ოდენობა (რადიანი წამში)" + + msgid "Angular Velocity Axis" msgstr "კუთხოვანი სისწრაფის ღერძი" +msgid "What axis is used to change particle rotation with time" +msgstr "რა ღერძი გამოიყენება დროთა განმავლობაში ნაწილაკთა ბრუნვის შესაცვლელად" + + msgid "Global X" msgstr "გლობალური X" @@ -24777,52 +26115,120 @@ msgid "Effect Children" msgstr "ეფექტი შვილებზე" +msgid "Apply effectors to children" +msgstr "ეფექტორების გამოყენება შვილებზე" + + +msgid "Random Bending Stiffness" +msgstr "დრეკის შემთხვევითი გახევება" + + +msgid "Random stiffness of hairs" +msgstr "თმის ღერების შემთხვევითი გახევება" + + +msgid "Threshold of branching" +msgstr "დატოტვის ზღვარი" + + msgid "Brownian" msgstr "ბრაუნის მოძრაობა" +msgid "Amount of random, erratic particle movement" +msgstr "ნაწილაკების შემთხვევითი, მერყევი მოძრაობის ოდენობა" + + +msgid "Length of child paths" +msgstr "შვილი ბილიკების სიგრძე" + + +msgid "Amount of particles left untouched by child path length" +msgstr "შვილი ბილიკების სიგრძის მიერ ხელშეუხებელი ნაწილაკების რაოდენობა" + + msgid "Children Per Parent" msgstr "შვილთა რიცხვი თითო მშობელზე" +msgid "Number of children per parent" +msgstr "შვილთა რიცხვი თითო მშობელზე" + + msgid "Parting Factor" -msgstr "გაყრის კოეფიციენტი" +msgstr "გაყოფის კოეფიციენტი" + + +msgid "Create parting in the children based on parent strands" +msgstr "შექმენი გაყოფა შვილებში მშობელი ღერების მიხედვით" msgid "Parting Maximum" -msgstr "გაყრის მაქსიმუმი" +msgstr "გაყოფის მაქსიმუმი" + + +msgid "Maximum root to tip angle (tip distance/root distance for long hair)" +msgstr "მაქსიმალური კუთხე ძირიდან წვერამდე (წვერის მანძილი/ძირის მანძილი გრძელი თმისთვის)" msgid "Parting Minimum" msgstr "გაყრის მინიმუმი" +msgid "Minimum root to tip angle (tip distance/root distance for long hair)" +msgstr "მინიმალური კუთხე ძირიდან წვერამდე (წვერის მანძილი/ძირის მანძილი გრძელი თმისთვის)" + + msgid "Child Radius" msgstr "შვილის რადიუსი" +msgid "Radius of children around parent" +msgstr "შვილების რადიუსი მშობლის გარშემო" + + msgid "Child Roundness" msgstr "შვილის სიმრგვალე" +msgid "Roundness of children around parent" +msgstr "შვილების სიმრგვალე მშობლის გარშემო" + + msgid "Child Size" -msgstr "ვილობილის ზომა" +msgstr "შვილის ზომა" + + +msgid "A multiplier for the child particle size" +msgstr "მამრავლი შვილი ნაწილაკის ზომისთვის" msgid "Random Child Size" msgstr "შვილის შემთხვევითი ზომა" +msgid "Random variation to the size of the child particles" +msgstr "შვილი ნაწილაკის ზომის შემთხვევითი ვარიაცია" + + msgid "Children From" msgstr "შვილი აქედან" +msgid "Create child particles" +msgstr "შვილი ნაწილაკების შექმნა" + + msgid "Interpolated" msgstr "ინტერპოლირებული" msgid "Clump Curve" -msgstr "გროვის მრუდი" +msgstr "გროვის წირი" + + +msgid "Curve defining clump tapering" +msgstr "წირი, რომელიც განსაზღვრავს გროვის წაწვრილებას" msgid "Clump" @@ -24837,30 +26243,62 @@ msgid "Size of clump noise" msgstr "გროვის ხმაურის ზომა" +msgid "Limit colliders to this collection" +msgstr "შემოფარგლე შემჯახებლები ამ კოლექციით" + + msgid "Color Maximum" msgstr "ფერის მაქსიმუმი" +msgid "Maximum length of the particle color vector" +msgstr "ნაწილაკის ფერის ვექტორის მაქსიმალური სიგრძე" + + +msgid "Total number of particles" +msgstr "ნაწილაკების ჯამური რიცხვი" + + msgid "Adaptive Subframe Threshold" msgstr "ადაპტირებადი ქვეკადრის ზღვარი" +msgid "The relative distance a particle can move before requiring more subframes (target Courant number); 0.01 to 0.3 is the recommended range" +msgstr "ფარდობითი მანძილი, რომლის გავლაც შეუძლია ნაწილაკს, სანამ მეტი ქვეკადრი დაჭირდება (სამიზნე კურანტის რიცხვი); 0.01-დან 0.03-ის ჩათვლით არის რეკომენდირებული დიაპაზონი" + + msgid "Long Hair" msgstr "გრძელი თმა" +msgid "Calculate children that suit long hair well" +msgstr "გამოთვალე მხოლოდ ის შვილები, რომლებიც გრძელ თმას უხდება" + + msgid "Damp" msgstr "დემპფირება" +msgid "Amount of damping" +msgstr "დემპფირების ოდენობა" + + msgid "Display Color" msgstr "ასახული ფერი" +msgid "Display additional particle data as a color" +msgstr "ასახე ნაწილაკების დამატებითი მონაცემები ფერად" + + msgid "Particle Display" msgstr "ნაწილაკის ასახვა" +msgid "How particles are displayed in viewport" +msgstr "როგორ აისახება ნაწილაკები სარკმელში" + + msgid "Rendered" msgstr "დარენდერებული" @@ -24873,26 +26311,62 @@ msgid "Display" msgstr "ასახვა" +msgid "Percentage of particles to display in 3D view" +msgstr "3გ ხედში ასასახი ნაწილაკების პროცენტული რაოდენობა" + + +msgid "Size of particles on viewport" +msgstr "ნაწილაკების ზომა სარკმელში" + + +msgid "How many steps paths are displayed with (power of 2)" +msgstr "რამდენი საფეხურით აისახება ბილიკები (ხარისხად 2)" + + msgid "Distribution" msgstr "გადანაწილება" +msgid "How to distribute particles on selected element" +msgstr "როგორ გადანაწილდეს ნაწილაკები მონიშნულ ელემენტებზე" + + msgid "Jittered" msgstr "ნარყევი" +msgid "Amount of air drag" +msgstr "ჰაერის წინაღობის ოდენობა" + + msgid "Stiffness" msgstr "გახევება" +msgid "Hair stiffness for effectors" +msgstr "თმის გახევება ეფექტორებისთვის" + + msgid "Effector Number" msgstr "ეფექტორთა რიცხვი" +msgid "How many particles are effectors (0 is all particles)" +msgstr "რამდენი ნაწილაკია ეფექტორი (0 ყველა ნაწილაკია)" + + msgid "Emit From" msgstr "გამომცემი" +msgid "Where to emit particles from" +msgstr "საიდან უნდა გამოიცეს ნაწილაკები" + + +msgid "Give the starting velocity a random variation" +msgstr "მიეცი საწყის სისწრაფეს შემთხვევითი ვარიაცია" + + msgid "SPH Fluid Settings" msgstr "SPH დენადი ნივთიერების პარამეტრები" @@ -24905,26 +26379,70 @@ msgid "Force Field 2" msgstr "ძალის ველი 2" +msgid "Frame number to stop emitting particles" +msgstr "იმ კადრის ნომერი, რომელზეც ნაწილაკების გამოცემა უნდა შეწყდეს" + + +msgid "Frame number to start emitting particles" +msgstr "იმ კადრის ნომერი, რომელზეც ნაწილაკების გამოცემა უნდა დაიწყოს" + + msgid "Grid Randomness" msgstr "ცხრილის შემთხვევითობა" +msgid "Add random offset to the grid locations" +msgstr "დაამატე შემთხვევითი აცდენა ცხრილის მდებარეობებს" + + +msgid "The resolution of the particle grid" +msgstr "ნაწილაკების ცხრილის გარჩევადობა" + + msgid "Hair Length" msgstr "თმის სიგრძე" +msgid "Length of the hair" +msgstr "თმის სიგრძე" + + +msgid "Number of hair segments" +msgstr "თმის სეგმენტების რიცხვი" + + msgid "Hexagonal Grid" msgstr "ექვსკუთხოვანი ცხრილი" +msgid "Create the grid in a hexagonal pattern" +msgstr "შექმენი ცხრილი ექვსკუთხოვან განმეორებად შაბლონში" + + +msgid "Show objects in this collection in place of particles" +msgstr "აჩვენე ამ კოლექციაში მყოფი ობიექტები ნაწილაკების ადგილას" + + +msgid "Show this object in place of particles" +msgstr "აჩვენე ეს ობიექტი ნაწილაკების ადგილას" + + msgid "Instance Collection Weights" msgstr "ინსტანციათა კოლექციის წონები" +msgid "Weights for all of the objects in the instance collection" +msgstr "წონები ყველა ობიექტისთვის ინსტანციათა კოლექციაში" + + msgid "Integration" msgstr "ინტეგრაცია" +msgid "Algorithm used to calculate physics, from the fastest to the most stable and accurate: Midpoint, Euler, Verlet, RK4" +msgstr "ფიზიკის გამოსათვლელად გამოყენებული ალგორითმი, უსწრაფესიდან ყველაზე სტაბილურსა და ზუსტამდე: შუაწერტილი, ეილერი, ვერლე, RK4" + + msgid "Euler" msgstr "ეილერი" @@ -24942,15 +26460,35 @@ msgstr "RK4" msgid "Invert Grid" -msgstr "ცხრილის ინვერტირება" +msgstr "ცხრილის შექცევა" + + +msgid "Invert what is considered object and what is not" +msgstr "შეაქციე ის, თუ რა ითვლება ობიექტად და რა - არა" + + +msgid "Particles were created by a fluid simulation" +msgstr "ნაწილაკები შექმნა დენადი ნივთიერების სიმულაციამ" + + +msgid "Amount of jitter applied to the sampling" +msgstr "რყევის ოდენობა გამოყენებული სემპლინგზე" msgid "Loop Count" msgstr "მარყუჟების რაოდენობა" +msgid "Number of times the keys are looped" +msgstr "რამდენჯერ მეორდება ციკლურად სოლები" + + msgid "Keys Step" -msgstr "საკვანძო ფაზების ნაბიჯი" +msgstr "სოლების საფეხური" + + +msgid "Type of periodic offset on the path" +msgstr "ბილიკზე პერიოდული აცდენის ტიპი" msgid "Spiral" @@ -24961,74 +26499,170 @@ msgid "Amplitude Clump" msgstr "გროვის ამპლიტუდა" +msgid "How much clump affects kink amplitude" +msgstr "რამდენად ზემოქმედებს გროვა დახვევის ამპლიტუდაზე" + + msgid "Amplitude Random" msgstr "შემთხვევითი ამპლიტუდა" +msgid "Random variation of the amplitude" +msgstr "ამპლიტუდის შემთხვევითი ვარიაცია" + + msgid "Axis Random" msgstr "შემთხვევითი ღერძი" +msgid "Random variation of the orientation" +msgstr "ორიენტაციის შემთხვევითი ვარიაცია" + + msgid "Extra Steps" -msgstr "დამატებითი ნაბიჯები" +msgstr "დამატებითი საფეხურები" + + +msgid "Extra steps for resolution of special kink features" +msgstr "დამატებითი საფეხურები დახვევის განსაკუთრებული მახასიათებლების გარჩევადობისთვის" msgid "Flatness" msgstr "სიბრტყელე" +msgid "How flat the hairs are" +msgstr "რამდენად ბრტყელია თმები" + + msgid "Random Length" msgstr "შემთხვევითი სიგრძე" +msgid "Give path length a random variation" +msgstr "მიეცი ბილიკის სიგრძეს შემთხვევითი ვარიაცია" + + msgid "Lifetime" msgstr "დღეგრძელობა" +msgid "Life span of the particles" +msgstr "ნაწილაკების სიცოცხლის ხანგრძლივობა" + + +msgid "Give the particle life a random variation" +msgstr "მიეცი ნაწილაკის დღეგრძელობას შემთხვევითი ვარიაცია" + + +msgid "Length of the line's head" +msgstr "ხაზის თავის სიგრძე" + + +msgid "Length of the line's tail" +msgstr "ხაზის კუდის სიგრძე" + + msgid "Boids 2D" msgstr "ბოიდები 2გ" +msgid "Constrain boids to a surface" +msgstr "მიბორკე ბოიდები ზედაპირზე" + + msgid "Mass" msgstr "მასა" +msgid "Mass of the particles" +msgstr "ნაწილაკების მასა" + + +msgid "Index of material slot used for rendering particles" +msgstr "ნაწილაკთა რენდერისთვის გამოყენებული მასალის სლოტის ინდექსი" + + msgid "Material Slot" msgstr "მასალის სლოტი" +msgid "Material slot used for rendering particles" +msgstr "ნაწილაკთა რენდერისთვის გამოყენებული მასალის სლოტი" + + msgid "Dummy" msgstr "ფუჭი" +msgid "Let the surface normal give the particle a starting velocity" +msgstr "საშუალება მიეცი ზედაპირის ნორმალს, მიანიჭოს ნაწილაკს საწყისი სისწრაფე" + + msgid "Object Aligned" msgstr "გამწკრივებული ობიექტი" +msgid "Let the emitter object orientation give the particle a starting velocity" +msgstr "საშუალება მიეცი გამომცემი ობიექტის ორიენტაციას, მიანიჭოს ნაწილაკს საწყისი სისწრაფე" + + msgid "Object Velocity" msgstr "ობიექტის სისწრაფე" +msgid "Let the object give the particle a starting velocity" +msgstr "საშუალება მიეცი ობიექტს, მიანიჭოს ნაწილაკს საწყისი სისწრაფე" + + msgid "Particle" msgstr "ნაწილაკი" +msgid "Let the target particle give the particle a starting velocity" +msgstr "საშუალება მიეცი სამიზნე ნაწილაკს, მიანიჭოს ნაწილაკს საწყისი სისწრაფე" + + +msgid "The size of the particles" +msgstr "ნაწილაკების ზომა" + + msgid "Path End" msgstr "ტრაექტორიის ბოლო" +msgid "End time of path" +msgstr "ტრაექტორიის დასასრულის დრო" + + msgid "Path Start" msgstr "ტრაექტორიის თავი" +msgid "Starting time of path" +msgstr "ტრაექტორიის დასაწყისის დრო" + + +msgid "Rotation around the chosen orientation axis" +msgstr "ბრუნვა რჩეული საორიენტაციო ღერძის გარშემო" + + msgid "Random Phase" msgstr "შემთხვევითი ფაზა" +msgid "Randomize rotation around the chosen orientation axis" +msgstr "გააშემთხვევითე ბრუნვა რჩეული საორიენტაციო ღერძის გარშემო" + + msgid "Physics Type" msgstr "ფიზიკის ტიპი" +msgid "Particle physics type" +msgstr "ნაწილაკების ფიზიკის ტიპი" + + msgid "Newtonian" msgstr "ნიუტონის" @@ -25038,13 +26672,21 @@ msgstr "ჩასოლილი" msgid "Diameter Scale" -msgstr "სიამეტრის მასშტაბირება" +msgstr "დიამეტრის მასშტაბირება" + + +msgid "Multiplier of diameter properties" +msgstr "დიამეტრის მახასიათებლების მამრავლი" msgid "React On" msgstr "რეაქციის გამომწვევი" +msgid "The event of target particles to react on" +msgstr "მოვლენა, რომელმაც უნდა გამოიწვიოს ნაწილაკების რეაქცია" + + msgid "Death" msgstr "სიკვდილი" @@ -25053,30 +26695,58 @@ msgid "Reactor" msgstr "რეაქტორი" +msgid "Let the vector away from the target particle's location give the particle a starting velocity" +msgstr "საშუალება მიეცი სამიზნე ნაწილაკის მდებარეობიდან მიმართულ ვექტორს, მისცეს ნაწილაკს საწყისი სისწრაფე" + + +msgid "How many steps paths are rendered with (power of 2)" +msgstr "რამდენი საფეხურით რენდერდება ბილიკები (ხარისხად 2)" + + msgid "Particle Rendering" msgstr "ნაწილაკთა რენდერი" +msgid "How particles are rendered" +msgstr "როგორ რენდერდება ნაწილაკები" + + msgid "Halo" -msgstr "შარავანდი" +msgstr "შარავანდედი" msgid "Rendered Children" msgstr "დარენდერებული შვილები" +msgid "Number of children per parent for rendering" +msgstr "შვილების რაოდენობა თითო მშობელზე რენდერისთვის" + + msgid "Root Diameter" msgstr "ძირის დიამეტრი" +msgid "Strand diameter width at the root" +msgstr "ღერის დიამეტრი ძირთან" + + msgid "Random Orientation" msgstr "შემთხვევითი ორიენტაცია" +msgid "Randomize particle orientation" +msgstr "გააშემთხვევითე ნაწილაკთა ორიენტაცია" + + msgid "Orientation Axis" msgstr "ორიენტაციის ღერძი" +msgid "Particle orientation axis (does not affect Explode modifier's results)" +msgstr "ნაწილაკის ორიენტაციის ღერძი (არ ზემოქმედებს აფეთქების მოდიფიკატორის შედეგებზე)" + + msgid "Normal-Tangent" msgstr "ნორმალი-მხები" @@ -25101,56 +26771,164 @@ msgid "Roughness 1" msgstr "ხეშეშობა 1" +msgid "Amount of location dependent roughness" +msgstr "მდებარეობაზე დამოკიდებული ხეშეშობის ოდენობა" + + msgid "Size 1" msgstr "ზომა 1" +msgid "Size of location dependent roughness" +msgstr "მდებარეობაზე დამოკიდებული ხეშეშობის ზომა" + + msgid "Roughness 2" msgstr "ხეშეშობა 2" +msgid "Amount of random roughness" +msgstr "შემთხვევითი ხეშეშობის ოდენობა" + + msgid "Size 2" msgstr "ზომა 2" +msgid "Size of random roughness" +msgstr "შემთხვევითი ხეშეშობის ზომა" + + +msgid "Amount of particles left untouched by random roughness" +msgstr "შემთხვევითი ხეშეშობის მიერ ხელშეუხებელი ნაწილაკების რაოდენობა" + + msgid "Roughness Curve" -msgstr "ხეშეშობის მრუდი" +msgstr "ხეშეშობის წირი" + + +msgid "Curve defining roughness" +msgstr "ხეშეშობის განმსაზღვრელი წირი" + + +msgid "Shape of endpoint roughness" +msgstr "ბოლო წერტილის ხეშეშობის ფორმა" msgid "Roughness Endpoint" msgstr "ხეშეშობის ბოლო წერტილი" +msgid "Amount of endpoint roughness" +msgstr "ბოლო წერტილის ხეშეშობის ოდენობა" + + +msgid "Strand shape parameter" +msgstr "ღერის ფორმის პარამეტრი" + + msgid "Guide Hairs" -msgstr "მეგზური თმები" +msgstr "ნიშნული თმები" + + +msgid "Show guide hairs" +msgstr "აჩვენე ნიშნული თმები" + + +msgid "Show hair simulation grid" +msgstr "აჩვენე თმის სიმულაციის ცხრილი" + + +msgid "Display boid health" +msgstr "ასახე ბოიდის ჯანმრთელობა" + + +msgid "Number" +msgstr "რიცხვი" + + +msgid "Show particle number" +msgstr "აჩვენე ნაწილაკის ნომერი" + + +msgid "Show particle size" +msgstr "აჩვენე ნაწილაკის ზომა" msgid "Unborn" msgstr "უშობელი" +msgid "Show particles before they are emitted" +msgstr "აჩვენე ნაწილაკები, სანამ გამოიცემიან" + + +msgid "Show particle velocity" +msgstr "აჩვენე ნაწილაკების სისწრაფე" + + msgid "Random Size" msgstr "შემთხვევითი ზომა" +msgid "Give the particle size a random variation" +msgstr "მიეცი ნაწილაკების ზომას შემთხვევითი ვარიაცია" + + +msgid "Subframes to simulate for improved stability and finer granularity simulations (dt = timestep / (subframes + 1))" +msgstr "ქვეკადრები, რომელთა სიმულირება უნდა მოხდეს გაუმჯობესებული სტაბილურობისა და უფრო წვრილმანი მარცვლოვნებისთვის (dt = დროის საფეხური / (ქვეკადრები + 1))" + + +msgid "Let the surface tangent give the particle a starting velocity" +msgstr "საშუალება მიეცი ზედაპირის მხებს, მიანიჭოს ნაწილაკს საწყისი სისწრაფე" + + +msgid "Rotate the surface tangent" +msgstr "აბრუნე ზედაპირის მხები" + + msgid "Tweak" msgstr "ჩხიკინი" +msgid "A multiplier for physics timestep (1.0 means one frame = 1/25 seconds)" +msgstr "მამრავლი ფიზიკის დროის საფეხურისთვის (1.0 ნიშნავს, რომ ერთი კადრი = 1/25 წამს)" + + msgid "Timestep" msgstr "დროის საფეხური" +msgid "The simulation timestep per frame (seconds per frame)" +msgstr "სიმულაციის დროის საფეხური ყოველ კადრზე (წამი კადრზე)" + + msgid "Tip Diameter" msgstr "წვეროს დიამეტრი" +msgid "Strand diameter width at the tip" +msgstr "ღერის დიამეტრის სიმსხვილე წვეროსთან" + + msgid "Trail Count" -msgstr "კუდების რიცხვი" +msgstr "კვლების რიცხვი" + + +msgid "Number of trail particles" +msgstr "კვალის ნაწილაკების რიცხვი" + + +msgid "Number of turns around parent along the strand" +msgstr "მშობლის გარშემო შემოტრიალებების რაოდენობა ღერის გაყოლებაზე" msgid "Twist Curve" -msgstr "მოგრეხვის მრუდი" +msgstr "მოგრეხვის წირი" + + +msgid "Curve defining twist" +msgstr "მოგრეხვის განმსაზღვრელი წირი" msgid "Particle type" @@ -25161,146 +26939,355 @@ msgid "Absolute Path Time" msgstr "ტრაექტორიის აბსოლუტური დრო" +msgid "Path timing is in absolute frames" +msgstr "ბილიკის დროში განაწილება ხდება აბსოლუტურ კადრებში" + + msgid "Automatic Subframes" msgstr "ავტომატური ქვეკადრები" +msgid "Automatically set the number of subframes" +msgstr "ავტომატურად დააყენე ქვეკადრების რაოდენობა" + + msgid "Advanced" msgstr "გაფართოებული" +msgid "Use full physics calculations for growing hair" +msgstr "გამოიყენე სრული ფიზიკის გამოთვლები თმის ზრდისთვის" + + msgid "Close Tip" msgstr "დახურული წვერი" +msgid "Set tip radius to zero" +msgstr "დააყენე წვეროს რადიუსი ნულზე" + + msgid "Use Clump Curve" -msgstr "გროვის მრუდის გამოყენება" +msgstr "გროვის წირის გამოყენება" + + +msgid "Use a curve to define clump tapering" +msgstr "გამოიყენე წირი გროვის წაწვრილების განსასაზღვრად" msgid "Use Clump Noise" msgstr "გროვის ხმაურის გამოყენება" +msgid "Create random clumps around the parent" +msgstr "შექმენი შემთხვევითი გროვები მშობლის გარშემო" + + msgid "Use Count" msgstr "რიცხვის გამოყენება" +msgid "Use object multiple times in the same collection" +msgstr "გამოიყენე ობიექტი მრავალჯერ ერთსა და იმავე კოლექციაში" + + msgid "Pick Random" msgstr "შემთხვევით ამორჩევა" +msgid "Pick objects from collection randomly" +msgstr "ამოირჩიე ობიექტები კოლექციიდან შემთხვევითობის პრინციპით" + + msgid "Died" msgstr "მოკვდა" +msgid "Show particles after they have died" +msgstr "აჩვენე ნაწილაკები სიკვდილის შემდეგ" + + msgid "Die on Hit" msgstr "სიკვდილი დარტყმისას" +msgid "Particles die when they collide with a deflector object" +msgstr "ნაწილაკები იღუპება, როცა ეჯახება დეფლექტორ ობიექტს" + + +msgid "Particle rotations are affected by collisions and effectors" +msgstr "ნაწილაკთა ბრუნვებზე ზემოქმედებს შეჯახებები და ეფექტორები" + + +msgid "Emit in random order of elements" +msgstr "გამოეცი ელემენტების შემთხვევითი თანმიმდევრობით" + + msgid "Even Distribution" msgstr "თანაბარი გადანაწილება" +msgid "Use even distribution from faces based on face areas or edge lengths" +msgstr "გამოიყენე თანაბარი გადანაწილება წახნაგებიდან, წახნაგების არეალების, ან წიბოების სიგრძეების მიხედვით" + + +msgid "Use object's global coordinates for duplication" +msgstr "გამოიყენე ობიექტის გლობალური კოორდინატები დუბლიკაციისთვის" + + +msgid "Interpolate hair using B-Splines" +msgstr "მოახდინე თმის ინტერპოლირება B-სფლაინების გამოყენებით" + + msgid "Use Modifier Stack" msgstr "მოდიფიკატორების სტეკის გამოყენება" +msgid "Emit particles from mesh with modifiers applied (must use same subdivision surface level for viewport and render for correct results)" +msgstr "გამოეცი ნაწილაკები მოდიფიკატორებგამოყენებული მეშიდან (სწორი შედეგებისთვის უნდა იყენებდეს ქვედანაყოფებიანი ზედაპირის ერთსა და იმავე დონეს სარკმელსა და რენდერში)" + + msgid "Mass from Size" msgstr "მასა ზომიდან" +msgid "Multiply mass by particle size" +msgstr "გაამრავლე მასა ნაწილაკების ზომაზე" + + +msgctxt "ParticleSettings" +msgid "Parents" +msgstr "მშობლები" + + +msgid "Render parent particles" +msgstr "დაარენდერე მშობელი ნაწილაკები" + + msgid "Multi React" -msgstr "მრავალრეაქცია" +msgstr "მრავალი რეაქცია" + + +msgid "React multiple times" +msgstr "რეაქცია მრავალჯერ" msgid "Start/End" msgstr "დასაწყისი/დასასრული" +msgid "Give birth to unreacted particles eventually" +msgstr "დაბადე არარეაგირებული ნაწილაკები დროთა განმავლობაში" + + msgid "Regrow" msgstr "ხელახლა გაზრდა" +msgid "Regrow hair for each frame" +msgstr "ყოველი კადრისთვის ხელახლა გაზარდე თმა" + + msgid "Adaptive Render" msgstr "ადაპტირებადი რენდერი" +msgid "Display steps of the particle path" +msgstr "ასახე ნაწილაკთა ბილიკის საფეხურები" + + +msgid "Use object's rotation for duplication (global x-axis is aligned particle rotation axis)" +msgstr "გამოიყენე ობიექტის ბრუნვა დუბლიკაციისთვის (გლობალური x-ღერძი უსწორდება ნაწილაკის ბრუნვის ღერძს)" + + msgid "Rotations" msgstr "ბრუნვები" +msgid "Calculate particle rotations" +msgstr "გამოთვალე ნაწილაკის ბრუნვები" + + msgid "Use Roughness Curve" -msgstr "ხეშეშობის მრუდის გამოყენება" +msgstr "ხეშეშობის წირის გამოყენება" + + +msgid "Use a curve to define roughness" +msgstr "ხეშეშობის განსასაზღვრად გამოიყენე წირი" + + +msgid "Use object's scale for duplication" +msgstr "დუბლიკაციისთვის გამოიყენე ობიექტის მასშტაბი" msgid "Self Effect" -msgstr "თვით-ეფექტი" +msgstr "თვითეფექტი" + + +msgid "Particle effectors affect themselves" +msgstr "ნაწილაკთა ეფექტორები თავიანთ თავებზე ზემოქმედებენ" msgid "Size Deflect" msgstr "ზომისმიერი ასხლეტა" +msgid "Use particle's size in deflection" +msgstr "ასხლეტაში გამოიყენე ნაწილაკის ზომა" + + msgid "Strand Render" msgstr "ღერის რენდერი" +msgid "Use the strand primitive for rendering" +msgstr "რენდერისთვის გამოიყენე ღერის პრიმიტივი" + + msgid "Use Twist Curve" -msgstr "მოგრეხვის მრუდის გამოყენება" +msgstr "მოგრეხვის წირის გამოყენება" + + +msgid "Use a curve to define twist" +msgstr "მოგრეხვის განსასაზღვრად გამოიყენე წირი" + + +msgid "Multiply line length by particle speed" +msgstr "ხაზის სიგრძის გამრავლება ნაწილაკის სიჩქარეზე" msgid "Whole Collection" msgstr "მთელი კოლექცია" +msgid "Use whole collection at once" +msgstr "ერთდროულად გამოიყენე მთელი კოლექცია" + + msgid "Particles/Face" -msgstr "ნაწილაკები/წახნაგზე" +msgstr "ნაწილაკები/წახნაგი" + + +msgid "Emission locations per face (0 = automatic)" +msgstr "გამოცემის მდებარეობები თითოეულ წახნაგზე (0 = ავტომატურს)" msgid "Virtual Parents" msgstr "ვირტუალური მშობლები" +msgid "Relative amount of virtual parents" +msgstr "ვირტუალური მშობლების შეფარდებითი რაოდენობა" + + msgid "Point Cloud" msgstr "წერტილების ღრუბელი" +msgid "Point cloud data-block" +msgstr "წერტილოვანი ღრუბლის მონაცემთა ბლოკი" + + msgid "Scene data-block, consisting in objects and defining time and render related settings" -msgstr "სცენის მონაცემთა ბლოკი, რომელიც შედგება ობიექტებისგან და განსაზღვრული აქვს დროსა და რენდერთან დაკავშირებული პარამეტრები" +msgstr "სცენის მონაცემთა ბლოკი, რომელიც შედგება ობიექტებისგან და განსაზღვრავს დროსა და რენდერთან დაკავშირებულ პარამეტრებს" msgid "Active Movie Clip" msgstr "აქტიური ვიდეო კლიპი" +msgid "Active Movie Clip that can be used by motion tracking constraints or as a camera's background image" +msgstr "აქტიური ვიდეო კლიპი, რომელიც შეიძლება გამოყენებულ იქნას მოძრაობის მიდევნების ბორკილების მიერ, ან კამერის ფონურ გამოსახულებად" + + msgid "Distance Model" msgstr "მანძილის მოდელი" +msgid "Distance model for distance attenuation calculation" +msgstr "მანძილის მოდელი მანძილის შესუსტების გამოთვლისთვის" + + +msgid "No distance attenuation" +msgstr "მანძილის შესუსტების გარეშე" + + msgid "Inverse" -msgstr "ინვერსიული" +msgstr "შექცეული" + + +msgid "Inverse distance model" +msgstr "მანძილის შექცეული მოდელი" msgid "Inverse Clamped" -msgstr "ინვერსიული აღკვეთილი" +msgstr "შექცეული აღკვეთილი" + + +msgid "Inverse distance model with clamping" +msgstr "მანძილის შექცეული მოდელი აღკვეთით" + + +msgid "Linear distance model" +msgstr "წრფივი მანძილის მოდელი" msgid "Linear Clamped" msgstr "წრფივი აღკვეთილი" +msgid "Linear distance model with clamping" +msgstr "მანძილის წრფივი მოდელი აღკვეთით" + + +msgid "Exponential" +msgstr "ექსპონენტური" + + +msgid "Exponential distance model" +msgstr "მანძილის ექსპონენტური მოდელი" + + +msgid "Exponential Clamped" +msgstr "ექსპონენტური აღკვეთით" + + +msgid "Exponential distance model with clamping" +msgstr "ექსპონენტური მანძილის მოდელი აღკვეთით" + + msgid "Doppler Factor" msgstr "დოპლერის კოეფიციენტი" +msgid "Pitch factor for Doppler effect calculation" +msgstr "ბგერის სიმაღლის კოეფიციენტი დოპლერის ეფექტის გამოსათვლელად" + + msgid "Speed of Sound" msgstr "ბგერის სიჩქარე" +msgid "Speed of sound for Doppler effect calculation" +msgstr "ბგერის სიჩქარე დოპლერის ეფექტის გამოსათვლელად" + + msgid "Background Scene" msgstr "ფონური სცენა" +msgid "Background set scene" +msgstr "ფონზე მოწყობილი სცენა" + + +msgid "Active camera, used for rendering the scene" +msgstr "აქტიური კამერა, გამოყენებული სცენის რენდერისთვის" + + +msgid "Scene root collection that owns all the objects and other collections instantiated in the scene" +msgstr "სცენის ძირეული კოლექცია, რომელიც ფლობს ყველა ობიექტს და სცენაში ინსტანცირებულ სხვა კოლექციებს" + + msgid "3D Cursor" msgstr "3გ კურსორი" @@ -25314,33 +27301,57 @@ msgstr "Cycles-ის რენდერის პარამეტრები msgid "Cycles Curves Rendering Settings" -msgstr "Cycles-ის მრუდთა რენდერის პარამეტრები" +msgstr "Cycles-ის წირთა რენდერის პარამეტრები" msgid "Cycles curves rendering settings" -msgstr "Cycles-ის მრუდთა რენდერის პარამეტრები" +msgstr "Cycles-ის წირთა რენდერის პარამეტრები" msgid "Scene Display" msgstr "სცენის ასახვა" +msgid "Scene display settings for 3D viewport" +msgstr "სცენის ასახვის პარამეტრები 3გ სარკმელში" + + msgid "Display Settings" msgstr "ასახვის პარამეტრები" +msgid "Settings of device saved image would be displayed on" +msgstr "იმ მოწყობილობის პარამეტრები, რომელზეც გამოსახულება აისახებოდა" + + msgid "Eevee" msgstr "Eevee" +msgid "Eevee settings for the scene" +msgstr "Eevee პარამეტრები სცენისთვის" + + msgid "Current Frame" msgstr "მიმდინარე კადრი" +msgid "Current frame, to update animation data from python frame_set() instead" +msgstr "მიმდინარე კადრი, ანიმაციის მონაცემების python frame_set()-იდან განახლებისთვის" + + msgid "Current Frame Final" msgstr "საბოლოო მიმდინარე კადრი" +msgid "Current frame with subframe and time remapping applied" +msgstr "მიმდინარე კადრი ქვეკადრისა და დროის განაწილების გამოყენებით" + + +msgid "Final frame of the playback/rendering range" +msgstr "უკანასკნელი კადრი დაკვრის/რენდერის დიაპაზონში" + + msgid "Current Subframe" msgstr "მიმდინარე ქვეკადრი" @@ -25349,10 +27360,26 @@ msgid "Preview Range End Frame" msgstr "წინასწარი ხედის დიაპაზონის ბოლო კადრი" +msgid "Alternative end frame for UI playback" +msgstr "ალტერნატიული საბოლოო კადრი UI დაკვრისთვის" + + msgid "Preview Range Start Frame" msgstr "წინასწარი ხედის დიაპაზონის საწყისი კადრი" +msgid "Alternative start frame for UI playback" +msgstr "ალტერნატიული საწყისი კადრი UI დაკვრისთვის" + + +msgid "First frame of the playback/rendering range" +msgstr "დაკვრის/რენდერის დიაპაზონის პირველი კადრი" + + +msgid "Number of frames to skip forward while rendering/playing back each frame" +msgstr "თითოეული კადრის რენდერის/დაკვრის დროს წინ გადასახტომი კადრების რიცხვი" + + msgid "Constant acceleration in a given direction" msgstr "თანაბარი აჩქარება მოცემული მიმართულებით" @@ -25361,22 +27388,50 @@ msgid "Annotations" msgstr "ანოტაციები" +msgid "Grease Pencil data-block used for annotations in the 3D view" +msgstr "ცვილის ფანქრის მონაცემთა ბლოკები გამოყენებული ანოტაციებისთვის 3გ ხედში" + + +msgid "Grease Pencil settings for the scene" +msgstr "ცვილის ფანქრის პარამეტრები სცენისთვის" + + msgid "NLA Tweak Mode" msgstr "NLA ჩხიკინის რეჟიმი" +msgid "Whether there is any action referenced by NLA being edited (strictly read-only)" +msgstr "არის თუ არა რაიმე ქმედება მითითებული რედაქტირებაში მყოფი NLA-ის მიერ (მხოლოდ წაკითხვადი)" + + msgid "Absolute Keying Sets" -msgstr "სოლების აბსოლუტური ნაკრებები" +msgstr "აბსოლუტური ჩასოლვის ნაკრებები" + + +msgid "Absolute Keying Sets for this Scene" +msgstr "აბსოლუტური ჩასოლვის ნაკრებები ამ სცენისთვის" msgid "All Keying Sets" msgstr "სოლების ყველა ნაკრები" +msgid "All Keying Sets available for use (Builtins and Absolute Keying Sets for this Scene)" +msgstr "ჩასოლვის ყველა ნაკრები, რომელიც ხელმისაწვდომია გამოსაყენებლად (ჩაშენებები და აბსოლუტური ჩასოლვის ნაკრებები ამ სცენისთვის)" + + msgid "Lock Frame Selection" msgstr "კადრის მონიშნვის ჩაკეტვა" +msgid "Don't allow frame to be selected with mouse outside of frame range" +msgstr "ნუ მისცემ საშუალებას კადრს, იყოს თაგვით მონიშნული კადრთა დიაპაზონის გარეთ" + + +msgid "Compositing node tree" +msgstr "კომპოზიტინგის კვანძური ხე" + + msgid "Render Data" msgstr "რენდერის მონაცემები" @@ -25393,34 +27448,66 @@ msgid "Sequencer Color Space Settings" msgstr "სეკვენსერის ფერის სივრცის პარამეტრები" +msgid "Settings of color space sequencer is working in" +msgstr "იმ ფერის სივრცის პარამეტრები, რომელშიც სეკვენსერი მუშაობს" + + msgid "Only Keyframes from Selected Channels" msgstr "საკვანძო ფაზები მხოლოდ მონიშნული არხებიდან" +msgid "Consider keyframes for active object and/or its selected bones only (in timeline and when jumping between keyframes)" +msgstr "განიხილე საკვანძო ფაზები მხოლოდ აქტიური ობიექტისთვის და/ან მისი მონიშნული ძვლისთვის (დროის ზოლში და საკვანძო ფაზებს შორის გადახტომისას)" + + msgid "Show Subframe" msgstr "ქვეკადრის ჩვენება" +msgid "Show current scene subframe and allow set it using interface tools" +msgstr "აჩვენე მიმდინარე სცენის ქვეკადრი და დაუშვი მისი ინტერფეისის ხელსაწყოებით დაყენება" + + msgid "Sync Mode" msgstr "სინქრონული რეჟიმი" +msgid "How to sync playback" +msgstr "როგორ დავასინქრონირო დაკვრა" + + msgid "Play Every Frame" msgstr "ყოველი კადრის დაკვრა" +msgid "Do not sync, play every frame" +msgstr "ნუ დაასინქრონირებ, დაუკარი ყოველი კადრი" + + msgid "Frame Dropping" msgstr "კადრების ჩაგდება" +msgid "Drop frames if playback is too slow" +msgstr "გამოტოვე კადრები, თუ დაკვრა მეტისმეტად ნელია" + + msgid "Sync to Audio" msgstr "სინქრონირება აუდიოსთან" +msgid "Sync to audio playback, dropping frames" +msgstr "დაასინქრონირე აუდიოს დაკვრასთან, კადრების გამოტოვებით" + + msgid "Timeline Markers" msgstr "დროის ზოლის მარკერები" +msgid "Markers used in all timelines for the current scene" +msgstr "მარკერები გამოყენებული ყველა დროის ზოლში მიმდინარე სცენისთვის" + + msgid "Tool Settings" msgstr "ხელსაწყოს პარამეტრები" @@ -25433,26 +27520,54 @@ msgid "Unit Settings" msgstr "ერთეულის პარამეტრები" +msgid "Unit editing settings" +msgstr "ერთეულის რედაქტირების პარამეტრები" + + msgid "Audio Muted" msgstr "უხმო" +msgid "Play back of audio from Sequence Editor will be muted" +msgstr "აუდიოს დაკვრა თანამიმდევრობის რედაქტორიდან უხმო იქნება" + + msgid "Audio Scrubbing" msgstr "აუდიო სკრაბინგი" +msgid "Play audio from Sequence Editor while scrubbing" +msgstr "დაუკარი აუდიო თანამიმდევრობის რედაქტორიდან სკრაბინგის დროს" + + msgid "Global Gravity" msgstr "გლობალური გრავიტაცია" +msgid "Use global gravity for all dynamics" +msgstr "გამოიყენე გლობალური გრავიტაცია ყველანაირი დინამიკისთვის" + + +msgid "Enable the compositing node tree" +msgstr "ჩართე კომპოზიტინგის კვანძური ხე" + + msgid "Use Preview Range" msgstr "წინასწარი ხედის დიაპაზონის გამოყენება" +msgid "Use an alternative start/end frame range for animation playback and view renders" +msgstr "გამოიყენე ალტერნატიული საწყისი/საბოლოო კადრის დიაპაზონი ანიმაციის დასაკრავად და ხედის რენდერებისთვის" + + msgid "Stamp Note" msgstr "ბეჭდის შენიშვნა" +msgid "User defined note for the render stamping" +msgstr "მომხმარებლის მიერ განსაზღვრული შენიშვნა რენდერის დასაბეჭდად" + + msgid "View Layers" msgstr "ხედის შრეები" @@ -25616,10 +27731,6 @@ msgid "Modified" msgstr "მოდიფიცირებული" -msgid "Lines" -msgstr "ხაზები" - - msgid "Selection End Character" msgstr "მონიშნვის დამასრულებელი სიმბოლო" @@ -25938,6 +28049,14 @@ msgid "Pattern" msgstr "შაბლონი" +msgid "Sharp" +msgstr "მკვეთრი" + + +msgid "Sharper" +msgstr "უფრო მკვეთრი" + + msgid "Noise Basis 2" msgstr "ხმაურის საფუძველი 2" @@ -29872,6 +31991,10 @@ msgid "Split Normals" msgstr "გახლიჩე ნორმალები" +msgid "Root" +msgstr "ფესვი" + + msgid "Intersect" msgstr "გადაკვეთა" @@ -30307,6 +32430,10 @@ msgid "Line Thickness" msgstr "ხაზის სისქე" +msgid "Lines" +msgstr "ხაზები" + + msgid "Camera's focal length" msgstr "კამერის ფოკუსური მანძილი" @@ -31881,10 +34008,6 @@ msgid "Export scene as glTF 2.0 file" msgstr "სცენის ექსპორტი glTF 2.0 ფაილად" -msgid "Copyright" -msgstr "კოპირაითი" - - msgid "Exports a single file, with all data packed in JSON. Less efficient than binary, but easier to edit later" msgstr "აექსპორტებს ერთ ფაილს, ყველა მონაცემს ალაგებს JSON-ში. ბინარულზე ნაკლებად ეფექტურია, მაგრამ უფრო იოლია მოგვიანებით დასამუშავებლად" @@ -41899,6 +44022,10 @@ msgid "Exponent" msgstr "ექსპონენტი" +msgid "Second" +msgstr "მეორე" + + msgid "Light Clamping" msgstr "სინათლის აღკვეთა" @@ -42791,10 +44918,6 @@ msgid "Author:" msgstr "ავტორი:" -msgid "author" -msgstr "ავტორი" - - msgid "Version:" msgstr "ვერსია:" @@ -43755,7 +45878,7 @@ msgstr "ჩართე-გამორთე დაბოლოებები" msgid "Scale Thickness" -msgstr "დაამასშტაბირე სიმსქე" +msgstr "დაამასშტაბირე სისქე" msgctxt "Operator" @@ -46826,7 +48949,7 @@ msgstr "უზბეკური კირილური (Ўзбек)" msgid "Hindi (मानक हिन्दी)" -msgstr "ჰინდი मानक हिन्दी)" +msgstr "ჰინდი (मानक हिन्दी)" msgid "Vietnamese (tiếng Việt)" diff --git a/locale/po/ko.po b/locale/po/ko.po index 8577b88b3b5..da733b10f66 100644 --- a/locale/po/ko.po +++ b/locale/po/ko.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2020-01-04 05:04+0900\n" "Last-Translator: Geuntak Jeong \n" "Language-Team: Korean (http://www.transifex.com/lxlalexlxl/blender/language/ko/)\n" @@ -927,6 +927,10 @@ msgid "Armatures active edit bone" msgstr "아마튜어의 활성 편집본" +msgid "Copyright" +msgstr "저작권" + + msgid "Description" msgstr "설명" @@ -11305,10 +11309,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "셀당 최소 파티클들의 수 (각 셀에 최소한이 정도의 파티클들이 있는지 보장)" -msgid "Number" -msgstr "번호" - - msgid "Particle number factor (higher value results in more particles)" msgstr "파티클 수 팩터 (값이 클수록 파티클들이 많아짐)" @@ -14914,30 +14914,6 @@ msgid "Editable falloff curve" msgstr "편집 가능한 커브 감소" -msgid "Curve Preset" -msgstr "커브 프리셋" - - -msgid "Smoother" -msgstr "더 매끄럽게" - - -msgid "Root" -msgstr "루트" - - -msgid "Sharp" -msgstr "샤프" - - -msgid "Sharper" -msgstr "샤프터" - - -msgid "Inverse Square" -msgstr "제곱 반전" - - msgid "Dash Ratio" msgstr "대시 비율" @@ -15842,10 +15818,6 @@ msgid "Up" msgstr "위쪽" -msgid "Second" -msgstr "초" - - msgid "Camera data-block for storing camera settings" msgstr "카메라 설정을 저장하기 위한 카메라 데이터 블록" @@ -18104,6 +18076,10 @@ msgid "Inverse Linear" msgstr "선형을 반전" +msgid "Inverse Square" +msgstr "제곱 반전" + + msgid "Inverse Coefficients" msgstr "반전 계수" @@ -20751,6 +20727,10 @@ msgid "Show hair simulation grid" msgstr "헤어 시뮬레이션 격자를 표시" +msgid "Number" +msgstr "번호" + + msgid "Show particle number" msgstr "파티클 번호를 표시" @@ -21617,10 +21597,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "디스크상의 텍스트 파일은 메모리 것과 다름" -msgid "Lines" -msgstr "라인" - - msgid "Lines of text" msgstr "텍스트의 행" @@ -22241,10 +22217,18 @@ msgid "Use soft marble" msgstr "소프트 마블을 사용" +msgid "Sharp" +msgstr "샤프" + + msgid "Use more clearly defined marble" msgstr "더 명확하게 정의된 대리석을 사용" +msgid "Sharper" +msgstr "샤프터" + + msgid "Use very clearly defined marble" msgstr "아주 명확하게 정의된 대리석을 사용" @@ -27336,6 +27320,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "버텍스에 인접한 여러 에지가 있는 경우에는 버텍스에 직접 선체됨" +msgid "Root" +msgstr "루트" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "버텍스는 회전 계산 및 아마튜어 생성을 위한 루트이며, 이 플래그를 설정하면 동일한 메시 아일랜드의 다른 루트가 지워지지 않습니다" @@ -31140,6 +31128,10 @@ msgid "Line Thickness" msgstr "라인 두께" +msgid "Lines" +msgstr "라인" + + msgid "Motion Path Points" msgstr "모션 경로 포인트" @@ -40626,10 +40618,6 @@ msgid "Export vertex colors with meshes" msgstr "메쉬로 버텍스 컬러를 내보내기" -msgid "Copyright" -msgstr "저작권" - - msgid "Legal rights and conditions for the model" msgstr "모델에 대한 법적 권리와 조건" @@ -53650,10 +53638,6 @@ msgid "Fill Range by Selection" msgstr "선택으로 범위를 채우기" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "선택된 메쉬 오브젝트와 소스 오브젝트 사이의 최소/최대 거리로 최소/최대 범위 항목을 채우기 " - - msgid "Name of the modifier to work on" msgstr "다음에 작동하는 모디파이어의 이름" @@ -77423,10 +77407,6 @@ msgid "Invert Selection" msgstr "선택을 반전" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "트래킹" @@ -78310,22 +78290,10 @@ msgid "Hair dynamics disabled" msgstr "헤어 역학 사용 중지됨" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "반복: %d .. %d (avg. %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "오류: %.5f .. %.5f (avg. %.5f)" - - msgid "Multiply Mass with Size" msgstr "크기에 질량을 곱하기" -msgid "Spacing: %g" -msgstr "간격: %g" - - msgid "Show Emitter" msgstr "이미터를 표시" @@ -78370,10 +78338,6 @@ msgid "Coordinate System" msgstr "좌표 시스템" -msgid "%d fluid particles for this frame" -msgstr "이 프레임에 대한 %d 유체 파티클" - - msgctxt "Operator" msgid "Delete Edit" msgstr "편집을 삭제" @@ -78387,6 +78351,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "디스플레이 백분율은 배이킹하지 않고 역학을 부정확하게 만듭니다" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "반복: %d .. %d (avg. %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "오류: %.5f .. %.5f (avg. %.5f)" + + +msgid "Spacing: %g" +msgstr "간격: %g" + + msgid "Not yet functional" msgstr "아직 작동하지 않음" @@ -78401,6 +78377,10 @@ msgid "Disconnect All" msgstr "모두 연결 끊기" +msgid "%d fluid particles for this frame" +msgstr "이 프레임에 대한 %d 유체 파티클" + + msgid "Speed Multiplier" msgstr "속력 배율" @@ -78785,6 +78765,10 @@ msgid "Velocity Linear" msgstr "속도 선형" +msgid "Second" +msgstr "초" + + msgid "X Stiffness" msgstr "X 강성" @@ -79165,11 +79149,6 @@ msgid "Set Keyframe B" msgstr "키 프레임 B를 설정" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "줌 %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "뷰 맞추기" @@ -80201,10 +80180,6 @@ msgid "Rotation" msgstr "회전" -msgid "Original frame range: %d-%d (%d)" -msgstr "원본 프레임 범위: %d-%d (%d)" - - msgid "Strip Offset Start" msgstr "스트립 오프셋 시작" @@ -80249,10 +80224,6 @@ msgid "Effect Fader" msgstr "이펙트 페더" -msgid "%dx%d" -msgstr "%dx%d" - - msgid "Original Frame Range" msgstr "원본 프레임 범위" @@ -80269,6 +80240,10 @@ msgid "Pack" msgstr "포장" +msgid "Original frame range: %d-%d (%d)" +msgstr "원본 프레임 범위: %d-%d (%d)" + + msgid "Source Channel" msgstr "소스 채널" @@ -80357,10 +80332,6 @@ msgid "Move Line(s) Down" msgstr "라인을 아래로 이동" -msgid "Text: ExternalText: Internal" -msgstr "텍스트: 외부 텍스트: 내부" - - msgid "File: *%s (unsaved)" msgstr "파일: *%s (저장되지 않음)" @@ -80799,10 +80770,6 @@ msgid "Author:" msgstr "작성자:" -msgid "author" -msgstr "작성자" - - msgid "Version:" msgstr "버젼:" @@ -88337,22 +88304,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "NLA 스트립 '%s'을 트랙 '%s'에서 찾을 수 없습니다" -msgid "Functions" -msgstr "함수" - - -msgid "Comparison" -msgstr "비교" - - -msgid "Trigonometric" -msgstr "삼각법" - - -msgid "Conversion" -msgstr "변환" - - msgid "Same input/output direction of sockets" msgstr "소켓의 동일한 입력/출력 방향" diff --git a/locale/po/ky.po b/locale/po/ky.po index 0d229e863f7..0b99af31954 100644 --- a/locale/po/ky.po +++ b/locale/po/ky.po @@ -1,10 +1,10 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "(b'0000000000000000000000000000000000000000')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2013-11-05 13:47+0600\n" "Last-Translator: Chyngyz Dzhumaliev \n" "Language-Team: Kirghiz \n" @@ -3234,10 +3234,6 @@ msgid "Statistics" msgstr "Статистика" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Трекинг" @@ -3464,10 +3460,6 @@ msgid "Author:" msgstr "Автору:" -msgid "author" -msgstr "автор" - - msgid "Version:" msgstr "Версиясы:" diff --git a/locale/po/nl.po b/locale/po/nl.po index a84969a7f12..5faa45f6950 100644 --- a/locale/po/nl.po +++ b/locale/po/nl.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2021-12-05 20:05+0100\n" "Language: nl\n" "MIME-Version: 1.0\n" @@ -1503,10 +1503,6 @@ msgid "Compression" msgstr "Compressie" -msgid "Number" -msgstr "Nummer" - - msgid "Maximum Resolution" msgstr "Maximale Resolutie" @@ -1957,22 +1953,6 @@ msgid "Subtract Color" msgstr "Trek Kleur Af" -msgid "Smoother" -msgstr "Gladder" - - -msgid "Root" -msgstr "Wortel" - - -msgid "Sharp" -msgstr "Scherp" - - -msgid "Inverse Square" -msgstr "Inverse Wortel" - - msgid "Cloth Simulation" msgstr "Kledingsimulatie" @@ -2033,10 +2013,6 @@ msgid "Forward" msgstr "Vooruit" -msgid "Second" -msgstr "Seconde" - - msgid "Clip End" msgstr "Clip Einde" @@ -2260,6 +2236,10 @@ msgid "Falloff Type" msgstr "Type Afvlakking" +msgid "Inverse Square" +msgstr "Inverse Wortel" + + msgid "Shadow Color" msgstr "Schaduwkleur" @@ -2416,6 +2396,10 @@ msgid "Size 2" msgstr "Grootte 2" +msgid "Number" +msgstr "Nummer" + + msgid "Random Size" msgstr "Willekeurige Grootte" @@ -2489,6 +2473,10 @@ msgid "Mirror Y" msgstr "Spiegel Y" +msgid "Sharp" +msgstr "Scherp" + + msgid "Workspace" msgstr "Werkomgeving" @@ -2878,6 +2866,10 @@ msgid "Split Normals" msgstr "Splits Normalen" +msgid "Root" +msgstr "Wortel" + + msgid "Size X" msgstr "Grote X" @@ -7804,6 +7796,10 @@ msgid "Resume" msgstr "Hervat" +msgid "Second" +msgstr "Seconde" + + msgid "Auto-Step" msgstr "Auto-Stap" @@ -8399,10 +8395,6 @@ msgid "Author:" msgstr "Auteur:" -msgid "author" -msgstr "auteur" - - msgid "Version:" msgstr "Versie:" diff --git a/locale/po/pl.po b/locale/po/pl.po index cc2c43846d9..d3b4787a68d 100644 --- a/locale/po/pl.po +++ b/locale/po/pl.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2017-08-26 11:13+0200\n" "Last-Translator: Mikołaj Juda \n" "Language: pl\n" diff --git a/locale/po/pt.po b/locale/po/pt.po index c7ce4519fa6..a25d618a3e0 100644 --- a/locale/po/pt.po +++ b/locale/po/pt.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: Ivan Paulos Tomé \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2017-09-08 21:24-0300\n" "Last-Translator: Ivan Paulos Tomé \n" "Language-Team: Ivan Paulos Tomé, Inês Almeida, João Brandão (ULISBOA), Paulo Martins \n" @@ -9290,10 +9290,6 @@ msgid "Data Depth" msgstr "Profundidade de dados" -msgid "Number" -msgstr "Número(s)" - - msgid "Randomness" msgstr "Aleatorização" @@ -11313,22 +11309,6 @@ msgid "Editable falloff curve" msgstr "Curva de decaimento editável." -msgid "Root" -msgstr "Raiz" - - -msgid "Sharp" -msgstr "Ressaltar" - - -msgid "Sharper" -msgstr "Aguçar" - - -msgid "Inverse Square" -msgstr "Inverso quadrático" - - msgid "Paint most on faces pointing towards the view according to this angle" msgstr "Executa a pintura com mais potência nas faces que apontam na direção da visualização, de acordo com este ângulo." @@ -13753,6 +13733,10 @@ msgid "Inverse Linear" msgstr "Linear inverso" +msgid "Inverse Square" +msgstr "Inverso quadrático" + + msgid "Inverse Coefficients" msgstr "Coeficientes inversos" @@ -15689,6 +15673,10 @@ msgid "Show hair simulation grid" msgstr "Mostra a grelha de simulação de cabelos." +msgid "Number" +msgstr "Número(s)" + + msgid "Show particle number" msgstr "Mostra os números das partículas." @@ -16463,10 +16451,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "O ficheiro de texto no disco é diferente do que está na memória." -msgid "Lines" -msgstr "Linhas" - - msgid "Lines of text" msgstr "Linhas de texto" @@ -17075,10 +17059,18 @@ msgid "Use soft marble" msgstr "Usa um mármore suave." +msgid "Sharp" +msgstr "Ressaltar" + + msgid "Use more clearly defined marble" msgstr "Usa um mármore bem definido." +msgid "Sharper" +msgstr "Aguçar" + + msgid "Use very clearly defined marble" msgstr "Usa um mármore mais bem definido." @@ -21371,6 +21363,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "Caso o vértice tenha múltiplas arestas adjacentes, ele está corrigido por estas automaticamente." +msgid "Root" +msgstr "Raiz" + + msgid "Mesh Skin Vertex Layer" msgstr "Camada de vértices de malha de cobertura" @@ -24506,6 +24502,10 @@ msgid "Line Thickness" msgstr "Espessura da linha" +msgid "Lines" +msgstr "Linhas" + + msgid "Motion Path Points" msgstr "Pontos de caminho de movimento" @@ -42779,10 +42779,6 @@ msgid "Fill Range by Selection" msgstr "Preencher campo pela seleção" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Preenche as entradas de alcance mínima e máxima pela distância mínima e máxima entre os objetos de malhas selecionadas e o objeto fonte." - - msgid "Name of the modifier to work on" msgstr "Nome do modificador no qual trabalhar." @@ -60040,10 +60036,6 @@ msgid "Invert Selection" msgstr "Inverter seleção" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Rastreamento" @@ -60464,6 +60456,18 @@ msgid "Strand Shape" msgstr "Formato das vertentes" +msgid "Settings used for fluid" +msgstr "Definições usadas para fluidos." + + +msgid "Jittering Amount" +msgstr "Montante de tremulação" + + +msgid "Use Timing" +msgstr "Usar temporizações" + + msgid "Iterations: %d .. %d (avg. %d)" msgstr "Interações: %d .. %d (média: %d)" @@ -60476,22 +60480,6 @@ msgid "Spacing: %g" msgstr "Espaçamento: %g" -msgid "Settings used for fluid" -msgstr "Definições usadas para fluidos." - - -msgid "Jittering Amount" -msgstr "Montante de tremulação" - - -msgid "%d fluid particles for this frame" -msgstr "%d partículas de fluido para este fotograma." - - -msgid "Use Timing" -msgstr "Usar temporizações" - - msgid "Not yet functional" msgstr "Ainda não funcional" @@ -60506,6 +60494,10 @@ msgid "Disconnect All" msgstr "Desconectar todos" +msgid "%d fluid particles for this frame" +msgstr "%d partículas de fluido para este fotograma." + + msgid "Dynamic Mesh" msgstr "Malha dinâmica" @@ -61317,10 +61309,6 @@ msgid "Rotation" msgstr "Rotação" -msgid "Original frame range: %d-%d (%d)" -msgstr "Intervalo de fotogramas original: %d-%d (%d)" - - msgctxt "Operator" msgid "Clip" msgstr "Clipe" @@ -61330,6 +61318,10 @@ msgid "Unpack" msgstr "Desempacotar" +msgid "Original frame range: %d-%d (%d)" +msgstr "Intervalo de fotogramas original: %d-%d (%d)" + + msgid "Source Channel" msgstr "Canal de fonte" @@ -61533,10 +61525,6 @@ msgid "Author:" msgstr "Autor:" -msgid "author" -msgstr "autor" - - msgid "Version:" msgstr "Versão:" diff --git a/locale/po/pt_BR.po b/locale/po/pt_BR.po index cf8a3331227..194221dcdb1 100644 --- a/locale/po/pt_BR.po +++ b/locale/po/pt_BR.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: Leandro Paganelli \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2022-03-21 19:03-0300\n" "Last-Translator: Leandro Paganelli \n" "Language-Team: Leandro Paganelli, Ivan Paulos Tomé, Dalai Felinto, Bruno Gonçalves Pirajá, Samuel Arataca, Daniel Tavares, Moraes Junior \n" @@ -9840,10 +9840,6 @@ msgid "Data Depth" msgstr "Profundidade de dados" -msgid "Number" -msgstr "Número(s)" - - msgid "Randomness" msgstr "Aleatorização" @@ -12088,22 +12084,6 @@ msgid "Editable falloff curve" msgstr "Curva de decaimento editável." -msgid "Root" -msgstr "Raiz" - - -msgid "Sharp" -msgstr "Ressaltar" - - -msgid "Sharper" -msgstr "Aguçar" - - -msgid "Inverse Square" -msgstr "Inverso quadrático" - - msgid "Falloff Angle" msgstr "Ângulo de decaimento" @@ -14690,6 +14670,10 @@ msgid "Inverse Linear" msgstr "Linear inverso" +msgid "Inverse Square" +msgstr "Inverso quadrático" + + msgid "Inverse Coefficients" msgstr "Coeficientes inversos" @@ -16738,6 +16722,10 @@ msgid "Show hair simulation grid" msgstr "Mostra a grade de simulação de cabelos." +msgid "Number" +msgstr "Número(s)" + + msgid "Show particle number" msgstr "Mostra os números das partículas." @@ -17548,10 +17536,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "O arquivo de texto no disco é diferente do que está na memória." -msgid "Lines" -msgstr "Linhas" - - msgid "Lines of text" msgstr "Linhas de texto" @@ -18164,10 +18148,18 @@ msgid "Use soft marble" msgstr "Usa um mármore suave." +msgid "Sharp" +msgstr "Ressaltar" + + msgid "Use more clearly defined marble" msgstr "Usa um mármore bem definido." +msgid "Sharper" +msgstr "Aguçar" + + msgid "Use very clearly defined marble" msgstr "Usa um mármore mais bem definido." @@ -22921,6 +22913,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "Caso o vértice tenha múltiplas arestas adjacentes, ele está corrigido por estas automaticamente." +msgid "Root" +msgstr "Raiz" + + msgid "Mesh Skin Vertex Layer" msgstr "Camada de vértices de malha de cobertura" @@ -26221,6 +26217,10 @@ msgid "Line Thickness" msgstr "Espessura das linhas" +msgid "Lines" +msgstr "Linhas" + + msgid "Motion Path Points" msgstr "Pontos de caminho de movimento" @@ -46954,10 +46954,6 @@ msgid "Fill Range by Selection" msgstr "Preencher campo pela seleção" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Preenche as entradas de alcance mínima e máxima pela distância mínima e máxima entre os objetos de malhas selecionadas e o objeto fonte." - - msgid "Name of the modifier to work on" msgstr "Nome do modificador no qual trabalhar." @@ -66425,10 +66421,6 @@ msgid "Invert Selection" msgstr "Inverter seleção" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Rastreamento" @@ -66459,10 +66451,6 @@ msgid "Active object is not a mesh" msgstr "Objeto ativo não é uma malha." -msgid "Rename %d %s" -msgstr "Renomear %d %s" - - msgid "Renamed %d of %d %s" msgstr "Renomeadas %d de %d %s" @@ -66531,6 +66519,10 @@ msgid "Manual" msgstr "Manual" +msgid "Rename %d %s" +msgstr "Renomear %d %s" + + msgctxt "Operator" msgid "Load %d.%d Settings" msgstr "Abrir Configurações %d.%d" @@ -66743,10 +66735,6 @@ msgid "Lock Invert All" msgstr "Inverter a trava de todos" -msgid "%s ▶ %s" -msgstr "%s ▶ %s" - - msgctxt "Operator" msgid "Sort by Name" msgstr "Ordenar por nome" @@ -67032,18 +67020,6 @@ msgid "Strand Shape" msgstr "Formato das vertentes" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Interações: %d .. %d (média: %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Erros: %.5f .. %.5f (média: %.5f)" - - -msgid "Spacing: %g" -msgstr "Espaçamento: %g" - - msgid "Strand Steps" msgstr "Passos do fio" @@ -67056,14 +67032,22 @@ msgid "Jittering Amount" msgstr "Montante de tremulação" -msgid "%d fluid particles for this frame" -msgstr "%d partículas de fluido para este quadro." - - msgid "Use Timing" msgstr "Usar temporizações" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Interações: %d .. %d (média: %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Erros: %.5f .. %.5f (média: %.5f)" + + +msgid "Spacing: %g" +msgstr "Espaçamento: %g" + + msgid "Not yet functional" msgstr "Ainda não funcional" @@ -67078,6 +67062,10 @@ msgid "Disconnect All" msgstr "Desconectar todos" +msgid "%d fluid particles for this frame" +msgstr "%d partículas de fluido para este quadro." + + msgid "Air Viscosity" msgstr "Viscosidade do Ar" @@ -67463,11 +67451,6 @@ msgid "Match Previous" msgstr "Combinar com Anterior" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Zoom %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "Encaixar visualização" @@ -68314,10 +68297,6 @@ msgid "Stretch To Fill" msgstr "Esticar para preencher" -msgid "Original frame range: %d-%d (%d)" -msgstr "Intervalo de quadros original: %d-%d (%d)" - - msgctxt "Operator" msgid "Clip" msgstr "Clipe" @@ -68332,18 +68311,14 @@ msgid "Effect Fader" msgstr "Esmaecedor de efeitos" -msgid "%dx%d" -msgstr "%dx%d" - - -msgid "%.2f" -msgstr "%.2f" - - msgid "Unpack" msgstr "Desempacotar" +msgid "Original frame range: %d-%d (%d)" +msgstr "Intervalo de quadros original: %d-%d (%d)" + + msgid "Source Channel" msgstr "Canal de fonte" @@ -68853,10 +68828,6 @@ msgid "Author:" msgstr "Autor:" -msgid "author" -msgstr "autor" - - msgid "Version:" msgstr "Versão:" @@ -75302,10 +75273,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "Faixa de animação não linear '%s' não encontrada na trilha '%s'" -msgid "Trigonometric" -msgstr "Trigonométrico" - - msgid "Same input/output direction of sockets" msgstr "Mesma direção de entrada ou saída de conectores." diff --git a/locale/po/ru.po b/locale/po/ru.po index 48f4dd92f91..8a80ae67955 100644 --- a/locale/po/ru.po +++ b/locale/po/ru.po @@ -1,16 +1,16 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2018-01-03 14:47+0000\n" -"Last-Translator: Lockal , 2021\n" +"Last-Translator: Lockal , 2023\n" "Language-Team: Russian (https://www.transifex.com/translateblender/teams/82039/ru/)\n" +"Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: ru\n" "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" @@ -202,6 +202,10 @@ msgid "Mute" msgstr "Выключить" +msgid "Action group is muted" +msgstr "Группа действий отключена" + + msgid "Select" msgstr "Выделение" @@ -306,14 +310,38 @@ msgid "Device to use for computation (rendering with Cycles)" msgstr "Устройство, используемое для вычислений (при использовании Cycles)" +msgid "Kernel Optimization" +msgstr "Оптимизация ядра" + + +msgid "Kernels can be optimized based on scene content. Optimized kernels are requested at the start of a render. If optimized kernels are not available, rendering will proceed using generic kernels until the optimized set is available in the cache. This can result in additional CPU usage for a brief time (tens of seconds)" +msgstr "Ядра можно оптимизировать на основе содержимого сцены. Оптимизированные ядра запрашиваются в начале рендера. Если оптимизированные ядра недоступны, рендеринг будет продолжаться с использованием универсальных ядер до тех пор, пока оптимизированный набор не будет доступен в кэше. Это может привести к дополнительной загрузке ЦП на короткое время (десятки секунд)" + + msgid "Off" msgstr "Выкл." +msgid "Disable kernel optimization. Slowest rendering, no extra background CPU usage" +msgstr "Отключить оптимизацию ядра. Самый медленный рендеринг, без дополнительной загрузки ЦП в фоновом режиме" + + +msgid "Intersection only" +msgstr "Только пересечения" + + +msgid "Optimize only intersection kernels. Faster rendering, negligible extra background CPU usage" +msgstr "Оптимизировать только ядра пересечения. Более быстрый рендеринг, незначительное дополнительное использование ЦП в фоновом режиме" + + msgid "Full" msgstr "Полностью" +msgid "Optimize all kernels. Fastest rendering, may result in extra background CPU usage" +msgstr "Оптимизировать все ядра. Самый быстрый рендеринг, может привести к дополнительной загрузке процессора в фоновом режиме." + + msgid "Distribute memory across devices" msgstr "Распределить память между устройствами" @@ -322,6 +350,26 @@ msgid "Make more room for large scenes to fit by distributing memory across inte msgstr "Освободите место для больших сцен, распределяя память между взаимосвязанными устройствами (например, через NVLink), а не дублируя ее" +msgid "MetalRT (Experimental)" +msgstr "MetalRT (экспериментально)" + + +msgid "MetalRT for ray tracing uses less memory for scenes which use curves extensively, and can give better performance in specific cases. However this support is experimental and some scenes may render incorrectly" +msgstr "MetalRT для трассировки лучей использует меньше памяти для сцен, в которых широко используются кривые, и может обеспечить более высокую производительность в определённых случаях. Однако эта поддержка является экспериментальной, и некоторые сцены могут отображаться неправильно" + + +msgid "KHR_materials_variants_ui" +msgstr "KHR_materials_variants_ui" + + +msgid "Displays glTF UI to manage material variants" +msgstr "Показать пользовательский интерфейс glTF для управления вариантами материалов" + + +msgid "Displays glTF Material Output node in Shader Editor (Menu Add > Output)" +msgstr "Отобразить ноду вывода материала glTF в редакторе шейдеров (меню Добавить > Вывод)" + + msgid "Fribidi Library" msgstr "Библиотека FriBidi" @@ -630,6 +678,46 @@ msgid "Are there any bone paths that will need updating (read-only)" msgstr "Есть ли пути костей, нуждающиеся в обновлении (только для чтения)" +msgid "Paths Range" +msgstr "Диапазон траекторий" + + +msgid "Type of range to calculate for Motion Paths" +msgstr "Тип вычисляемого диапазона для траекторий движения" + + +msgid "All Keys" +msgstr "Все ключи" + + +msgid "From the first keyframe to the last" +msgstr "От первого ключевого кадра до последнего" + + +msgid "Selected Keys" +msgstr "Выделенные ключи" + + +msgid "From the first selected keyframe to the last" +msgstr "От первого выбранного ключевого кадра до последнего" + + +msgid "Scene Frame Range" +msgstr "Диапазон кадров сцены" + + +msgid "The entire Scene / Preview range" +msgstr "Вся сцена / диапазон предпросмотра" + + +msgid "Manual Range" +msgstr "Ручной диапазон" + + +msgid "Manually determined frame range" +msgstr "Задать диапазон кадров вручную" + + msgid "Show Frame Numbers" msgstr "Отображать номера кадров" @@ -966,6 +1054,10 @@ msgid "Armatures active edit bone" msgstr "Арматуры активной редактируемой кости" +msgid "Catalog Path" +msgstr "Путь к каталог" + + msgid "Asset Library Reference" msgstr "Ссылка на библиотеку ассетов" @@ -990,6 +1082,34 @@ msgid "Index of the tag set for editing" msgstr "Индекс редактируемого набора тегов" +msgid "Author" +msgstr "Автор" + + +msgid "Name of the creator of the asset" +msgstr "Имя создателя ассета" + + +msgid "Catalog UUID" +msgstr "UUID каталога" + + +msgid "Identifier for the asset's catalog, used by Blender to look up the asset's catalog path. Must be a UUID according to RFC4122" +msgstr "Идентификатор каталога ассета, используемый Blender'ом для поиска пути к каталогу ассета. Должен быть UUID в соответствии с RFC4122" + + +msgid "Catalog Simple Name" +msgstr "Короткое имя каталога" + + +msgid "Simple name of the asset's catalog, for debugging and data recovery purposes" +msgstr "Простое имя каталога ассета, используется для отладки и восстановления данных" + + +msgid "Copyright" +msgstr "Копирайт" + + msgid "Description" msgstr "Описание" @@ -1062,10 +1182,18 @@ msgid "3D vector with floating-point values" msgstr "Трёхмерный нецелочисленный вектор" +msgid "RGBA color with 32-bit floating-point values" +msgstr "Цвет RGBA с 32-битными значениями с плавающей точкой" + + msgid "Byte Color" msgstr "Байтовый цвет" +msgid "RGBA color with 8-bit positive integer values" +msgstr "Цвет RGBA с 8-битными положительными целочисленными значениями" + + msgid "String" msgstr "Строка" @@ -1090,6 +1218,14 @@ msgid "2D vector with floating-point values" msgstr "2D-вектор чисел с плавающей точкой" +msgid "8-Bit Integer" +msgstr "8-битное целое число" + + +msgid "Smaller integer with a range from -128 to 127" +msgstr "Целое число в диапазоне от -128 до 127" + + msgid "Domain" msgstr "Домен" @@ -1138,6 +1274,22 @@ msgid "Attribute on spline" msgstr "Атрибут сплайна" +msgid "Instance" +msgstr "Экземпляр" + + +msgid "Attribute on instance" +msgstr "Атрибут экземпляра" + + +msgid "Is Internal" +msgstr "Является внутренним" + + +msgid "The attribute is meant for internal use by Blender" +msgstr "Атрибут предназначен для внутреннего использования в Blender" + + msgid "Name of the Attribute" msgstr "Имя атрибута" @@ -1146,10 +1298,18 @@ msgid "Bool Attribute" msgstr "Булевый атрибут" +msgid "Geometry attribute that stores booleans" +msgstr "Атрибут геометрии, хранящий булевы значения" + + msgid "Byte Color Attribute" msgstr "Атрибут байтового цвета" +msgid "Geometry attribute that stores RGBA colors as positive integer values using 8-bits per channel" +msgstr "Атрибут геометрии, который хранит цвета RGBA как положительные целочисленные значения, используя 8 бит на канал" + + msgid "Float2 Attribute" msgstr "Атрибут Float2" @@ -1982,6 +2142,10 @@ msgid "Collection of grease pencils" msgstr "Коллекция Grease Pencil" +msgid "Collection of hair curves" +msgstr "Коллекция кривых волос" + + msgid "Main Images" msgstr "Основные изображения" @@ -2102,6 +2266,10 @@ msgid "Collection of particle settings" msgstr "Коллекция параметров частиц" +msgid "Collection of point clouds" +msgstr "Коллекция облаков точек" + + msgid "Main Light Probes" msgstr "Основные зонды освещения" @@ -3286,6 +3454,14 @@ msgid "Count" msgstr "Количество" +msgid "Length of newly added curves when it is not interpolated from other curves" +msgstr "Длина добавленных кривых, если она не интерполирована от других кривых" + + +msgid "How many times the Density brush tries to add a new curve" +msgstr "Количество попыток кисти «‎Плотность»‎ добавить новую кривую" + + msgid "Remove" msgstr "Удалить" @@ -3295,11 +3471,11 @@ msgstr "Мин. расстояние" msgid "Grease Pencil Brush Settings" -msgstr "Настройки кисти Grease Pencil" +msgstr "Параметры кисти Grease Pencil" msgid "Settings for grease pencil brush" -msgstr "Настройки кисти Grease Pencil" +msgstr "Параметры кисти Grease Pencil" msgid "Active Smooth" @@ -3319,11 +3495,11 @@ msgstr "Направление штриха, при котором кисть и msgid "Angle Factor" -msgstr "Коэффициент угла" +msgstr "Множитель угла" msgid "Reduce brush thickness by this factor when stroke is perpendicular to 'Angle' direction" -msgstr "Коэффициент уменьшения толщины, если штрих перпендикулярен направлению угла" +msgstr "Уменьшить толщину кисти на этот множитель, если штрих перпендикулярен направлению угла" msgid "Aspect" @@ -3915,7 +4091,7 @@ msgstr "Случайные настройки" msgid "Random brush settings" -msgstr "Случайные настройки кисти" +msgstr "Случайные параметры кисти" msgid "Use Stabilizer" @@ -3998,6 +4174,10 @@ msgid "RGBA color in scene linear color space" msgstr "RGBA-цвет в линейном цветовом пространстве сцены" +msgid "Collection of cache layers" +msgstr "Коллекция слоёв кэша" + + msgid "Active Layer" msgstr "Активный слой" @@ -9142,11 +9322,11 @@ msgstr "Расстояние между двумя костями или объ msgid "Brush Settings" -msgstr "Настройки кисти" +msgstr "Параметры кисти" msgid "Brush settings" -msgstr "Настройки кисти" +msgstr "Параметры кисти" msgid "Inner Proximity" @@ -12811,10 +12991,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "Минимальное число частиц на клетку (гарантирует, что в каждой клетке есть по крайней мере это количество частиц)" -msgid "Number" -msgstr "Число" - - msgid "Particle number factor (higher value results in more particles)" msgstr "Множитель числа частиц (более высокое значение увеличивает число частиц)" @@ -15398,7 +15574,7 @@ msgstr "Развернуть модификатор в пользователь msgid "Edit Mode" -msgstr "Режим редактирования" +msgstr "Редактирование" msgid "Display modifier in Edit mode" @@ -16247,6 +16423,14 @@ msgid "Require matching all intersection masks instead of just one" msgstr "Требовать соответствия всем маскам пересечения, а не только одного" +msgid "Invert Collection Filtering" +msgstr "Инвертировать фильтрацию коллекции" + + +msgid "Select everything except lines from specified collection" +msgstr "Выделить всё, кроме строк из указанной коллекции" + + msgid "Use Loose" msgstr "Использовать свободные рёбра" @@ -17616,26 +17800,6 @@ msgid "Editable falloff curve" msgstr "Редактируемая кривая спада" -msgid "Curve Preset" -msgstr "Предустановка кривой" - - -msgid "Root" -msgstr "Корень" - - -msgid "Sharp" -msgstr "Остро" - - -msgid "Sharper" -msgstr "Острее" - - -msgid "Inverse Square" -msgstr "Обратно-квадратично" - - msgid "Ratio of samples in a cycle that the brush is enabled" msgstr "Число сэмплов на цикли при включении кисти" @@ -18476,10 +18640,6 @@ msgid "Up" msgstr "Вверх" -msgid "Second" -msgstr "Второй" - - msgid "Camera data-block for storing camera settings" msgstr "Датаблок камеры для хранения настроек камеры" @@ -20754,6 +20914,10 @@ msgid "Inverse Linear" msgstr "Обратно-линейно" +msgid "Inverse Square" +msgstr "Обратно-квадратично" + + msgid "Inverse Coefficients" msgstr "Обратные коэффициенты" @@ -22415,7 +22579,7 @@ msgstr "Режим взаимодействия с объектом" msgid "Object Mode" -msgstr "Объектный режим" +msgstr "Объекты" msgid "Pose Mode" @@ -22423,7 +22587,7 @@ msgstr "Режим позы" msgid "Sculpt Mode" -msgstr "Режим скульптинга" +msgstr "Скульптинг" msgid "Vertex Paint" @@ -22435,7 +22599,7 @@ msgstr "Рисование веса" msgid "Texture Paint" -msgstr "Режим текстурирования" +msgstr "Текстурирование" msgid "Particle Edit" @@ -23441,6 +23605,10 @@ msgid "Show hair simulation grid" msgstr "Показывать сетку симуляции волос" +msgid "Number" +msgstr "Число" + + msgid "Show particle number" msgstr "Отобразить число частиц" @@ -24311,10 +24479,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "Текстовой файл на диске отличается от файла в памяти" -msgid "Lines" -msgstr "Линии" - - msgid "Lines of text" msgstr "Строки текста" @@ -24935,10 +25099,18 @@ msgid "Use soft marble" msgstr "Использовать мягкий мрамор" +msgid "Sharp" +msgstr "Остро" + + msgid "Use more clearly defined marble" msgstr "Использовать мрамор с более чёткими границами" +msgid "Sharper" +msgstr "Острее" + + msgid "Use very clearly defined marble" msgstr "Использовать мрамор с очень чёткими границами" @@ -30015,6 +30187,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "Если у вершины несколько прилежащих рёбер, обёртывать их напрямую" +msgid "Root" +msgstr "Корень" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "Использовать вершину как основную при расчёте вращения и генерации арматуры; эта настройка не очищает другие такие же точки в этом же меш-острове" @@ -33659,6 +33835,10 @@ msgid "Line Thickness" msgstr "Толщина линий" +msgid "Lines" +msgstr "Линии" + + msgid "Motion Path Points" msgstr "Точки траектории движения" @@ -40146,7 +40326,7 @@ msgstr "Сбросить кисть" msgid "Return brush to defaults based on current tool" -msgstr "Сбросить настройки кисти к настройкам по умолчанию для текущего инструмента" +msgstr "Сбросить параметры кисти к значениям по умолчанию для текущего инструмента" msgctxt "Operator" @@ -43062,10 +43242,6 @@ msgid "Export vertex colors with meshes" msgstr "Экспортировать цвета вершин вместе с мешами" -msgid "Copyright" -msgstr "Копирайт" - - msgid "Legal rights and conditions for the model" msgstr "Условия использования модели" @@ -45227,6 +45403,10 @@ msgid "Use whole stroke, not only selected points" msgstr "Использовать весь штрих, а не только выделенные точки" +msgid "New Material" +msgstr "Создать материал" + + msgctxt "Operator" msgid "Sample Stroke" msgstr "Сэмплировать штрих" @@ -51854,7 +52034,7 @@ msgstr "Примитив" msgctxt "Operator" msgid "Set Object Mode" -msgstr "Установить объектный режим" +msgstr "Перейти в объектный режим" msgid "Sets the object interaction mode" @@ -55985,10 +56165,6 @@ msgid "Fill Range by Selection" msgstr "Заполнить диапазон выделением" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Заполнить значения минимума/максимума минимальным и максимальным расстоянием между выделенным меш-объектом и исходным объектом" - - msgid "Name of the modifier to work on" msgstr "Имя модификатора, с которым осуществляется работа" @@ -66072,6 +66248,10 @@ msgid "Python Scripts Directory" msgstr "Папка скриптов Python" +msgid "Alternate script path, matching the default layout with subdirectories: `startup`, `addons`, `modules`, and `presets` (requires restart)" +msgstr "Альтернативная директория скриптов, совпадающая со стандартной схемой субдиректорий: `startup`, `addons`, `modules` и `presets` (необходим перезапуск)" + + msgid "Sounds Directory" msgstr "Папка со звуками" @@ -66817,7 +66997,7 @@ msgstr "Выполнять рендеринг сцены с 32 сэмплами msgid "Color Picker Type" -msgstr "Инструмент выбора цвета" +msgstr "Выбор цвета" msgid "Different styles of displaying the color picker widget" @@ -66865,7 +67045,7 @@ msgstr "Квадрат, отображающий оттенок и значен msgid "Factor Display Type" -msgstr "Показ коэффициентов" +msgstr "Вид коэффициентов" msgid "How factor values are displayed" @@ -66952,6 +67132,10 @@ msgid "Language used for translation" msgstr "Язык, используемый для перевода" +msgid "Automatic (Automatic)" +msgstr "Автоматически (автоматически)" + + msgid "Automatically choose system's defined language if available, or fall-back to English" msgstr "Автоматически выбирать системный язык (если задан) или использовать английский по умолчанию" @@ -77345,7 +77529,7 @@ msgstr "Объект, используемый для считывания тр msgid "Overrides for some of the active brush's settings" -msgstr "Переопределяет некоторые настройки активной кисти" +msgstr "Переопределяет некоторые параметры активной кисти" msgid "Radius of the brush" @@ -79822,10 +80006,6 @@ msgid "Invert Selection" msgstr "Инвертировать выделение" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: «{}» ({})" - - msgid "Tracking" msgstr "Трекинг" @@ -79868,18 +80048,6 @@ msgid "Open..." msgstr "Открыть…" -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "Дата: %s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "Хэш: %sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "Ветка: %sutf-8replace" - - msgid "Blender is free software" msgstr "Blender является свободным программным обеспечением" @@ -79911,7 +80079,12 @@ msgstr "Приступая к работе" msgctxt "Operator" msgid "Release Notes" -msgstr "Примечания к выпуску" +msgstr "Заметки о релизе" + + +msgctxt "Operator" +msgid "Development Fund" +msgstr "Фонд поддержки разработки" msgctxt "Operator" @@ -80776,22 +80949,10 @@ msgid "Hair dynamics disabled" msgstr "Динамика волос отключена" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Итераций: %d .. %d (в среднем %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Ошибка: %.5f .. %.5f (в среднем %.5f)" - - msgid "Multiply Mass with Size" msgstr "Умножить массу на размер" -msgid "Spacing: %g" -msgstr "Интервал: %g" - - msgid "Show Emitter" msgstr "Показать излучатель" @@ -80836,10 +80997,6 @@ msgid "Coordinate System" msgstr "Система координат" -msgid "%d fluid particles for this frame" -msgstr "%d частиц жидкости на этот кадр" - - msgctxt "Operator" msgid "Delete Edit" msgstr "Удалить изменения" @@ -80853,6 +81010,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "Отображение процентной завершённости без запекания ухудшает качество динамики" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Итераций: %d .. %d (в среднем %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Ошибка: %.5f .. %.5f (в среднем %.5f)" + + +msgid "Spacing: %g" +msgstr "Интервал: %g" + + msgid "Not yet functional" msgstr "Пока ещё не функционирует" @@ -80867,6 +81036,10 @@ msgid "Disconnect All" msgstr "Отсоединить все" +msgid "%d fluid particles for this frame" +msgstr "%d частиц жидкости на этот кадр" + + msgid "Speed Multiplier" msgstr "Множитель скорости" @@ -81142,6 +81315,10 @@ msgid "Velocity Linear" msgstr "Линейная скорость" +msgid "Second" +msgstr "Второй" + + msgid "X Stiffness" msgstr "Жёсткость X" @@ -81522,11 +81699,6 @@ msgid "Set Keyframe B" msgstr "Установить ключевой кадр B" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Масштабировать %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "Вписать вид" @@ -82291,6 +82463,11 @@ msgid "Hide One Level" msgstr "Скрыть один уровень" +msgctxt "Collection" +msgid "New" +msgstr "Создать" + + msgctxt "Operator" msgid "Link to Scene" msgstr "Ссылка в сцену" @@ -82602,10 +82779,6 @@ msgid "Rotation" msgstr "Повернуть" -msgid "Original frame range: %d-%d (%d)" -msgstr "Исходный диапазон кадров: %d-%d (%d)" - - msgid "Strip Offset Start" msgstr "Начальное смещение дорожки" @@ -82655,10 +82828,6 @@ msgid "Effect Fader" msgstr "Регулятор эффекта" -msgid "%dx%d" -msgstr "%d×%d" - - msgid "Original Frame Range" msgstr "Исходный диапазон кадров" @@ -82675,6 +82844,10 @@ msgid "Pack" msgstr "Упаковать" +msgid "Original frame range: %d-%d (%d)" +msgstr "Исходный диапазон кадров: %d-%d (%d)" + + msgid "Source Channel" msgstr "Канал-источник" @@ -82763,10 +82936,6 @@ msgid "Move Line(s) Down" msgstr "Переместить строки вниз" -msgid "Text: ExternalText: Internal" -msgstr "Текст: Внешний текст: Внутренний" - - msgid "File: *%s (unsaved)" msgstr "Файл: *%s (не сохранён)" @@ -82846,6 +83015,11 @@ msgid "Install Application Template..." msgstr "Установить шаблон приложения…" +msgctxt "WindowManager" +msgid "New" +msgstr "Создать" + + msgctxt "Operator" msgid "Quit" msgstr "Выход" @@ -82901,6 +83075,11 @@ msgid "Rename Active Item..." msgstr "Переименовать активный элемент…" +msgctxt "Operator" +msgid "Batch Rename..." +msgstr "Массовое переименование…" + + msgctxt "Operator" msgid "Preferences..." msgstr "Настройки…" @@ -83013,7 +83192,7 @@ msgstr "Вернуть сохранённые настройки" msgid "Resolution Scale" -msgstr "Масштаб разрешения экрана" +msgstr "Масштаб разрешения" msgid "Splash Screen" @@ -83210,14 +83389,6 @@ msgid "Save as Studio light" msgstr "Сохранить как студийный свет" -msgid "Color Set %d" -msgstr "Цветовой набор %d" - - -msgid "Color %d" -msgstr "Цвет %d" - - msgid "Player" msgstr "Программа воспроизведения" @@ -83250,6 +83421,14 @@ msgid ":" msgstr ":" +msgid "Color Set %d" +msgstr "Цветовой набор %d" + + +msgid "Color %d" +msgstr "Цвет %d" + + msgid "Description:" msgstr "Описание:" @@ -83266,10 +83445,6 @@ msgid "Author:" msgstr "Автор:" -msgid "author" -msgstr "автор" - - msgid "Version:" msgstr "Версия:" @@ -85416,6 +85591,10 @@ msgid "Eevee material conversion problem. Error in console" msgstr "Ошибка преобразования материалов EEVEE. Текст ошибки в консоли" +msgid "Video_Editing" +msgstr "Video_Editing" + + msgid "Unable to make version backup: filename too short" msgstr "Ошибка создания резервной копии версии: слишком короткое имя файла" @@ -87044,6 +87223,11 @@ msgid "New" msgstr "Создать" +msgctxt "Curves" +msgid "New" +msgstr "Создать" + + msgctxt "PointCloud" msgid "New" msgstr "Создать" @@ -92316,6 +92500,78 @@ msgid "Stereo 3D Mode requires the window to be fullscreen" msgstr "Для работы в режиме стерео-3d необходимо полноэкранное окно" +msgctxt "WorkSpace" +msgid "Animation" +msgstr "Анимация" + + +msgctxt "WorkSpace" +msgid "Compositing" +msgstr "Композитинг" + + +msgctxt "WorkSpace" +msgid "Geometry Nodes" +msgstr "Ноды геометрии" + + +msgctxt "WorkSpace" +msgid "Layout" +msgstr "Планировка" + + +msgctxt "WorkSpace" +msgid "Modeling" +msgstr "Моделирование" + + +msgctxt "WorkSpace" +msgid "Rendering" +msgstr "Рендеринг" + + +msgctxt "WorkSpace" +msgid "Scripting" +msgstr "Скриптинг" + + +msgctxt "WorkSpace" +msgid "Sculpting" +msgstr "Скульптинг" + + +msgctxt "WorkSpace" +msgid "Shading" +msgstr "Шейдинг" + + +msgctxt "WorkSpace" +msgid "Texture Paint" +msgstr "Текстурирование" + + +msgctxt "WorkSpace" +msgid "UV Editing" +msgstr "UV-редактор" + + +msgctxt "WorkSpace" +msgid "Video Editing" +msgstr "Редактирование видео" + + +msgid "UV Layout" +msgstr "UV-развёртка" + + +msgid "UV Editor > UV > Export UV Layout" +msgstr "Редактор UV > UV > Экспорт развёртки UV" + + +msgid "Export the UV layout as a 2D graphic" +msgstr "Экспортировать UV-развёртку в 2D-графику" + + msgid "All Add-ons" msgstr "Все аддоны" @@ -92488,6 +92744,10 @@ msgid "Uzbek (Oʻzbek)" msgstr "Узбекский (Oʻzbek)" +msgid "Uzbek Cyrillic (Ўзбек)" +msgstr "Узбекский кириллицей (Oʻzbek)" + + msgid "Hindi (मानक हिन्दी)" msgstr "Хинди (मानक हिन्दी)" diff --git a/locale/po/sk.po b/locale/po/sk.po index 83b71a9d901..c7f864feba8 100644 --- a/locale/po/sk.po +++ b/locale/po/sk.po @@ -1,10 +1,10 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" -"PO-Revision-Date: 2023-03-01 09:06+0100\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" +"PO-Revision-Date: 2023-03-08 07:56+0100\n" "Last-Translator: Jozef Matta \n" "Language-Team: Jozef Matta\n" "Language: sk_SK\n" @@ -1108,6 +1108,10 @@ msgid "Simple name of the asset's catalog, for debugging and data recovery purpo msgstr "Jednoduchý názov katalógu aktíva na účely ladenia a obnovy údajov" +msgid "Copyright" +msgstr "Autorské práva" + + msgid "Description" msgstr "Popis" @@ -5654,6 +5658,10 @@ msgid "Enabled" msgstr "Povolené" +msgid "Enable this object as a collider for physics systems" +msgstr "Povolí tento objekt ako urýchľovač pre fyzikálne systémy" + + msgid "Single Sided" msgstr "Jednostranný" @@ -13695,10 +13703,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "Minimálny počet častíc na bunku (zabezpečuje, aby každá bunka obsahovala aspoň toto množstvo častíc)" -msgid "Number" -msgstr "Počet" - - msgid "Particle number factor (higher value results in more particles)" msgstr "Faktor počtu častíc (vyššia hodnota vedie k početnejším časticiam)" @@ -16417,6 +16421,10 @@ msgid "Texture Mapping" msgstr "Mapovanie textúry" +msgid "Change stroke UV texture values" +msgstr "Ťahom zmení hodnoty UV textúry" + + msgid "Time Offset" msgstr "Omeškanie" @@ -17927,6 +17935,10 @@ msgid "Amount of noise to apply to thickness" msgstr "Množstvo šumu pre použitie na hrúbku" +msgid "Amount of noise to apply to UV rotation" +msgstr "Množstvo šumu pre použitie UV rotácie" + + msgid "Noise Offset" msgstr "Posuv šumu" @@ -19532,30 +19544,6 @@ msgid "Editable falloff curve" msgstr "Upravovateľné dopady krivky" -msgid "Curve Preset" -msgstr "Predvoľba krivky" - - -msgid "Smoother" -msgstr "Hladšie" - - -msgid "Root" -msgstr "Koreňový" - - -msgid "Sharp" -msgstr "Ostré" - - -msgid "Sharper" -msgstr "Ostrejšie" - - -msgid "Inverse Square" -msgstr "Inverzný štvorec" - - msgid "Curves Sculpt Settings" msgstr "Nastavenia tvarovania kriviek" @@ -21000,18 +20988,10 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "Názov atribútu Alembic, ktorý sa používa na generovanie údajov o rozostrení pohybom" -msgid "Velocity Unit" -msgstr "Jednotka rýchlosti" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "Definuje, ako sa majú vektory rýchlosti interpretovať s ohľadom na čas, „snímka“ znamená, že delta čas je 1 snímka, „druhé“ znamená, že delta čas je 1 / sním/s" -msgid "Second" -msgstr "Druhá" - - msgid "Camera data-block for storing camera settings" msgstr "Blok údajov kamery na uloženie nastavení kamery" @@ -23795,6 +23775,10 @@ msgid "Inverse Linear" msgstr "Lineárna inverzia" +msgid "Inverse Square" +msgstr "Inverzný štvorec" + + msgid "Inverse Coefficients" msgstr "Koeficienty inverzie" @@ -26951,6 +26935,10 @@ msgid "Display boid health" msgstr "Zobrazí zdravie kŕdľa" +msgid "Number" +msgstr "Počet" + + msgid "Show particle number" msgstr "Zobrazí počet častíc" @@ -28026,10 +28014,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "Textový súbor na disku je iný ako ten v pamäti" -msgid "Lines" -msgstr "Riadky" - - msgid "Lines of text" msgstr "Riadky textu" @@ -28700,10 +28684,18 @@ msgid "Use soft marble" msgstr "Použije jemné mramorovanie" +msgid "Sharp" +msgstr "Ostré" + + msgid "Use more clearly defined marble" msgstr "Použije jasne ohraničený mramor" +msgid "Sharper" +msgstr "Ostrejšie" + + msgid "Use very clearly defined marble" msgstr "Použije veľmi jasne ohraničený mramor" @@ -34932,6 +34924,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "Ak má vrchol viacero susediacich hrán, je obalený priamo" +msgid "Root" +msgstr "Koreňový" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "Vrchol je koreňom pre výpočty rotácie a generovania armatúry, pričom tento príznak nevymaže ostatné korene na rovnakom ostrove povrchovej siete" @@ -35060,6 +35056,10 @@ msgid "UV Pin" msgstr "Pripnuté UV" +msgid "UV pinned state in the UV editor" +msgstr "Stav pripnutia UV v UV editore" + + msgid "UV coordinates on face corners" msgstr "UV súradnice na rohoch plôšok" @@ -38893,6 +38893,10 @@ msgid "UVWarp Modifier" msgstr "Modifikátor UV skrivenia" +msgid "Add target position to UV coordinates" +msgstr "Pridá cieľovú pozíciu do UV súradníc" + + msgid "U-Axis" msgstr "Osi U" @@ -39676,6 +39680,10 @@ msgid "Line thickness for motion path" msgstr "Hrúbka čiary pre dráhu pohybu" +msgid "Lines" +msgstr "Riadky" + + msgid "Use straight lines between keyframe points" msgstr "Používa rovné čiary medzi bodmi kľúčovej snímky" @@ -54032,14 +54040,18 @@ msgid "Export vertex colors with meshes" msgstr "Exportuje farby vrcholov s povrchovými sieťami" -msgid "Copyright" -msgstr "Autorské práva" - - msgid "Legal rights and conditions for the model" msgstr "Zákonné práva a podmienky pre model" +msgid "Use Current Frame" +msgstr "Použiť aktuálnu snímku" + + +msgid "Export the scene in the current animation frame" +msgstr "Exportuje scénu do aktuálnej snímky animácie" + + msgid "Export Deformation Bones Only" msgstr "Exportuje iba deformácie kostí" @@ -54236,6 +54248,14 @@ msgid "Export vertex tangents with shape keys (morph targets)" msgstr "Exportuje dotyčnice vrcholov s kľúčovými tvarmi (ciele Morph)" +msgid "Group by NLA Track" +msgstr "Skupina podľa stopy NLA" + + +msgid "When on, multiple actions become part of the same glTF animation if they're pushed onto NLA tracks with the same name. When off, all the currently assigned actions become one glTF animation" +msgstr "Keď je zapnutá, viac akcií sa stane súčasťou rovnakej animácie glTF, ak sú stlačené do stopy NLA s rovnakým názvom. Keď je vypnutá, všetky aktuálne priradené akcie sa stanú jednou animáciou glTF" + + msgid "Merged Animation Name" msgstr "Zlúčený názov animácie" @@ -65530,6 +65550,10 @@ msgid "Hook selected vertices to the first selected object" msgstr "Zahákuje vybrané vrcholy na prvý vybraný objekt" +msgid "Assign the hook to the hook object's active bone" +msgstr "Priradí hák k aktívnej kosti predmetu háku" + + msgctxt "Operator" msgid "Assign to Hook" msgstr "Priradiť k háku" @@ -68408,6 +68432,14 @@ msgid "Library Operation" msgstr "Operácia knižnice" +msgid "" +"Delete this library and all its items.\n" +"Warning: No undo" +msgstr "" +"Odstráni túto knižnicu a všetky jej položky.\n" +"Upozornenie: Nemožno vrátiť späť" + + msgid "Relocate" msgstr "Premiestniť" @@ -68826,6 +68858,10 @@ msgid "Add Simple UVs" msgstr "Pridať jednoduché UV" +msgid "Add cube map UVs on mesh" +msgstr "Pridá kockovú mapu UV súradníc na povrchovú sieť" + + msgctxt "Operator" msgid "Add Paint Slot" msgstr "Pridať zásuvku maľovania" @@ -71289,8 +71325,8 @@ msgid "Fill Range by Selection" msgstr "Rozsah vyplnenia podľa výberu" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Vyplní položky min/max rozsahu podľa min/max vzdialenosti medzi vybranými povrchovými sieťami objektov a zdrojovým objektom " +msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object (either a user-specified object or the active camera)" +msgstr "Vyplní položky Rozsah Min/Max o minimálnu/maximálnu vzdialenosť medzi vybranými objektami povrchovej siete a zdrojovým objektom (buď užívateľom zadaným objektom, alebo aktívnou kamerou)" msgid "Name of the modifier to work on" @@ -76396,6 +76432,10 @@ msgid "Align Rotation" msgstr "Zarovnať rotáciu" +msgid "Align the UV island's rotation" +msgstr "Zarovná rotáciu UV ostrova" + + msgid "Axis to align to" msgstr "Zarovnať os na" @@ -76844,6 +76884,10 @@ msgid "Use orthographic projection" msgstr "Použije kolmé premietanie" +msgid "Randomize the UV island's location, rotation, and scale" +msgstr "Vytvorí náhodnú polohu, rotáciu a mierku UV ostrova" + + msgid "Maximum rotation" msgstr "Maximálna rotácia" @@ -90021,10 +90065,6 @@ msgid "Additional subdivision along the curves" msgstr "Dodatočné delenie pozdĺž kriviek" -msgid "Curves Shape Type" -msgstr "Typ tvaru krivky" - - msgid "Curves shape type" msgstr "Typ tvaru krivky" @@ -96883,7 +96923,11 @@ msgstr "Zobrazí farebné plôšky podľa rozdielu v tvare medzi UV a ich 3D sú msgid "Display Texture Paint UVs" -msgstr "Zobraziť textúru UV kresby" +msgstr "Zobraziť kresbu textúry UV" + + +msgid "Display overlay of texture paint UV layer" +msgstr "Zobrazí prekrytie kresbou textúry UV vrstvy." msgid "Tile Grid Shape" @@ -105252,20 +105296,28 @@ msgid "No compatible GPUs found for Cycles" msgstr "Pre Cykly neboli nájdené žiadne kompatibilné GPU" -msgid "(TM)TRADE MARK SIGN(tm)TRADE MARK SIGN(R)REGISTERED SIGN(C)COPYRIGHT SIGN" -msgstr "(TM)OZNAČENIE OCHRANNEJ ZNÁMKY(R)REGISTROVANÉ OZNAČENIE(C)OZNAČENIE AUTORSKÝCH PRÁV" - - msgid "Requires NVIDIA GPU with compute capability %s" msgstr "Vyžaduje grafický procesor NVIDIA s možnosťou výpočtu %s" +msgid "Requires AMD GPU with Vega or RDNA architecture" +msgstr "Vyžaduje AMD GPU s architektúrou Vega alebo RDNA" + + msgid "and NVIDIA driver version %s or newer" msgstr "a NVIDIA driver verzia %s alebo novšia" -msgid "Requires AMD GPU with Vega or RDNA architecture" -msgstr "Vyžaduje AMD GPU s architektúrou Vega alebo RDNA" +msgid "Requires Intel GPU with Xe-HPG architecture" +msgstr "Vyžaduje GPU Intel s architektúrou Xe-HPG" + + +msgid "Requires Intel GPU with Xe-HPG architecture and" +msgstr "Vyžaduje GPU Intel s architektúrou Xe-HPG a" + + +msgid " - oneAPI Level-Zero Loader" +msgstr " - zavádzač oneAPI Level-Zero" msgid "and AMD Radeon Pro %s driver or newer" @@ -105276,10 +105328,6 @@ msgid "and AMD driver version %s or newer" msgstr "a verzia ovládača AMD %s alebo novšia" -msgid "Requires Intel GPU with Xe-HPG architecture" -msgstr "Vyžaduje GPU Intel s architektúrou Xe-HPG" - - msgid "and Windows driver version %s or newer" msgstr "a ovládač systému Windows %s alebo novší" @@ -105292,18 +105340,10 @@ msgid "or AMD with macOS %s or newer" msgstr "alebo AMD so systémom macOS %s alebo novším" -msgid "Requires Intel GPU with Xe-HPG architecture and" -msgstr "Vyžaduje GPU Intel s architektúrou Xe-HPG a" - - msgid " - intel-level-zero-gpu version %s or newer" msgstr " - Intel-level-zero-GPU verzia %s alebo novšia" -msgid " - oneAPI Level-Zero Loader" -msgstr " - zavádzač oneAPI Level-Zero" - - msgid "Noise Threshold" msgstr "Prah šumu" @@ -106090,10 +106130,6 @@ msgid "Invert Selection" msgstr "Invertovať výber" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Snímanie" @@ -106185,15 +106221,15 @@ msgid "Restore" msgstr "Obnoviť" -msgid "%s (Global)" -msgstr "%s (globálne)" - - msgctxt "WindowManager" msgid "Add New" msgstr "Pridať nový" +msgid "%s (Global)" +msgstr "%s (globálne)" + + msgctxt "Operator" msgid "New" msgstr "Nový" @@ -106508,14 +106544,6 @@ msgid "Current frame not within strip framerange" msgstr "Aktuálna snímka sa nenachádza v rozsahu pásov" -msgid "Remove Add-on: %r?" -msgstr "Odstrániť doplnok: %r?" - - -msgid "Path: %r" -msgstr "Cesta: %r" - - msgid "Reload Start-Up file to restore settings" msgstr "Obnoviť pôvodný súbor a obnoviť nastavenia" @@ -106580,6 +106608,14 @@ msgid "Source file is in the add-on search path: %r" msgstr "Zdrojový súbor je na ceste hľadania doplnku: %r" +msgid "Remove Add-on: %r?" +msgstr "Odstrániť doplnok: %r?" + + +msgid "Path: %r" +msgstr "Cesta: %r" + + msgid "Active face must be a quad" msgstr "Aktívna plôška musí byť štvorec" @@ -106600,10 +106636,6 @@ msgid "See OperatorList.txt text block" msgstr "Pozri blok textu OperatorList.txt" -msgid "Rename %d %s" -msgstr "Premenovať %d %s" - - msgid "Renamed %d of %d %s" msgstr "Premenované %d z %d %s" @@ -106621,18 +106653,6 @@ msgid "Open..." msgstr "Otvoriť..." -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "Dátum: %s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "Haš súčet: %sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "Vetva: %sutf-8replace" - - msgid "Blender is free software" msgstr "Blender je voľný softvér" @@ -106697,11 +106717,6 @@ msgid "Spacebar" msgstr "medzerník" -msgctxt "Operator" -msgid "Load %d.%d SettingsOperator" -msgstr "Načítať %d.%d operátor nastavení" - - msgctxt "Operator" msgid "Save New Settings" msgstr "Uložiť nové nastavenia" @@ -106726,10 +106741,6 @@ msgid "Development Fund" msgstr "Vývojársky fond" -msgid "Windowing Environment: %s" -msgstr "Prostredie okna: %s" - - msgctxt "Operator" msgid "Credits" msgstr "Prispeli" @@ -106913,6 +106924,10 @@ msgid "Strip From" msgstr "Pás z" +msgid "Rename %d %s" +msgstr "Premenovať %d %s" + + msgid "Date: %s %s" msgstr "Dátum: %s %s" @@ -106946,6 +106961,10 @@ msgid "Load %d.%d Settings" msgstr "Načítať nastavenia %d.%d" +msgid "Windowing Environment: %s" +msgstr "Prostredie okna: %s" + + msgid "Type \"%s\" can not be found" msgstr "Typ \"%s\" sa nenašiel" @@ -107465,10 +107484,6 @@ msgid "Apply All Shape Keys" msgstr "Použiť všetky kľúčové tvary" -msgid "%s ▶ %s" -msgstr "%s ▶ %s" - - msgid "Name collisions: , " msgstr "Kolízie názvov: , " @@ -108137,22 +108152,10 @@ msgid "Hair dynamics disabled" msgstr "Zakázať dynamiku vlasov" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Opakovania: %d .. %d (priemer %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Chyba: %.5f .. %.5f (priemer %.5f)" - - msgid "Multiply Mass with Size" msgstr "Vynásobiť hmotnosť veľkosťou" -msgid "Spacing: %g" -msgstr "Medzery: %g" - - msgid "Show Emitter" msgstr "Zobraziť emitor" @@ -108197,10 +108200,6 @@ msgid "Coordinate System" msgstr "Systém súradníc" -msgid "%d fluid particles for this frame" -msgstr "%d častíc kvapaliny pre túto snímku" - - msgctxt "Operator" msgid "Delete Edit" msgstr "Odstrániť úpravy" @@ -108214,6 +108213,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "Zobrazenie percenta vytvára nepresnú dynamiku bez zapečenia" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Opakovania: %d .. %d (priemer %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Chyba: %.5f .. %.5f (priemer %.5f)" + + +msgid "Spacing: %g" +msgstr "Medzery: %g" + + msgid "Not yet functional" msgstr "Zatiaľ nefunkčné" @@ -108228,6 +108239,10 @@ msgid "Disconnect All" msgstr "Rozpojiť všetko" +msgid "%d fluid particles for this frame" +msgstr "%d častíc kvapaliny pre túto snímku" + + msgid "Speed Multiplier" msgstr "Násobič rýchlosti" @@ -108688,6 +108703,10 @@ msgid "This object is part of a compound shape" msgstr "Tento objekt je súčasťou zloženého tvaru" +msgid "Second" +msgstr "Druhá" + + msgid "X Stiffness" msgstr "Tuhosť X" @@ -108904,11 +108923,6 @@ msgid "Unknown add-ons" msgstr "Neznáme doplnky" -msgctxt "Operator" -msgid "%s: %s" -msgstr "%s: %s" - - msgid "category" msgstr "kategória" @@ -109188,11 +109202,6 @@ msgid "Tracks for Rotation/Scale" msgstr "Stopy pre rotáciu/mierku" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Priblíženie %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "Zobraziť zhodu" @@ -109213,14 +109222,14 @@ msgid "Frame All Fit" msgstr "Prispôsobiť všetky snímky" -msgid "Solve error: %.2f px" -msgstr "Chyba riešenia: %.2f px" - - msgid "Zoom %d:%d" msgstr "Priblíženie %d:%d" +msgid "Solve error: %.2f px" +msgstr "Chyba riešenia: %.2f px" + + msgctxt "Operator" msgid "Copy as Script" msgstr "Kopírovať ako skript" @@ -110606,10 +110615,6 @@ msgid "Default Fade" msgstr "Predvolené vytrácanie" -msgid "Original frame range: %d-%d (%d)" -msgstr "Pôvodný rozsah snímky: %d-%d (%d)" - - msgid "Strip Offset Start" msgstr "Posuv pásu Začiatok" @@ -110673,14 +110678,6 @@ msgid "Effect Fader" msgstr "Efekt vytrácania" -msgid "%dx%d" -msgstr "%dx%d" - - -msgid "%.2f" -msgstr "%.2f" - - msgid "Original Frame Range" msgstr "Rozsah pôvodných snímok" @@ -110705,8 +110702,8 @@ msgid "Pack" msgstr "Zbaliť" -msgid "%d Hz" -msgstr "%d Hz" +msgid "Original frame range: %d-%d (%d)" +msgstr "Pôvodný rozsah snímky: %d-%d (%d)" msgid "Source Channel" @@ -110823,10 +110820,6 @@ msgid "Move Line(s) Down" msgstr "Presunúť riadok(y) dole" -msgid "Text: ExternalText: Internal" -msgstr "Text: Externý text: Interný" - - msgid "File: *%s (unsaved)" msgstr "Súbor: *%s (neuložený)" @@ -111151,11 +111144,6 @@ msgid "Load Factory Blender Settings" msgstr "Načítať továrenské nastavenie Blenderu" -msgctxt "Operator" -msgid "Load Factory %s Settings" -msgstr "Načítať továrenské nastavenie %s" - - msgctxt "Operator" msgid "Collada (.dae)" msgstr "Collada (.dae)" @@ -111261,6 +111249,11 @@ msgid "NLA Strip Name" msgstr "Názov pásu NLA" +msgctxt "Operator" +msgid "Load Factory %s Settings" +msgstr "Načítať továrenské nastavenie %s" + + msgid "Auto-Save Preferences" msgstr "Automatické ukladanie predvolieb" @@ -111554,23 +111547,10 @@ msgid "Load Factory Blender Preferences" msgstr "Načítať továrenské predvoľby Blendera" -msgctxt "Operator" -msgid "Load Factory %s Preferences" -msgstr "Načítať továrenské %s predvoľby" - - msgid "Requires a restart of Blender to take effect" msgstr "Pre nadobudnutie účinku vyžaduje reštart Blenderu" -msgid "Color Set %d" -msgstr "Sústava farieb %d" - - -msgid "Color %d" -msgstr "Farba %d" - - msgid "Player" msgstr "Hráč" @@ -111611,6 +111591,14 @@ msgid "Load Factory %s Preferences" msgstr "Načítať továrenské %s predvoľby" +msgid "Color Set %d" +msgstr "Sústava farieb %d" + + +msgid "Color %d" +msgstr "Farba %d" + + msgid "Description:" msgstr "Popis:" @@ -111627,10 +111615,6 @@ msgid "Author:" msgstr "Autor:" -msgid "author" -msgstr "autor" - - msgid "Version:" msgstr "Verzia:" @@ -112805,10 +112789,6 @@ msgid "Snap To" msgstr "Prichytiť na" -msgid "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" -msgstr "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" - - msgid "Fade Inactive Layers" msgstr "Vytrácanie neaktívnych vrstiev" @@ -113905,6 +113885,10 @@ msgid "File written by newer Blender binary (%d.%d), expect loss of data!" msgstr "Súbor napísaný novším binárnym mixérom (%d.%d). Očakávajte stratu dát!" +msgid "File could not be read, critical data corruption detected" +msgstr "Súbor sa nepodarilo prečítať, zistilo sa kritické poškodenie údajov" + + msgid "Loading failed: " msgstr "Načítanie zlyhalo: " @@ -120835,10 +120819,6 @@ msgid "Undefined Socket Type" msgstr "Nedefinovaný typ zásuvky" -msgid "Group Input " -msgstr "Vstup skupiny " - - msgid "Could not determine type of group node" msgstr "Nepodarilo sa určiť typ uzla skupiny" @@ -123131,6 +123111,14 @@ msgid "Driver not found in this animation data" msgstr "V týchto údajoch animácie sa ovládač nenašiel" +msgid "%s '%s' is too long, maximum length is %d" +msgstr "%s '%s' je príliš dlhá, maximálna dĺžka je %d" + + +msgid "%s '%s', bl_idname '%s' %s" +msgstr "%s '%s', bl_idname '%s' %s" + + msgid "NlaTrack '%s' cannot be removed" msgstr "Nemožno odstrániť stopu NLA '%s'" @@ -123706,22 +123694,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "Pás NLA '%s' sa v stope '%s' nenašiel" -msgid "Functions" -msgstr "Funkcie" - - -msgid "Comparison" -msgstr "Porovnanie" - - -msgid "Trigonometric" -msgstr "Trigonometrický" - - -msgid "Conversion" -msgstr "Konverzia" - - msgid "CustomGroup" msgstr "Vlastná skupina" @@ -123762,6 +123734,10 @@ msgid "Unable to move sockets in built-in node" msgstr "Nemožno presunúť zásuvky vo vstavanom uzle" +msgid "%s '%s', bl_idname '%s' could not be unregistered" +msgstr "%s '%s', bl_idname '%s' nemožno zrušiť registráciu" + + msgid "Node tree '%s' has undefined type %s" msgstr "Strom uzla '%s' má nedefinovaný typ %s" @@ -124107,6 +124083,14 @@ msgid "Region not found in space type" msgstr "Oblasť sa v type priestoru nenašla" +msgid "%s '%s' has category '%s' " +msgstr "%s '%s' má kategóriu '%s' " + + +msgid "%s parent '%s' for '%s' not found" +msgstr "%s rodič '%s' pre '%s' sa nenašiel" + + msgid "Add-on is no longer valid" msgstr "Doplnok je už neplatný" @@ -124184,7 +124168,11 @@ msgstr "Typ manipulačného prvku '%s' nie je známy" msgid "GizmoType '%s' is for a 3D gizmo-group. The 'draw_select' callback is set where only 'test_select' will be used" -msgstr "GizmoType '%s' je pre skupinu 3D skupinu manipulačného prvku (gizmo). Je nastavené spätné volanie 'draw_select', kde sa použije iba 'test_select'" +msgstr "Typ manipulačného prvku '%s' je pre skupinu 3D skupinu manipulačného prvku (gizmo). Je nastavené spätné volanie 'draw_select', kde sa použije iba 'test_select'" + + +msgid "%s area type does not support gizmos" +msgstr "Typ oblasti %s nepodporuje manipulačné prvky" msgid "Gizmo target property '%s.%s' not found" diff --git a/locale/po/sr.po b/locale/po/sr.po index e467fa2ed2b..afe8983e3ac 100644 --- a/locale/po/sr.po +++ b/locale/po/sr.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2012-09-07 22:32+0100\n" "Last-Translator: Nikola Radovanovic \n" "Language-Team: Nikola Radovanovic\n" @@ -4533,10 +4533,6 @@ msgid "Effective but slow compression" msgstr "Ефикасна, али спора компресија" -msgid "Number" -msgstr "Број" - - msgid "p0" msgstr "п0" @@ -5446,18 +5442,6 @@ msgid "Mask Texture Overlay Alpha" msgstr "Маскирај провидност преклапања текстуре" -msgid "Root" -msgstr "Корен" - - -msgid "Sharp" -msgstr "Оштро" - - -msgid "Sharper" -msgstr "Оштрије" - - msgid "Fill Threshold" msgstr "Праг испуне" @@ -7638,6 +7622,10 @@ msgid "Roughness Curve" msgstr "Крива храпавости" +msgid "Number" +msgstr "Број" + + msgid "Show particle number" msgstr "Прикажи број честица" @@ -8008,10 +7996,6 @@ msgid "Modified" msgstr "Измењен" -msgid "Lines" -msgstr "Линије" - - msgid "Lines of text" msgstr "Линије текста" @@ -8332,10 +8316,18 @@ msgid "Use soft marble" msgstr "Користи меки мермер" +msgid "Sharp" +msgstr "Оштро" + + msgid "Use more clearly defined marble" msgstr "Користи јесније дефинисан мермер" +msgid "Sharper" +msgstr "Оштрије" + + msgid "Use very clearly defined marble" msgstr "Користи врло јасно дефинисан мермер" @@ -9619,6 +9611,10 @@ msgid "Radius of the skin" msgstr "Радиус коже" +msgid "Root" +msgstr "Корен" + + msgid "Name of skin layer" msgstr "Име слоја коже" @@ -10746,6 +10742,10 @@ msgid "Number of frames cached" msgstr "Број кадрова у остави" +msgid "Lines" +msgstr "Линије" + + msgid "Free Run" msgstr "Без поравнања" @@ -25127,10 +25127,6 @@ msgid "Invert Selection" msgstr "Обрни избор" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Праћење" @@ -25985,10 +25981,6 @@ msgid "Author:" msgstr "Аутор:" -msgid "author" -msgstr "аутор" - - msgid "Version:" msgstr "Верзија:" diff --git a/locale/po/sr@latin.po b/locale/po/sr@latin.po index 18c1ef15ae3..395d90f2612 100644 --- a/locale/po/sr@latin.po +++ b/locale/po/sr@latin.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2012-09-07 22:32+0100\n" "Last-Translator: Nikola Radovanovic \n" "Language-Team: Nikola Radovanovic\n" @@ -4533,10 +4533,6 @@ msgid "Effective but slow compression" msgstr "Efikasna, ali spora kompresija" -msgid "Number" -msgstr "Broj" - - msgid "p0" msgstr "p0" @@ -5446,18 +5442,6 @@ msgid "Mask Texture Overlay Alpha" msgstr "Maskiraj providnost preklapanja teksture" -msgid "Root" -msgstr "Koren" - - -msgid "Sharp" -msgstr "Oštro" - - -msgid "Sharper" -msgstr "Oštrije" - - msgid "Fill Threshold" msgstr "Prag ispune" @@ -7638,6 +7622,10 @@ msgid "Roughness Curve" msgstr "Kriva hrapavosti" +msgid "Number" +msgstr "Broj" + + msgid "Show particle number" msgstr "Prikaži broj čestica" @@ -8008,10 +7996,6 @@ msgid "Modified" msgstr "Izmenjen" -msgid "Lines" -msgstr "Linije" - - msgid "Lines of text" msgstr "Linije teksta" @@ -8332,10 +8316,18 @@ msgid "Use soft marble" msgstr "Koristi meki mermer" +msgid "Sharp" +msgstr "Oštro" + + msgid "Use more clearly defined marble" msgstr "Koristi jesnije definisan mermer" +msgid "Sharper" +msgstr "Oštrije" + + msgid "Use very clearly defined marble" msgstr "Koristi vrlo jasno definisan mermer" @@ -9619,6 +9611,10 @@ msgid "Radius of the skin" msgstr "Radius kože" +msgid "Root" +msgstr "Koren" + + msgid "Name of skin layer" msgstr "Ime sloja kože" @@ -10746,6 +10742,10 @@ msgid "Number of frames cached" msgstr "Broj kadrova u ostavi" +msgid "Lines" +msgstr "Linije" + + msgid "Free Run" msgstr "Bez poravnanja" @@ -25127,10 +25127,6 @@ msgid "Invert Selection" msgstr "Obrni izbor" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Praćenje" @@ -25985,10 +25981,6 @@ msgid "Author:" msgstr "Autor:" -msgid "author" -msgstr "autor" - - msgid "Version:" msgstr "Verzija:" diff --git a/locale/po/sv.po b/locale/po/sv.po index 316d58e4b6f..82e6aa12406 100644 --- a/locale/po/sv.po +++ b/locale/po/sv.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: \n" "Last-Translator: Arvid Rudling \n" "Language-Team: \n" @@ -897,10 +897,6 @@ msgid "Global" msgstr "Global" -msgid "Root" -msgstr "Rot" - - msgid "Repeat" msgstr "Upprepa" @@ -1325,6 +1321,10 @@ msgid "Sculpt" msgstr "Skulptera" +msgid "Root" +msgstr "Rot" + + msgid "Active Clone" msgstr "Klona aktivt" diff --git a/locale/po/th.po b/locale/po/th.po index 5f60ce8438c..be2163e9713 100644 --- a/locale/po/th.po +++ b/locale/po/th.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2019-12-08 17:40+0700\n" "Last-Translator: gongpha \n" "Language-Team: Thai Translation Team \n" @@ -1359,18 +1359,6 @@ msgid "Add Color" msgstr "เพิ่มสี" -msgid "Root" -msgstr "ฐาน" - - -msgid "Sharp" -msgstr "แหลม" - - -msgid "Inverse Square" -msgstr "จัตุรัสผกผัน" - - msgid "Repeat" msgstr "ทำซ้ำ" @@ -1569,6 +1557,10 @@ msgid "Area" msgstr "พื้นที่" +msgid "Inverse Square" +msgstr "จัตุรัสผกผัน" + + msgid "Samples" msgstr "ตัวอย่าง" @@ -1868,10 +1860,6 @@ msgid "Memory" msgstr "หน่วยความจำ" -msgid "Lines" -msgstr "เส้น" - - msgid "Register" msgstr "ทะเบียน" @@ -1916,6 +1904,10 @@ msgid "Pattern" msgstr "ลวดลาย" +msgid "Sharp" +msgstr "แหลม" + + msgid "Rings" msgstr "แหวน" @@ -2253,6 +2245,10 @@ msgid "Polygon Center" msgstr "ศูนย์กลางโพลิกอน" +msgid "Root" +msgstr "ฐาน" + + msgid "Intersect" msgstr "ตัดกัน" @@ -2358,6 +2354,10 @@ msgid "Face Area" msgstr "พื้นที่ด้าน" +msgid "Lines" +msgstr "เส้น" + + msgid "Units" msgstr "หน่วย" @@ -4118,10 +4118,6 @@ msgid " RNA Context: " msgstr " บริบท RNA: " -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgctxt "Operator" msgid "New" msgstr "ใหม่" @@ -4257,11 +4253,6 @@ msgid "Location" msgstr "ตำแหน่ง" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "ซูม %d:%d" - - msgid "Zoom %d:%d" msgstr "ซูม %d:%d" @@ -4755,10 +4746,6 @@ msgid "Author:" msgstr "ผู้สร้าง:" -msgid "author" -msgstr "ผู้สร้าง" - - msgid "Version:" msgstr "เวอร์ชัน:" diff --git a/locale/po/tr.po b/locale/po/tr.po index 332ff6a92c1..6b123b8d008 100644 --- a/locale/po/tr.po +++ b/locale/po/tr.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2023-02-05 22:00+0300\n" "Last-Translator: Emir SARI \n" "Language-Team: Turkish <>\n" @@ -4479,10 +4479,6 @@ msgid "Global" msgstr "Evrensel" -msgid "Curve Preset" -msgstr "Eğri Önayarı" - - msgid "Erase" msgstr "Sil" diff --git a/locale/po/uk.po b/locale/po/uk.po index 4a93ba5e7fb..02ba446711a 100644 --- a/locale/po/uk.po +++ b/locale/po/uk.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2021-03-01 19:15+0000\n" "Last-Translator: lxlalexlxl \n" "Language-Team: Ukrainian (Ukraine) (http://www.transifex.com/lxlalexlxl/blender/language/uk_UA/)\n" @@ -974,6 +974,10 @@ msgid "Index of the tag set for editing" msgstr "Індекс значника, заданого для редагування" +msgid "Copyright" +msgstr "Авторське право" + + msgid "Description" msgstr "Опис" @@ -12551,10 +12555,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "Мінімальна кількість частинок по комірках (гарантує, що кожна комірка має принаймні цю кількість частинок)" -msgid "Number" -msgstr "Номер" - - msgid "Particle number factor (higher value results in more particles)" msgstr "Фактор кількості частинок (вище значення дає більше частинок)" @@ -17152,30 +17152,6 @@ msgid "Editable falloff curve" msgstr "Редагована крива спаду" -msgid "Curve Preset" -msgstr "Передустава Кривої" - - -msgid "Smoother" -msgstr "Згладженіше" - - -msgid "Root" -msgstr "Корінь" - - -msgid "Sharp" -msgstr "Гостро" - - -msgid "Sharper" -msgstr "Різкіше" - - -msgid "Inverse Square" -msgstr "Обернено до квадрату" - - msgid "Dash Ratio" msgstr "Пропорція Риски" @@ -18480,18 +18456,10 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "Назва атрибута Alembic, що використовується для генерування даних розмиву рухом" -msgid "Velocity Unit" -msgstr "Одиниця Скорості" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "Визначає як вектори скорості інтерпретуються залежно від часу, кадр 'frame' означає, що дельта часу є 1 кадр, секунда 'second' означає, що дельта часу є одиниця на частоту кадрів за секунду 1 / FPS" -msgid "Second" -msgstr "Секунда" - - msgid "Camera data-block for storing camera settings" msgstr "Блок даних камери для зберігання налаштувань камери" @@ -21002,6 +20970,10 @@ msgid "Inverse Linear" msgstr "Обернено пропорційно" +msgid "Inverse Square" +msgstr "Обернено до квадрату" + + msgid "Inverse Coefficients" msgstr "Обернути коефіцієнти" @@ -23869,6 +23841,10 @@ msgid "Show hair simulation grid" msgstr "Показати сітку моделювання волосся" +msgid "Number" +msgstr "Номер" + + msgid "Show particle number" msgstr "Показати кількість частинок" @@ -24823,10 +24799,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "Текстовий файл на диску відрізняється від того, що у пам'яті" -msgid "Lines" -msgstr "Лінії" - - msgid "Lines of text" msgstr "Рядки тексту" @@ -25455,10 +25427,18 @@ msgid "Use soft marble" msgstr "Використати м'який мармур" +msgid "Sharp" +msgstr "Гостро" + + msgid "Use more clearly defined marble" msgstr "Використати більш чіткий мармур" +msgid "Sharper" +msgstr "Різкіше" + + msgid "Use very clearly defined marble" msgstr "Використати дуже чіткий мармур" @@ -30918,6 +30898,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "Якщо до вершини прилягає декілька ребер, обгортати їх напряму" +msgid "Root" +msgstr "Корінь" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "Вершина є коренем для розрахунків обертання та генерування арматури, задання цього стяга не зчищає інші корені у цьому ж самому острові сіті" @@ -35418,6 +35402,10 @@ msgid "Line Thickness" msgstr "Товщина лінії" +msgid "Lines" +msgstr "Лінії" + + msgid "Motion Path Points" msgstr "Точки шляху руху" @@ -46166,10 +46154,6 @@ msgid "Export vertex colors with meshes" msgstr "Експортувати кольори вершин із сітями" -msgid "Copyright" -msgstr "Авторське право" - - msgid "Legal rights and conditions for the model" msgstr "Захищені законом права та умови для моделі" @@ -61322,10 +61306,6 @@ msgid "Fill Range by Selection" msgstr "Заповнити діапазон вибраним" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Заповнити значення Мін та Макс Діапазону найменшою/найбільшою відстанню від вибраних сітьових об'єктів до джерельного об'єкта" - - msgid "Name of the modifier to work on" msgstr "Назва модифікатора, з яким працювати" @@ -89001,10 +88981,6 @@ msgid "Invert Selection" msgstr "Інвертувати Вибрання" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Стеження" @@ -89290,14 +89266,6 @@ msgid "The selected strips don't overlap" msgstr "Вибрані смужки не перекриваються" -msgid "Remove Add-on: %r?" -msgstr "Вилучити Додаток: %r?" - - -msgid "Path: %r" -msgstr "Шлях: %r" - - msgid "Reload Start-Up file to restore settings" msgstr "Перезавантажити Стартовий файл для відновлення устав" @@ -89362,6 +89330,14 @@ msgid "Source file is in the add-on search path: %r" msgstr "Джерельний файл знаходиться по шляху пошуку додатка: %r" +msgid "Remove Add-on: %r?" +msgstr "Вилучити Додаток: %r?" + + +msgid "Path: %r" +msgstr "Шлях: %r" + + msgid "Active face must be a quad" msgstr "Активна грань повинна бути чотирикутною" @@ -89382,10 +89358,6 @@ msgid "See OperatorList.txt text block" msgstr "Дивіться блок тексту OperatorList.txt" -msgid "Rename %d %s" -msgstr "Перейменувати %d %s" - - msgid "Renamed %d of %d %s" msgstr "Перейменовано %d з %d %s" @@ -89403,18 +89375,6 @@ msgid "Open..." msgstr "Відкриття..." -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "Дата: %s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "Хеш: %sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "Гілка: %sutf-8replace" - - msgid "Blender is free software" msgstr "Blender є безоплатним програмним забезпеченням" @@ -89554,6 +89514,10 @@ msgid "Strip From" msgstr "Смужка Із" +msgid "Rename %d %s" +msgstr "Перейменувати %d %s" + + msgid "Date: %s %s" msgstr "Дата: %s %s" @@ -90579,22 +90543,10 @@ msgid "Hair dynamics disabled" msgstr "Динаміку волосся вимкнено" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Повтори: %d .. %d (сер. %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Помилка: %.5f .. %.5f (сер. %.5f)" - - msgid "Multiply Mass with Size" msgstr "Множити Масу на Розмір" -msgid "Spacing: %g" -msgstr "Інтервал: %g" - - msgid "Show Emitter" msgstr "Показ Емітера" @@ -90639,10 +90591,6 @@ msgid "Coordinate System" msgstr "Система Координат" -msgid "%d fluid particles for this frame" -msgstr "%d частинок флюїду для цього кадру" - - msgctxt "Operator" msgid "Delete Edit" msgstr "Видалити Редагування" @@ -90656,6 +90604,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "Показ відсотків робить динаміку неточною без запікання" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Повтори: %d .. %d (сер. %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Помилка: %.5f .. %.5f (сер. %.5f)" + + +msgid "Spacing: %g" +msgstr "Інтервал: %g" + + msgid "Not yet functional" msgstr "Ще не функціонує" @@ -90670,6 +90630,10 @@ msgid "Disconnect All" msgstr "Від'єднати Все" +msgid "%d fluid particles for this frame" +msgstr "%d частинок флюїду для цього кадру" + + msgid "Speed Multiplier" msgstr "Множник Швидкості" @@ -91130,6 +91094,10 @@ msgid "This object is part of a compound shape" msgstr "Цей об'єкт є частиною складеної форми" +msgid "Second" +msgstr "Секунда" + + msgid "X Stiffness" msgstr "Тугість X" @@ -91589,11 +91557,6 @@ msgid "Tracks for Rotation/Scale" msgstr "Відстеження для Обертання/Масштабу" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Зум %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "Підгонка Огляду" @@ -91614,14 +91577,14 @@ msgid "Frame All Fit" msgstr "Усе у Кадр Підгонка" -msgid "Solve error: %.2f px" -msgstr "Помилка рішача: %.2f px" - - msgid "Zoom %d:%d" msgstr "Зум %d:%d" +msgid "Solve error: %.2f px" +msgstr "Помилка рішача: %.2f px" + + msgctxt "Operator" msgid "Copy as Script" msgstr "Копіювати як Скрипт" @@ -92804,10 +92767,6 @@ msgid "Default Fade" msgstr "Стандартне Зникання" -msgid "Original frame range: %d-%d (%d)" -msgstr "Оригінальний діапазон кадрів: %d-%d (%d)" - - msgid "Strip Offset Start" msgstr "Зсув Смужки Старт" @@ -92861,10 +92820,6 @@ msgid "Effect Fader" msgstr "Зникач Ефекту" -msgid "%dx%d" -msgstr "%dx%d" - - msgid "Original Frame Range" msgstr "Оригінальний Діапазон Кадрів" @@ -92885,6 +92840,10 @@ msgid "Pack" msgstr "Упакування" +msgid "Original frame range: %d-%d (%d)" +msgstr "Оригінальний діапазон кадрів: %d-%d (%d)" + + msgid "Source Channel" msgstr "Канал Джерела" @@ -92982,10 +92941,6 @@ msgid "Move Line(s) Down" msgstr "Перемістити Рядок(и) Вниз" -msgid "Text: ExternalText: Internal" -msgstr "Текст: Зовнішньо Текст: Внутрішньо" - - msgid "File: *%s (unsaved)" msgstr "Файл: *%s (незбережено)" @@ -93600,14 +93555,6 @@ msgid "Save as Studio light" msgstr "Зберегти як Студійний освітлювач" -msgid "Color Set %d" -msgstr "Набір Кольорів %d" - - -msgid "Color %d" -msgstr "Колір %d" - - msgid "Player" msgstr "Програвач" @@ -93644,6 +93591,14 @@ msgid ":" msgstr ":" +msgid "Color Set %d" +msgstr "Набір Кольорів %d" + + +msgid "Color %d" +msgstr "Колір %d" + + msgid "Description:" msgstr "Опис:" @@ -93660,10 +93615,6 @@ msgid "Author:" msgstr "Автор:" -msgid "author" -msgstr "автор" - - msgid "Version:" msgstr "Версія:" @@ -94689,10 +94640,6 @@ msgid "Snap To" msgstr "Підхоп До" -msgid "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" -msgstr "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" - - msgctxt "Operator" msgid "Move Texture Space" msgstr "Перемістити Простір Текстур" @@ -102596,22 +102543,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "Смужки НЛА '%s' не знайдено на доріжці '%s'" -msgid "Functions" -msgstr "Функції" - - -msgid "Comparison" -msgstr "Порівняння" - - -msgid "Trigonometric" -msgstr "Тригонометричне" - - -msgid "Conversion" -msgstr "Конверсія" - - msgid "Same input/output direction of sockets" msgstr "Однаковий напрям вводу/виводу роз'ємів" diff --git a/locale/po/vi.po b/locale/po/vi.po index e64e8759ed3..5ea65674b48 100644 --- a/locale/po/vi.po +++ b/locale/po/vi.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2022-08-19 12:33+0700\n" "Last-Translator: HỒ NHỰT CHÂU \n" "Language-Team: Tỉnh An Giang, Đình Bình Phú\n" @@ -1070,6 +1070,10 @@ msgid "Simple name of the asset's catalog, for debugging and data recovery purpo msgstr "Tên đơn giản cho danh mục của tích sản, cho sửa lỗi lầm và lý do hoàn lại dữ liệu" +msgid "Copyright" +msgstr "Bản Quyền" + + msgid "Description" msgstr "Chính Tả" @@ -13456,10 +13460,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "Số lượng cực tiểu của hạt từng tế bào (làm chắc mỗi tế bào có ít nhất số lượng hạt này)" -msgid "Number" -msgstr "Số" - - msgid "Particle number factor (higher value results in more particles)" msgstr "Hệ số số lượng hạt (giá trị cao hơn có hạt nhiều hơn)" @@ -19113,30 +19113,6 @@ msgid "Editable falloff curve" msgstr "Đường cong sự giảm có thể biên tập" -msgid "Curve Preset" -msgstr "Đặt Sẵn Đường Cong" - - -msgid "Smoother" -msgstr "Mịn Hơn" - - -msgid "Root" -msgstr "Rễ" - - -msgid "Sharp" -msgstr "Bén" - - -msgid "Sharper" -msgstr "Bén Hơn" - - -msgid "Inverse Square" -msgstr "Nghịch Biến Bậc Hai" - - msgid "Curves Sculpt Settings" msgstr "Cài Đặt Khắc Đường Cong" @@ -20533,18 +20509,10 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "Tên của đặc điểm Alembic được dùng cho chế tạo dữ liệu mờ hóa chuyển động" -msgid "Velocity Unit" -msgstr "Đơn Vị Vận Tốc" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "Định nghĩa làm sao vectơ vận tốc được xử lú tùy thừi gian, 'bức ảnh' nghĩa ∆t là 1 bức, 'giây' nghĩa ∆t là 1/(bức ảnh giây)" -msgid "Second" -msgstr "Giây" - - msgid "Camera data-block for storing camera settings" msgstr "Cục dữ liệu máy quay phim cho chứa cài đặt máy quay phim" @@ -23272,6 +23240,10 @@ msgid "Inverse Linear" msgstr "Nghịch Biến Bậc Một" +msgid "Inverse Square" +msgstr "Nghịch Biến Bậc Hai" + + msgid "Inverse Coefficients" msgstr "Hệ Số Đảo Nghịch" @@ -26388,6 +26360,10 @@ msgid "Display boid health" msgstr "Hiện thỉ sức khỏe quần thể" +msgid "Number" +msgstr "Số" + + msgid "Show particle number" msgstr "Hiện số hạt" @@ -27427,10 +27403,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "Tập tin văn bản trên đĩa không giống tập tin trong bộ nhớ" -msgid "Lines" -msgstr "Dòng" - - msgid "Lines of text" msgstr "Dòng Văn Bản" @@ -28071,10 +28043,18 @@ msgid "Use soft marble" msgstr "Dùng đá hoa mềm" +msgid "Sharp" +msgstr "Bén" + + msgid "Use more clearly defined marble" msgstr "Dùng đá hoa được chỉ định rõ hơn" +msgid "Sharper" +msgstr "Bén Hơn" + + msgid "Use very clearly defined marble" msgstr "Dùng đá hoa được chỉ định rất rõ" @@ -34227,6 +34207,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "Nếu đỉnh có nhiều cạnh kề, nó được vỏ hóa với chúng nó trực tiếp" +msgid "Root" +msgstr "Rễ" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "Đỉnh là rễ cho tính toán xoay và chế tạo cốt, đặt cờ này không xóa rễ khác trong cùng đảo mạng lưới" @@ -38867,6 +38851,10 @@ msgid "Line thickness for motion path" msgstr "Bề rộng nét cho đường chuyển động" +msgid "Lines" +msgstr "Dòng" + + msgid "Use straight lines between keyframe points" msgstr "Vẽ đường thẳng giữa các điểm bức ảnh mẫu" @@ -52683,10 +52671,6 @@ msgid "Export vertex colors with meshes" msgstr "Xuất màu đỉnh với mạng lưới" -msgid "Copyright" -msgstr "Bản Quyền" - - msgid "Legal rights and conditions for the model" msgstr "Quyền luật pháp và điều kiện của mô hình" @@ -69316,10 +69300,6 @@ msgid "Fill Range by Selection" msgstr "Đầy Phạm Vi Tùy Lựa Chọn" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "Đầy các mục Cực Đại/Tiểu Phạm Vi bằng khoảng cách cực đại/cực tiểu giữa vật thể mạng lưới được chọn và vật thể nguồn" - - msgid "Name of the modifier to work on" msgstr "Tên của bộ điều chỉnh để chỉnh" @@ -87316,10 +87296,6 @@ msgid "Additional subdivision along the curves" msgstr "Phân hóa thêm theo đường cong" -msgid "Curves Shape Type" -msgstr "Loại Hình Dạng Đường Cong" - - msgid "Curves shape type" msgstr "Loại hình dạng đường cong" @@ -102403,10 +102379,6 @@ msgid "Invert Selection" msgstr "Đảo Nghịch Sự Lựa Chọn" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "Theo Đõi" @@ -102765,14 +102737,6 @@ msgid "Current frame not within strip framerange" msgstr "Bức ảnh hiện tại không ở trong phạm vi đoàn" -msgid "Remove Add-on: %r?" -msgstr "Xóa Đồ Kèm: %r?" - - -msgid "Path: %r" -msgstr "Đường Dẫn: %r" - - msgid "Reload Start-Up file to restore settings" msgstr "Nhập lại tập tin Khởi Động để đặt lại những cài đặt" @@ -102837,6 +102801,14 @@ msgid "Source file is in the add-on search path: %r" msgstr "Tập tin nguồn đang ở trong đường dẫn tìm kiếm của đồ kèm: %r" +msgid "Remove Add-on: %r?" +msgstr "Xóa Đồ Kèm: %r?" + + +msgid "Path: %r" +msgstr "Đường Dẫn: %r" + + msgid "Active face must be a quad" msgstr "Mặt hoạt động phải là tư giác" @@ -102857,10 +102829,6 @@ msgid "See OperatorList.txt text block" msgstr "Xem cục văn bản DachSáchThaoTác.txt" -msgid "Rename %d %s" -msgstr "Đặt lại tên %d %s" - - msgid "Renamed %d of %d %s" msgstr "Đã đặt lại tên cho %d của %d %s" @@ -102878,18 +102846,6 @@ msgid "Open..." msgstr "Mở..." -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "Ngày: %s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "Băm: %sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "Chi nhánn: %sutf-8replace" - - msgid "Blender is free software" msgstr "Blender là phầm mềm tự do" @@ -102954,11 +102910,6 @@ msgid "Spacebar" msgstr "Thanh Dấu Cách" -msgctxt "Operator" -msgid "Load %d.%d SettingsOperator" -msgstr "Nhập %d.%d TươngThácCàiĐặt" - - msgctxt "Operator" msgid "Save New Settings" msgstr "Lưu Cài Đặt Mới" @@ -103162,6 +103113,10 @@ msgid "Strip From" msgstr "Đoạn Từ" +msgid "Rename %d %s" +msgstr "Đặt lại tên %d %s" + + msgid "Date: %s %s" msgstr "Ngày: %s %s" @@ -103687,10 +103642,6 @@ msgid "Apply All Shape Keys" msgstr "Áp Dụng Hết Mẫu Dạng" -msgid "%s ▶ %s" -msgstr "%s ▶ %s" - - msgid "Name collisions: , " msgstr "Va chạm tên: , " @@ -104350,22 +104301,10 @@ msgid "Hair dynamics disabled" msgstr "Động lý tóc được tắt" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "Lặp Lặi: %d .. %d (trung bình %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "Sai Lầm: %.5f .. %.5f (trung bình %.5f)" - - msgid "Multiply Mass with Size" msgstr "Nhân Khối Lượng Với Kích Cỡ" -msgid "Spacing: %g" -msgstr "Khoảng cách: %g" - - msgid "Show Emitter" msgstr "Hiện Đồ Phát" @@ -104410,10 +104349,6 @@ msgid "Coordinate System" msgstr "Hệ Thống Tọa Độ" -msgid "%d fluid particles for this frame" -msgstr "%d hạt chất lỏng cho bức ảnh này" - - msgctxt "Operator" msgid "Delete Edit" msgstr "Xoá Biên Tập" @@ -104427,6 +104362,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "Hiển thị phần trăm được làm động lý không chính xác mà không nướng" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "Lặp Lặi: %d .. %d (trung bình %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "Sai Lầm: %.5f .. %.5f (trung bình %.5f)" + + +msgid "Spacing: %g" +msgstr "Khoảng cách: %g" + + msgid "Not yet functional" msgstr "Chưa được hoạt động" @@ -104441,6 +104388,10 @@ msgid "Disconnect All" msgstr "Ngắt Hết" +msgid "%d fluid particles for this frame" +msgstr "%d hạt chất lỏng cho bức ảnh này" + + msgid "Speed Multiplier" msgstr "Hệ Số Nhân Tốc Độ" @@ -104901,6 +104852,10 @@ msgid "This object is part of a compound shape" msgstr "Vật thể này là một bộ phận của hình dạng ghép" +msgid "Second" +msgstr "Giây" + + msgid "X Stiffness" msgstr "Độ Cứng X" @@ -105372,11 +105327,6 @@ msgid "Tracks for Rotation/Scale" msgstr "Theo Dõi cho Xoay/Phóng To" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "Phóng To %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "Vừa Màn" @@ -105397,14 +105347,14 @@ msgid "Frame All Fit" msgstr "Vừa Khung" -msgid "Solve error: %.2f px" -msgstr "Sai lầm: %.2f điểm ảnh" - - msgid "Zoom %d:%d" msgstr "Phóng To %d:%d" +msgid "Solve error: %.2f px" +msgstr "Sai lầm: %.2f điểm ảnh" + + msgctxt "Operator" msgid "Copy as Script" msgstr "Chép như Văn Thảo" @@ -106717,10 +106667,6 @@ msgid "Default Fade" msgstr "Phai Mặc Định" -msgid "Original frame range: %d-%d (%d)" -msgstr "Phạm vi bức ảnh ban đầu: %d-%d (%d)" - - msgid "Strip Offset Start" msgstr "Bắt Đầu Dịch Đoạn" @@ -106784,14 +106730,6 @@ msgid "Effect Fader" msgstr "Bộ Phai Hiệu Ứng" -msgid "%dx%d" -msgstr "%dx%d" - - -msgid "%.2f" -msgstr "%.2f" - - msgid "Original Frame Range" msgstr "Phạm Vi Bức Ảnh Ban Đầu" @@ -106816,8 +106754,8 @@ msgid "Pack" msgstr "Gói Lại" -msgid "%d Hz" -msgstr "%d Hz" +msgid "Original frame range: %d-%d (%d)" +msgstr "Phạm vi bức ảnh ban đầu: %d-%d (%d)" msgid "Source Channel" @@ -106930,10 +106868,6 @@ msgid "Move Line(s) Down" msgstr "Di Chuyển (Các) Dòng Xuống" -msgid "Text: ExternalText: Internal" -msgstr "Văn Bản: Văn Bản Ngoại Bộ: văn Bản Nội Bộ" - - msgid "File: *%s (unsaved)" msgstr "Tập Tin: *%s (chưa lưu)" @@ -107636,14 +107570,6 @@ msgid "Save as Studio light" msgstr "Lưu như Đèn Xưởng" -msgid "Color Set %d" -msgstr "Tập Hợp Màu %d" - - -msgid "Color %d" -msgstr "Màu %d" - - msgid "Player" msgstr "Bộ Hát Lại" @@ -107680,6 +107606,14 @@ msgid ":" msgstr ":" +msgid "Color Set %d" +msgstr "Tập Hợp Màu %d" + + +msgid "Color %d" +msgstr "Màu %d" + + msgid "Description:" msgstr "Mô Tả:" @@ -107696,10 +107630,6 @@ msgid "Author:" msgstr "Tác Giả:" -msgid "author" -msgstr "tác giả" - - msgid "Version:" msgstr "Phiên Bản" @@ -108846,10 +108776,6 @@ msgid "Snap To" msgstr "Hút Dính Đến" -msgid "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" -msgstr "SƠN_BIÊNTẬPBÚTSÁP_KHẮCBUTSÁP_QUYỀNLƯỜNGBÚTSÁP_ĐỈNHBÚTSÁP_VẬTTHỂBÚTSÁPVẽ BiênTậpBútSáp KhắcBútSáp QuyềnLượngBútSáp ĐỉnhSápBút BútSáp" - - msgid "Fade Inactive Layers" msgstr "Phai Lớp Không Hoạt Động" @@ -116390,10 +116316,6 @@ msgid "Undefined Socket Type" msgstr "Loại Ổ Cắm Không Xác Định" -msgid "Group Input " -msgstr "Ngõ Vào Nhóm" - - msgid "Could not determine type of group node" msgstr "Không thể quyết định loại của nhóm điểm" @@ -118933,22 +118855,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "Không tìm được đoạn NLA '%s' trong rãnh '%s'" -msgid "Functions" -msgstr "Hàm Số" - - -msgid "Comparison" -msgstr "So Sánh" - - -msgid "Trigonometric" -msgstr "Lượng Giác Học" - - -msgid "Conversion" -msgstr "Biến Đổi" - - msgid "Same input/output direction of sockets" msgstr "Ổ cắm có cùng hướng ngõ vào/ngõ ra" diff --git a/locale/po/zh_CN.po b/locale/po/zh_CN.po index 599b9b8e4df..44aa8b68018 100644 --- a/locale/po/zh_CN.po +++ b/locale/po/zh_CN.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: \n" "Last-Translator: DeathBlood\n" "Language-Team: \n" @@ -1109,6 +1109,10 @@ msgid "Simple name of the asset's catalog, for debugging and data recovery purpo msgstr "用于调试和数据恢复目的的资产目录的简单名称" +msgid "Copyright" +msgstr "版权" + + msgid "Description" msgstr "描述" @@ -13696,10 +13700,6 @@ msgid "Minimum number of particles per cell (ensures that each cell has at least msgstr "每个单元的最小粒子数(确保每个单元至少具有此数量的粒子)" -msgid "Number" -msgstr "*Number" - - msgid "Particle number factor (higher value results in more particles)" msgstr "粒子数因子(值越高,粒子越多)" @@ -19533,30 +19533,6 @@ msgid "Editable falloff curve" msgstr "可编辑衰减曲线" -msgid "Curve Preset" -msgstr "曲线预设" - - -msgid "Smoother" -msgstr "平滑器" - - -msgid "Root" -msgstr "根" - - -msgid "Sharp" -msgstr "锐边" - - -msgid "Sharper" -msgstr "较锐利" - - -msgid "Inverse Square" -msgstr "反向平方" - - msgid "Curves Sculpt Settings" msgstr "曲线雕刻设置" @@ -21001,18 +20977,10 @@ msgid "Name of the Alembic attribute used for generating motion blur data" msgstr "用于生成运动模糊数据的Alembic属性的名称" -msgid "Velocity Unit" -msgstr "速度单位" - - msgid "Define how the velocity vectors are interpreted with regard to time, 'frame' means the delta time is 1 frame, 'second' means the delta time is 1 / FPS" msgstr "定义如何速度矢量相对时间的解析方式, '帧'表示时间增量是1帧, \"秒\" 表示时间增量是 1/Fps" -msgid "Second" -msgstr "第二" - - msgid "Camera data-block for storing camera settings" msgstr "用于存储摄像机设置的摄像机数据块" @@ -23796,6 +23764,10 @@ msgid "Inverse Linear" msgstr "反向线性" +msgid "Inverse Square" +msgstr "反向平方" + + msgid "Inverse Coefficients" msgstr "反向系数" @@ -26952,6 +26924,10 @@ msgid "Display boid health" msgstr "显示群集康度" +msgid "Number" +msgstr "*Number" + + msgid "Show particle number" msgstr "显示粒子数" @@ -28027,10 +28003,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "磁盘上的文本文件与内存中的不同" -msgid "Lines" -msgstr "行数(线)" - - msgid "Lines of text" msgstr "文本行" @@ -28701,10 +28673,18 @@ msgid "Use soft marble" msgstr "使用柔和的大理石纹" +msgid "Sharp" +msgstr "锐边" + + msgid "Use more clearly defined marble" msgstr "使用轮廓更加分明的大理石纹" +msgid "Sharper" +msgstr "较锐利" + + msgid "Use very clearly defined marble" msgstr "使用轮廓非常分明的大理石纹" @@ -34932,6 +34912,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "如果顶点被多条相邻边共用, 那么它会直接附在其上" +msgid "Root" +msgstr "根" + + msgid "Vertex is a root for rotation calculations and armature generation, setting this flag does not clear other roots in the same mesh island" msgstr "顶点是用于旋转计算和骨架生成的一个根, 设定此标识在相同网格孤岛不清除其它根" @@ -39676,6 +39660,10 @@ msgid "Line thickness for motion path" msgstr "用于运动路径的线条宽度" +msgid "Lines" +msgstr "行数(线)" + + msgid "Use straight lines between keyframe points" msgstr "在关键帧点间绘制直线" @@ -54032,10 +54020,6 @@ msgid "Export vertex colors with meshes" msgstr "随网格导出顶点色" -msgid "Copyright" -msgstr "版权" - - msgid "Legal rights and conditions for the model" msgstr "模型的法律权限和条款" @@ -71252,10 +71236,6 @@ msgid "Fill Range by Selection" msgstr "按选中项填充范围" -msgid "Fill the Range Min/Max entries by the min/max distance between selected mesh objects and the source object " -msgstr "根据所选网格对象和源对象之间的最小/最大距离,填充范围最小/最大条目 " - - msgid "Name of the modifier to work on" msgstr "工作中的修改器名称" @@ -89954,10 +89934,6 @@ msgid "Additional subdivision along the curves" msgstr "沿着曲线附加细分" -msgid "Curves Shape Type" -msgstr "曲线形状类型" - - msgid "Curves shape type" msgstr "曲线形状类型" @@ -105083,10 +105059,6 @@ msgid "No compatible GPUs found for Cycles" msgstr "找不到Cycles的兼容 GPU" -msgid "(TM)TRADE MARK SIGN(tm)TRADE MARK SIGN(R)REGISTERED SIGN(C)COPYRIGHT SIGN" -msgstr "(TM)TRADE MARK SIGN(tm)TRADE MARK SIGN(R)REGISTERED SIGN(C)COPYRIGHT SIGN" - - msgid "Requires NVIDIA GPU with compute capability %s" msgstr "要求具有计算能力 %s 的Nvidia GPU" @@ -105095,6 +105067,18 @@ msgid "and NVIDIA driver version %s or newer" msgstr "以及Nvidia驱动程序 %s 版本或更新" +msgid "Requires Intel GPU with Xe-HPG architecture" +msgstr "需要Xe-HPG 架构的英特尔 GPU" + + +msgid "Requires Intel GPU with Xe-HPG architecture and" +msgstr "需要Xe-HPG 架构的英特尔 GPU 以及" + + +msgid " - oneAPI Level-Zero Loader" +msgstr " - oneAPI Level-Zero 加载器" + + msgid "and AMD Radeon Pro %s driver or newer" msgstr "以及AMD Radeon Pro %s 驱动器或更新" @@ -105103,10 +105087,6 @@ msgid "and AMD driver version %s or newer" msgstr "以及AMD驱动程序 %s 版本或更新" -msgid "Requires Intel GPU with Xe-HPG architecture" -msgstr "需要Xe-HPG 架构的英特尔 GPU" - - msgid "and Windows driver version %s or newer" msgstr "以及Windows驱动版本 %s 或更新" @@ -105119,18 +105099,10 @@ msgid "or AMD with macOS %s or newer" msgstr "或者AMD搭配 macOS %s 或更新版本" -msgid "Requires Intel GPU with Xe-HPG architecture and" -msgstr "需要Xe-HPG 架构的英特尔 GPU 以及" - - msgid " - intel-level-zero-gpu version %s or newer" msgstr " - intel-level-zero-gpu 版本 %s 或更新版本" -msgid " - oneAPI Level-Zero Loader" -msgstr " - oneAPI Level-Zero 加载器" - - msgid "Noise Threshold" msgstr "噪波阈值" @@ -105917,10 +105889,6 @@ msgid "Invert Selection" msgstr "反选" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "追踪" @@ -106004,15 +105972,15 @@ msgid "Restore" msgstr "恢复" -msgid "%s (Global)" -msgstr "%s (全局)" - - msgctxt "WindowManager" msgid "Add New" msgstr "新增" +msgid "%s (Global)" +msgstr "%s (全局)" + + msgctxt "Operator" msgid "New" msgstr "新建" @@ -106327,14 +106295,6 @@ msgid "Current frame not within strip framerange" msgstr "当前帧不在片段帧范围内" -msgid "Remove Add-on: %r?" -msgstr "删除插件: %r?" - - -msgid "Path: %r" -msgstr "路径: %r" - - msgid "Reload Start-Up file to restore settings" msgstr "重新加载启动文件以还原设置" @@ -106399,6 +106359,14 @@ msgid "Source file is in the add-on search path: %r" msgstr "源文件位于插件查找路径中: %r" +msgid "Remove Add-on: %r?" +msgstr "删除插件: %r?" + + +msgid "Path: %r" +msgstr "路径: %r" + + msgid "Active face must be a quad" msgstr "活动面必须是四边形" @@ -106419,10 +106387,6 @@ msgid "See OperatorList.txt text block" msgstr "见OperatorList.txt 文本块" -msgid "Rename %d %s" -msgstr "重命名 %d %s" - - msgid "Renamed %d of %d %s" msgstr "已重命名 %d of %d %s" @@ -106440,18 +106404,6 @@ msgid "Open..." msgstr "打开..." -msgid "Date: %s %sutf-8replaceutf-8replace" -msgstr "日期: %s %sutf-8replaceutf-8replace" - - -msgid "Hash: %sascii" -msgstr "哈希: %sascii" - - -msgid "Branch: %sutf-8replace" -msgstr "分支: %sutf-8replace" - - msgid "Blender is free software" msgstr "Blender是自由软件" @@ -106516,11 +106468,6 @@ msgid "Spacebar" msgstr "空格" -msgctxt "Operator" -msgid "Load %d.%d SettingsOperator" -msgstr "加载 %d.%d 设置操作" - - msgctxt "Operator" msgid "Save New Settings" msgstr "保存新设置" @@ -106545,10 +106492,6 @@ msgid "Development Fund" msgstr "开发筹资" -msgid "Windowing Environment: %s" -msgstr "窗口环境:%s" - - msgctxt "Operator" msgid "Credits" msgstr "贡献者名单" @@ -106732,6 +106675,10 @@ msgid "Strip From" msgstr "片段来自" +msgid "Rename %d %s" +msgstr "重命名 %d %s" + + msgid "Date: %s %s" msgstr "日期: %s %s" @@ -106765,6 +106712,10 @@ msgid "Load %d.%d Settings" msgstr "加载 %d.%d 设置" +msgid "Windowing Environment: %s" +msgstr "窗口环境:%s" + + msgid "Type \"%s\" can not be found" msgstr "找不到类型 \"%s\"" @@ -107279,10 +107230,6 @@ msgid "Apply All Shape Keys" msgstr "应用全部形态键" -msgid "%s ▶ %s" -msgstr "%s ▶ %s" - - msgid "Name collisions: , " msgstr "名称冲突: , " @@ -107951,22 +107898,10 @@ msgid "Hair dynamics disabled" msgstr "已禁用毛发动力学" -msgid "Iterations: %d .. %d (avg. %d)" -msgstr "迭代:%d .. %d (avg. %d)" - - -msgid "Error: %.5f .. %.5f (avg. %.5f)" -msgstr "错误: %.5f .. %.5f (avg. %.5f)" - - msgid "Multiply Mass with Size" msgstr "将粒子尺寸与质量相乘" -msgid "Spacing: %g" -msgstr "间隔: %g" - - msgid "Show Emitter" msgstr "显示发射体" @@ -108011,10 +107946,6 @@ msgid "Coordinate System" msgstr "坐标系系统" -msgid "%d fluid particles for this frame" -msgstr "此帧包含 %d 个液体粒子" - - msgctxt "Operator" msgid "Delete Edit" msgstr "删除编辑" @@ -108028,6 +107959,18 @@ msgid "Display percentage makes dynamics inaccurate without baking" msgstr "在非烘焙情况下非精确仿真效果的显示百分比" +msgid "Iterations: %d .. %d (avg. %d)" +msgstr "迭代:%d .. %d (avg. %d)" + + +msgid "Error: %.5f .. %.5f (avg. %.5f)" +msgstr "错误: %.5f .. %.5f (avg. %.5f)" + + +msgid "Spacing: %g" +msgstr "间隔: %g" + + msgid "Not yet functional" msgstr "开发中" @@ -108042,6 +107985,10 @@ msgid "Disconnect All" msgstr "全部断开" +msgid "%d fluid particles for this frame" +msgstr "此帧包含 %d 个液体粒子" + + msgid "Speed Multiplier" msgstr "速率倍增" @@ -108502,6 +108449,10 @@ msgid "This object is part of a compound shape" msgstr "此物体是复合形状的一部分" +msgid "Second" +msgstr "第二" + + msgid "X Stiffness" msgstr "X 硬度" @@ -108714,11 +108665,6 @@ msgid "Unknown add-ons" msgstr "未知插件" -msgctxt "Operator" -msgid "%s: %s" -msgstr "%s:%s" - - msgid "category" msgstr "类别" @@ -108994,11 +108940,6 @@ msgid "Tracks for Rotation/Scale" msgstr "用于旋转/缩放的轨迹" -msgctxt "Operator" -msgid "Zoom %d:%d" -msgstr "缩放比 %d:%d" - - msgctxt "Operator" msgid "View Fit" msgstr "匹配视图" @@ -109019,14 +108960,14 @@ msgid "Frame All Fit" msgstr "框显完全匹配" -msgid "Solve error: %.2f px" -msgstr "解算错误: %.2f px" - - msgid "Zoom %d:%d" msgstr "缩放比 %d:%d" +msgid "Solve error: %.2f px" +msgstr "解算错误: %.2f px" + + msgctxt "Operator" msgid "Copy as Script" msgstr "复制为脚本" @@ -110412,10 +110353,6 @@ msgid "Default Fade" msgstr "默认过渡" -msgid "Original frame range: %d-%d (%d)" -msgstr "原始帧范围: %d-%d (%d)" - - msgid "Strip Offset Start" msgstr "片段偏移量起始" @@ -110479,14 +110416,6 @@ msgid "Effect Fader" msgstr "效果渐变" -msgid "%dx%d" -msgstr "%dx%d" - - -msgid "%.2f" -msgstr "%.2f" - - msgid "Original Frame Range" msgstr "原始帧范围" @@ -110511,8 +110440,8 @@ msgid "Pack" msgstr "打包" -msgid "%d Hz" -msgstr "%d Hz" +msgid "Original frame range: %d-%d (%d)" +msgstr "原始帧范围: %d-%d (%d)" msgid "Source Channel" @@ -110629,10 +110558,6 @@ msgid "Move Line(s) Down" msgstr "向下移行" -msgid "Text: ExternalText: Internal" -msgstr "文本: 外部文本; 内部" - - msgid "File: *%s (unsaved)" msgstr "文件: *%s (未保存)" @@ -110957,11 +110882,6 @@ msgid "Load Factory Blender Settings" msgstr "加载Blender初始设置" -msgctxt "Operator" -msgid "Load Factory %s Settings" -msgstr "加载初始 %s 设置" - - msgctxt "Operator" msgid "Collada (.dae)" msgstr "Collada (.dae)" @@ -111067,6 +110987,11 @@ msgid "NLA Strip Name" msgstr "NLA片段名称" +msgctxt "Operator" +msgid "Load Factory %s Settings" +msgstr "加载初始 %s 设置" + + msgid "Auto-Save Preferences" msgstr "自动保存设置" @@ -111360,23 +111285,10 @@ msgid "Load Factory Blender Preferences" msgstr "加载初始Blender偏好设置" -msgctxt "Operator" -msgid "Load Factory %s Preferences" -msgstr "加载初始 %s 偏好设置" - - msgid "Requires a restart of Blender to take effect" msgstr "需要重新启动 Blender 才能生效" -msgid "Color Set %d" -msgstr "颜色集 %d" - - -msgid "Color %d" -msgstr "颜色 %d" - - msgid "Player" msgstr "播放器" @@ -111417,6 +111329,14 @@ msgid "Load Factory %s Preferences" msgstr "加载初始 %s 偏好设置" +msgid "Color Set %d" +msgstr "颜色集 %d" + + +msgid "Color %d" +msgstr "颜色 %d" + + msgid "Description:" msgstr "描述:" @@ -111433,10 +111353,6 @@ msgid "Author:" msgstr "作者:" -msgid "author" -msgstr "作者" - - msgid "Version:" msgstr "版本:" @@ -112597,10 +112513,6 @@ msgid "Snap To" msgstr "吸附至" -msgid "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" -msgstr "PAINT_GPENCILEDIT_GPENCILSCULPT_GPENCILWEIGHT_GPENCILVERTEX_GPENCILOBJECTDraw Grease PencilEdit Grease PencilSculpt Grease PencilWeight Grease PencilVertex Grease PencilGrease Pencil" - - msgid "Fade Inactive Layers" msgstr "淡化非活动层" @@ -120521,10 +120433,6 @@ msgid "Undefined Socket Type" msgstr "未定义的接口类型" -msgid "Group Input " -msgstr "组输入 " - - msgid "Could not determine type of group node" msgstr "无法确定组节点的类型" @@ -123372,22 +123280,6 @@ msgid "NLA strip '%s' not found in track '%s'" msgstr "NLA 片段 '%s' 未在轨道 '%s' 中找到" -msgid "Functions" -msgstr "函数" - - -msgid "Comparison" -msgstr "比较" - - -msgid "Trigonometric" -msgstr "三角函数" - - -msgid "Conversion" -msgstr "转换" - - msgid "CustomGroup" msgstr "自定义组" diff --git a/locale/po/zh_TW.po b/locale/po/zh_TW.po index 852b9840ac0..44cb063b309 100644 --- a/locale/po/zh_TW.po +++ b/locale/po/zh_TW.po @@ -1,9 +1,9 @@ msgid "" msgstr "" -"Project-Id-Version: Blender 3.5.0 Beta (b'4e3286478670')\n" +"Project-Id-Version: Blender 3.5.0 Beta (b'4096bcfb25f6')\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-06 08:08:35\n" +"POT-Creation-Date: 2023-03-13 11:29:34\n" "PO-Revision-Date: 2023-01-28 11:09+0800\n" "Last-Translator: Cheng-Chia Tseng \n" "Language-Team: Chinese (Traditional) \n" @@ -9753,10 +9753,6 @@ msgid "Effective but slow compression" msgstr "有效但緩慢的壓縮" -msgid "Number" -msgstr "數目" - - msgid "Randomness" msgstr "隨機度" @@ -11612,22 +11608,6 @@ msgid "Editable falloff curve" msgstr "可編輯的衰減曲線" -msgid "Root" -msgstr "基根" - - -msgid "Sharp" -msgstr "銳利" - - -msgid "Sharper" -msgstr "更銳利" - - -msgid "Inverse Square" -msgstr "反轉平方" - - msgid "Paint most on faces pointing towards the view according to this angle" msgstr "大多根據此角度繪製在指向視圖的面上" @@ -13926,6 +13906,10 @@ msgid "Inverse Linear" msgstr "反轉線性" +msgid "Inverse Square" +msgstr "反轉平方" + + msgid "Lin/Quad Weighted" msgstr "線性/二次型權重" @@ -15773,6 +15757,10 @@ msgid "Show guide hairs" msgstr "顯示導引毛髮" +msgid "Number" +msgstr "數目" + + msgid "Show particle number" msgstr "顯示粒子數目" @@ -16491,10 +16479,6 @@ msgid "Text file on disk is different than the one in memory" msgstr "磁碟上的文字檔與記憶體中的不同" -msgid "Lines" -msgstr "線條" - - msgid "Lines of text" msgstr "文字的列" @@ -17099,10 +17083,18 @@ msgid "Use soft marble" msgstr "使用柔大理石" +msgid "Sharp" +msgstr "銳利" + + msgid "Use more clearly defined marble" msgstr "使用更清晰定義的大理石" +msgid "Sharper" +msgstr "更銳利" + + msgid "Use very clearly defined marble" msgstr "使用非常清晰定義的大理石" @@ -19774,6 +19766,10 @@ msgid "If vertex has multiple adjacent edges, it is hulled to them directly" msgstr "如果頂點有多條相鄰邊線,它會被它們直接拉過去" +msgid "Root" +msgstr "基根" + + msgid "Mesh Skin Vertex Layer" msgstr "網格皮膚頂點分層" @@ -22449,6 +22445,10 @@ msgid "Line Thickness" msgstr "線條厚度" +msgid "Lines" +msgstr "線條" + + msgid "Use straight lines between keyframe points" msgstr "在關鍵幀點之間使用直線型" @@ -54225,10 +54225,6 @@ msgid "Invert Selection" msgstr "反轉選取項" -msgid "[{}]: \"{}\" ({})" -msgstr "[{}]: \"{}\" ({})" - - msgid "Tracking" msgstr "跟蹤" @@ -54258,14 +54254,14 @@ msgid "Active object is not a mesh" msgstr "作用中物體非網格" -msgid "Remove Add-on: %r?" -msgstr "是否移除擴充元件:%r?" - - msgid "Warning, file already exists. Overwrite existing file?" msgstr "警告:檔案已經存在。是否覆蓋既有檔案?" +msgid "Remove Add-on: %r?" +msgstr "是否移除擴充元件:%r?" + + msgctxt "Operator" msgid "Open..." msgstr "開啟..." @@ -54680,10 +54676,6 @@ msgid "Strand Shape" msgstr "股段外形" -msgid "Spacing: %g" -msgstr "間隔:%g" - - msgid "Settings used for fluid" msgstr "用於流體的設定" @@ -54692,18 +54684,22 @@ msgid "Jittering Amount" msgstr "抖動量" -msgid "%d fluid particles for this frame" -msgstr "此框幀的 %d 個流體粒子" - - msgid "Use Timing" msgstr "使用計時" +msgid "Spacing: %g" +msgstr "間隔:%g" + + msgid "Not yet functional" msgstr "尚未能運作" +msgid "%d fluid particles for this frame" +msgstr "此框幀的 %d 個流體粒子" + + msgid "Dynamic Mesh" msgstr "動態網格" @@ -55440,14 +55436,14 @@ msgid "Rotation" msgstr "旋轉" -msgid "Original frame range: %d-%d (%d)" -msgstr "原始框幀區間:%d-%d (%d)" - - msgid "Unpack" msgstr "解包" +msgid "Original frame range: %d-%d (%d)" +msgstr "原始框幀區間:%d-%d (%d)" + + msgctxt "Text" msgid "New" msgstr "新增" @@ -55652,10 +55648,6 @@ msgid "Excluded Paths" msgstr "排除的路徑" -msgid "Color Set %d" -msgstr "色彩集 %d" - - msgid "Invert Wheel Zoom Direction" msgstr "反轉滾輪遠近調焦方向" @@ -55668,6 +55660,10 @@ msgid "Missing script files" msgstr "遺失的指令稿檔案" +msgid "Color Set %d" +msgstr "色彩集 %d" + + msgid "Description:" msgstr "描述:" @@ -55684,10 +55680,6 @@ msgid "Author:" msgstr "作者:" -msgid "author" -msgstr "作者" - - msgid "Version:" msgstr "版本:" diff --git a/make.bat b/make.bat index 239be60ebf0..b81f679654b 100644 --- a/make.bat +++ b/make.bat @@ -113,9 +113,6 @@ if "%TEST%" == "1" ( goto EOF ) -call "%BLENDER_DIR%\build_files\windows\check_submodules.cmd" -if errorlevel 1 goto EOF - if "%BUILD_WITH_NINJA%" == "" ( call "%BLENDER_DIR%\build_files\windows\configure_msbuild.cmd" if errorlevel 1 goto EOF diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index cbcd99d4b3f..d62f95d83f6 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -66,8 +66,8 @@ const UserDef U_default = { /** Default so DPI is detected automatically. */ .dpi = 0, - .dpi_fac = 0.0, - .inv_dpi_fac = 0.0, /* run-time. */ + .scale_factor = 0.0, + .inv_scale_factor = 0.0, /* run-time. */ .pixelsize = 1, .virtual_pixel = 0, @@ -128,7 +128,7 @@ const UserDef U_default = { .pad_rot_angle = 15, .rvisize = 25, .rvibright = 8, - .recent_files = 10, + .recent_files = 20, .smooth_viewtx = 200, .glreslimit = 0, .color_picker_type = USER_CP_CIRCLE_HSV, @@ -157,6 +157,7 @@ const UserDef U_default = { .glalphaclip = 0.004, .autokey_mode = (AUTOKEY_MODE_NORMAL & ~AUTOKEY_ON), .autokey_flag = AUTOKEY_FLAG_XYZ2RGB, + .animation_flag = USER_ANIM_HIGH_QUALITY_DRAWING, .text_render = 0, .navigation_mode = VIEW_NAVIGATION_WALK, .view_rotate_sensitivity_turntable = DEG2RAD(0.4), diff --git a/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 93e4f0cbda6..e9fd9bcf733 100644 --- a/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -929,7 +929,7 @@ def dump_template_messages(msgs, reports, settings): def dump_addon_bl_info(msgs, reports, module, settings): - for prop in ('name', 'location', 'description'): + for prop in ('name', 'location', 'description', 'warning'): process_msg( msgs, settings.DEFAULT_CONTEXT, diff --git a/scripts/modules/bl_keymap_utils/keymap_hierarchy.py b/scripts/modules/bl_keymap_utils/keymap_hierarchy.py index f183877749c..6215bb9fa9e 100644 --- a/scripts/modules/bl_keymap_utils/keymap_hierarchy.py +++ b/scripts/modules/bl_keymap_utils/keymap_hierarchy.py @@ -226,4 +226,5 @@ _km_hierarchy = [ ('Transform Modal Map', 'EMPTY', 'WINDOW', []), ('Eyedropper Modal Map', 'EMPTY', 'WINDOW', []), ('Eyedropper ColorRamp PointSampling Map', 'EMPTY', 'WINDOW', []), + ('Mesh Filter Modal Map', 'EMPTY', 'WINDOW', []), ] diff --git a/scripts/modules/bpy_extras/node_shader_utils.py b/scripts/modules/bpy_extras/node_shader_utils.py index 0c349084220..c5b1b1d4499 100644 --- a/scripts/modules/bpy_extras/node_shader_utils.py +++ b/scripts/modules/bpy_extras/node_shader_utils.py @@ -671,6 +671,7 @@ class ShaderImageTextureWrapper(): tree.links.new(node_image.outputs["Alpha" if self.use_alpha else "Color"], self.socket_dst) if self.use_alpha: self.owner_shader.material.blend_method = 'BLEND' + self.owner_shader.material.show_transparent_back = False self._node_image = node_image return self._node_image diff --git a/scripts/presets/keyconfig/keymap_data/blender_default.py b/scripts/presets/keyconfig/keymap_data/blender_default.py index 7f34593e2b8..9b0e5f22ca0 100644 --- a/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -6319,6 +6319,26 @@ def km_sculpt_expand_modal(_params): return keymap +def km_sculpt_mesh_filter_modal_map(_params): + items = [] + keymap = ( + "Mesh Filter Modal Map", + {"space_type": 'EMPTY', "region_type": 'WINDOW', "modal": True}, + {"items": items}, + ) + + items.extend([ + ("CONFIRM", {"type": 'LEFTMOUSE', "value": 'PRESS', "any": True}, None), + ("CONFIRM", {"type": 'LEFTMOUSE', "value": 'RELEASE', "any": True}, None), + ("CONFIRM", {"type": 'RET', "value": 'RELEASE', "any": True}, None), + ("CONFIRM", {"type": 'NUMPAD_ENTER', "value": 'RELEASE', "any": True}, None), + + ("CANCEL", {"type": 'ESC', "value": 'PRESS', "any": True}, None), + ("CANCEL", {"type": 'RIGHTMOUSE', "value": 'PRESS', "any": True}, None), + ]) + return keymap + + def km_curve_pen_modal_map(_params): items = [] keymap = ( @@ -8126,6 +8146,7 @@ def generate_keymaps(params=None): km_view3d_dolly_modal(params), km_paint_stroke_modal(params), km_sculpt_expand_modal(params), + km_sculpt_mesh_filter_modal_map(params), km_curve_pen_modal_map(params), km_node_link_modal_map(params), diff --git a/scripts/startup/bl_operators/freestyle.py b/scripts/startup/bl_operators/freestyle.py index 12d19b19a84..70ec1024f17 100644 --- a/scripts/startup/bl_operators/freestyle.py +++ b/scripts/startup/bl_operators/freestyle.py @@ -54,6 +54,9 @@ class SCENE_OT_freestyle_fill_range_by_selection(Operator): # Find the reference object if m.type == 'DISTANCE_FROM_CAMERA': ref = scene.camera + if ref is None: + self.report({'ERROR'}, "No active camera in the scene") + return {'CANCELLED'} matrix_to_camera = ref.matrix_world.inverted() elif m.type == 'DISTANCE_FROM_OBJECT': if m.target is None: diff --git a/scripts/startup/bl_operators/object_quick_effects.py b/scripts/startup/bl_operators/object_quick_effects.py index dc3edcd9b75..7712b222979 100644 --- a/scripts/startup/bl_operators/object_quick_effects.py +++ b/scripts/startup/bl_operators/object_quick_effects.py @@ -138,10 +138,10 @@ class QuickFur(ObjectModeOperator, Operator): generate_modifier.node_group = generate_group generate_modifier["Input_2"] = mesh_object generate_modifier["Input_18_attribute_name"] = curves.surface_uv_map + generate_modifier["Input_12"] = True generate_modifier["Input_20"] = self.length generate_modifier["Input_22"] = material generate_modifier["Input_15"] = density * 0.01 - curves_object.modifiers.move(1, 0) radius_modifier = curves_object.modifiers.new(name="Set Hair Curve Profile", type='NODES') radius_modifier.node_group = radius_group @@ -151,6 +151,7 @@ class QuickFur(ObjectModeOperator, Operator): interpolate_modifier.node_group = interpolate_group interpolate_modifier["Input_2"] = mesh_object interpolate_modifier["Input_18_attribute_name"] = curves.surface_uv_map + interpolate_modifier["Input_12"] = True interpolate_modifier["Input_15"] = density interpolate_modifier["Input_17"] = self.view_percentage interpolate_modifier["Input_24"] = True @@ -167,6 +168,8 @@ class QuickFur(ObjectModeOperator, Operator): with context.temp_override(object=curves_object): bpy.ops.object.modifier_apply(modifier=generate_modifier.name) + curves_object.modifiers.move(0, len(curves_object.modifiers) - 1) + return {'FINISHED'} diff --git a/scripts/startup/bl_ui/properties_data_mesh.py b/scripts/startup/bl_ui/properties_data_mesh.py index c837a038c9f..f098172db0b 100644 --- a/scripts/startup/bl_ui/properties_data_mesh.py +++ b/scripts/startup/bl_ui/properties_data_mesh.py @@ -604,7 +604,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): colliding_names = [] for collection in ( # Built-in names. - {"shade_smooth": None, "crease": None}, + {"crease": None}, mesh.attributes, None if ob is None else ob.vertex_groups, ): diff --git a/scripts/startup/bl_ui/space_filebrowser.py b/scripts/startup/bl_ui/space_filebrowser.py index 88fdc087584..1a8063da420 100644 --- a/scripts/startup/bl_ui/space_filebrowser.py +++ b/scripts/startup/bl_ui/space_filebrowser.py @@ -745,6 +745,8 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): row.operator("asset.open_containing_blend_file", text="", icon='TOOL_SETTINGS') layout.prop(asset_file_handle.asset_data, "description") + layout.prop(asset_file_handle.asset_data, "license") + layout.prop(asset_file_handle.asset_data, "copyright") layout.prop(asset_file_handle.asset_data, "author") diff --git a/scripts/startup/bl_ui/space_graph.py b/scripts/startup/bl_ui/space_graph.py index ae52c6a5e0d..7bec97ab5fd 100644 --- a/scripts/startup/bl_ui/space_graph.py +++ b/scripts/startup/bl_ui/space_graph.py @@ -107,16 +107,9 @@ class GRAPH_MT_view(Menu): layout.separator() layout.prop(st, "show_markers") - layout.separator() - layout.prop(st, "use_beauty_drawing") - - layout.separator() - layout.prop(st, "show_extrapolation") layout.prop(st, "show_handles") - - layout.prop(st, "use_only_selected_curves_handles") layout.prop(st, "use_only_selected_keyframe_handles") layout.prop(st, "show_seconds") @@ -255,7 +248,7 @@ class GRAPH_MT_key(Menu): layout.separator() layout.operator_menu_enum("graph.keyframe_insert", "type") - layout.operator_menu_enum("graph.fmodifier_add", "type") + layout.operator_menu_enum("graph.fmodifier_add", "type").only_active = False layout.operator("graph.sound_bake") layout.separator() diff --git a/scripts/startup/bl_ui/space_node.py b/scripts/startup/bl_ui/space_node.py index b63a84cfc81..95bf75301f4 100644 --- a/scripts/startup/bl_ui/space_node.py +++ b/scripts/startup/bl_ui/space_node.py @@ -312,7 +312,7 @@ class NODE_MT_node(Menu): snode = context.space_data is_compositor = snode.tree_type == 'CompositorNodeTree' - layout.operator("transform.translate") + layout.operator("transform.translate").view2d_edge_pan = True layout.operator("transform.rotate") layout.operator("transform.resize") diff --git a/scripts/startup/bl_ui/space_sequencer.py b/scripts/startup/bl_ui/space_sequencer.py index 5fce60035a6..303030050db 100644 --- a/scripts/startup/bl_ui/space_sequencer.py +++ b/scripts/startup/bl_ui/space_sequencer.py @@ -836,7 +836,7 @@ class SEQUENCER_MT_strip_transform(Menu): layout.operator("transform.rotate", text="Rotate") layout.operator("transform.resize", text="Scale") else: - layout.operator("transform.seq_slide", text="Move") + layout.operator("transform.seq_slide", text="Move").view2d_edge_pan = True layout.operator("transform.transform", text="Move/Extend from Current Frame").mode = 'TIME_EXTEND' layout.operator("sequencer.slip", text="Slip Strip Contents") diff --git a/scripts/startup/bl_ui/space_userpref.py b/scripts/startup/bl_ui/space_userpref.py index f0dedc42c54..7066e2e7d66 100644 --- a/scripts/startup/bl_ui/space_userpref.py +++ b/scripts/startup/bl_ui/space_userpref.py @@ -559,6 +559,8 @@ class USERPREF_PT_animation_fcurves(AnimationPanel, CenterAlignMixIn, Panel): flow.prop(edit, "keyframe_new_handle_type", text="Default Handles") flow.prop(edit, "use_insertkey_xyz_to_rgb", text="XYZ to RGB") flow.prop(edit, "use_anim_channel_group_colors") + flow.prop(edit, "show_only_selected_curve_keyframes") + flow.prop(edit, "use_fcurve_high_quality_drawing") # ----------------------------------------------------------------------------- @@ -726,7 +728,7 @@ class USERPREF_PT_viewport_display(ViewportPanel, CenterAlignMixIn, Panel): col.separator() - col.prop(view, "mini_axis_type", text="3D Viewport Axis") + col.prop(view, "mini_axis_type", text="3D Viewport Axes") if view.mini_axis_type == 'MINIMAL': col.prop(view, "mini_axis_size", text="Size") diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index d896d131832..b60988353fc 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -3221,17 +3221,35 @@ class VIEW3D_MT_sculpt(Menu): def draw(self, _context): layout = self.layout + layout.operator("transform.translate") + layout.operator("transform.rotate") + layout.operator("transform.resize", text="Scale") + + props = layout.operator("sculpt.mesh_filter", text="Sphere") + props.type = 'SPHERE' + + layout.separator() + + props = layout.operator("paint.hide_show", text="Box Hide") + props.action = 'HIDE' + + props = layout.operator("paint.hide_show", text="Box Show") + props.action = 'SHOW' + + layout.separator() + + props = layout.operator("sculpt.face_set_change_visibility", text="Toggle Visibility") + props.mode = 'TOGGLE' + + props = layout.operator("sculpt.face_set_change_visibility", text="Hide Active Face Set") + props.mode = 'HIDE_ACTIVE' + props = layout.operator("paint.hide_show", text="Show All") props.action = 'SHOW' props.area = 'ALL' - props = layout.operator("paint.hide_show", text="Box Show") - props.action = 'SHOW' - props.area = 'INSIDE' - - props = layout.operator("paint.hide_show", text="Box Hide") - props.action = 'HIDE' - props.area = 'INSIDE' + props = layout.operator("sculpt.face_set_change_visibility", text="Invert Visible") + props.mode = 'INVERT' props = layout.operator("paint.hide_show", text="Hide Masked") props.action = 'HIDE' @@ -3239,10 +3257,55 @@ class VIEW3D_MT_sculpt(Menu): layout.separator() + props = layout.operator("sculpt.trim_box_gesture", text="Box Trim") + props.trim_mode = 'DIFFERENCE' + + props = layout.operator("sculpt.trim_lasso_gesture", text="Lasso Trim") + props.trim_mode = 'DIFFERENCE' + + props = layout.operator("sculpt.trim_box_gesture", text="Box Add") + props.trim_mode = 'JOIN' + + props = layout.operator("sculpt.trim_lasso_gesture", text="Lasso Add") + props.trim_mode = 'JOIN' + + layout.operator("sculpt.project_line_gesture", text="Line Project") + + layout.separator() + + # Fair Positions + props = layout.operator("sculpt.face_set_edit", text="Fair Positions") + props.mode = 'FAIR_POSITIONS' + + # Fair Tangency + props = layout.operator("sculpt.face_set_edit", text="Fair Tangency") + props.mode = 'FAIR_TANGENCY' + + layout.separator() + + sculpt_filters_types = [ + ('SMOOTH', "Smooth"), + ('SURFACE_SMOOTH', "Surface Smooth"), + ('INFLATE', "Inflate"), + ('RELAX', "Relax Topology"), + ('RELAX_FACE_SETS', "Relax Face Sets"), + ('SHARPEN', "Sharpen"), + ('ENHANCE_DETAILS', "Enhance Details"), + ('ERASE_DISCPLACEMENT', "Erase Multires Displacement"), + ('RANDOM', "Randomize") + ] + + for filter_type, ui_name in sculpt_filters_types: + props = layout.operator("sculpt.mesh_filter", text=ui_name) + props.type = filter_type + + layout.separator() + layout.menu("VIEW3D_MT_sculpt_set_pivot", text="Set Pivot") layout.separator() + # Rebuild BVH layout.operator("sculpt.optimize") layout.separator() diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt index 2ffd223653a..9a166bb572e 100644 --- a/source/blender/CMakeLists.txt +++ b/source/blender/CMakeLists.txt @@ -30,7 +30,7 @@ set(SRC_DNA_INC ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_freestyle_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_genfile.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_types.h - ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_types.h + ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_legacy_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpu_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_types.h ${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_ipo_types.h diff --git a/source/blender/asset_system/AS_asset_identifier.hh b/source/blender/asset_system/AS_asset_identifier.hh index 33b7f71becc..5c5e4f26a00 100644 --- a/source/blender/asset_system/AS_asset_identifier.hh +++ b/source/blender/asset_system/AS_asset_identifier.hh @@ -25,6 +25,7 @@ class AssetIdentifier { AssetIdentifier(const AssetIdentifier &) = default; std::string full_path() const; + std::string full_library_path() const; }; } // namespace blender::asset_system diff --git a/source/blender/asset_system/AS_asset_representation.h b/source/blender/asset_system/AS_asset_representation.h index 359567cbf0b..366c1a1f16e 100644 --- a/source/blender/asset_system/AS_asset_representation.h +++ b/source/blender/asset_system/AS_asset_representation.h @@ -21,6 +21,8 @@ const char *AS_asset_representation_name_get(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT; AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT; +struct ID *AS_asset_representation_local_id_get(const AssetRepresentation *asset) + ATTR_WARN_UNUSED_RESULT; bool AS_asset_representation_is_local_id(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT; bool AS_asset_representation_is_never_link(const AssetRepresentation *asset) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/asset_system/AS_asset_representation.hh b/source/blender/asset_system/AS_asset_representation.hh index 99fde7d3dc2..6e84fa2aa20 100644 --- a/source/blender/asset_system/AS_asset_representation.hh +++ b/source/blender/asset_system/AS_asset_representation.hh @@ -82,6 +82,9 @@ class AssetRepresentation { * #get_import_method(). Also returns true if there is no predefined import method * (when #get_import_method() returns no value). */ bool may_override_import_method() const; + /** If this asset is stored inside this current file (#is_local_id() is true), this returns the + * ID's pointer, otherwise null. */ + ID *local_id() const; /** Returns if this asset is stored inside this current file, and as such fully editable. */ bool is_local_id() const; const AssetLibrary &owner_asset_library() const; @@ -92,7 +95,11 @@ class AssetRepresentation { /* C-Handle */ struct AssetRepresentation; -const std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset); +std::string AS_asset_representation_full_path_get(const ::AssetRepresentation *asset); +/** Get the absolute path to the .blend file containing the given asset. String will be empty if + * the asset could not be mapped to a valid .blend file path. Valid in this case also means that + * the file needs to exist on disk. */ +std::string AS_asset_representation_full_library_path_get(const ::AssetRepresentation *asset); std::optional AS_asset_representation_import_method_get( const ::AssetRepresentation *asset_handle); bool AS_asset_representation_may_override_import_method(const ::AssetRepresentation *asset_handle); diff --git a/source/blender/asset_system/intern/asset_identifier.cc b/source/blender/asset_system/intern/asset_identifier.cc index 94a15103b52..3509eb1e4aa 100644 --- a/source/blender/asset_system/intern/asset_identifier.cc +++ b/source/blender/asset_system/intern/asset_identifier.cc @@ -4,8 +4,11 @@ * \ingroup asset_system */ +#include + +#include "BKE_blendfile.h" + #include "BLI_path_util.h" -#include #include "AS_asset_identifier.hh" @@ -24,4 +27,16 @@ std::string AssetIdentifier::full_path() const return path; } +std::string AssetIdentifier::full_library_path() const +{ + std::string asset_path = full_path(); + + char blend_path[1090 /*FILE_MAX_LIBEXTRA*/]; + if (!BKE_blendfile_library_path_explode(asset_path.c_str(), blend_path, nullptr, nullptr)) { + return {}; + } + + return blend_path; +} + } // namespace blender::asset_system diff --git a/source/blender/asset_system/intern/asset_representation.cc b/source/blender/asset_system/intern/asset_representation.cc index daaa7bdff0f..6ebd6dd4c6c 100644 --- a/source/blender/asset_system/intern/asset_representation.cc +++ b/source/blender/asset_system/intern/asset_representation.cc @@ -97,6 +97,11 @@ bool AssetRepresentation::may_override_import_method() const return owner_asset_library_->may_override_import_method_; } +ID *AssetRepresentation::local_id() const +{ + return is_local_id_ ? local_asset_id_ : nullptr; +} + bool AssetRepresentation::is_local_id() const { return is_local_id_; @@ -111,7 +116,7 @@ const AssetLibrary &AssetRepresentation::owner_asset_library() const using namespace blender; -const std::string AS_asset_representation_full_path_get(const AssetRepresentation *asset_handle) +std::string AS_asset_representation_full_path_get(const AssetRepresentation *asset_handle) { const asset_system::AssetRepresentation *asset = reinterpret_cast(asset_handle); @@ -119,6 +124,13 @@ const std::string AS_asset_representation_full_path_get(const AssetRepresentatio return identifier.full_path(); } +std::string AS_asset_representation_full_library_path_get(const AssetRepresentation *asset_handle) +{ + const asset_system::AssetRepresentation *asset = + reinterpret_cast(asset_handle); + return asset->get_identifier().full_library_path(); +} + std::optional AS_asset_representation_import_method_get( const AssetRepresentation *asset_handle) { @@ -152,6 +164,13 @@ AssetMetaData *AS_asset_representation_metadata_get(const AssetRepresentation *a return &asset->get_metadata(); } +ID *AS_asset_representation_local_id_get(const AssetRepresentation *asset_handle) +{ + const asset_system::AssetRepresentation *asset = + reinterpret_cast(asset_handle); + return asset->local_id(); +} + bool AS_asset_representation_is_local_id(const AssetRepresentation *asset_handle) { const asset_system::AssetRepresentation *asset = diff --git a/source/blender/blenfont/intern/blf_default.c b/source/blender/blenfont/intern/blf_default.c index 738683284e3..58b4f3c8906 100644 --- a/source/blender/blenfont/intern/blf_default.c +++ b/source/blender/blenfont/intern/blf_default.c @@ -45,7 +45,7 @@ int BLF_set_default(void) { ASSERT_DEFAULT_SET; - BLF_size(global_font_default, global_font_size * U.dpi_fac); + BLF_size(global_font_default, global_font_size * UI_SCALE_FAC); return global_font_default; } @@ -53,7 +53,7 @@ int BLF_set_default(void) void BLF_draw_default(float x, float y, float z, const char *str, const size_t str_len) { ASSERT_DEFAULT_SET; - BLF_size(global_font_default, global_font_size * U.dpi_fac); + BLF_size(global_font_default, global_font_size * UI_SCALE_FAC); BLF_position(global_font_default, x, y, z); BLF_draw(global_font_default, str, str_len); } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 226ad9e6cc3..74f3fed2a4a 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -60,7 +60,7 @@ static FT_Library ft_lib = NULL; static FTC_Manager ftc_manager = NULL; static FTC_CMapCache ftc_charmap_cache = NULL; -/* Lock for FreeType library, used around face creation and deletion. */ +/* Lock for FreeType library, used around face creation and deletion. */ static ThreadMutex ft_lib_mutex; /* May be set to #UI_widgetbase_draw_cache_flush. */ @@ -1566,7 +1566,7 @@ FontBLF *blf_font_new_ex(const char *name, } } - /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */ + /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */ if (font->unicode_ranges[0] == 0xffffffffU && font->unicode_ranges[1] == 0xffffffffU && font->unicode_ranges[2] == 0xffffffffU && font->unicode_ranges[3] >= 0x7FFFFFFU) { font->flags |= BLF_LAST_RESORT; diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 8601c61bdac..69c158ad442 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -300,7 +300,7 @@ typedef struct FontBLF { /** Font size. */ float size; - /** Axes data for Adobe MM, TrueType GX, or OpenType variation fonts. */ + /** Axes data for Adobe MM, TrueType GX, or OpenType variation fonts. */ FT_MM_Var *variations; /** Character variation; 0=default, -1=min, +1=max. */ diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 0a0ae32af87..417fd815284 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -246,7 +246,7 @@ static const char32_t *blf_get_sample_text(FT_Face face) return def; } - /* Detect "Last resort" fonts. They have everything, except the last 5 bits. */ + /* Detect "Last resort" fonts. They have everything, except the last 5 bits. */ if (os2_table->ulUnicodeRange1 == 0xffffffffU && os2_table->ulUnicodeRange2 == 0xffffffffU && os2_table->ulUnicodeRange3 == 0xffffffffU && os2_table->ulUnicodeRange4 >= 0x7FFFFFFU) { return U"\xE000\xFFFF"; diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 967f9ea240c..d0a894389f4 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -74,7 +74,7 @@ struct Scene; /* keep in sync with MFace/MPoly types */ typedef struct DMFlagMat { short mat_nr; - char flag; + bool sharp; } DMFlagMat; typedef enum DerivedMeshType { diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 76558b9ba28..096c89098bb 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -106,28 +106,11 @@ int BKE_id_attribute_to_index(const struct ID *id, eAttrDomainMask domain_mask, eCustomDataMask layer_mask); -/** - * Sets up a temporary ID with arbitrary CustomData domains. `r_id` will - * be zero initialized with ID type id_type and any non-nullptr - * CustomData parameter will be copied into the appropriate struct members. - * - * \param r_id: Pointer to storage sufficient for ID type-code id_type. - */ -void BKE_id_attribute_copy_domains_temp(short id_type, - const struct CustomData *vdata, - const struct CustomData *edata, - const struct CustomData *ldata, - const struct CustomData *pdata, - const struct CustomData *cdata, - struct ID *r_id); - const char *BKE_id_attributes_active_color_name(const struct ID *id); const char *BKE_id_attributes_default_color_name(const struct ID *id); - -struct CustomDataLayer *BKE_id_attributes_active_color_get(const struct ID *id); void BKE_id_attributes_active_color_set(struct ID *id, const char *name); -struct CustomDataLayer *BKE_id_attributes_default_color_get(const struct ID *id); void BKE_id_attributes_default_color_set(struct ID *id, const char *name); + struct CustomDataLayer *BKE_id_attributes_color_find(const struct ID *id, const char *name); bool BKE_id_attribute_calc_unique_name(struct ID *id, const char *name, char *outname); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 6f33219c7f6..6c85f234d57 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -25,7 +25,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 1 +#define BLENDER_FILE_SUBVERSION 4 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_blendfile.h b/source/blender/blenkernel/BKE_blendfile.h index feee80b4edc..f216ff58ab3 100644 --- a/source/blender/blenkernel/BKE_blendfile.h +++ b/source/blender/blenkernel/BKE_blendfile.h @@ -19,6 +19,32 @@ struct ReportList; struct UserDef; struct bContext; +/** + * Check whether given path ends with a blend file compatible extension + * (`.blend`, `.ble` or `.blend.gz`). + * + * \param str: The path to check. + * \return true is this path ends with a blender file extension. + */ +bool BKE_blendfile_extension_check(const char *str); +/** + * Try to explode given path into its 'library components' + * (i.e. a .blend file, id type/group, and data-block itself). + * + * \param path: the full path to explode. + * \param r_dir: the string that'll contain path up to blend file itself ('library' path). + * WARNING! Must be at least #FILE_MAX_LIBEXTRA long (it also stores group and name strings)! + * \param r_group: a pointer within `r_dir` to the 'group' part of the path, if any ('\0' + * terminated). May be NULL. + * \param r_name: a pointer within `r_dir` to the data-block name, if any ('\0' terminated). May be + * NULL. + * \return true if path contains a blend file. + */ +bool BKE_blendfile_library_path_explode(const char *path, + char *r_dir, + char **r_group, + char **r_name); + /** * Shared setup function that makes the data from `bfd` into the current blend file, * replacing the contents of #G.main. diff --git a/source/blender/blenkernel/BKE_callbacks.h b/source/blender/blenkernel/BKE_callbacks.h index 8c65214c78e..0f6ab7383db 100644 --- a/source/blender/blenkernel/BKE_callbacks.h +++ b/source/blender/blenkernel/BKE_callbacks.h @@ -83,8 +83,10 @@ typedef enum { BKE_CB_EVT_RENDER_CANCEL, BKE_CB_EVT_LOAD_PRE, BKE_CB_EVT_LOAD_POST, + BKE_CB_EVT_LOAD_POST_FAIL, BKE_CB_EVT_SAVE_PRE, BKE_CB_EVT_SAVE_POST, + BKE_CB_EVT_SAVE_POST_FAIL, BKE_CB_EVT_UNDO_PRE, BKE_CB_EVT_UNDO_POST, BKE_CB_EVT_REDO_PRE, @@ -123,6 +125,7 @@ void BKE_callback_exec_id_depsgraph(struct Main *bmain, struct ID *id, struct Depsgraph *depsgraph, eCbEvent evt); +void BKE_callback_exec_string(struct Main *bmain, eCbEvent evt, const char *str); void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt); void BKE_callback_remove(bCallbackFuncStore *funcstore, eCbEvent evt); diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 61f3e675391..fddd576aee1 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -181,18 +181,13 @@ bool BKE_scene_collections_object_remove(struct Main *bmain, bool free_us); /** - * Check all collections in \a bmain (including embedded ones in scenes) for CollectionObject with - * NULL object pointer, and remove them. - */ -void BKE_collections_object_remove_nulls(struct Main *bmain); - -/** - * Check all collections in \a bmain (including embedded ones in scenes) for duplicate - * CollectionObject with a same object pointer within a same object, and remove them. + * Check all collections in \a bmain (including embedded ones in scenes) for invalid + * CollectionObject (either with NULL object pointer, or duplicates), and remove them. * - * NOTE: Always keeps the first of the detected duplicates. + * \note In case of duplicates, the first CollectionObject in the list is kept, all others are + * removed. */ -void BKE_collections_object_remove_duplicates(struct Main *bmain); +void BKE_collections_object_remove_invalids(struct Main *bmain); /** * Remove all NULL children from parent collections of changed \a collection. diff --git a/source/blender/blenkernel/BKE_colortools.h b/source/blender/blenkernel/BKE_colortools.h index d52fd91ccdd..e1dcd28b83a 100644 --- a/source/blender/blenkernel/BKE_colortools.h +++ b/source/blender/blenkernel/BKE_colortools.h @@ -133,21 +133,26 @@ void BKE_curvemapping_table_RGBA(const struct CurveMapping *cumap, float **array void BKE_curvemapping_get_range_minimums(const struct CurveMapping *curve_mapping, float minimums[4]); -/** Get the reciprocal of the difference between the maximum and the minimum x value of each curve +/** + * Get the reciprocal of the difference between the maximum and the minimum x value of each curve * map table. Evaluation parameters can be multiplied by this value to be normalized. If the - * difference is zero, 1^8 is returned. */ + * difference is zero, 1^8 is returned. + */ void BKE_curvemapping_compute_range_dividers(const struct CurveMapping *curve_mapping, float dividers[4]); -/** Compute the slopes at the start and end points of each curve map. The slopes are multiplied by +/** + * Compute the slopes at the start and end points of each curve map. The slopes are multiplied by * the range of the curve map to compensate for parameter normalization. If the slope is vertical, - * 1^8 is returned. */ + * 1^8 is returned. + */ void BKE_curvemapping_compute_slopes(const struct CurveMapping *curve_mapping, float start_slopes[4], float end_slopes[4]); -/** Check if the curve map at the index is identity, that is, does nothing. A curve map is said to - * be identity if: +/** + * Check if the curve map at the index is identity, that is, does nothing. + * A curve map is said to be identity if: * - The curve mapping uses extrapolation. * - Its range is 1. * - The slope at its start point is 1. diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index f836b98f3b2..0b58adf7ca7 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -381,6 +381,8 @@ bool CTX_data_editable_gpencil_strokes(const bContext *C, ListBase *list); const struct AssetLibraryReference *CTX_wm_asset_library_ref(const bContext *C); struct AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid); +struct AssetRepresentation *CTX_wm_asset(const bContext *C); + bool CTX_wm_interface_locked(const bContext *C); /** diff --git a/source/blender/blenkernel/BKE_curves.hh b/source/blender/blenkernel/BKE_curves.hh index c3ad7c027a1..e4a5bf8b733 100644 --- a/source/blender/blenkernel/BKE_curves.hh +++ b/source/blender/blenkernel/BKE_curves.hh @@ -384,6 +384,13 @@ class CurvesGeometry : public ::CurvesGeometry { { return this->adapt_domain(GVArray(varray), from, to).typed(); } + + /* -------------------------------------------------------------------- + * File Read/Write. + */ + + void blend_read(BlendDataReader &reader); + void blend_write(BlendWriter &writer, ID &id); }; static_assert(sizeof(blender::bke::CurvesGeometry) == sizeof(::CurvesGeometry)); diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h index 297cd3c2433..ddfe0f9c158 100644 --- a/source/blender/blenkernel/BKE_customdata.h +++ b/source/blender/blenkernel/BKE_customdata.h @@ -233,17 +233,28 @@ void CustomData_free_temporary(struct CustomData *data, int totelem); * backed by an external data array. the different allocation types are * defined above. returns the data of the layer. */ -void *CustomData_add_layer( - struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem); +void *CustomData_add_layer(struct CustomData *data, + eCustomDataType type, + eCDAllocType alloctype, + int totelem); +const void *CustomData_add_layer_with_data(struct CustomData *data, + eCustomDataType type, + void *layer_data, + int totelem); + /** * Same as above but accepts a name. */ void *CustomData_add_layer_named(struct CustomData *data, - int type, + eCustomDataType type, eCDAllocType alloctype, - void *layer, int totelem, const char *name); +const void *CustomData_add_layer_named_with_data(struct CustomData *data, + eCustomDataType type, + void *layer_data, + int totelem, + const char *name); void *CustomData_add_layer_anonymous(struct CustomData *data, int type, eCDAllocType alloctype, @@ -475,6 +486,8 @@ const char *CustomData_get_active_layer_name(const struct CustomData *data, int */ const char *CustomData_get_render_layer_name(const struct CustomData *data, int type); +bool CustomData_layer_is_anonymous(const struct CustomData *data, int type, int n); + void CustomData_bmesh_set(const struct CustomData *data, void *block, int type, diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index 69cf1f1edf6..2f18eef7850 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -44,7 +44,7 @@ typedef struct CfraElem { /* ************** F-Curve Modifiers *************** */ /** - * F-Curve Modifier Type-Info (fmi): + * F-Curve Modifier Type-Info (`fmi`): * This struct provides function pointers for runtime, so that functions can be * written more generally (with fewer/no special exceptions for various modifiers). * @@ -366,24 +366,25 @@ int BKE_fcurve_pathcache_find_array(struct FCurvePathCache *fcache, int fcurve_result_len); /** - * Calculate the extents of F-Curve's keyframes. + * Calculate the x range of the given F-Curve's data. + * \return true if a range has been found. */ -bool BKE_fcurve_calc_range( - const struct FCurve *fcu, float *min, float *max, bool do_sel_only, bool do_min_length); +bool BKE_fcurve_calc_range(const struct FCurve *fcu, + float *r_min, + float *r_max, + bool selected_keys_only); /** - * Calculate the extents of F-Curve's data. - * \param range Only calculate the bounds of the FCurve in the given range. + * Calculate the x and y extents of F-Curve's data. + * \param frame_range: Only calculate the bounds of the FCurve in the given range. * Does the full range if NULL. + * \return true if the bounds have been found. */ bool BKE_fcurve_calc_bounds(const struct FCurve *fcu, - float *xmin, - float *xmax, - float *ymin, - float *ymax, - bool do_sel_only, + bool selected_keys_only, bool include_handles, - const float range[2]); + const float frame_range[2], + struct rctf *r_bounds); /** * Return an array of keyed frames, rounded to `interval`. diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve_legacy.h similarity index 100% rename from source/blender/blenkernel/BKE_gpencil_curve.h rename to source/blender/blenkernel/BKE_gpencil_curve_legacy.h diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom_legacy.h similarity index 99% rename from source/blender/blenkernel/BKE_gpencil_geom.h rename to source/blender/blenkernel/BKE_gpencil_geom_legacy.h index bec3782df90..12dad5a2e6e 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom_legacy.h @@ -16,6 +16,7 @@ struct Main; struct Object; struct Scene; struct bGPDcurve; +struct bGPDlayer; struct bGPDframe; struct bGPDspoint; struct bGPDstroke; diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil_legacy.h similarity index 99% rename from source/blender/blenkernel/BKE_gpencil.h rename to source/blender/blenkernel/BKE_gpencil_legacy.h index 55ca1c38af4..8a558747a25 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil_legacy.h @@ -344,7 +344,7 @@ typedef enum eGP_GetFrame_Mode { /** * Get the appropriate gp-frame from a given layer - * - this sets the layer's actframe var (if allowed to) + * - this sets the layer's `actframe` var (if allowed to) * - extension beyond range (if first gp-frame is after all frame in interest and cannot add) * * \param gpl: Grease pencil layer @@ -523,7 +523,7 @@ struct Material *BKE_gpencil_object_material_new(struct Main *bmain, int *r_index); /** - * Get material index (0-based like mat_nr not actcol). + * Get material index (0-based like mat_nr not #Object::actcol). * \param ob: Grease pencil object * \param ma: Material * \return Index of the material diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier_legacy.h similarity index 100% rename from source/blender/blenkernel/BKE_gpencil_modifier.h rename to source/blender/blenkernel/BKE_gpencil_modifier_legacy.h diff --git a/source/blender/blenkernel/BKE_gpencil_update_cache.h b/source/blender/blenkernel/BKE_gpencil_update_cache_legacy.h similarity index 100% rename from source/blender/blenkernel/BKE_gpencil_update_cache.h rename to source/blender/blenkernel/BKE_gpencil_update_cache_legacy.h diff --git a/source/blender/blenkernel/BKE_idtype.h b/source/blender/blenkernel/BKE_idtype.h index be13a3c1d2a..02e6088e483 100644 --- a/source/blender/blenkernel/BKE_idtype.h +++ b/source/blender/blenkernel/BKE_idtype.h @@ -259,7 +259,7 @@ extern IDTypeInfo IDType_ID_AC; extern IDTypeInfo IDType_ID_NT; extern IDTypeInfo IDType_ID_BR; extern IDTypeInfo IDType_ID_PA; -extern IDTypeInfo IDType_ID_GD; +extern IDTypeInfo IDType_ID_GD_LEGACY; extern IDTypeInfo IDType_ID_WM; extern IDTypeInfo IDType_ID_MC; extern IDTypeInfo IDType_ID_MSK; diff --git a/source/blender/blenkernel/BKE_image_wrappers.hh b/source/blender/blenkernel/BKE_image_wrappers.hh index 7fa26066e73..fe01d9e1e62 100644 --- a/source/blender/blenkernel/BKE_image_wrappers.hh +++ b/source/blender/blenkernel/BKE_image_wrappers.hh @@ -9,8 +9,11 @@ #include "DNA_image_types.h" +#include "BLI_math.h" #include "BLI_math_vector_types.hh" +#include "IMB_imbuf_types.h" + namespace blender::bke::image { /** Type to use for UDIM tile numbers (1001). */ @@ -44,4 +47,44 @@ struct ImageTileWrapper { return (tile_number - 1001) / 10; } }; + +template struct ImageBufferAccessor { + static_assert(std::is_same_v || std::is_same_v); + + ImBuf &image_buffer; + + ImageBufferAccessor(ImBuf &image_buffer) : image_buffer(image_buffer) + { + } + + float4 read_pixel(const int2 coordinate) + { + if constexpr ((std::is_same_v)) { + int offset = (coordinate.y * image_buffer.x + coordinate.x) * Channels; + return float4(&image_buffer.rect_float[offset]); + } + if constexpr ((std::is_same_v)) { + int offset = (coordinate.y * image_buffer.x + coordinate.x); + float4 result; + rgba_uchar_to_float(result, + static_cast(static_cast(&image_buffer.rect[offset]))); + return result; + } + return float4(); + } + + void write_pixel(const int2 coordinate, float4 new_value) + { + if constexpr ((std::is_same_v)) { + int offset = (coordinate.y * image_buffer.x + coordinate.x) * Channels; + copy_v4_v4(&image_buffer.rect_float[offset], new_value); + } + if constexpr ((std::is_same_v)) { + int offset = (coordinate.y * image_buffer.x + coordinate.x); + rgba_float_to_uchar(static_cast(static_cast(&image_buffer.rect[offset])), + new_value); + } + } +}; + } // namespace blender::bke::image diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index fc538cba221..4f543c4cfe1 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -139,11 +139,15 @@ enum { /** Do not process ID pointers inside embedded IDs. Needed by depsgraph processing e.g. */ IDWALK_IGNORE_EMBEDDED_ID = (1 << 3), - /** Also process internal ID pointers like `ID.newid` or `ID.orig_id`. - * WARNING: Dangerous, use with caution. */ + /** + * Also process internal ID pointers like `ID.newid` or `ID.orig_id`. + * WARNING: Dangerous, use with caution. + */ IDWALK_DO_INTERNAL_RUNTIME_POINTERS = (1 << 9), - /** Also process the ID.lib pointer. It is an option because this pointer can usually be fully - ignored. */ + /** + * Also process the ID.lib pointer. It is an option because this pointer can usually be fully + * ignored. + */ IDWALK_DO_LIBRARY_POINTER = (1 << 10), }; diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h index f4ac0cfd0e7..59fa11109c1 100644 --- a/source/blender/blenkernel/BKE_main.h +++ b/source/blender/blenkernel/BKE_main.h @@ -185,8 +185,8 @@ typedef struct Main { ListBase particles; ListBase palettes; ListBase paintcurves; - ListBase wm; /* Singleton (exception). */ - ListBase gpencils; + ListBase wm; /* Singleton (exception). */ + ListBase gpencils; /* Legacy Grease Pencil. */ ListBase movieclips; ListBase masks; ListBase linestyles; diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 2f36e36859a..70d6f1a0383 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -25,7 +25,6 @@ struct BoundBox; struct CustomData; struct CustomData_MeshMasks; struct Depsgraph; -struct EdgeHash; struct ID; struct KeyBlock; struct LinkNode; @@ -316,49 +315,25 @@ void BKE_mesh_vert_coords_apply(struct Mesh *mesh, const float (*vert_coords)[3] void BKE_mesh_recalc_looptri(const struct MLoop *mloop, const struct MPoly *polys, const float (*vert_positions)[3], + int totvert, int totloop, int totpoly, struct MLoopTri *mlooptri); -/** - * A version of #BKE_mesh_recalc_looptri which takes pre-calculated polygon normals - * (used to avoid having to calculate the face normal for NGON tessellation). - * - * \note Only use this function if normals have already been calculated, there is no need - * to calculate normals just to use this function as it will cause the normals for triangles - * to be calculated which aren't needed for tessellation. - */ -void BKE_mesh_recalc_looptri_with_normals(const struct MLoop *mloop, - const struct MPoly *polys, - const float (*vert_positions)[3], - int totloop, - int totpoly, - struct MLoopTri *mlooptri, - const float (*poly_normals)[3]); /* *** mesh_normals.cc *** */ /** - * Returns the normals for each vertex, which is defined as the weighted average of the normals - * from a vertices surrounding faces, or the normalized position of vertices connected to no faces. - * \warning May still return null if the mesh is empty. + * See #Mesh::vert_normals(). + * \warning May return null if the mesh is empty. */ const float (*BKE_mesh_vert_normals_ensure(const struct Mesh *mesh))[3]; /** - * Return the normal direction of every polygon, which is defined by the winding direction of its - * corners. - * \warning May still return null if the mesh is empty or has no polygons. + * See #Mesh::poly_normals(). + * \warning May return null if the mesh is empty or has no polygons. */ const float (*BKE_mesh_poly_normals_ensure(const struct Mesh *mesh))[3]; -/** - * Tag mesh vertex and face normals to be recalculated when/if they are needed later. - * - * \note Dirty tagged normals are the default state of a new mesh, so tagging them - * dirty explicitly is not always necessary if the mesh is created locally. - */ -void BKE_mesh_normals_tag_dirty(struct Mesh *mesh); - /** * Retrieve write access to the cached vertex normals, ensuring that they are allocated but *not* * that they are calculated. The provided vertex normals should be the same as if they were @@ -409,60 +384,17 @@ bool BKE_mesh_vert_normals_are_dirty(const struct Mesh *mesh); */ bool BKE_mesh_poly_normals_are_dirty(const struct Mesh *mesh); -void BKE_mesh_calc_poly_normal(const struct MPoly *polys, - const struct MLoop *loopstart, +void BKE_mesh_calc_poly_normal(const struct MLoop *poly_loops, + int poly_size, const float (*vert_positions)[3], + int verts_num, float r_no[3]); -/** - * Calculate face normals directly into a result array. - * - * \note Usually #BKE_mesh_poly_normals_ensure is the preferred way to access face normals, - * since they may already be calculated and cached on the mesh. - */ -void BKE_mesh_calc_normals_poly(const float (*vert_positions)[3], - int mvert_len, - const struct MLoop *mloop, - int mloop_len, - const struct MPoly *polys, - int polys_len, - float (*r_poly_normals)[3]); - -/** - * Calculate face and vertex normals directly into result arrays. - * - * \note Usually #BKE_mesh_vert_normals_ensure is the preferred way to access vertex normals, - * since they may already be calculated and cached on the mesh. - */ -void BKE_mesh_calc_normals_poly_and_vertex(const float (*vert_positions)[3], - int mvert_len, - const struct MLoop *mloop, - int mloop_len, - const struct MPoly *polys, - int polys_len, - float (*r_poly_normals)[3], - float (*r_vert_normals)[3]); - /** * Called after calculating all modifiers. */ void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh); -/** - * Define sharp edges as needed to mimic 'autosmooth' from angle threshold. - * - * Used when defining an empty custom loop normals data layer, - * to keep same shading as with auto-smooth! - */ -void BKE_edges_sharp_from_angle_set(int numEdges, - const struct MLoop *mloops, - int numLoops, - const struct MPoly *polys, - const float (*poly_normals)[3], - int numPolys, - float split_angle, - bool *sharp_edges); - /** * References a contiguous loop-fan with normal offset vars. */ @@ -566,62 +498,6 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2]); -/* Medium-level custom normals functions. */ - -/** - * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). - * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry - * (splitting edges). - * - * \param loop_to_poly_map: Optional pre-created map from loops to their polygon. - * \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on - * each side of the edge. - */ -void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], - const float (*vert_normals)[3], - int numVerts, - const struct MEdge *edges, - int numEdges, - const struct MLoop *mloops, - float (*r_loop_normals)[3], - int numLoops, - const struct MPoly *polys, - const float (*poly_normals)[3], - int numPolys, - bool use_split_normals, - float split_angle, - const bool *sharp_edges, - const int *loop_to_poly_map, - MLoopNorSpaceArray *r_lnors_spacearr, - short (*clnors_data)[2]); - -void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3], - const float (*vert_normals)[3], - int numVerts, - const struct MEdge *edges, - int numEdges, - const struct MLoop *mloops, - float (*r_custom_loop_normals)[3], - int numLoops, - const struct MPoly *polys, - const float (*poly_normals)[3], - int numPolys, - bool *sharp_edges, - short (*r_clnors_data)[2]); -void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3], - const float (*vert_normals)[3], - float (*r_custom_vert_normals)[3], - int numVerts, - const struct MEdge *edges, - int numEdges, - const struct MLoop *mloops, - int numLoops, - const struct MPoly *polys, - const float (*poly_normals)[3], - int numPolys, - bool *sharp_edges, - short (*r_clnors_data)[2]); - /** * Computes average per-vertex normals from given custom loop normals. * @@ -653,7 +529,7 @@ void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh, /** * Higher level functions hiding most of the code needed around call to - * #BKE_mesh_normals_loop_custom_set(). + * #normals_loop_custom_set(). * * \param r_custom_loop_normals: is not const, since code will replace zero_v3 normals there * with automatically computed vectors. @@ -661,7 +537,7 @@ void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh, void BKE_mesh_set_custom_normals(struct Mesh *mesh, float (*r_custom_loop_normals)[3]); /** * Higher level functions hiding most of the code needed around call to - * #BKE_mesh_normals_loop_custom_from_verts_set(). + * #normals_loop_custom_set_from_verts(). * * \param r_custom_vert_normals: is not const, since code will replace zero_v3 normals there * with automatically computed vectors. @@ -670,26 +546,16 @@ void BKE_mesh_set_custom_normals_from_verts(struct Mesh *mesh, float (*r_custom_ /* *** mesh_evaluate.cc *** */ -void BKE_mesh_calc_poly_center(const struct MPoly *poly, - const struct MLoop *loopstart, +void BKE_mesh_calc_poly_center(const struct MLoop *poly_loops, + int poly_size, const float (*vert_positions)[3], + int verts_num, float r_cent[3]); -/* NOTE: passing poly-normal is only a speedup so we can skip calculating it. */ -float BKE_mesh_calc_poly_area(const struct MPoly *poly, - const struct MLoop *loopstart, - const float (*vert_positions)[3]); +float BKE_mesh_calc_poly_area(const struct MLoop *poly_loops, + int poly_size, + const float (*vert_positions)[3], + int verts_num); float BKE_mesh_calc_area(const struct Mesh *me); -void BKE_mesh_calc_poly_angles(const struct MPoly *poly, - const struct MLoop *loopstart, - const float (*vert_positions)[3], - float angles[]); - -void BKE_mesh_poly_edgehash_insert(struct EdgeHash *ehash, - const struct MPoly *mp, - const struct MLoop *mloop); -void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap, - const struct MPoly *mp, - const struct MLoop *mloop); bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]); /** @@ -922,7 +788,7 @@ BLI_INLINE int *BKE_mesh_material_indices_for_write(Mesh *mesh) return indices; } return (int *)CustomData_add_layer_named( - &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, NULL, mesh->totpoly, "material_index"); + &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, mesh->totpoly, "material_index"); } BLI_INLINE const float (*BKE_mesh_vert_positions(const Mesh *mesh))[3] @@ -974,80 +840,11 @@ BLI_INLINE MDeformVert *BKE_mesh_deform_verts_for_write(Mesh *mesh) return dvert; } return (MDeformVert *)CustomData_add_layer( - &mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, NULL, mesh->totvert); + &mesh->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, mesh->totvert); } #ifdef __cplusplus } #endif -#ifdef __cplusplus - -# include "BLI_math_vector_types.hh" -# include "BLI_span.hh" - -inline blender::Span Mesh::vert_positions() const -{ - return {reinterpret_cast(BKE_mesh_vert_positions(this)), this->totvert}; -} -inline blender::MutableSpan Mesh::vert_positions_for_write() -{ - return {reinterpret_cast(BKE_mesh_vert_positions_for_write(this)), - this->totvert}; -} - -inline blender::Span Mesh::edges() const -{ - return {BKE_mesh_edges(this), this->totedge}; -} -inline blender::MutableSpan Mesh::edges_for_write() -{ - return {BKE_mesh_edges_for_write(this), this->totedge}; -} - -inline blender::Span Mesh::polys() const -{ - return {BKE_mesh_polys(this), this->totpoly}; -} -inline blender::MutableSpan Mesh::polys_for_write() -{ - return {BKE_mesh_polys_for_write(this), this->totpoly}; -} - -inline blender::Span Mesh::loops() const -{ - return {BKE_mesh_loops(this), this->totloop}; -} -inline blender::MutableSpan Mesh::loops_for_write() -{ - return {BKE_mesh_loops_for_write(this), this->totloop}; -} - -inline blender::Span Mesh::deform_verts() const -{ - const MDeformVert *dverts = BKE_mesh_deform_verts(this); - if (!dverts) { - return {}; - } - return {dverts, this->totvert}; -} -inline blender::MutableSpan Mesh::deform_verts_for_write() -{ - return {BKE_mesh_deform_verts_for_write(this), this->totvert}; -} - -inline blender::Span Mesh::poly_normals() const -{ - return {reinterpret_cast(BKE_mesh_poly_normals_ensure(this)), - this->totpoly}; -} - -inline blender::Span Mesh::vert_normals() const -{ - return {reinterpret_cast(BKE_mesh_vert_normals_ensure(this)), - this->totvert}; -} - -#endif - /** \} */ diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh new file mode 100644 index 00000000000..7035b80dfd6 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -0,0 +1,199 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later. */ + +#pragma once + +/** \file + * \ingroup bke + */ + +#include "BKE_mesh.h" + +namespace blender::bke::mesh { + +/* -------------------------------------------------------------------- */ +/** \name Polygon Data Evaluation + * \{ */ + +/** Calculate the up direction for the polygon, depending on its winding direction. */ +float3 poly_normal_calc(Span vert_positions, Span poly_loops); + +/** + * Calculate tessellation into #MLoopTri which exist only for this purpose. + */ +void looptris_calc(Span vert_positions, + Span polys, + Span loops, + MutableSpan looptris); +/** + * A version of #looptris_calc which takes pre-calculated polygon normals + * (used to avoid having to calculate the face normal for NGON tessellation). + * + * \note Only use this function if normals have already been calculated, there is no need + * to calculate normals just to use this function. + */ +void looptris_calc_with_normals(Span vert_positions, + Span polys, + Span loops, + Span poly_normals, + MutableSpan looptris); + +/** Calculate the average position of the vertices in the polygon. */ +float3 poly_center_calc(Span vert_positions, Span poly_loops); + +/** Calculate the surface area of the polygon described by the indexed vertices. */ +float poly_area_calc(Span vert_positions, Span poly_loops); + +/** Calculate the angles at each of the polygons corners. */ +void poly_angles_calc(Span vert_positions, + Span poly_loops, + MutableSpan angles); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Medium-Level Normals Calculation + * \{ */ + +/** + * Calculate face normals directly into a result array. + * + * \note Usually #Mesh::poly_normals() is the preferred way to access face normals, + * since they may already be calculated and cached on the mesh. + */ +void normals_calc_polys(Span vert_positions, + Span polys, + Span loops, + MutableSpan poly_normals); + +/** + * Calculate face and vertex normals directly into result arrays. + * + * \note Usually #Mesh::vert_normals() is the preferred way to access vertex normals, + * since they may already be calculated and cached on the mesh. + */ +void normals_calc_poly_vert(Span vert_positions, + Span polys, + Span loops, + MutableSpan poly_normals, + MutableSpan vert_normals); + +/** + * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). + * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry + * (splitting edges). + * + * \param loop_to_poly_map: Optional pre-created map from loops to their polygon. + * \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on + * each side of the edge. + */ +void normals_calc_loop(Span vert_positions, + Span edges, + Span polys, + Span loops, + Span loop_to_poly_map, + Span vert_normals, + Span poly_normals, + const bool *sharp_edges, + const bool *sharp_faces, + bool use_split_normals, + float split_angle, + short (*clnors_data)[2], + MLoopNorSpaceArray *r_lnors_spacearr, + MutableSpan r_loop_normals); + +void normals_loop_custom_set(Span vert_positions, + Span edges, + Span polys, + Span loops, + Span vert_normals, + Span poly_normals, + const bool *sharp_faces, + MutableSpan sharp_edges, + MutableSpan r_custom_loop_normals, + short (*r_clnors_data)[2]); + +void normals_loop_custom_set_from_verts(Span vert_positions, + Span edges, + Span polys, + Span loops, + Span vert_normals, + Span poly_normals, + const bool *sharp_faces, + MutableSpan sharp_edges, + MutableSpan r_custom_vert_normals, + short (*r_clnors_data)[2]); + +/** + * Define sharp edges as needed to mimic 'autosmooth' from angle threshold. + * + * Used when defining an empty custom loop normals data layer, + * to keep same shading as with auto-smooth! + * + * \param sharp_faces: Optional array used to mark specific faces for sharp shading. + */ +void edges_sharp_from_angle_set(Span polys, + Span loops, + Span poly_normals, + const bool *sharp_faces, + const float split_angle, + MutableSpan sharp_edges); + +} // namespace blender::bke::mesh + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline Mesh Data Access + * \{ */ + +inline blender::Span Mesh::vert_positions() const +{ + return {reinterpret_cast(BKE_mesh_vert_positions(this)), this->totvert}; +} +inline blender::MutableSpan Mesh::vert_positions_for_write() +{ + return {reinterpret_cast(BKE_mesh_vert_positions_for_write(this)), + this->totvert}; +} + +inline blender::Span Mesh::edges() const +{ + return {BKE_mesh_edges(this), this->totedge}; +} +inline blender::MutableSpan Mesh::edges_for_write() +{ + return {BKE_mesh_edges_for_write(this), this->totedge}; +} + +inline blender::Span Mesh::polys() const +{ + return {BKE_mesh_polys(this), this->totpoly}; +} +inline blender::MutableSpan Mesh::polys_for_write() +{ + return {BKE_mesh_polys_for_write(this), this->totpoly}; +} + +inline blender::Span Mesh::loops() const +{ + return {BKE_mesh_loops(this), this->totloop}; +} +inline blender::MutableSpan Mesh::loops_for_write() +{ + return {BKE_mesh_loops_for_write(this), this->totloop}; +} + +inline blender::Span Mesh::deform_verts() const +{ + const MDeformVert *dverts = BKE_mesh_deform_verts(this); + if (!dverts) { + return {}; + } + return {dverts, this->totvert}; +} +inline blender::MutableSpan Mesh::deform_verts_for_write() +{ + return {BKE_mesh_deform_verts_for_write(this), this->totvert}; +} + +/** \} */ diff --git a/source/blender/blenkernel/BKE_mesh_legacy_convert.h b/source/blender/blenkernel/BKE_mesh_legacy_convert.h index 38c4ba7d882..950cf76174c 100644 --- a/source/blender/blenkernel/BKE_mesh_legacy_convert.h +++ b/source/blender/blenkernel/BKE_mesh_legacy_convert.h @@ -96,6 +96,9 @@ void BKE_mesh_legacy_convert_loose_edges_to_flag(struct Mesh *mesh); void BKE_mesh_legacy_attribute_flags_to_strings(struct Mesh *mesh); void BKE_mesh_legacy_attribute_strings_to_flags(struct Mesh *mesh); +void BKE_mesh_legacy_sharp_faces_to_flags(struct Mesh *mesh); +void BKE_mesh_legacy_sharp_faces_from_flags(struct Mesh *mesh); + void BKE_mesh_legacy_sharp_edges_to_flags(struct Mesh *mesh); void BKE_mesh_legacy_sharp_edges_from_flags(struct Mesh *mesh); diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index 3835e3f78e2..6f14b25588f 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -324,6 +324,7 @@ int *BKE_mesh_calc_smoothgroups(int totedge, const struct MLoop *mloop, int totloop, const bool *sharp_edges, + const bool *sharp_faces, int *r_totgroup, bool use_bitflags); diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h index 7508821860c..d08c6cbbcee 100644 --- a/source/blender/blenkernel/BKE_mesh_remap.h +++ b/source/blender/blenkernel/BKE_mesh_remap.h @@ -45,7 +45,7 @@ void BKE_mesh_remap_item_define_invalid(MeshPairRemap *map, int index); * https://blenderartists.org/t/619105 * * We could also use similar topology mappings inside a same mesh - * (cf. Campbell's 'select face islands from similar topology' wip work). + * (cf. Campbell's 'select face islands from similar topology' WIP work). * Also, users will have to check, whether we can get rid of some modes here, * not sure all will be useful! */ @@ -221,6 +221,7 @@ void BKE_mesh_remap_calc_polys_from_mesh(int mode, float ray_radius, const struct Mesh *mesh_dst, const float (*vert_positions_dst)[3], + int numverts_dst, const struct MLoop *loops_dst, const struct MPoly *polys_dst, int numpolys_dst, diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h index a9d7ba2163e..085096c77f1 100644 --- a/source/blender/blenkernel/BKE_mesh_tangent.h +++ b/source/blender/blenkernel/BKE_mesh_tangent.h @@ -48,6 +48,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3], const struct MLoop *mloop, const struct MLoopTri *looptri, uint looptri_len, + const bool *sharp_faces, struct CustomData *loopdata, bool calc_active_tangent, diff --git a/source/blender/blenkernel/BKE_mesh_types.h b/source/blender/blenkernel/BKE_mesh_types.h index b9c62f39c57..9b9efeeb761 100644 --- a/source/blender/blenkernel/BKE_mesh_types.h +++ b/source/blender/blenkernel/BKE_mesh_types.h @@ -19,6 +19,7 @@ # include "BLI_math_vector_types.hh" # include "BLI_shared_cache.hh" # include "BLI_span.hh" +# include "BLI_vector.hh" # include "DNA_customdata_types.h" # include "DNA_meshdata_types.h" @@ -158,8 +159,8 @@ struct MeshRuntime { */ bool vert_normals_dirty = true; bool poly_normals_dirty = true; - float (*vert_normals)[3] = nullptr; - float (*poly_normals)[3] = nullptr; + mutable Vector vert_normals; + mutable Vector poly_normals; /** * A cache of data about the loose edges. Can be shared with other data-blocks with unchanged diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 28aa407f633..001aef4b6cc 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -345,11 +345,6 @@ typedef struct bNodeType { /* Execute a geometry node. */ NodeGeometryExecFunction geometry_node_execute; - /** - * If true, the geometry nodes evaluator can call the execute function multiple times to improve - * performance by specifying required data in one call and using it for calculations in another. - */ - bool geometry_node_execute_supports_laziness; /* Declares which sockets the node has. */ NodeDeclareFunction declare; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 2a7aca450ba..833cb425987 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -783,10 +783,8 @@ bool BKE_pbvh_node_has_vert_with_normal_update_tag(PBVH *pbvh, PBVHNode *node); // void BKE_pbvh_node_BB_expand(PBVHNode *node, float co[3]); bool pbvh_has_mask(const PBVH *pbvh); -void pbvh_show_mask_set(PBVH *pbvh, bool show_mask); bool pbvh_has_face_sets(PBVH *pbvh); -void pbvh_show_face_sets_set(PBVH *pbvh, bool show_face_sets); /* Parallelization. */ diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh index 31dbad0abe1..9110ba4f8f9 100644 --- a/source/blender/blenkernel/BKE_pbvh_pixels.hh +++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh @@ -3,8 +3,10 @@ #pragma once +#include + #include "BLI_math.h" -#include "BLI_math_vector_types.hh" +#include "BLI_math_vector.hh" #include "BLI_rect.h" #include "BLI_vector.hh" @@ -233,6 +235,15 @@ struct NodeData { } } + void collect_dirty_tiles(Vector &r_dirty_tiles) + { + for (UDIMTilePixels &tile : tiles) { + if (tile.flags.dirty) { + r_dirty_tiles.append_non_duplicates(tile.tile_number); + } + } + } + void clear_data() { tiles.clear(); @@ -246,10 +257,165 @@ struct NodeData { } }; +/* -------------------------------------------------------------------- */ +/** \name Fix non-manifold edge bleeding. + * \{ */ + +struct DeltaCopyPixelCommand { + char2 delta_source_1; + char2 delta_source_2; + uint8_t mix_factor; + + DeltaCopyPixelCommand(char2 delta_source_1, char2 delta_source_2, uint8_t mix_factor) + : delta_source_1(delta_source_1), delta_source_2(delta_source_2), mix_factor(mix_factor) + { + } +}; + +struct CopyPixelGroup { + int2 start_destination; + int2 start_source_1; + int64_t start_delta_index; + int num_deltas; +}; + +/** Pixel copy command to mix 2 source pixels and write to a destination pixel. */ +struct CopyPixelCommand { + /** Pixel coordinate to write to. */ + int2 destination; + /** Pixel coordinate to read first source from. */ + int2 source_1; + /** Pixel coordinate to read second source from. */ + int2 source_2; + /** Factor to mix between first and second source. */ + float mix_factor; + + CopyPixelCommand() = default; + CopyPixelCommand(const CopyPixelGroup &group) + : destination(group.start_destination), + source_1(group.start_source_1), + source_2(), + mix_factor(0.0f) + { + } + + template + void mix_source_and_write_destination(image::ImageBufferAccessor &tile_buffer) const + { + float4 source_color_1 = tile_buffer.read_pixel(source_1); + float4 source_color_2 = tile_buffer.read_pixel(source_2); + float4 destination_color = source_color_1 * (1.0f - mix_factor) + source_color_2 * mix_factor; + tile_buffer.write_pixel(destination, destination_color); + } + + void apply(const DeltaCopyPixelCommand &item) + { + destination.x += 1; + source_1 += int2(item.delta_source_1); + source_2 = source_1 + int2(item.delta_source_2); + mix_factor = float(item.mix_factor) / 255.0f; + } + + DeltaCopyPixelCommand encode_delta(const CopyPixelCommand &next_command) const + { + return DeltaCopyPixelCommand(char2(next_command.source_1 - source_1), + char2(next_command.source_2 - next_command.source_1), + uint8_t(next_command.mix_factor * 255)); + } + + bool can_be_extended(const CopyPixelCommand &command) const + { + /* Can only extend sequential pixels. */ + if (destination.x != command.destination.x - 1 || destination.y != command.destination.y) { + return false; + } + + /* Can only extend when the delta between with the previous source fits in a single byte.*/ + int2 delta_source_1 = source_1 - command.source_1; + if (max_ii(UNPACK2(blender::math::abs(delta_source_1))) > 127) { + return false; + } + return true; + } +}; + +struct CopyPixelTile { + image::TileNumber tile_number; + Vector groups; + Vector command_deltas; + + CopyPixelTile(image::TileNumber tile_number) : tile_number(tile_number) + { + } + + void copy_pixels(ImBuf &tile_buffer, IndexRange group_range) const + { + if (tile_buffer.rect_float) { + image::ImageBufferAccessor accessor(tile_buffer); + copy_pixels(accessor, group_range); + } + else { + image::ImageBufferAccessor accessor(tile_buffer); + copy_pixels(accessor, group_range); + } + } + + void print_compression_rate() + { + int decoded_size = command_deltas.size() * sizeof(CopyPixelCommand); + int encoded_size = groups.size() * sizeof(CopyPixelGroup) + + command_deltas.size() * sizeof(DeltaCopyPixelCommand); + printf("Tile %d compression rate: %d->%d = %d%%\n", + tile_number, + decoded_size, + encoded_size, + int(100.0 * float(encoded_size) / float(decoded_size))); + } + + private: + template + void copy_pixels(image::ImageBufferAccessor &image_buffer, IndexRange group_range) const + { + for (const int64_t group_index : group_range) { + const CopyPixelGroup &group = groups[group_index]; + CopyPixelCommand copy_command(group); + for (const DeltaCopyPixelCommand &item : Span( + &command_deltas[group.start_delta_index], group.num_deltas)) { + copy_command.apply(item); + copy_command.mix_source_and_write_destination(image_buffer); + } + } + } +}; + +struct CopyPixelTiles { + Vector tiles; + + std::optional> find_tile(image::TileNumber tile_number) + { + for (CopyPixelTile &tile : tiles) { + if (tile.tile_number == tile_number) { + return tile; + } + } + return std::nullopt; + } + + void clear() + { + tiles.clear(); + } +}; + +/** \} */ + struct PBVHData { /* Per UVPRimitive contains the paint data. */ PaintGeometryPrimitives geom_primitives; + /** Per ImageTile the pixels to copy to fix non-manifold bleeding. */ + CopyPixelTiles tiles_copy_pixels; + void clear_data() { geom_primitives.clear(); @@ -259,5 +425,11 @@ struct PBVHData { NodeData &BKE_pbvh_pixels_node_data_get(PBVHNode &node); void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &image_user); PBVHData &BKE_pbvh_pixels_data_get(PBVH &pbvh); +void BKE_pbvh_pixels_collect_dirty_tiles(PBVHNode &node, Vector &r_dirty_tiles); + +void BKE_pbvh_pixels_copy_pixels(PBVH &pbvh, + Image &image, + ImageUser &image_user, + image::TileNumber tile_number); } // namespace blender::bke::pbvh::pixels diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index 79a3bdf7c3c..dc05646884c 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -122,11 +122,11 @@ typedef struct PTCacheID { /* flags defined in DNA_object_force_types.h */ unsigned int data_types, info_types; - /* copies point data to cache data */ + /* Copies point data to cache data. */ int (*write_point)(int index, void *calldata, void **data, int cfra); - /* copies cache cata to point data */ + /* Copies cache data to point data. */ void (*read_point)(int index, void *calldata, void **data, float cfra, const float *old_data); - /* interpolated between previously read point data and cache data */ + /* Interpolated between previously read point data and cache data. */ void (*interpolate_point)(int index, void *calldata, void **data, diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 448a8938bd3..707dbc0ada6 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -76,6 +76,7 @@ typedef struct ShrinkwrapTreeData { const struct MPoly *polys; const float (*vert_normals)[3]; const float (*poly_normals)[3]; + const bool *sharp_faces; const float (*clnors)[3]; ShrinkwrapBoundaryData *boundary; } ShrinkwrapTreeData; diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 1e7a0ac316f..12b8b96b0bc 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -143,11 +143,11 @@ set(SRC intern/geometry_fields.cc intern/geometry_set.cc intern/geometry_set_instances.cc - intern/gpencil.c - intern/gpencil_curve.c - intern/gpencil_geom.cc - intern/gpencil_modifier.c - intern/gpencil_update_cache.c + intern/gpencil_legacy.c + intern/gpencil_curve_legacy.c + intern/gpencil_geom_legacy.cc + intern/gpencil_modifier_legacy.c + intern/gpencil_update_cache_legacy.c intern/icons.cc intern/icons_rasterize.c intern/idprop.c @@ -251,6 +251,7 @@ set(SRC intern/pbvh_bmesh.cc intern/pbvh_colors.cc intern/pbvh_pixels.cc + intern/pbvh_pixels_copy.cc intern/pbvh_uv_islands.cc intern/pointcache.c intern/pointcloud.cc @@ -382,11 +383,11 @@ set(SRC BKE_geometry_set.hh BKE_geometry_set_instances.hh BKE_global.h - BKE_gpencil.h - BKE_gpencil_curve.h - BKE_gpencil_geom.h - BKE_gpencil_modifier.h - BKE_gpencil_update_cache.h + BKE_gpencil_legacy.h + BKE_gpencil_curve_legacy.h + BKE_gpencil_geom_legacy.h + BKE_gpencil_modifier_legacy.h + BKE_gpencil_update_cache_legacy.h BKE_icons.h BKE_idprop.h BKE_idprop.hh @@ -419,6 +420,7 @@ set(SRC BKE_mball.h BKE_mball_tessellate.h BKE_mesh.h + BKE_mesh.hh BKE_mesh_boolean_convert.hh BKE_mesh_fair.h BKE_mesh_iterators.h @@ -494,6 +496,7 @@ set(SRC nla_private.h particle_private.h tracking_private.h + intern/CCGSubSurf.h intern/CCGSubSurf_inline.h intern/CCGSubSurf_intern.h @@ -505,6 +508,7 @@ set(SRC intern/multires_unsubdivide.h intern/ocean_intern.h intern/pbvh_intern.hh + intern/pbvh_pixels_copy.hh intern/pbvh_uv_islands.hh intern/subdiv_converter.h intern/subdiv_inline.h diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 61ca1b81771..e42892ea937 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -42,7 +42,7 @@ #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_iterators.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" @@ -99,7 +99,7 @@ static float *dm_getVertArray(DerivedMesh *dm) if (!positions) { positions = (float(*)[3])CustomData_add_layer_named( - &dm->vertData, CD_PROP_FLOAT3, CD_SET_DEFAULT, nullptr, dm->getNumVerts(dm), "position"); + &dm->vertData, CD_PROP_FLOAT3, CD_SET_DEFAULT, dm->getNumVerts(dm), "position"); CustomData_set_layer_flag(&dm->vertData, CD_PROP_FLOAT3, CD_FLAG_TEMPORARY); dm->copyVertArray(dm, positions); } @@ -114,7 +114,7 @@ static MEdge *dm_getEdgeArray(DerivedMesh *dm) if (!edge) { edge = (MEdge *)CustomData_add_layer( - &dm->edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, dm->getNumEdges(dm)); + &dm->edgeData, CD_MEDGE, CD_SET_DEFAULT, dm->getNumEdges(dm)); CustomData_set_layer_flag(&dm->edgeData, CD_MEDGE, CD_FLAG_TEMPORARY); dm->copyEdgeArray(dm, edge); } @@ -129,7 +129,7 @@ static MLoop *dm_getLoopArray(DerivedMesh *dm) if (!mloop) { mloop = (MLoop *)CustomData_add_layer( - &dm->loopData, CD_MLOOP, CD_SET_DEFAULT, nullptr, dm->getNumLoops(dm)); + &dm->loopData, CD_MLOOP, CD_SET_DEFAULT, dm->getNumLoops(dm)); CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY); dm->copyLoopArray(dm, mloop); } @@ -144,7 +144,7 @@ static MPoly *dm_getPolyArray(DerivedMesh *dm) if (!mpoly) { mpoly = (MPoly *)CustomData_add_layer( - &dm->polyData, CD_MPOLY, CD_SET_DEFAULT, nullptr, dm->getNumPolys(dm)); + &dm->polyData, CD_MPOLY, CD_SET_DEFAULT, dm->getNumPolys(dm)); CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY); dm->copyPolyArray(dm, mpoly); } @@ -505,7 +505,7 @@ static void add_orco_mesh(Object *ob, BMEditMesh *em, Mesh *mesh, Mesh *mesh_orc layerorco = (float(*)[3])CustomData_get_layer_for_write(&mesh->vdata, layer, mesh->totvert); if (!layerorco) { layerorco = (float(*)[3])CustomData_add_layer( - &mesh->vdata, layer, CD_SET_DEFAULT, nullptr, mesh->totvert); + &mesh->vdata, eCustomDataType(layer), CD_SET_DEFAULT, mesh->totvert); } memcpy(layerorco, orco, sizeof(float[3]) * totvert); @@ -886,11 +886,11 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, ((nextmask.vmask | nextmask.emask | nextmask.pmask) & CD_MASK_ORIGINDEX)) { /* calc */ CustomData_add_layer( - &mesh_final->vdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totvert); + &mesh_final->vdata, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->totvert); CustomData_add_layer( - &mesh_final->edata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totedge); + &mesh_final->edata, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->totedge); CustomData_add_layer( - &mesh_final->pdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh_final->totpoly); + &mesh_final->pdata, CD_ORIGINDEX, CD_CONSTRUCT, mesh_final->totpoly); /* Not worth parallelizing this, * gives less than 0.1% overall speedup in best of best cases... */ @@ -929,11 +929,8 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph, /* add an origspace layer if needed */ if ((md_datamask->mask.lmask) & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer(&mesh_final->ldata, - CD_ORIGSPACE_MLOOP, - CD_SET_DEFAULT, - nullptr, - mesh_final->totloop); + CustomData_add_layer( + &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh_final->totloop); mesh_init_origspace(mesh_final); } } @@ -1380,11 +1377,8 @@ static void editbmesh_calc_modifiers(struct Depsgraph *depsgraph, if (mask.lmask & CD_MASK_ORIGSPACE_MLOOP) { if (!CustomData_has_layer(&mesh_final->ldata, CD_ORIGSPACE_MLOOP)) { - CustomData_add_layer(&mesh_final->ldata, - CD_ORIGSPACE_MLOOP, - CD_SET_DEFAULT, - nullptr, - mesh_final->totloop); + CustomData_add_layer( + &mesh_final->ldata, CD_ORIGSPACE_MLOOP, CD_SET_DEFAULT, mesh_final->totloop); mesh_init_origspace(mesh_final); } } @@ -1914,14 +1908,15 @@ static void mesh_init_origspace(Mesh *mesh) } else { const MLoop *l = &loops[poly.loopstart]; - float p_nor[3], co[3]; + float co[3]; float mat[3][3]; float min[2] = {FLT_MAX, FLT_MAX}, max[2] = {-FLT_MAX, -FLT_MAX}; float translate[2], scale[2]; - BKE_mesh_calc_poly_normal( - &poly, l, reinterpret_cast(positions.data()), p_nor); + const float3 p_nor = blender::bke::mesh::poly_normal_calc( + positions, loops.slice(poly.loopstart, poly.totloop)); + axis_dominant_v3_to_m3(mat, p_nor); vcos_2d.resize(poly.totloop); diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 8549f2df1dc..dea3319ac68 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -1408,7 +1408,7 @@ void calc_action_range(const bAction *act, float *start, float *end, short incl_ * single-keyframe curves will increase the overall length by * a phantom frame (#50354) */ - BKE_fcurve_calc_range(fcu, &nmin, &nmax, false, false); + BKE_fcurve_calc_range(fcu, &nmin, &nmax, false); /* compare to the running tally */ min = min_ff(min, nmin); diff --git a/source/blender/blenkernel/intern/armature_deform.c b/source/blender/blenkernel/intern/armature_deform.c index 973fdbd0c57..647c937737d 100644 --- a/source/blender/blenkernel/intern/armature_deform.c +++ b/source/blender/blenkernel/intern/armature_deform.c @@ -22,7 +22,7 @@ #include "BLI_utildefines.h" #include "DNA_armature_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_listBase.h" #include "DNA_mesh_types.h" @@ -515,7 +515,7 @@ static void armature_deform_coords_impl(const Object *ob_arm, dverts_len = lt->pntsu * lt->pntsv * lt->pntsw; } } - else if (ob_target->type == OB_GPENCIL) { + else if (ob_target->type == OB_GPENCIL_LEGACY) { target_data_id = (const ID *)ob_target->data; dverts = gps_target->dvert; if (dverts) { diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc index 8fa5fc5842b..051bb3d3584 100644 --- a/source/blender/blenkernel/intern/asset.cc +++ b/source/blender/blenkernel/intern/asset.cc @@ -44,6 +44,8 @@ AssetMetaData::~AssetMetaData() } MEM_SAFE_FREE(author); MEM_SAFE_FREE(description); + MEM_SAFE_FREE(copyright); + MEM_SAFE_FREE(license); BLI_freelistN(&tags); } @@ -161,13 +163,19 @@ void BKE_asset_metadata_write(BlendWriter *writer, AssetMetaData *asset_data) if (asset_data->properties) { IDP_BlendWrite(writer, asset_data->properties); } - if (asset_data->author) { BLO_write_string(writer, asset_data->author); } if (asset_data->description) { BLO_write_string(writer, asset_data->description); } + if (asset_data->copyright) { + BLO_write_string(writer, asset_data->copyright); + } + if (asset_data->license) { + BLO_write_string(writer, asset_data->license); + } + LISTBASE_FOREACH (AssetTag *, tag, &asset_data->tags) { BLO_write_struct(writer, AssetTag, tag); } @@ -185,6 +193,8 @@ void BKE_asset_metadata_read(BlendDataReader *reader, AssetMetaData *asset_data) BLO_read_data_address(reader, &asset_data->author); BLO_read_data_address(reader, &asset_data->description); + BLO_read_data_address(reader, &asset_data->copyright); + BLO_read_data_address(reader, &asset_data->license); BLO_read_list(reader, &asset_data->tags); BLI_assert(BLI_listbase_count(&asset_data->tags) == asset_data->tot_tags); } diff --git a/source/blender/blenkernel/intern/attribute.cc b/source/blender/blenkernel/intern/attribute.cc index 32d12e1af17..3922d5b5238 100644 --- a/source/blender/blenkernel/intern/attribute.cc +++ b/source/blender/blenkernel/intern/attribute.cc @@ -31,7 +31,7 @@ #include "BKE_curves.hh" #include "BKE_customdata.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "BKE_report.h" @@ -778,11 +778,6 @@ const char *BKE_id_attributes_default_color_name(const ID *id) return nullptr; } -CustomDataLayer *BKE_id_attributes_active_color_get(const ID *id) -{ - return BKE_id_attributes_color_find(id, BKE_id_attributes_active_color_name(id)); -} - void BKE_id_attributes_active_color_set(ID *id, const char *name) { switch (GS(id->name)) { @@ -799,11 +794,6 @@ void BKE_id_attributes_active_color_set(ID *id, const char *name) } } -CustomDataLayer *BKE_id_attributes_default_color_get(const ID *id) -{ - return BKE_id_attributes_color_find(id, BKE_id_attributes_default_color_name(id)); -} - void BKE_id_attributes_default_color_set(ID *id, const char *name) { switch (GS(id->name)) { @@ -822,71 +812,22 @@ void BKE_id_attributes_default_color_set(ID *id, const char *name) CustomDataLayer *BKE_id_attributes_color_find(const ID *id, const char *name) { - if (!name) { - return nullptr; + if (CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT)) { + return layer; } - CustomDataLayer *layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_POINT); - if (layer == nullptr) { - layer = BKE_id_attribute_find(id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER); + if (CustomDataLayer *layer = BKE_id_attribute_find( + id, name, CD_PROP_COLOR, ATTR_DOMAIN_CORNER)) { + return layer; } - if (layer == nullptr) { - layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_POINT); + if (CustomDataLayer *layer = BKE_id_attribute_find( + id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_POINT)) { + return layer; } - if (layer == nullptr) { - layer = BKE_id_attribute_find(id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER); + if (CustomDataLayer *layer = BKE_id_attribute_find( + id, name, CD_PROP_BYTE_COLOR, ATTR_DOMAIN_CORNER)) { + return layer; } - - return layer; -} - -void BKE_id_attribute_copy_domains_temp(short id_type, - const CustomData *vdata, - const CustomData *edata, - const CustomData *ldata, - const CustomData *pdata, - const CustomData *cdata, - ID *r_id) -{ - CustomData reset; - - CustomData_reset(&reset); - - switch (id_type) { - case ID_ME: { - Mesh *me = (Mesh *)r_id; - memset((void *)me, 0, sizeof(*me)); - - me->edit_mesh = nullptr; - - me->vdata = vdata ? *vdata : reset; - me->edata = edata ? *edata : reset; - me->ldata = ldata ? *ldata : reset; - me->pdata = pdata ? *pdata : reset; - - break; - } - case ID_PT: { - PointCloud *pointcloud = (PointCloud *)r_id; - - memset((void *)pointcloud, 0, sizeof(*pointcloud)); - - pointcloud->pdata = vdata ? *vdata : reset; - break; - } - case ID_CV: { - Curves *curves = (Curves *)r_id; - - memset((void *)curves, 0, sizeof(*curves)); - - curves->geometry.point_data = vdata ? *vdata : reset; - curves->geometry.curve_data = cdata ? *cdata : reset; - break; - } - default: - break; - } - - *((short *)r_id->name) = id_type; + return nullptr; } const char *BKE_uv_map_vert_select_name_get(const char *uv_map_name, char *buffer) diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 2ba03b6d1cf..94402c199b9 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -6,7 +6,7 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_geometry_set.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "BKE_type_conversions.hh" @@ -63,6 +63,9 @@ bool allow_procedural_attribute_access(StringRef attribute_name) if (attribute_name.startswith(".hide")) { return false; } + if (attribute_name.startswith(".uv")) { + return false; + } if (attribute_name.startswith("." UV_VERTSEL_NAME ".")) { return false; } @@ -178,18 +181,15 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data { switch (initializer.type) { case AttributeInit::Type::Construct: { - void *data = CustomData_add_layer( - &custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num); + void *data = CustomData_add_layer(&custom_data, data_type, CD_CONSTRUCT, domain_num); return data != nullptr; } case AttributeInit::Type::DefaultValue: { - void *data = CustomData_add_layer( - &custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num); + void *data = CustomData_add_layer(&custom_data, data_type, CD_SET_DEFAULT, domain_num); return data != nullptr; } case AttributeInit::Type::VArray: { - void *data = CustomData_add_layer( - &custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num); + void *data = CustomData_add_layer(&custom_data, data_type, CD_CONSTRUCT, domain_num); if (data == nullptr) { return false; } @@ -199,8 +199,8 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data } case AttributeInit::Type::MoveArray: { void *source_data = static_cast(initializer).data; - void *data = CustomData_add_layer( - &custom_data, data_type, CD_ASSIGN, source_data, domain_num); + const void *data = CustomData_add_layer_with_data( + &custom_data, data_type, source_data, domain_num); if (data == nullptr) { MEM_freeN(source_data); return false; @@ -216,19 +216,36 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data static void *add_generic_custom_data_layer(CustomData &custom_data, const eCustomDataType data_type, const eCDAllocType alloctype, - void *layer_data, - const int domain_num, + const int domain_size, const AttributeIDRef &attribute_id) { if (!attribute_id.is_anonymous()) { char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME]; attribute_id.name().copy(attribute_name_c); return CustomData_add_layer_named( - &custom_data, data_type, alloctype, layer_data, domain_num, attribute_name_c); + &custom_data, data_type, alloctype, domain_size, attribute_name_c); } const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); return CustomData_add_layer_anonymous( - &custom_data, data_type, alloctype, layer_data, domain_num, &anonymous_id); + &custom_data, data_type, alloctype, nullptr, domain_size, &anonymous_id); +} + +static const void *add_generic_custom_data_layer_with_existing_data( + CustomData &custom_data, + const eCustomDataType data_type, + void *layer_data, + const int domain_size, + const AttributeIDRef &attribute_id) +{ + if (!attribute_id.is_anonymous()) { + char attribute_name_c[MAX_CUSTOMDATA_LAYER_NAME]; + attribute_id.name().copy(attribute_name_c); + return CustomData_add_layer_named_with_data( + &custom_data, data_type, layer_data, domain_size, attribute_name_c); + } + const AnonymousAttributeID &anonymous_id = attribute_id.anonymous_id(); + return CustomData_add_layer_anonymous( + &custom_data, data_type, CD_ASSIGN, layer_data, domain_size, &anonymous_id); } static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attribute_id, @@ -241,17 +258,17 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr switch (initializer.type) { case AttributeInit::Type::Construct: { add_generic_custom_data_layer( - custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_CONSTRUCT, domain_num, attribute_id); break; } case AttributeInit::Type::DefaultValue: { add_generic_custom_data_layer( - custom_data, data_type, CD_SET_DEFAULT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_SET_DEFAULT, domain_num, attribute_id); break; } case AttributeInit::Type::VArray: { void *data = add_generic_custom_data_layer( - custom_data, data_type, CD_CONSTRUCT, nullptr, domain_num, attribute_id); + custom_data, data_type, CD_CONSTRUCT, domain_num, attribute_id); if (data != nullptr) { const GVArray &varray = static_cast(initializer).varray; varray.materialize_to_uninitialized(varray.index_range(), data); @@ -260,8 +277,8 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr } case AttributeInit::Type::MoveArray: { void *source_data = static_cast(initializer).data; - add_generic_custom_data_layer( - custom_data, data_type, CD_ASSIGN, source_data, domain_num, attribute_id); + add_generic_custom_data_layer_with_existing_data( + custom_data, data_type, source_data, domain_num, attribute_id); break; } } @@ -630,7 +647,7 @@ bool CustomDataAttributes::create(const AttributeIDRef &attribute_id, const eCustomDataType data_type) { void *result = add_generic_custom_data_layer( - data, data_type, CD_SET_DEFAULT, nullptr, size_, attribute_id); + data, data_type, CD_SET_DEFAULT, size_, attribute_id); return result != nullptr; } @@ -638,8 +655,8 @@ bool CustomDataAttributes::create_by_move(const AttributeIDRef &attribute_id, const eCustomDataType data_type, void *buffer) { - void *result = add_generic_custom_data_layer( - data, data_type, CD_ASSIGN, buffer, size_, attribute_id); + const void *result = add_generic_custom_data_layer_with_existing_data( + data, data_type, buffer, size_, attribute_id); return result != nullptr; } diff --git a/source/blender/blenkernel/intern/blendfile.cc b/source/blender/blenkernel/intern/blendfile.cc index a0ecb0c95b5..0d12ddf152e 100644 --- a/source/blender/blenkernel/intern/blendfile.cc +++ b/source/blender/blenkernel/intern/blendfile.cc @@ -14,6 +14,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_space_types.h" #include "DNA_workspace_types.h" #include "BLI_fileops.h" @@ -62,6 +63,81 @@ # include "BPY_extern.h" #endif +/* -------------------------------------------------------------------- */ +/** \name Blend/Library Paths + * \{ */ + +bool BKE_blendfile_extension_check(const char *str) +{ + const char *ext_test[4] = {".blend", ".ble", ".blend.gz", nullptr}; + return BLI_path_extension_check_array(str, ext_test); +} + +bool BKE_blendfile_library_path_explode(const char *path, + char *r_dir, + char **r_group, + char **r_name) +{ + /* We might get some data names with slashes, + * so we have to go up in path until we find blend file itself, + * then we know next path item is group, and everything else is data name. */ + char *slash = nullptr, *prev_slash = nullptr, c = '\0'; + + r_dir[0] = '\0'; + if (r_group) { + *r_group = nullptr; + } + if (r_name) { + *r_name = nullptr; + } + + /* if path leads to an existing directory, we can be sure we're not (in) a library */ + if (BLI_is_dir(path)) { + return false; + } + + BLI_strncpy(r_dir, path, FILE_MAX_LIBEXTRA); + + while ((slash = (char *)BLI_path_slash_rfind(r_dir))) { + char tc = *slash; + *slash = '\0'; + if (BKE_blendfile_extension_check(r_dir) && BLI_is_file(r_dir)) { + break; + } + if (STREQ(r_dir, BLO_EMBEDDED_STARTUP_BLEND)) { + break; + } + + if (prev_slash) { + *prev_slash = c; + } + prev_slash = slash; + c = tc; + } + + if (!slash) { + return false; + } + + if (slash[1] != '\0') { + BLI_assert(strlen(slash + 1) < BLO_GROUP_MAX); + if (r_group) { + *r_group = slash + 1; + } + } + + if (prev_slash && (prev_slash[1] != '\0')) { + BLI_assert(strlen(prev_slash + 1) < MAX_ID_NAME - 2); + if (r_name) { + *r_name = prev_slash + 1; + } + } + + return true; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Blend File IO (High Level) * \{ */ @@ -506,7 +582,7 @@ struct BlendFileData *BKE_blendfile_read(const char *filepath, { /* Don't print startup file loading. */ if (params->is_startup == false) { - printf("Read blend: %s\n", filepath); + printf("Read blend: \"%s\"\n", filepath); } BlendFileData *bfd = BLO_read_from_file(filepath, eBLOReadSkip(params->skip_flags), reports); @@ -518,7 +594,7 @@ struct BlendFileData *BKE_blendfile_read(const char *filepath, handle_subversion_warning(bfd->main, reports); } else { - BKE_reports_prependf(reports->reports, "Loading '%s' failed: ", filepath); + BKE_reports_prependf(reports->reports, "Loading \"%s\" failed: ", filepath); } return bfd; } @@ -768,7 +844,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports) bool ok_write; BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE); - printf("Writing userprefs: '%s' ", filepath); + printf("Writing userprefs: \"%s\" ", filepath); if (use_template_userpref) { ok_write = BKE_blendfile_userdef_write_app_template(filepath, reports); } @@ -795,7 +871,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports) /* Also save app-template prefs */ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE); - printf("Writing userprefs app-template: '%s' ", filepath); + printf("Writing userprefs app-template: \"%s\" ", filepath); if (BKE_blendfile_userdef_write(filepath, reports) != 0) { printf("ok\n"); } diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index cd2be70530b..73f415ac058 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -8,7 +8,7 @@ #include "DNA_brush_types.h" #include "DNA_defaults.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -23,7 +23,7 @@ #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_icons.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc index 5a9d008ed88..feb2577e09f 100644 --- a/source/blender/blenkernel/intern/bvhutils.cc +++ b/source/blender/blenkernel/intern/bvhutils.cc @@ -24,7 +24,7 @@ #include "BKE_attribute.hh" #include "BKE_bvhutils.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/blenkernel/intern/callbacks.c b/source/blender/blenkernel/intern/callbacks.c index 66364186d32..604b04dc296 100644 --- a/source/blender/blenkernel/intern/callbacks.c +++ b/source/blender/blenkernel/intern/callbacks.c @@ -69,6 +69,18 @@ void BKE_callback_exec_id_depsgraph(struct Main *bmain, BKE_callback_exec(bmain, pointers, 2, evt); } +void BKE_callback_exec_string(struct Main *bmain, eCbEvent evt, const char *str) +{ + PointerRNA str_ptr; + PrimitiveStringRNA data = {NULL}; + data.value = str; + RNA_pointer_create(NULL, &RNA_PrimitiveString, &data, &str_ptr); + + PointerRNA *pointers[1] = {&str_ptr}; + + BKE_callback_exec(bmain, pointers, 1, evt); +} + void BKE_callback_add(bCallbackFuncStore *funcstore, eCbEvent evt) { ASSERT_CALLBACKS_INITIALIZED(); diff --git a/source/blender/blenkernel/intern/cdderivedmesh.cc b/source/blender/blenkernel/intern/cdderivedmesh.cc index 37ad64f7f21..9d244f1b441 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.cc +++ b/source/blender/blenkernel/intern/cdderivedmesh.cc @@ -20,7 +20,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_curve.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -39,7 +39,7 @@ struct CDDerivedMesh { /* these point to data in the DerivedMesh custom data layers, * they are only here for efficiency and convenience */ float (*vert_positions)[3]; - const float (*vert_normals)[3]; + const blender::float3 *vert_normals; MEdge *medge; MFace *mface; MLoop *mloop; @@ -121,12 +121,11 @@ static void cdDM_recalc_looptri(DerivedMesh *dm) DM_ensure_looptri_data(dm); BLI_assert(totpoly == 0 || cddm->dm.looptris.array_wip != NULL); - BKE_mesh_recalc_looptri(cddm->mloop, - cddm->mpoly, - cddm->vert_positions, - totloop, - totpoly, - cddm->dm.looptris.array_wip); + blender::bke::mesh::looptris_calc( + {reinterpret_cast(cddm->vert_positions), dm->numVertData}, + {cddm->mpoly, totpoly}, + {cddm->mloop, totloop}, + {dm->looptris.array_wip, dm->looptris.num}); BLI_assert(cddm->dm.looptris.array == NULL); atomic_cas_ptr( @@ -222,7 +221,7 @@ static DerivedMesh *cdDM_from_mesh_ex(Mesh *mesh, &dm->vertData, CD_PROP_FLOAT3, "position", mesh->totvert)); /* Though this may be an unnecessary calculation, simply retrieving the layer may return nothing * or dirty normals. */ - cddm->vert_normals = BKE_mesh_vert_normals_ensure(mesh); + cddm->vert_normals = mesh->vert_normals().data(); cddm->medge = static_cast( CustomData_get_layer_for_write(&dm->edgeData, CD_MEDGE, mesh->totedge)); cddm->mloop = static_cast( diff --git a/source/blender/blenkernel/intern/cloth.cc b/source/blender/blenkernel/intern/cloth.cc index ae7ebb8f96f..f83e8056109 100644 --- a/source/blender/blenkernel/intern/cloth.cc +++ b/source/blender/blenkernel/intern/cloth.cc @@ -27,7 +27,7 @@ #include "BKE_effect.h" #include "BKE_global.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_pointcache.h" @@ -1387,7 +1387,7 @@ BLI_INLINE bool cloth_bend_set_poly_vert_array(int **poly, int len, const MLoop } static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata, - const float (*vert_normals)[3], + const blender::Span vert_normals, uint v_idx, RNG *rng, float max_length, @@ -1530,7 +1530,8 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh) BKE_bvhtree_from_mesh_get(&treedata, tmp_mesh ? tmp_mesh : mesh, BVHTREE_FROM_LOOPTRI, 2); rng = BLI_rng_new_srandom(0); - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(tmp_mesh ? tmp_mesh : mesh); + const blender::Span vert_normals = tmp_mesh ? tmp_mesh->vert_normals() : + mesh->vert_normals(); for (int i = 0; i < mvert_num; i++) { if (find_internal_spring_target_vertex( diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 55fb7112942..014dff8c181 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -83,17 +83,10 @@ static bool collection_find_child_recursive(const Collection *parent, const Collection *collection); static void collection_gobject_hash_ensure(Collection *collection); -static void collection_gobject_hash_remove_object(Collection *collection, const Object *ob); static void collection_gobject_hash_update_object(Collection *collection, Object *ob_old, CollectionObject *cob); -/** Does nothing unless #USE_DEBUG_EXTRA_GOBJECT_ASSERT is defined. */ -static void collection_gobject_hash_assert_internal_consistency(Collection *collection); - -#define BLI_ASSERT_COLLECION_GOBJECT_HASH_IS_VALID(collection) \ - collection_gobject_hash_assert_internal_consistency(collection) - /** \} */ /* -------------------------------------------------------------------- */ @@ -183,8 +176,16 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, cob->ob, IDWALK_CB_USER); if (collection->runtime.gobject_hash) { + /* If the remapping does not create inconsistent data (NULL object pointer or duplicate + * CollectionObjects), keeping the ghash consistent is also possible. Otherwise, this call + * will take care of tagging the collection objects list as dirty. */ collection_gobject_hash_update_object(collection, cob_ob_old, cob); } + else if (cob_ob_old != cob->ob || cob->ob == NULL) { + /* If there is no reference GHash, duplicates cannot be reliably detected, so assume that any + * NULL pointer or changed pointer may create an invalid collection object list. */ + collection->runtime.tag |= COLLECTION_TAG_COLLECTION_OBJECT_DIRTY; + } } LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { BKE_LIB_FOREACHID_PROCESS_IDSUPER( @@ -983,7 +984,6 @@ bool BKE_collection_has_object(Collection *collection, const Object *ob) if (ELEM(NULL, collection, ob)) { return false; } - BLI_ASSERT_COLLECION_GOBJECT_HASH_IS_VALID(collection); collection_gobject_hash_ensure(collection); return BLI_ghash_lookup(collection->runtime.gobject_hash, ob); } @@ -1053,6 +1053,173 @@ bool BKE_collection_is_empty(const Collection *collection) /** \name Collection Objects * \{ */ +static void collection_gobject_assert_internal_consistency(Collection *collection, + const bool do_extensive_check); + +static GHash *collection_gobject_hash_alloc(const Collection *collection) +{ + return BLI_ghash_ptr_new_ex(__func__, (uint)BLI_listbase_count(&collection->gobject)); +} + +static void collection_gobject_hash_create(Collection *collection) +{ + GHash *gobject_hash = collection_gobject_hash_alloc(collection); + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + if (UNLIKELY(cob->ob == NULL)) { + BLI_assert(collection->runtime.tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY); + continue; + } + CollectionObject **cob_p; + /* Do not overwrite an already existing entry. */ + if (UNLIKELY(BLI_ghash_ensure_p(gobject_hash, cob->ob, (void ***)&cob_p))) { + BLI_assert(collection->runtime.tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY); + continue; + } + *cob_p = cob; + } + collection->runtime.gobject_hash = gobject_hash; +} + +static void collection_gobject_hash_ensure(Collection *collection) +{ + if (collection->runtime.gobject_hash) { +#ifdef USE_DEBUG_EXTRA_GOBJECT_ASSERT + collection_gobject_assert_internal_consistency(collection, true); +#endif + return; + } + + collection_gobject_hash_create(collection); + + collection_gobject_assert_internal_consistency(collection, true); +} + +/** Similar to #collection_gobject_hash_ensure/#collection_gobject_hash_create, but does fix + * inconsistencies in the collection objects list. */ +static void collection_gobject_hash_ensure_fix(Collection *collection) +{ + bool changed = false; + + if ((collection->runtime.tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY) == 0) { +#ifdef USE_DEBUG_EXTRA_GOBJECT_ASSERT + collection_gobject_assert_internal_consistency(collection, true); +#endif + return; + } + + GHash *gobject_hash = collection->runtime.gobject_hash; + if (gobject_hash) { + BLI_ghash_clear_ex(gobject_hash, NULL, NULL, BLI_ghash_len(gobject_hash)); + } + else { + collection->runtime.gobject_hash = gobject_hash = collection_gobject_hash_alloc(collection); + } + + LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) { + if (cob->ob == NULL) { + BLI_freelinkN(&collection->gobject, cob); + changed = true; + continue; + } + CollectionObject **cob_p; + if (BLI_ghash_ensure_p(gobject_hash, cob->ob, (void ***)&cob_p)) { + BLI_freelinkN(&collection->gobject, cob); + changed = true; + continue; + } + *cob_p = cob; + } + + if (changed) { + BKE_collection_object_cache_free(collection); + } + + collection->runtime.tag &= ~COLLECTION_TAG_COLLECTION_OBJECT_DIRTY; + collection_gobject_assert_internal_consistency(collection, true); +} + +/** + * Update the collections object hash, removing `ob_old`, inserting `cob->ob` as the new key. + * + * \note This function is called from #IDTypeInfo::foreach_id callback, + * and a difference of Object pointers is only expected in case ID remapping is happening. + * This code is the only are in Blender allowed to (temporarily) leave the #CollectionObject list + * in an inconsistent/invalid state (with NULL object pointers, or duplicates of + * #CollectionObjects). If such invalid cases are encountered, + * it will tag the collection objects list as dirty. + * + * \param ob_old: The existing key to `cob` in the hash, not removed when NULL. + * \param cob: The `cob->ob` is to be used as the new key, + * when NULL it's not added back into the hash. + */ +static void collection_gobject_hash_update_object(Collection *collection, + Object *ob_old, + CollectionObject *cob) +{ + if (ob_old == cob->ob) { + return; + } + + if (ob_old) { + CollectionObject *cob_old = BLI_ghash_popkey(collection->runtime.gobject_hash, ob_old, NULL); + if (cob_old != cob) { + /* Old object already removed from the #GHash. */ + collection->runtime.tag |= COLLECTION_TAG_COLLECTION_OBJECT_DIRTY; + } + } + + if (cob->ob) { + CollectionObject **cob_p; + if (!BLI_ghash_ensure_p(collection->runtime.gobject_hash, cob->ob, (void ***)&cob_p)) { + *cob_p = cob; + } + else { + /* Duplicate #CollectionObject entries. */ + collection->runtime.tag |= COLLECTION_TAG_COLLECTION_OBJECT_DIRTY; + } + } + else { + /* #CollectionObject with NULL object pointer. */ + collection->runtime.tag |= COLLECTION_TAG_COLLECTION_OBJECT_DIRTY; + } +} + +/** + * Validate the integrity of the collection's #CollectionObject list, and of its mapping. + * + * Simple test is very fast, as it only checks that the 'dirty' tag for collection's objects is not + * set. + * + * The extensive check is expensive. This should not be done from within loops over collections + * items, or from low-level operations that can be assumed safe (like adding or removing an object + * from a collection). It ensures that: + * - There is a `gobject_hash` mapping. + * - There is no NULL-object #CollectionObject items. + * - there is no duplicate #CollectionObject items (two or more referencing the same Object). + */ +static void collection_gobject_assert_internal_consistency(Collection *collection, + const bool do_extensive_check) +{ + BLI_assert((collection->runtime.tag & COLLECTION_TAG_COLLECTION_OBJECT_DIRTY) == 0); + if (!do_extensive_check) { + return; + } + + if (collection->runtime.gobject_hash == NULL) { + /* NOTE: If the `ghash` does not exist yet, it's creation will assert on errors, + * so in theory the second loop below could be skipped. */ + collection_gobject_hash_create(collection); + } + GHash *gobject_hash = collection->runtime.gobject_hash; + UNUSED_VARS_NDEBUG(gobject_hash); + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + BLI_assert(cob->ob != NULL); + /* If there are more than one #CollectionObject for the same object, + * at most one of them will pass this test. */ + BLI_assert(BLI_ghash_lookup(gobject_hash, cob->ob) == cob); + } +} + static void collection_tag_update_parent_recursive(Main *bmain, Collection *collection, const int flag) @@ -1336,83 +1503,14 @@ bool BKE_scene_collections_object_remove(Main *bmain, Scene *scene, Object *ob, return scene_collections_object_remove(bmain, scene, ob, free_us, NULL); } -/* - * Remove all NULL objects from collections. - * This is used for library remapping, where these pointers have been set to NULL. - * Otherwise this should never happen. - */ -static void collection_object_remove_nulls(Collection *collection) -{ - bool changed = false; - - LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) { - if (cob->ob == NULL) { - BLI_freelinkN(&collection->gobject, cob); - changed = true; - } - } - - if (changed) { - BKE_collection_object_cache_free(collection); - } -} - -void BKE_collections_object_remove_nulls(Main *bmain) +void BKE_collections_object_remove_invalids(Main *bmain) { LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - collection_object_remove_nulls(scene->master_collection); + collection_gobject_hash_ensure_fix(scene->master_collection); } LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - collection_object_remove_nulls(collection); - } -} - -/* - * Remove all duplicate objects from collections. - * This is used for library remapping, happens when remapping an object to another one already - * present in the collection. Otherwise this should never happen. - */ -static void collection_object_remove_duplicates(Collection *collection) -{ - bool changed = false; - BLI_ASSERT_COLLECION_GOBJECT_HASH_IS_VALID(collection); - const bool use_hash_exists = (collection->runtime.gobject_hash != NULL); - - LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) { - if (cob->ob->runtime.collection_management) { - if (use_hash_exists) { - collection_gobject_hash_remove_object(collection, cob->ob); - } - BLI_freelinkN(&collection->gobject, cob); - changed = true; - continue; - } - cob->ob->runtime.collection_management = true; - } - - /* Cleanup. */ - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - cob->ob->runtime.collection_management = false; - } - - if (changed) { - BKE_collection_object_cache_free(collection); - } -} - -void BKE_collections_object_remove_duplicates(struct Main *bmain) -{ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - ob->runtime.collection_management = false; - } - - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - collection_object_remove_duplicates(scene->master_collection); - } - - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - collection_object_remove_duplicates(collection); + collection_gobject_hash_ensure_fix(collection); } } @@ -1646,79 +1744,6 @@ static CollectionParent *collection_find_parent(Collection *child, Collection *c return BLI_findptr(&child->runtime.parents, collection, offsetof(CollectionParent, collection)); } -static void collection_gobject_hash_ensure(Collection *collection) -{ - if (collection->runtime.gobject_hash) { - BLI_ASSERT_COLLECION_GOBJECT_HASH_IS_VALID(collection); - return; - } - GHash *gobject_hash = BLI_ghash_ptr_new_ex(__func__, BLI_listbase_count(&collection->gobject)); - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - BLI_ghash_insert(gobject_hash, cob->ob, cob); - } - collection->runtime.gobject_hash = gobject_hash; - - BLI_ASSERT_COLLECION_GOBJECT_HASH_IS_VALID(collection); -} - -static void collection_gobject_hash_remove_object(Collection *collection, const Object *ob) -{ - const bool found = BLI_ghash_remove(collection->runtime.gobject_hash, ob, NULL, NULL); - BLI_assert(found); - UNUSED_VARS_NDEBUG(found); -} - -/** - * Update the collections object hash, removing `ob_old`, inserting `cob->ob` as the new key. - * - * \param ob_old: The existing key to `cob` in the hash, not removed when NULL. - * \param cob: The `cob->ob` is to be used as the new key, - * when NULL it's not added back into the hash. - */ -static void collection_gobject_hash_update_object(Collection *collection, - Object *ob_old, - CollectionObject *cob) -{ - if (ob_old == cob->ob) { - return; - } - BLI_ASSERT_COLLECION_GOBJECT_HASH_IS_VALID(collection); - if (ob_old) { - collection_gobject_hash_remove_object(collection, ob_old); - } - /* The object may be set to NULL if the ID is being cleared from #collection_foreach_id, - * generally `cob->ob` is not expected to be NULL. */ - if (cob->ob) { - BLI_ghash_insert(collection->runtime.gobject_hash, cob->ob, cob); - } -} - -/** - * Should only be called by: #BLI_ASSERT_COLLECION_GOBJECT_HASH_IS_VALID macro, - * this is an expensive operation intended only to be used for debugging. - */ -static void collection_gobject_hash_assert_internal_consistency(Collection *collection) -{ -#ifdef USE_DEBUG_EXTRA_GOBJECT_ASSERT - if (collection->runtime.gobject_hash == NULL) { - return; - } - GHash *gobject_hash = collection->runtime.gobject_hash; - int gobject_count = 0; - - LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - CollectionObject *cob_test = BLI_ghash_lookup(gobject_hash, cob->ob); - BLI_assert(cob == cob_test); - gobject_count += 1; - } - - const int gobject_hash_count = BLI_ghash_len(gobject_hash); - BLI_assert(gobject_count == gobject_hash_count); -#else - UNUSED_VARS(collection); -#endif /* USE_DEBUG_EXTRA_GOBJECT_ASSERT */ -} - static bool collection_child_add(Collection *parent, Collection *collection, const int flag, diff --git a/source/blender/blenkernel/intern/context.cc b/source/blender/blenkernel/intern/context.cc index 114ed1a49c8..36eec388622 100644 --- a/source/blender/blenkernel/intern/context.cc +++ b/source/blender/blenkernel/intern/context.cc @@ -11,7 +11,7 @@ #include "MEM_guardedalloc.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_linestyle_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -1493,6 +1493,11 @@ AssetHandle CTX_wm_asset_handle(const bContext *C, bool *r_is_valid) return AssetHandle{nullptr}; } +AssetRepresentation *CTX_wm_asset(const bContext *C) +{ + return static_cast(ctx_data_pointer_get(C, "asset")); +} + Depsgraph *CTX_data_depsgraph_pointer(const bContext *C) { Main *bmain = CTX_data_main(C); diff --git a/source/blender/blenkernel/intern/crazyspace.cc b/source/blender/blenkernel/intern/crazyspace.cc index dc9dfc9f199..0f1cd0a2f06 100644 --- a/source/blender/blenkernel/intern/crazyspace.cc +++ b/source/blender/blenkernel/intern/crazyspace.cc @@ -24,7 +24,7 @@ #include "BKE_editmesh.h" #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_multires.h" diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 869db006ce4..d0b986b7006 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -410,7 +410,7 @@ void BKE_curve_init(Curve *cu, const short curve_type) } cu->bevel_profile = nullptr; /* Initialize the offset to 1.0, to compensate for it being set to -1.0 - in the property getter. */ + * in the property getter. */ cu->offset = 1.0f; } diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 44472a94e7a..d90da24f2b2 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -12,7 +12,7 @@ #include "BKE_curves.hh" #include "BKE_geometry_set.hh" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_curve_to_mesh.hh" @@ -103,7 +103,6 @@ static void fill_mesh_topology(const int vert_offset, MPoly &poly = polys[ring_poly_offset + i_profile]; poly.loopstart = ring_segment_loop_offset; poly.totloop = 4; - poly.flag = ME_SMOOTH; MLoop &loop_a = loops[ring_segment_loop_offset]; loop_a.v = ring_vert_offset + i_profile; @@ -674,6 +673,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write(); foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) { fill_mesh_topology(info.vert_range.start(), @@ -690,6 +690,23 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, polys); }); + if (fill_caps) { + /* TODO: This is used to keep the tests passing after refactoring mesh shade smooth flags. It + * can be removed if the tests are updated and the final shading results will be the same. */ + SpanAttributeWriter sharp_faces = mesh_attributes.lookup_or_add_for_write_span( + "sharp_face", ATTR_DOMAIN_FACE); + foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) { + const bool has_caps = fill_caps && !info.main_cyclic && info.profile_cyclic; + if (has_caps) { + const int poly_num = info.main_segment_num * info.profile_segment_num; + const int cap_poly_offset = info.poly_range.start() + poly_num; + sharp_faces.span[cap_poly_offset] = true; + sharp_faces.span[cap_poly_offset + 1] = true; + } + }); + sharp_faces.finish(); + } + const Span main_positions = main.evaluated_positions(); const Span tangents = main.evaluated_tangents(); const Span normals = main.evaluated_normals(); @@ -721,8 +738,6 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, positions.slice(info.vert_range)); }); - MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write(); - SpanAttributeWriter sharp_edges; write_sharp_bezier_edges(curves_info, offsets, mesh_attributes, sharp_edges); if (fill_caps) { diff --git a/source/blender/blenkernel/intern/curves.cc b/source/blender/blenkernel/intern/curves.cc index 2ee37129b11..0dbdbaf0a57 100644 --- a/source/blender/blenkernel/intern/curves.cc +++ b/source/blender/blenkernel/intern/curves.cc @@ -130,30 +130,12 @@ static void curves_blend_write(BlendWriter *writer, ID *id, const void *id_addre { Curves *curves = (Curves *)id; - Vector point_layers; - Vector curve_layers; - CustomData_blend_write_prepare(curves->geometry.point_data, point_layers); - CustomData_blend_write_prepare(curves->geometry.curve_data, curve_layers); - /* Write LibData */ BLO_write_id_struct(writer, Curves, id_address, &curves->id); BKE_id_blend_write(writer, &curves->id); /* Direct data */ - CustomData_blend_write(writer, - &curves->geometry.point_data, - point_layers, - curves->geometry.point_num, - CD_MASK_ALL, - &curves->id); - CustomData_blend_write(writer, - &curves->geometry.curve_data, - curve_layers, - curves->geometry.curve_num, - CD_MASK_ALL, - &curves->id); - - BLO_write_int32_array(writer, curves->geometry.curve_num + 1, curves->geometry.curve_offsets); + curves->geometry.wrap().blend_write(*writer, curves->id); BLO_write_string(writer, curves->surface_uv_map); @@ -170,10 +152,7 @@ static void curves_blend_read_data(BlendDataReader *reader, ID *id) BKE_animdata_blend_read_data(reader, curves->adt); /* Geometry */ - CustomData_blend_read(reader, &curves->geometry.point_data, curves->geometry.point_num); - CustomData_blend_read(reader, &curves->geometry.curve_data, curves->geometry.curve_num); - - BLO_read_int32_array(reader, curves->geometry.curve_num + 1, &curves->geometry.curve_offsets); + curves->geometry.wrap().blend_read(*reader); BLO_read_data_address(reader, &curves->surface_uv_map); diff --git a/source/blender/blenkernel/intern/curves_geometry.cc b/source/blender/blenkernel/intern/curves_geometry.cc index be0af1eb8a9..241c84c5dc4 100644 --- a/source/blender/blenkernel/intern/curves_geometry.cc +++ b/source/blender/blenkernel/intern/curves_geometry.cc @@ -17,11 +17,14 @@ #include "BLI_math_rotation_legacy.hh" #include "BLI_task.hh" +#include "BLO_read_write.h" + #include "DNA_curves_types.h" #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_curves_utils.hh" +#include "BKE_customdata.h" namespace blender::bke { @@ -56,12 +59,8 @@ CurvesGeometry::CurvesGeometry(const int point_num, const int curve_num) CustomData_reset(&this->point_data); CustomData_reset(&this->curve_data); - CustomData_add_layer_named(&this->point_data, - CD_PROP_FLOAT3, - CD_CONSTRUCT, - nullptr, - this->point_num, - ATTR_POSITION.c_str()); + CustomData_add_layer_named( + &this->point_data, CD_PROP_FLOAT3, CD_CONSTRUCT, this->point_num, ATTR_POSITION.c_str()); this->curve_offsets = (int *)MEM_malloc_arrayN(this->curve_num + 1, sizeof(int), __func__); #ifdef DEBUG @@ -227,8 +226,7 @@ static MutableSpan get_mutable_attribute(CurvesGeometry &curves, if (data != nullptr) { return {data, num}; } - data = (T *)CustomData_add_layer_named( - &custom_data, type, CD_SET_DEFAULT, nullptr, num, name.c_str()); + data = (T *)CustomData_add_layer_named(&custom_data, type, CD_SET_DEFAULT, num, name.c_str()); MutableSpan span = {data, num}; if (num > 0 && span.first() != default_value) { span.fill(default_value); @@ -1572,4 +1570,33 @@ GVArray CurvesGeometry::adapt_domain(const GVArray &varray, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name File reading/writing. + * \{ */ + +void CurvesGeometry::blend_read(BlendDataReader &reader) +{ + CustomData_blend_read(&reader, &this->point_data, this->point_num); + CustomData_blend_read(&reader, &this->curve_data, this->curve_num); + + BLO_read_int32_array(&reader, this->curve_num + 1, &this->curve_offsets); +} + +void CurvesGeometry::blend_write(BlendWriter &writer, ID &id) +{ + Vector point_layers; + Vector curve_layers; + CustomData_blend_write_prepare(this->point_data, point_layers); + CustomData_blend_write_prepare(this->curve_data, curve_layers); + + CustomData_blend_write( + &writer, &this->point_data, point_layers, this->point_num, CD_MASK_ALL, &id); + CustomData_blend_write( + &writer, &this->curve_data, curve_layers, this->curve_num, CD_MASK_ALL, &id); + + BLO_write_int32_array(&writer, this->curve_num + 1, this->curve_offsets); +} + +/** \} */ + } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/customdata.cc b/source/blender/blenkernel/intern/customdata.cc index 2da8cb8aeca..d270b04bf50 100644 --- a/source/blender/blenkernel/intern/customdata.cc +++ b/source/blender/blenkernel/intern/customdata.cc @@ -2686,6 +2686,15 @@ void CustomData_clear_layer_flag(CustomData *data, const int type, const int fla } } +bool CustomData_layer_is_anonymous(const struct CustomData *data, int type, int n) +{ + const int layer_index = CustomData_get_layer_index_n(data, type, n); + + BLI_assert(layer_index >= 0); + + return data->layers[layer_index].anonymous_id != nullptr; +} + static bool customData_resize(CustomData *data, const int amount) { CustomDataLayer *tmp = static_cast( @@ -2835,7 +2844,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, return &data->layers[index]; } -void *CustomData_add_layer( +static void *customdata_add_layer( CustomData *data, const int type, eCDAllocType alloctype, void *layerdata, const int totelem) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); @@ -2851,12 +2860,28 @@ void *CustomData_add_layer( return nullptr; } -void *CustomData_add_layer_named(CustomData *data, - const int type, - const eCDAllocType alloctype, - void *layerdata, - const int totelem, - const char *name) +void *CustomData_add_layer(CustomData *data, + const eCustomDataType type, + const eCDAllocType alloctype, + const int totelem) +{ + return customdata_add_layer(data, type, alloctype, nullptr, totelem); +} + +const void *CustomData_add_layer_with_data(CustomData *data, + const eCustomDataType type, + void *layer_data, + const int totelem) +{ + return customdata_add_layer(data, type, CD_ASSIGN, layer_data, totelem); +} + +static void *customdata_add_layer_named(CustomData *data, + const eCustomDataType type, + const eCDAllocType alloctype, + void *layerdata, + const int totelem, + const char *name) { CustomDataLayer *layer = customData_add_layer__internal( data, type, alloctype, layerdata, totelem, name); @@ -2869,6 +2894,21 @@ void *CustomData_add_layer_named(CustomData *data, return nullptr; } +void *CustomData_add_layer_named(CustomData *data, + const eCustomDataType type, + const eCDAllocType alloctype, + const int totelem, + const char *name) +{ + return customdata_add_layer_named(data, type, alloctype, nullptr, totelem, name); +} + +const void *CustomData_add_layer_named_with_data( + CustomData *data, const eCustomDataType type, void *layer_data, int totelem, const char *name) +{ + return customdata_add_layer_named(data, type, CD_ASSIGN, layer_data, totelem, name); +} + void *CustomData_add_layer_anonymous(CustomData *data, const int type, const eCDAllocType alloctype, diff --git a/source/blender/blenkernel/intern/data_transfer.cc b/source/blender/blenkernel/intern/data_transfer.cc index 4c8ef7dc9fc..552de64cf26 100644 --- a/source/blender/blenkernel/intern/data_transfer.cc +++ b/source/blender/blenkernel/intern/data_transfer.cc @@ -24,7 +24,7 @@ #include "BKE_customdata.h" #include "BKE_data_transfer.h" #include "BKE_deform.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" #include "BKE_mesh_runtime.h" @@ -351,12 +351,6 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, { if (dtdata_type == DT_TYPE_LNOR) { /* Compute custom normals into regular loop normals, which will be used for the transfer. */ - - const float(*positions_dst)[3] = BKE_mesh_vert_positions(me_dst); - const int num_verts_dst = me_dst->totvert; - const blender::Span edges_dst = me_dst->edges(); - const blender::Span polys_dst = me_dst->polys(); - const blender::Span loops_dst = me_dst->loops(); CustomData *ldata_dst = &me_dst->ldata; const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0; @@ -366,39 +360,37 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, BLI_assert(CustomData_get_layer(&me_src->ldata, CD_NORMAL) != nullptr); (void)me_src; - float(*loop_nors_dst)[3]; short(*custom_nors_dst)[2] = static_cast( CustomData_get_layer_for_write(ldata_dst, CD_CUSTOMLOOPNORMAL, me_dst->totloop)); /* Cache loop nors into a temp CDLayer. */ - loop_nors_dst = static_cast( + blender::float3 *loop_nors_dst = static_cast( CustomData_get_layer_for_write(ldata_dst, CD_NORMAL, me_dst->totloop)); const bool do_loop_nors_dst = (loop_nors_dst == nullptr); if (do_loop_nors_dst) { - loop_nors_dst = static_cast( - CustomData_add_layer(ldata_dst, CD_NORMAL, CD_SET_DEFAULT, nullptr, loops_dst.size())); + loop_nors_dst = static_cast( + CustomData_add_layer(ldata_dst, CD_NORMAL, CD_SET_DEFAULT, me_dst->totloop)); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } if (dirty_nors_dst || do_loop_nors_dst) { const bool *sharp_edges = static_cast( CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge")); - BKE_mesh_normals_loop_split(positions_dst, - BKE_mesh_vert_normals_ensure(me_dst), - num_verts_dst, - edges_dst.data(), - edges_dst.size(), - loops_dst.data(), - loop_nors_dst, - loops_dst.size(), - polys_dst.data(), - BKE_mesh_poly_normals_ensure(me_dst), - polys_dst.size(), - use_split_nors_dst, - split_angle_dst, - sharp_edges, - nullptr, - nullptr, - custom_nors_dst); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")); + blender::bke::mesh::normals_calc_loop(me_dst->vert_positions(), + me_dst->edges(), + me_dst->polys(), + me_dst->loops(), + {}, + me_dst->vert_normals(), + me_dst->poly_normals(), + sharp_edges, + sharp_faces, + use_split_nors_dst, + split_angle_dst, + custom_nors_dst, + nullptr, + {loop_nors_dst, me_dst->totloop}); } } } @@ -415,45 +407,35 @@ static void data_transfer_dtdata_type_postprocess(Object * /*ob_src*/, if (!changed) { return; } - /* Bake edited destination loop normals into custom normals again. */ - const float(*positions_dst)[3] = BKE_mesh_vert_positions(me_dst); - const int num_verts_dst = me_dst->totvert; - const blender::Span edges_dst = me_dst->edges(); - blender::MutableSpan polys_dst = me_dst->polys_for_write(); - blender::MutableSpan loops_dst = me_dst->loops_for_write(); - CustomData *ldata_dst = &me_dst->ldata; - const float(*poly_nors_dst)[3] = BKE_mesh_poly_normals_ensure(me_dst); - float(*loop_nors_dst)[3] = static_cast( + blender::float3 *loop_nors_dst = static_cast( CustomData_get_layer_for_write(ldata_dst, CD_NORMAL, me_dst->totloop)); short(*custom_nors_dst)[2] = static_cast( CustomData_get_layer_for_write(ldata_dst, CD_CUSTOMLOOPNORMAL, me_dst->totloop)); if (!custom_nors_dst) { - custom_nors_dst = static_cast(CustomData_add_layer( - ldata_dst, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, loops_dst.size())); + custom_nors_dst = static_cast( + CustomData_add_layer(ldata_dst, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, me_dst->totloop)); } bke::MutableAttributeAccessor attributes = me_dst->attributes_for_write(); bke::SpanAttributeWriter sharp_edges = attributes.lookup_or_add_for_write_span( "sharp_edge", ATTR_DOMAIN_EDGE); - + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")); /* Note loop_nors_dst contains our custom normals as transferred from source... */ - BKE_mesh_normals_loop_custom_set(positions_dst, - BKE_mesh_vert_normals_ensure(me_dst), - num_verts_dst, - edges_dst.data(), - edges_dst.size(), - loops_dst.data(), - loop_nors_dst, - loops_dst.size(), - polys_dst.data(), - poly_nors_dst, - polys_dst.size(), - sharp_edges.span.data(), - custom_nors_dst); + blender::bke::mesh::normals_loop_custom_set(me_dst->vert_positions(), + me_dst->edges(), + me_dst->polys(), + me_dst->loops(), + me_dst->vert_normals(), + me_dst->poly_normals(), + sharp_faces, + sharp_edges.span, + {loop_nors_dst, me_dst->totloop}, + custom_nors_dst); sharp_edges.finish(); } } @@ -641,7 +623,8 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map if (use_create) { /* Create as much data layers as necessary! */ for (; idx_dst < idx_src; idx_dst++) { - CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, nullptr, num_elem_dst); + CustomData_add_layer( + cd_dst, eCustomDataType(cddata_type), CD_SET_DEFAULT, num_elem_dst); } } else { @@ -695,7 +678,7 @@ static bool data_transfer_layersmapping_cdlayers_multisrc_to_dst(ListBase *r_map if ((idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name)) == -1) { if (use_create) { CustomData_add_layer_named( - cd_dst, cddata_type, CD_SET_DEFAULT, nullptr, num_elem_dst, name); + cd_dst, eCustomDataType(cddata_type), CD_SET_DEFAULT, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } else { @@ -774,7 +757,8 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, if (!use_create) { return true; } - data_dst = CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, nullptr, num_elem_dst); + data_dst = CustomData_add_layer( + cd_dst, eCustomDataType(cddata_type), CD_SET_DEFAULT, num_elem_dst); } if (r_map) { @@ -815,7 +799,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, return true; } data_dst = CustomData_add_layer( - cd_dst, cddata_type, CD_SET_DEFAULT, nullptr, num_elem_dst); + cd_dst, eCustomDataType(cddata_type), CD_SET_DEFAULT, num_elem_dst); } else { data_dst = CustomData_get_layer_n_for_write(cd_dst, cddata_type, idx_dst, num_elem_dst); @@ -830,7 +814,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, } /* Create as much data layers as necessary! */ for (; num <= idx_dst; num++) { - CustomData_add_layer(cd_dst, cddata_type, CD_SET_DEFAULT, nullptr, num_elem_dst); + CustomData_add_layer(cd_dst, eCustomDataType(cddata_type), CD_SET_DEFAULT, num_elem_dst); } } data_dst = CustomData_get_layer_n_for_write(cd_dst, cddata_type, idx_dst, num_elem_dst); @@ -842,7 +826,7 @@ static bool data_transfer_layersmapping_cdlayers(ListBase *r_map, return true; } CustomData_add_layer_named( - cd_dst, cddata_type, CD_SET_DEFAULT, nullptr, num_elem_dst, name); + cd_dst, eCustomDataType(cddata_type), CD_SET_DEFAULT, num_elem_dst, name); idx_dst = CustomData_get_named_layer(cd_dst, cddata_type, name); } data_dst = CustomData_get_layer_n_for_write(cd_dst, cddata_type, idx_dst, num_elem_dst); @@ -1007,7 +991,7 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map, if (r_map && cddata_type == CD_FAKE_SEAM) { if (!CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, ".uv_seam")) { CustomData_add_layer_named( - &me_dst->edata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me_dst->totedge, ".uv_seam"); + &me_dst->edata, CD_PROP_BOOL, CD_SET_DEFAULT, me_dst->totedge, ".uv_seam"); } data_transfer_layersmapping_add_item_cd( r_map, @@ -1025,7 +1009,7 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map, if (r_map && cddata_type == CD_FAKE_SHARP) { if (!CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge")) { CustomData_add_layer_named( - &me_dst->edata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me_dst->totedge, "sharp_edge"); + &me_dst->edata, CD_PROP_BOOL, CD_SET_DEFAULT, me_dst->totedge, "sharp_edge"); } data_transfer_layersmapping_add_item_cd( r_map, @@ -1109,26 +1093,21 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map, return true; } if (r_map && cddata_type == CD_FAKE_SHARP) { - const size_t elem_size = sizeof(*((MPoly *)nullptr)); - const size_t data_size = sizeof(((MPoly *)nullptr)->flag); - const size_t data_offset = offsetof(MPoly, flag); - const uint64_t data_flag = ME_SMOOTH; - - data_transfer_layersmapping_add_item(r_map, - cddata_type, - mix_mode, - mix_factor, - mix_weights, - me_src->polys().data(), - me_dst->polys_for_write().data(), - me_src->totpoly, - me_dst->totpoly, - elem_size, - data_size, - data_offset, - data_flag, - nullptr, - interp_data); + if (!CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")) { + CustomData_add_layer_named( + &me_dst->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, me_dst->totpoly, "sharp_face"); + } + data_transfer_layersmapping_add_item_cd( + r_map, + CD_PROP_BOOL, + mix_mode, + mix_factor, + mix_weights, + CustomData_get_layer_named(&me_src->pdata, CD_PROP_BOOL, "sharp_face"), + CustomData_get_layer_named_for_write( + &me_dst->pdata, CD_PROP_BOOL, "sharp_face", num_elem_dst), + interp, + interp_data); return true; } @@ -1715,6 +1694,7 @@ bool BKE_object_data_transfer_ex(struct Depsgraph *depsgraph, ray_radius, me_dst, positions_dst, + num_verts_dst, loops_dst.data(), polys_dst.data(), polys_dst.size(), diff --git a/source/blender/blenkernel/intern/deform.cc b/source/blender/blenkernel/intern/deform.cc index 048e719c38c..e759d012e58 100644 --- a/source/blender/blenkernel/intern/deform.cc +++ b/source/blender/blenkernel/intern/deform.cc @@ -13,7 +13,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -31,7 +31,7 @@ #include "BKE_customdata.h" #include "BKE_data_transfer.h" #include "BKE_deform.h" /* own include */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_object.h" #include "BKE_object_deform.h" @@ -440,7 +440,7 @@ bool BKE_object_supports_vertex_groups(const Object *ob) return false; } - return ELEM(GS(id->name), ID_ME, ID_LT, ID_GD); + return ELEM(GS(id->name), ID_ME, ID_LT, ID_GD_LEGACY); } const ListBase *BKE_id_defgroup_list_get(const ID *id) @@ -454,7 +454,7 @@ const ListBase *BKE_id_defgroup_list_get(const ID *id) const Lattice *lt = (const Lattice *)id; return <->vertex_group_names; } - case ID_GD: { + case ID_GD_LEGACY: { const bGPdata *gpd = (const bGPdata *)id; return &gpd->vertex_group_names; } @@ -477,7 +477,7 @@ static const int *object_defgroup_active_index_get_p(const Object *ob) const Lattice *lattice = (const Lattice *)ob->data; return &lattice->vertex_group_active_index; } - case OB_GPENCIL: { + case OB_GPENCIL_LEGACY: { const bGPdata *gpd = (const bGPdata *)ob->data; return &gpd->vertex_group_active_index; } @@ -1262,7 +1262,7 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, * Again, use_create is not relevant in this case */ if (!data_dst) { data_dst = static_cast( - CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, num_elem_dst)); + CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, num_elem_dst)); } while (idx_src--) { @@ -1323,8 +1323,8 @@ static bool data_transfer_layersmapping_vgroups_multisrc_to_dst(ListBase *r_map, /* At this stage, we **need** a valid CD_MDEFORMVERT layer on dest! * use_create is not relevant in this case */ if (!data_dst) { - data_dst = static_cast(CustomData_add_layer( - cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, num_elem_dst)); + data_dst = static_cast( + CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, num_elem_dst)); } data_transfer_layersmapping_add_item(r_map, @@ -1467,7 +1467,7 @@ bool data_transfer_layersmapping_vgroups(ListBase *r_map, * use_create is not relevant in this case */ if (!data_dst) { data_dst = static_cast( - CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, num_elem_dst)); + CustomData_add_layer(cd_dst, CD_MDEFORMVERT, CD_SET_DEFAULT, num_elem_dst)); } data_transfer_layersmapping_add_item(r_map, diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc index 6500cf830b2..738e657ecfa 100644 --- a/source/blender/blenkernel/intern/displist.cc +++ b/source/blender/blenkernel/intern/displist.cc @@ -36,7 +36,7 @@ #include "BKE_key.h" #include "BKE_lib_id.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_vfont.h" diff --git a/source/blender/blenkernel/intern/dynamicpaint.cc b/source/blender/blenkernel/intern/dynamicpaint.cc index 514ab046b87..82ea253a27a 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.cc +++ b/source/blender/blenkernel/intern/dynamicpaint.cc @@ -48,7 +48,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -1789,7 +1789,7 @@ struct DynamicPaintModifierApplyData { Object *ob; float (*vert_positions)[3]; - const float (*vert_normals)[3]; + blender::Span vert_normals; blender::Span polys; blender::Span loops; @@ -1827,7 +1827,7 @@ static void dynamicPaint_applySurfaceDisplace(DynamicPaintSurface *surface, Mesh DynamicPaintModifierApplyData data{}; data.surface = surface; data.vert_positions = BKE_mesh_vert_positions_for_write(result); - data.vert_normals = BKE_mesh_vert_normals_ensure(result); + data.vert_normals = result->vert_normals(); TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); @@ -1958,7 +1958,6 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * mloopcol = static_cast(CustomData_add_layer_named(&result->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, - nullptr, loops.size(), surface->output_name)); } @@ -1972,7 +1971,6 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * CustomData_add_layer_named(&result->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, - nullptr, loops.size(), surface->output_name2)); } @@ -2003,7 +2001,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * /* apply weights into a vertex group, if doesn't exists add a new layer */ if (defgrp_index != -1 && !dvert && (surface->output_name[0] != '\0')) { dvert = static_cast(CustomData_add_layer( - &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, sData->total_points)); + &result->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, sData->total_points)); } if (defgrp_index != -1 && dvert) { for (int i = 0; i < sData->total_points; i++) { @@ -2028,7 +2026,7 @@ static Mesh *dynamicPaint_Modifier_apply(DynamicPaintModifierData *pmd, Object * DynamicPaintModifierApplyData data{}; data.surface = surface; data.vert_positions = BKE_mesh_vert_positions_for_write(result); - data.vert_normals = BKE_mesh_vert_normals_ensure(result); + data.vert_normals = result->vert_normals(); TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); @@ -4288,7 +4286,7 @@ static bool dynamicPaint_paintMesh(Depsgraph *depsgraph, mesh = BKE_mesh_copy_for_eval(brush_mesh, false); float(*positions)[3] = BKE_mesh_vert_positions_for_write(mesh); - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh); + const blender::Span vert_normals = mesh->vert_normals(); const blender::Span looptris = mesh->looptris(); const blender::Span loops = mesh->loops(); numOfVerts = mesh->totvert; @@ -5912,7 +5910,7 @@ struct DynamicPaintGenerateBakeData { Object *ob; const float (*positions)[3]; - const float (*vert_normals)[3]; + blender::Span vert_normals; const Vec3f *canvas_verts; bool do_velocity_data; @@ -6149,7 +6147,7 @@ static bool dynamicPaint_generateBakeData(DynamicPaintSurface *surface, data.surface = surface; data.ob = ob; data.positions = positions; - data.vert_normals = BKE_mesh_vert_normals_ensure(mesh); + data.vert_normals = mesh->vert_normals(); data.canvas_verts = canvas_verts; data.do_velocity_data = do_velocity_data; data.new_bdata = new_bdata; diff --git a/source/blender/blenkernel/intern/editmesh.cc b/source/blender/blenkernel/intern/editmesh.cc index b586b4110f2..108852ad94d 100644 --- a/source/blender/blenkernel/intern/editmesh.cc +++ b/source/blender/blenkernel/intern/editmesh.cc @@ -19,7 +19,7 @@ #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_iterators.h" #include "BKE_mesh_wrapper.h" #include "BKE_object.h" diff --git a/source/blender/blenkernel/intern/editmesh_tangent.cc b/source/blender/blenkernel/intern/editmesh_tangent.cc index 6af839585f7..ff57653d334 100644 --- a/source/blender/blenkernel/intern/editmesh_tangent.cc +++ b/source/blender/blenkernel/intern/editmesh_tangent.cc @@ -14,7 +14,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_editmesh_tangent.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_tangent.h" /* for utility functions */ #include "MEM_guardedalloc.h" @@ -194,7 +194,7 @@ void BKE_editmesh_loop_tangent_calc(BMEditMesh *em, if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata_out, CD_TANGENT, "") == -1) { CustomData_add_layer_named( - loopdata_out, CD_TANGENT, CD_SET_DEFAULT, nullptr, int(loopdata_out_len), ""); + loopdata_out, CD_TANGENT, CD_SET_DEFAULT, int(loopdata_out_len), ""); } if (calc_act && act_uv_name[0]) { BKE_mesh_add_loop_tangent_named_layer_for_uv( diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 8e054d4d35f..4372e2f81ab 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -556,252 +556,240 @@ int BKE_fcurve_bezt_binarysearch_index(const BezTriple array[], /* ...................................... */ -/* Helper for calc_fcurve_* functions -> find first and last BezTriple to be used. */ -static bool get_fcurve_end_keyframes(const FCurve *fcu, - BezTriple **first, - BezTriple **last, - const bool do_sel_only, - const float range[2]) +/** + * Get the first and last index to the bezt array that satisfies the given parameters. + * + * \param selected_keys_only: Only accept indices of bezt that are selected. + * Is a subset of frame_range. + * \param frame_range: Only consider keyframes in that frame interval. Can be NULL. + */ +static bool get_bounding_bezt_indices(const FCurve *fcu, + const bool selected_keys_only, + const float frame_range[2], + int *r_first, + int *r_last) { - bool found = false; - - /* Init outputs. */ - *first = NULL; - *last = NULL; - /* Sanity checks. */ if (fcu->bezt == NULL) { - return found; + return false; } - int first_index = 0; - int last_index = fcu->totvert - 1; + *r_first = 0; + *r_last = fcu->totvert - 1; - if (range != NULL) { + bool found = false; + if (frame_range != NULL) { /* If a range is passed in find the first and last keyframe within that range. */ bool replace = false; - first_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, range[0], fcu->totvert, &replace); - last_index = BKE_fcurve_bezt_binarysearch_index(fcu->bezt, range[1], fcu->totvert, &replace); + *r_first = BKE_fcurve_bezt_binarysearch_index( + fcu->bezt, frame_range[0], fcu->totvert, &replace); + *r_last = BKE_fcurve_bezt_binarysearch_index( + fcu->bezt, frame_range[1], fcu->totvert, &replace); /* If first and last index are the same, no keyframes were found in the range. */ - if (first_index == last_index) { - return found; + if (*r_first == *r_last) { + return false; } /* The binary search returns an index where a keyframe would be inserted, - so it needs to be clamped to ensure it is in range of the array. */ - first_index = clamp_i(first_index, 0, fcu->totvert - 1); - last_index = clamp_i(last_index - 1, 0, fcu->totvert - 1); + * so it needs to be clamped to ensure it is in range of the array. */ + *r_first = clamp_i(*r_first, 0, fcu->totvert - 1); + *r_last = clamp_i(*r_last - 1, 0, fcu->totvert - 1); } /* Only include selected items? */ - if (do_sel_only) { + if (selected_keys_only) { /* Find first selected. */ - for (int i = first_index; i <= last_index; i++) { + for (int i = *r_first; i <= *r_last; i++) { BezTriple *bezt = &fcu->bezt[i]; if (BEZT_ISSEL_ANY(bezt)) { - *first = bezt; + *r_first = i; found = true; break; } } /* Find last selected. */ - for (int i = last_index; i >= first_index; i--) { + for (int i = *r_last; i >= *r_first; i--) { BezTriple *bezt = &fcu->bezt[i]; if (BEZT_ISSEL_ANY(bezt)) { - *last = bezt; + *r_last = i; found = true; break; } } } else { - *first = &fcu->bezt[first_index]; - *last = &fcu->bezt[last_index]; found = true; } return found; } -bool BKE_fcurve_calc_bounds(const FCurve *fcu, - float *xmin, - float *xmax, - float *ymin, - float *ymax, - const bool do_sel_only, - const bool include_handles, - const float range[2]) +static void calculate_bezt_bounds_x(BezTriple *bezt_array, + const int index_range[2], + const bool include_handles, + float *r_min, + float *r_max) { - float xminv = 999999999.0f, xmaxv = -999999999.0f; - float yminv = 999999999.0f, ymaxv = -999999999.0f; - bool foundvert = false; + *r_min = bezt_array[index_range[0]].vec[1][0]; + *r_max = bezt_array[index_range[1]].vec[1][0]; - const bool use_range = range != NULL; - - if (fcu->totvert) { - if (fcu->bezt) { - - if (xmin || xmax) { - BezTriple *bezt_first = NULL, *bezt_last = NULL; - foundvert = get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only, range); - - if (bezt_first) { - BLI_assert(bezt_last != NULL); - foundvert = true; - if (include_handles) { - xminv = min_fff(xminv, bezt_first->vec[0][0], bezt_first->vec[1][0]); - xmaxv = max_fff(xmaxv, bezt_last->vec[1][0], bezt_last->vec[2][0]); - } - else { - xminv = min_ff(xminv, bezt_first->vec[1][0]); - xmaxv = max_ff(xmaxv, bezt_last->vec[1][0]); - } - } - } - - /* Only loop over keyframes to find extents for values if needed. */ - if (ymin || ymax) { - BezTriple *bezt, *prevbezt = NULL; - - int i; - for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) { - if (use_range && (bezt->vec[1][0] < range[0] || bezt->vec[1][0] > range[1])) { - continue; - } - if ((do_sel_only == false) || BEZT_ISSEL_ANY(bezt)) { - /* Keyframe itself. */ - yminv = min_ff(yminv, bezt->vec[1][1]); - ymaxv = max_ff(ymaxv, bezt->vec[1][1]); - - if (include_handles) { - /* Left handle - only if applicable. - * NOTE: for the very first keyframe, - * the left handle actually has no bearings on anything. */ - if (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)) { - yminv = min_ff(yminv, bezt->vec[0][1]); - ymaxv = max_ff(ymaxv, bezt->vec[0][1]); - } - - /* Right handle - only if applicable. */ - if (bezt->ipo == BEZT_IPO_BEZ) { - yminv = min_ff(yminv, bezt->vec[2][1]); - ymaxv = max_ff(ymaxv, bezt->vec[2][1]); - } - } - - foundvert = true; - } - } - } - } - else if (fcu->fpt) { - /* Frame range can be directly calculated from end verts. */ - if (xmin || xmax) { - xminv = min_ff(xminv, fcu->fpt[0].vec[0]); - xmaxv = max_ff(xmaxv, fcu->fpt[fcu->totvert - 1].vec[0]); - } - - /* Only loop over keyframes to find extents for values if needed. */ - if (ymin || ymax) { - int i = 0; - - for (FPoint *fpt = fcu->fpt; i < fcu->totvert; fpt++, i++) { - if (fpt->vec[1] < yminv) { - yminv = fpt->vec[1]; - } - if (fpt->vec[1] > ymaxv) { - ymaxv = fpt->vec[1]; - } - - foundvert = true; - } - } + if (include_handles) { + /* Need to check all handles because they might extend beyond their neighboring keys. */ + for (int i = index_range[0]; i <= index_range[1]; i++) { + const BezTriple *bezt = &bezt_array[i]; + *r_min = min_fff(*r_min, bezt->vec[0][0], bezt->vec[1][0]); + *r_max = max_fff(*r_max, bezt->vec[1][0], bezt->vec[2][0]); } } - - if (foundvert) { - if (xmin) { - *xmin = xminv; - } - if (xmax) { - *xmax = xmaxv; - } - - if (ymin) { - *ymin = yminv; - } - if (ymax) { - *ymax = ymaxv; - } - } - else { - if (G.debug & G_DEBUG) { - printf("F-Curve calc bounds didn't find anything, so assuming minimum bounds of 1.0\n"); - } - - if (xmin) { - *xmin = use_range ? range[0] : 0.0f; - } - if (xmax) { - *xmax = use_range ? range[1] : 1.0f; - } - - if (ymin) { - *ymin = 0.0f; - } - if (ymax) { - *ymax = 1.0f; - } - } - - return foundvert; } -bool BKE_fcurve_calc_range( - const FCurve *fcu, float *start, float *end, const bool do_sel_only, const bool do_min_length) +static void calculate_bezt_bounds_y(BezTriple *bezt_array, + const int index_range[2], + const bool selected_keys_only, + const bool include_handles, + float *r_min, + float *r_max) { - float min = 999999999.0f, max = -999999999.0f; + *r_min = bezt_array[index_range[0]].vec[1][1]; + *r_max = bezt_array[index_range[0]].vec[1][1]; + + for (int i = index_range[0]; i <= index_range[1]; i++) { + const BezTriple *bezt = &bezt_array[i]; + + if (selected_keys_only && !BEZT_ISSEL_ANY(bezt)) { + continue; + } + + *r_min = min_ff(*r_min, bezt->vec[1][1]); + *r_max = max_ff(*r_max, bezt->vec[1][1]); + + if (include_handles) { + *r_min = min_fff(*r_min, bezt->vec[0][1], bezt->vec[2][1]); + *r_max = max_fff(*r_max, bezt->vec[0][1], bezt->vec[2][1]); + } + } +} + +static bool calculate_bezt_bounds(const FCurve *fcu, + const bool selected_keys_only, + const bool include_handles, + const float frame_range[2], + rctf *r_bounds) +{ + int index_range[2]; + const bool found_indices = get_bounding_bezt_indices( + fcu, selected_keys_only, frame_range, &index_range[0], &index_range[1]); + if (!found_indices) { + return false; + } + calculate_bezt_bounds_x( + fcu->bezt, index_range, include_handles, &r_bounds->xmin, &r_bounds->xmax); + calculate_bezt_bounds_y(fcu->bezt, + index_range, + selected_keys_only, + include_handles, + &r_bounds->ymin, + &r_bounds->ymax); + return true; +} + +static bool calculate_fpt_bounds(const FCurve *fcu, const float frame_range[2], rctf *r_bounds) +{ + r_bounds->xmin = INFINITY; + r_bounds->xmax = -INFINITY; + r_bounds->ymin = INFINITY; + r_bounds->ymax = -INFINITY; + + const int first_index = 0; + const int last_index = fcu->totvert - 1; + int start_index = first_index; + int end_index = last_index; + + if (frame_range != NULL) { + /* Start index can be calculated because fpt has a key on every full frame. */ + const float start_index_f = frame_range[0] - fcu->fpt[0].vec[0]; + const float end_index_f = start_index_f + frame_range[1] - frame_range[0]; + + if (start_index_f > fcu->totvert - 1 || end_index_f < 0) { + /* Range is outside of keyframe samples. */ + return false; + } + + /* Range might be partially covering keyframe samples. */ + start_index = clamp_i(start_index_f, 0, fcu->totvert - 1); + end_index = clamp_i(end_index_f, 0, fcu->totvert - 1); + } + + /* X range can be directly calculated from end verts. */ + r_bounds->xmin = fcu->fpt[start_index].vec[0]; + r_bounds->xmax = fcu->fpt[end_index].vec[0]; + + for (int i = start_index; i <= end_index; i++) { + r_bounds->ymin = min_ff(r_bounds->ymin, fcu->fpt[i].vec[1]); + r_bounds->ymax = max_ff(r_bounds->ymax, fcu->fpt[i].vec[1]); + } + + return BLI_rctf_is_valid(r_bounds); +} + +bool BKE_fcurve_calc_bounds(const FCurve *fcu, + const bool selected_keys_only, + const bool include_handles, + const float frame_range[2], + rctf *r_bounds) +{ + if (fcu->totvert == 0) { + return false; + } + + if (fcu->bezt) { + const bool found_bounds = calculate_bezt_bounds( + fcu, selected_keys_only, include_handles, frame_range, r_bounds); + return found_bounds; + } + + if (fcu->fpt) { + const bool founds_bounds = calculate_fpt_bounds(fcu, frame_range, r_bounds); + return founds_bounds; + } + + return false; +} + +bool BKE_fcurve_calc_range(const FCurve *fcu, + float *r_start, + float *r_end, + const bool selected_keys_only) +{ + float min = 0.0f; + float max = 0.0f; bool foundvert = false; - if (fcu->totvert) { - if (fcu->bezt) { - BezTriple *bezt_first = NULL, *bezt_last = NULL; - - /* Get endpoint keyframes. */ - get_fcurve_end_keyframes(fcu, &bezt_first, &bezt_last, do_sel_only, NULL); - - if (bezt_first) { - BLI_assert(bezt_last != NULL); - - min = min_ff(min, bezt_first->vec[1][0]); - max = max_ff(max, bezt_last->vec[1][0]); - - foundvert = true; - } - } - else if (fcu->fpt) { - min = min_ff(min, fcu->fpt[0].vec[0]); - max = max_ff(max, fcu->fpt[fcu->totvert - 1].vec[0]); - - foundvert = true; - } + if (fcu->totvert == 0) { + return false; } - if (foundvert == false) { - min = max = 0.0f; - } - - if (do_min_length) { - /* Minimum length is 1 frame. */ - if (min == max) { - max += 1.0f; + if (fcu->bezt) { + int index_range[2]; + foundvert = get_bounding_bezt_indices( + fcu, selected_keys_only, NULL, &index_range[0], &index_range[1]); + if (!foundvert) { + return false; } + const bool include_handles = false; + calculate_bezt_bounds_x(fcu->bezt, index_range, include_handles, &min, &max); + } + else if (fcu->fpt) { + min = fcu->fpt[0].vec[0]; + max = fcu->fpt[fcu->totvert - 1].vec[0]; + + foundvert = true; } - *start = min; - *end = max; + *r_start = min; + *r_end = max; return foundvert; } diff --git a/source/blender/blenkernel/intern/fcurve_test.cc b/source/blender/blenkernel/intern/fcurve_test.cc index 66c4477ebc2..45faa44ff27 100644 --- a/source/blender/blenkernel/intern/fcurve_test.cc +++ b/source/blender/blenkernel/intern/fcurve_test.cc @@ -346,4 +346,204 @@ TEST(BKE_fcurve, BKE_fcurve_keyframe_move_value_with_handles) BKE_fcurve_free(fcu); } +TEST(BKE_fcurve, BKE_fcurve_calc_range) +{ + FCurve *fcu = BKE_fcurve_create(); + + insert_vert_fcurve(fcu, 1.0f, 7.5f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 4.0f, -15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 8.0f, 15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 14.0f, 8.2f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 18.2f, -20.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + + for (int i = 0; i < fcu->totvert; i++) { + fcu->bezt[i].f1 &= ~SELECT; + fcu->bezt[i].f2 &= ~SELECT; + fcu->bezt[i].f3 &= ~SELECT; + } + + float min, max; + bool success; + + /* All keys. */ + success = BKE_fcurve_calc_range(fcu, &min, &max, false); + EXPECT_TRUE(success) << "A non-empty FCurve should have a range."; + EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], min); + EXPECT_FLOAT_EQ(fcu->bezt[4].vec[1][0], max); + + /* Only selected. */ + success = BKE_fcurve_calc_range(fcu, &min, &max, true); + EXPECT_FALSE(success) + << "Using selected keyframes only should not find a range if nothing is selected."; + + fcu->bezt[1].f2 |= SELECT; + fcu->bezt[3].f2 |= SELECT; + + success = BKE_fcurve_calc_range(fcu, &min, &max, true); + EXPECT_TRUE(success) << "Range of selected keyframes should have been found."; + EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], min); + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[1][0], max); + + /* Curve samples. */ + const int sample_start = 1; + const int sample_end = 20; + fcurve_store_samples(fcu, nullptr, sample_start, sample_end, fcurve_samplingcb_evalcurve); + + success = BKE_fcurve_calc_range(fcu, &min, &max, true); + EXPECT_TRUE(success) << "FCurve samples should have a range."; + + EXPECT_FLOAT_EQ(sample_start, min); + EXPECT_FLOAT_EQ(sample_end, max); + + BKE_fcurve_free(fcu); +} + +TEST(BKE_fcurve, BKE_fcurve_calc_bounds) +{ + FCurve *fcu = BKE_fcurve_create(); + + insert_vert_fcurve(fcu, 1.0f, 7.5f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 4.0f, -15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 8.0f, 15.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 14.0f, 8.2f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + insert_vert_fcurve(fcu, 18.2f, -20.0f, BEZT_KEYTYPE_KEYFRAME, INSERTKEY_NO_USERPREF); + + for (int i = 0; i < fcu->totvert; i++) { + fcu->bezt[i].f1 &= ~SELECT; + fcu->bezt[i].f2 &= ~SELECT; + fcu->bezt[i].f3 &= ~SELECT; + } + + fcu->bezt[0].vec[0][0] = -5.0f; + fcu->bezt[4].vec[2][0] = 25.0f; + + rctf bounds; + bool success; + + /* All keys. */ + success = BKE_fcurve_calc_bounds(fcu, + false /* select only */, + false /* include handles */, + nullptr /* frame range */, + &bounds); + EXPECT_TRUE(success) << "A non-empty FCurve should have bounds."; + EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], bounds.xmin); + EXPECT_FLOAT_EQ(fcu->bezt[4].vec[1][0], bounds.xmax); + EXPECT_FLOAT_EQ(fcu->bezt[4].vec[1][1], bounds.ymin); + EXPECT_FLOAT_EQ(fcu->bezt[2].vec[1][1], bounds.ymax); + + /* Only selected. */ + success = BKE_fcurve_calc_bounds(fcu, + true /* select only */, + false /* include handles */, + nullptr /* frame range */, + &bounds); + EXPECT_FALSE(success) + << "Using selected keyframes only should not find bounds if nothing is selected."; + + fcu->bezt[1].f2 |= SELECT; + fcu->bezt[3].f2 |= SELECT; + + success = BKE_fcurve_calc_bounds(fcu, + true /* select only */, + false /* include handles */, + nullptr /* frame range */, + &bounds); + EXPECT_TRUE(success) << "Selected keys should have been found."; + EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][0], bounds.xmin); + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[1][0], bounds.xmax); + EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], bounds.ymin); + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[1][1], bounds.ymax); + + /* Including handles. */ + success = BKE_fcurve_calc_bounds(fcu, + false /* select only */, + true /* include handles */, + nullptr /* frame range */, + &bounds); + EXPECT_TRUE(success) << "A non-empty FCurve should have bounds including handles."; + EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][0], bounds.xmin); + EXPECT_FLOAT_EQ(fcu->bezt[4].vec[2][0], bounds.xmax); + EXPECT_FLOAT_EQ(fcu->bezt[4].vec[1][1], bounds.ymin); + EXPECT_FLOAT_EQ(fcu->bezt[2].vec[1][1], bounds.ymax); + + /* Range. */ + float range[2]; + + range[0] = 25; + range[1] = 30; + success = BKE_fcurve_calc_bounds( + fcu, false /* select only */, false /* include handles */, range /* frame range */, &bounds); + EXPECT_FALSE(success) << "A frame range outside the range of keyframes should not find bounds."; + + range[0] = 0; + range[1] = 18.2f; + success = BKE_fcurve_calc_bounds( + fcu, false /* select only */, false /* include handles */, range /* frame range */, &bounds); + EXPECT_TRUE(success) << "A frame range within the range of keyframes should find bounds."; + EXPECT_FLOAT_EQ(fcu->bezt[0].vec[1][0], bounds.xmin); + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[1][0], bounds.xmax); + EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], bounds.ymin); + EXPECT_FLOAT_EQ(fcu->bezt[2].vec[1][1], bounds.ymax); + + /* Range and handles. */ + success = BKE_fcurve_calc_bounds( + fcu, false /* select only */, true /* include handles */, range /* frame range */, &bounds); + EXPECT_TRUE(success) + << "A frame range within the range of keyframes should find bounds with handles."; + EXPECT_FLOAT_EQ(fcu->bezt[0].vec[0][0], bounds.xmin); + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[2][0], bounds.xmax); + EXPECT_FLOAT_EQ(fcu->bezt[1].vec[1][1], bounds.ymin); + EXPECT_FLOAT_EQ(fcu->bezt[2].vec[1][1], bounds.ymax); + + /* Range, handles and only selection. */ + range[0] = 8.0f; + range[1] = 18.2f; + success = BKE_fcurve_calc_bounds( + fcu, true /* select only */, true /* include handles */, range /* frame range */, &bounds); + EXPECT_TRUE(success) + << "A frame range within the range of keyframes should find bounds of selected keyframes."; + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[0][0], bounds.xmin); + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[2][0], bounds.xmax); + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[2][1], bounds.ymin); + EXPECT_FLOAT_EQ(fcu->bezt[3].vec[0][1], bounds.ymax); + + /* Curve samples. */ + const int sample_start = 1; + const int sample_end = 20; + fcurve_store_samples(fcu, nullptr, sample_start, sample_end, fcurve_samplingcb_evalcurve); + + success = BKE_fcurve_calc_bounds(fcu, + false /* select only */, + false /* include handles */, + nullptr /* frame range */, + &bounds); + EXPECT_TRUE(success) << "FCurve samples should have a range."; + + EXPECT_FLOAT_EQ(sample_start, bounds.xmin); + EXPECT_FLOAT_EQ(sample_end, bounds.xmax); + EXPECT_FLOAT_EQ(-20.0f, bounds.ymin); + EXPECT_FLOAT_EQ(15.0f, bounds.ymax); + + range[0] = 8.0f; + range[1] = 20.0f; + success = BKE_fcurve_calc_bounds( + fcu, false /* select only */, false /* include handles */, range /* frame range */, &bounds); + EXPECT_TRUE(success) << "FCurve samples should have a range."; + + EXPECT_FLOAT_EQ(range[0], bounds.xmin); + EXPECT_FLOAT_EQ(range[1], bounds.xmax); + EXPECT_FLOAT_EQ(-20.0f, bounds.ymin); + EXPECT_FLOAT_EQ(15.0f, bounds.ymax); + + range[0] = 20.1f; + range[1] = 30.0f; + success = BKE_fcurve_calc_bounds( + fcu, false /* select only */, false /* include handles */, range /* frame range */, &bounds); + EXPECT_FALSE(success) + << "A frame range outside the range of keyframe samples should not have bounds."; + + BKE_fcurve_free(fcu); +} + } // namespace blender::bke::tests diff --git a/source/blender/blenkernel/intern/fluid.cc b/source/blender/blenkernel/intern/fluid.cc index 0bc2564a8ba..af723bdd5e1 100644 --- a/source/blender/blenkernel/intern/fluid.cc +++ b/source/blender/blenkernel/intern/fluid.cc @@ -23,7 +23,7 @@ #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" -#include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_effect.h" #include "BKE_fluid.h" #include "BKE_global.h" @@ -56,7 +56,7 @@ # include "BKE_colortools.h" # include "BKE_customdata.h" # include "BKE_deform.h" -# include "BKE_mesh.h" +# include "BKE_mesh.hh" # include "BKE_mesh_runtime.h" # include "BKE_object.h" # include "BKE_particle.h" @@ -1785,7 +1785,7 @@ static void update_distances(int index, static void sample_mesh(FluidFlowSettings *ffs, const float (*vert_positions)[3], - const float (*vert_normals)[3], + const blender::Span vert_normals, const MLoop *mloop, const MLoopTri *mlooptri, const float (*mloopuv)[2], @@ -1980,7 +1980,7 @@ struct EmitFromDMData { FluidFlowSettings *ffs; const float (*vert_positions)[3]; - const float (*vert_normals)[3]; + blender::Span vert_normals; blender::Span loops; blender::Span looptris; const float (*mloopuv)[2]; @@ -2091,18 +2091,11 @@ static void emit_from_mesh( /* Transform mesh vertices to domain grid space for fast lookups. * This is valid because the mesh is copied above. */ - BKE_mesh_vert_normals_ensure(me); - float(*vert_normals)[3] = BKE_mesh_vert_normals_for_write(me); for (i = 0; i < numverts; i++) { /* Vertex position. */ mul_m4_v3(flow_ob->object_to_world, positions[i]); manta_pos_to_cell(fds, positions[i]); - /* Vertex normal. */ - mul_mat3_m4_v3(flow_ob->object_to_world, vert_normals[i]); - mul_mat3_m4_v3(fds->imat, vert_normals[i]); - normalize_v3(vert_normals[i]); - /* Vertex velocity. */ if (ffs->flags & FLUID_FLOW_INITVELOCITY) { float co[3]; @@ -2117,6 +2110,7 @@ static void emit_from_mesh( /* Calculate emission map bounds. */ bb_boundInsert(bb, positions[i]); } + BKE_mesh_tag_positions_changed(me); mul_m4_v3(flow_ob->object_to_world, flow_center); manta_pos_to_cell(fds, flow_center); @@ -2141,7 +2135,7 @@ static void emit_from_mesh( data.fds = fds; data.ffs = ffs; data.vert_positions = positions; - data.vert_normals = vert_normals; + data.vert_normals = me->vert_normals(); data.loops = loops; data.looptris = looptris; data.mloopuv = mloopuv; @@ -3213,16 +3207,8 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, float size[3]; float cell_size_scaled[3]; - /* Assign material + flags to new mesh. - * If there are no faces in original mesh, keep materials and flags unchanged. */ - MPoly mp_example = {0}; - if (MPoly *polys = BKE_mesh_polys_for_write(orgmesh)) { - mp_example = *polys; - } - const int *orig_material_indices = BKE_mesh_material_indices(orgmesh); const short mp_mat_nr = orig_material_indices ? orig_material_indices[0] : 0; - const char mp_flag = mp_example.flag; int i; int num_verts, num_faces; @@ -3251,6 +3237,10 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, blender::MutableSpan polys = me->polys_for_write(); blender::MutableSpan loops = me->loops_for_write(); + const bool is_sharp = orgmesh->attributes().lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false)[0]; + BKE_mesh_smooth_flag_set(me, !is_sharp); + /* Get size (dimension) but considering scaling. */ copy_v3_v3(cell_size_scaled, fds->cell_size); mul_v3_v3(cell_size_scaled, ob->scale); @@ -3338,7 +3328,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, for (const int i : polys.index_range()) { /* Initialize from existing face. */ material_indices[i] = mp_mat_nr; - polys[i].flag = mp_flag; polys[i].loopstart = i * 3; polys[i].totloop = 3; diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index a91a615532f..b5bc08039b2 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -12,7 +12,7 @@ #include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "FN_multi_function_builder.hh" @@ -913,16 +913,6 @@ static void tag_component_positions_changed(void *owner) } } -static bool get_shade_smooth(const MPoly &poly) -{ - return poly.flag & ME_SMOOTH; -} - -static void set_shade_smooth(MPoly &poly, bool value) -{ - SET_FLAG_FROM_TEST(poly.flag, value, ME_SMOOTH); -} - static float get_crease(const float &crease) { return crease; @@ -1217,17 +1207,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() nullptr, AttributeValidator{&material_index_clamp}); - static BuiltinCustomDataLayerProvider shade_smooth( - "shade_smooth", - ATTR_DOMAIN_FACE, - CD_PROP_BOOL, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::NonDeletable, - face_access, - make_derived_read_attribute, - make_derived_write_attribute, - nullptr); + static BuiltinCustomDataLayerProvider sharp_face("sharp_face", + ATTR_DOMAIN_FACE, + CD_PROP_BOOL, + CD_PROP_BOOL, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Deletable, + face_access, + make_array_read_attribute, + make_array_write_attribute, + nullptr); static BuiltinCustomDataLayerProvider sharp_edge("sharp_edge", ATTR_DOMAIN_EDGE, @@ -1259,7 +1248,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access); return ComponentAttributeProviders( - {&position, &id, &material_index, &shade_smooth, &sharp_edge, &crease}, + {&position, &id, &material_index, &sharp_face, &sharp_edge, &crease}, {&corner_custom_data, &vertex_groups, &point_custom_data, diff --git a/source/blender/blenkernel/intern/geometry_fields.cc b/source/blender/blenkernel/intern/geometry_fields.cc index fd07f7eceab..64a000ca4cf 100644 --- a/source/blender/blenkernel/intern/geometry_fields.cc +++ b/source/blender/blenkernel/intern/geometry_fields.cc @@ -7,7 +7,7 @@ #include "BKE_geometry_fields.hh" #include "BKE_geometry_set.hh" #include "BKE_instances.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "BKE_type_conversions.hh" diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 2417f8e2f73..3f5fadbe636 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -11,7 +11,7 @@ #include "BKE_geometry_set.hh" #include "BKE_instances.hh" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_pointcloud.h" diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 63f5ffe2740..e99efc19276 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -4,7 +4,7 @@ #include "BKE_geometry_set_instances.hh" #include "BKE_instances.hh" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_pointcloud.h" diff --git a/source/blender/blenkernel/intern/gpencil_curve.c b/source/blender/blenkernel/intern/gpencil_curve_legacy.c similarity index 98% rename from source/blender/blenkernel/intern/gpencil_curve.c rename to source/blender/blenkernel/intern/gpencil_curve_legacy.c index bf73b9d6ed6..c6a1cb1474a 100644 --- a/source/blender/blenkernel/intern/gpencil_curve.c +++ b/source/blender/blenkernel/intern/gpencil_curve_legacy.c @@ -21,7 +21,7 @@ #include "BLT_translation.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" @@ -29,9 +29,9 @@ #include "BKE_collection.h" #include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_object.h" @@ -368,7 +368,7 @@ static void gpencil_convert_spline(Main *bmain, if ((nu->flagu & CU_NURB_CYCLIC) == 0) { segments--; } - /* Get all interpolated curve points of Beziert */ + /* Get all interpolated curve points of Bezier. */ for (int s = 0; s < segments; s++) { int inext = (s + 1) % nu->pntsu; BezTriple *prevbezt = &nu->bezt[s]; @@ -468,7 +468,7 @@ void BKE_gpencil_convert_curve(Main *bmain, const float scale_thickness, const float sample) { - if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == NULL)) { + if (ELEM(NULL, ob_gp, ob_cu) || (ob_gp->type != OB_GPENCIL_LEGACY) || (ob_gp->data == NULL)) { return; } @@ -915,7 +915,7 @@ static float *gpencil_stroke_points_from_editcurve_adaptive_resolu( bool is_cyclic, int *r_points_len) { - /* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */ + /* One stride contains: `x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor`. */ const uint stride = sizeof(float[9]); const uint cpt_last = curve_point_array_len - 1; const uint num_segments = (is_cyclic) ? curve_point_array_len : curve_point_array_len - 1; @@ -983,7 +983,7 @@ static float *gpencil_stroke_points_from_editcurve_fixed_resolu(bGPDcurve_point bool is_cyclic, int *r_points_len) { - /* One stride contains: x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor */ + /* One stride contains: `x, y, z, pressure, strength, Vr, Vg, Vb, Vmix_factor`. */ const uint stride = sizeof(float[9]); const uint array_last = curve_point_array_len - 1; const uint resolu_stride = resolution * stride; diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom_legacy.cc similarity index 99% rename from source/blender/blenkernel/intern/gpencil_geom.cc rename to source/blender/blenkernel/intern/gpencil_geom_legacy.cc index db42ea806c1..ba0aac22385 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom_legacy.cc @@ -25,8 +25,8 @@ #include "BLI_polyfill_2d.h" #include "BLI_span.hh" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -38,12 +38,12 @@ #include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "DEG_depsgraph_query.h" @@ -2504,7 +2504,7 @@ static void gpencil_generate_edgeloops(Object *ob, const Span vert_positions = me->vert_positions(); const Span edges = me->edges(); const Span dverts = me->deform_verts(); - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(me); + const blender::Span vert_normals = me->vert_normals(); const bke::AttributeAccessor attributes = me->attributes(); const VArray uv_seams = attributes.lookup_or_default( ".uv_seam", ATTR_DOMAIN_EDGE, false); @@ -2703,7 +2703,8 @@ bool BKE_gpencil_convert_mesh(Main *bmain, { using namespace blender; using namespace blender::bke; - if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL) || (ob_gp->data == nullptr)) { + if (ELEM(nullptr, ob_gp, ob_mesh) || (ob_gp->type != OB_GPENCIL_LEGACY) || + (ob_gp->data == nullptr)) { return false; } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil_legacy.c similarity index 98% rename from source/blender/blenkernel/intern/gpencil.c rename to source/blender/blenkernel/intern/gpencil_legacy.c index 67b52f67cfc..1f86ecca321 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil_legacy.c @@ -27,7 +27,7 @@ /* Allow using deprecated functionality for .blend file I/O. */ #define DNA_DEPRECATED_ALLOW -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_space_types.h" @@ -37,9 +37,9 @@ #include "BKE_collection.h" #include "BKE_colortools.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_update_cache.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_update_cache_legacy.h" #include "BKE_icons.h" #include "BKE_idtype.h" #include "BKE_image.h" @@ -191,7 +191,7 @@ void BKE_gpencil_blend_read_data(BlendDataReader *reader, bGPdata *gpd) BLO_read_data_address(reader, &gpd->adt); BKE_animdata_blend_read_data(reader, gpd->adt); - /* Ensure full objectmode for linked grease pencil. */ + /* Ensure full object-mode for linked grease pencil. */ if (ID_IS_LINKED(gpd)) { gpd->flag &= ~GP_DATA_STROKE_PAINTMODE; gpd->flag &= ~GP_DATA_STROKE_EDITMODE; @@ -296,10 +296,10 @@ static void greasepencil_blend_read_expand(BlendExpander *expander, ID *id) } } -IDTypeInfo IDType_ID_GD = { - .id_code = ID_GD, - .id_filter = FILTER_ID_GD, - .main_listbase_index = INDEX_ID_GD, +IDTypeInfo IDType_ID_GD_LEGACY = { + .id_code = ID_GD_LEGACY, + .id_filter = FILTER_ID_GD_LEGACY, + .main_listbase_index = INDEX_ID_GD_LEGACY, .struct_size = sizeof(bGPdata), .name = "GPencil", .name_plural = "grease_pencils", @@ -707,7 +707,7 @@ bGPdata *BKE_gpencil_data_addnew(Main *bmain, const char name[]) bGPdata *gpd; /* allocate memory for a new block */ - gpd = BKE_libblock_alloc(bmain, ID_GD, name, 0); + gpd = BKE_libblock_alloc(bmain, ID_GD_LEGACY, name, 0); /* initial settings */ gpd->flag = (GP_DATA_DISPINFO | GP_DATA_EXPAND); @@ -1275,9 +1275,8 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_ gpl->actframe = gpf; } else if (addnew == GP_GETFRAME_ADD_COPY) { - /* The frame_addcopy function copies the active frame of gpl, - so we need to set the active frame before copying. - */ + /* The #BKE_gpencil_frame_addcopy function copies the active frame of gpl, + * so we need to set the active frame before copying. */ gpl->actframe = gpf; gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe); } @@ -1306,9 +1305,8 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_ gpl->actframe = gpf; } else if (addnew == GP_GETFRAME_ADD_COPY) { - /* The frame_addcopy function copies the active frame of gpl; - so we need to set the active frame before copying. - */ + /* The #BKE_gpencil_frame_addcopy function copies the active frame of gpl; + * so we need to set the active frame before copying. */ gpl->actframe = gpf; gpl->actframe = BKE_gpencil_frame_addcopy(gpl, cframe); } @@ -1366,9 +1364,9 @@ bGPDframe *BKE_gpencil_layer_frame_get(bGPDlayer *gpl, int cframe, eGP_GetFrame_ gpl->actframe = gpl->frames.first; } else { - /* unresolved errogenous situation! */ + /* Unresolved erogenous situation! */ CLOG_STR_ERROR(&LOG, "cannot find appropriate gp-frame"); - /* gpl->actframe should still be NULL */ + /* `gpl->actframe` should still be NULL. */ } } } @@ -2326,7 +2324,7 @@ bool BKE_gpencil_from_image( pt->strength = 1.0f - color[3]; } - /* Selet Alpha points. */ + /* Select Alpha points. */ if (pt->strength < 0.03f) { gps->flag |= GP_STROKE_SELECT; pt->flag |= GP_SPOINT_SELECT; @@ -2710,7 +2708,7 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, /* if not layer parented, try with object parented */ if (obparent_eval == NULL) { - if ((ob_eval != NULL) && (ob_eval->type == OB_GPENCIL)) { + if ((ob_eval != NULL) && (ob_eval->type == OB_GPENCIL_LEGACY)) { copy_m4_m4(diff_mat, ob_eval->object_to_world); mul_m4_m4m4(diff_mat, diff_mat, gpl->layer_mat); return; @@ -2748,7 +2746,7 @@ void BKE_gpencil_layer_transform_matrix_get(const Depsgraph *depsgraph, void BKE_gpencil_update_layer_transforms(const Depsgraph *depsgraph, Object *ob) { - if (ob->type != OB_GPENCIL) { + if (ob->type != OB_GPENCIL_LEGACY) { return; } diff --git a/source/blender/blenkernel/intern/gpencil_modifier.c b/source/blender/blenkernel/intern/gpencil_modifier_legacy.c similarity index 99% rename from source/blender/blenkernel/intern/gpencil_modifier.c rename to source/blender/blenkernel/intern/gpencil_modifier_legacy.c index 1ad7aeed41c..b9977f637bb 100644 --- a/source/blender/blenkernel/intern/gpencil_modifier.c +++ b/source/blender/blenkernel/intern/gpencil_modifier_legacy.c @@ -18,8 +18,8 @@ #include "BLT_translation.h" #include "DNA_armature_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -29,9 +29,9 @@ #include "BKE_colortools.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" diff --git a/source/blender/blenkernel/intern/gpencil_update_cache.c b/source/blender/blenkernel/intern/gpencil_update_cache_legacy.c similarity index 98% rename from source/blender/blenkernel/intern/gpencil_update_cache.c rename to source/blender/blenkernel/intern/gpencil_update_cache_legacy.c index 9113f2e2ab9..7759d6da062 100644 --- a/source/blender/blenkernel/intern/gpencil_update_cache.c +++ b/source/blender/blenkernel/intern/gpencil_update_cache_legacy.c @@ -7,14 +7,14 @@ #include -#include "BKE_gpencil_update_cache.h" +#include "BKE_gpencil_update_cache_legacy.h" #include "BLI_dlrbTree.h" #include "BLI_listbase.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_userdef_types.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index 7fd0515b52c..ca8e85cbce4 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -16,7 +16,7 @@ #include "DNA_brush_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" diff --git a/source/blender/blenkernel/intern/idtype.c b/source/blender/blenkernel/intern/idtype.c index 923582dff4c..c194dff45fd 100644 --- a/source/blender/blenkernel/intern/idtype.c +++ b/source/blender/blenkernel/intern/idtype.c @@ -81,7 +81,7 @@ static void id_type_init(void) INIT_TYPE(ID_NT); INIT_TYPE(ID_BR); INIT_TYPE(ID_PA); - INIT_TYPE(ID_GD); + INIT_TYPE(ID_GD_LEGACY); INIT_TYPE(ID_WM); INIT_TYPE(ID_MC); INIT_TYPE(ID_MSK); @@ -220,7 +220,7 @@ uint64_t BKE_idtype_idcode_to_idfilter(const short idcode) CASE_IDFILTER(CA); CASE_IDFILTER(CF); CASE_IDFILTER(CU_LEGACY); - CASE_IDFILTER(GD); + CASE_IDFILTER(GD_LEGACY); CASE_IDFILTER(GR); CASE_IDFILTER(CV); CASE_IDFILTER(IM); @@ -278,7 +278,7 @@ short BKE_idtype_idcode_from_idfilter(const uint64_t idfilter) CASE_IDFILTER(CA); CASE_IDFILTER(CF); CASE_IDFILTER(CU_LEGACY); - CASE_IDFILTER(GD); + CASE_IDFILTER(GD_LEGACY); CASE_IDFILTER(GR); CASE_IDFILTER(CV); CASE_IDFILTER(IM); @@ -334,7 +334,7 @@ int BKE_idtype_idcode_to_index(const short idcode) CASE_IDINDEX(CA); CASE_IDINDEX(CF); CASE_IDINDEX(CU_LEGACY); - CASE_IDINDEX(GD); + CASE_IDINDEX(GD_LEGACY); CASE_IDINDEX(GR); CASE_IDINDEX(CV); CASE_IDINDEX(IM); @@ -393,7 +393,7 @@ short BKE_idtype_idcode_from_index(const int index) CASE_IDCODE(CA); CASE_IDCODE(CF); CASE_IDCODE(CU_LEGACY); - CASE_IDCODE(GD); + CASE_IDCODE(GD_LEGACY); CASE_IDCODE(GR); CASE_IDCODE(CV); CASE_IDCODE(IM); diff --git a/source/blender/blenkernel/intern/key.cc b/source/blender/blenkernel/intern/key.cc index a4f3fbf2de3..ae29e681d50 100644 --- a/source/blender/blenkernel/intern/key.cc +++ b/source/blender/blenkernel/intern/key.cc @@ -42,7 +42,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_scene.h" #include "RNA_access.h" @@ -2258,46 +2258,42 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb, } if (poly_normals_needed) { - BKE_mesh_calc_normals_poly(positions, - mesh->totvert, - loops.data(), - loops.size(), - polys.data(), - polys.size(), - poly_normals); + blender::bke::mesh::normals_calc_polys( + {reinterpret_cast(positions), mesh->totvert}, + polys, + loops, + {reinterpret_cast(poly_normals), polys.size()}); } if (vert_normals_needed) { - BKE_mesh_calc_normals_poly_and_vertex(positions, - mesh->totvert, - loops.data(), - loops.size(), - polys.data(), - polys.size(), - poly_normals, - vert_normals); + blender::bke::mesh::normals_calc_poly_vert( + {reinterpret_cast(positions), mesh->totvert}, + polys, + loops, + {reinterpret_cast(poly_normals), polys.size()}, + {reinterpret_cast(vert_normals), mesh->totvert}); } if (loop_normals_needed) { short(*clnors)[2] = static_cast(CustomData_get_layer_for_write( &mesh->ldata, CD_CUSTOMLOOPNORMAL, loops.size())); /* May be nullptr. */ const bool *sharp_edges = static_cast( CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge")); - BKE_mesh_normals_loop_split(positions, - vert_normals, - mesh->totvert, - edges.data(), - mesh->totedge, - loops.data(), - r_loop_normals, - loops.size(), - polys.data(), - poly_normals, - polys.size(), - (mesh->flag & ME_AUTOSMOOTH) != 0, - mesh->smoothresh, - sharp_edges, - nullptr, - nullptr, - clnors); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); + blender::bke::mesh::normals_calc_loop( + {reinterpret_cast(positions), mesh->totvert}, + edges, + polys, + loops, + {}, + {reinterpret_cast(vert_normals), mesh->totvert}, + {reinterpret_cast(poly_normals), polys.size()}, + sharp_edges, + sharp_faces, + (mesh->flag & ME_AUTOSMOOTH) != 0, + mesh->smoothresh, + clnors, + nullptr, + {reinterpret_cast(r_loop_normals), loops.size()}); } if (free_vert_normals) { diff --git a/source/blender/blenkernel/intern/layer.cc b/source/blender/blenkernel/intern/layer.cc index f8575125c80..3e824506677 100644 --- a/source/blender/blenkernel/intern/layer.cc +++ b/source/blender/blenkernel/intern/layer.cc @@ -2514,8 +2514,9 @@ ViewLayerAOV *BKE_view_layer_add_aov(ViewLayer *view_layer) void BKE_view_layer_remove_aov(ViewLayer *view_layer, ViewLayerAOV *aov) { - BLI_assert(BLI_findindex(&view_layer->aovs, aov) != -1); - BLI_assert(aov != nullptr); + if (aov == nullptr || BLI_findindex(&view_layer->aovs, aov) == -1) { + return; + } if (view_layer->active_aov == aov) { if (aov->next) { viewlayer_aov_active_set(view_layer, aov->next); diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index d09511ec4b3..866e3af4894 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -22,7 +22,7 @@ #include "DNA_ID.h" #include "DNA_anim_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_node_types.h" #include "DNA_workspace_types.h" @@ -44,7 +44,7 @@ #include "BKE_bpath.h" #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_key.h" @@ -839,7 +839,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) RNA_property_update(C, ptr, prop); /* tag grease pencil data-block and disable onion */ - if (GS(id->name) == ID_GD) { + if (GS(id->name) == ID_GD_LEGACY) { DEG_id_tag_update(id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); DEG_id_tag_update(newid, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); bGPdata *gpd = (bGPdata *)newid; diff --git a/source/blender/blenkernel/intern/lib_override.cc b/source/blender/blenkernel/intern/lib_override.cc index 065ee010e72..56143273862 100644 --- a/source/blender/blenkernel/intern/lib_override.cc +++ b/source/blender/blenkernel/intern/lib_override.cc @@ -2525,8 +2525,16 @@ static void lib_override_library_main_resync_on_library_indirect_level( BLI_assert(id_resync_root_iter == id_resync_roots->list && id_resync_root_iter == id_resync_roots->last_node); } - BLI_assert(!lib_override_resync_tagging_finalize_recurse( - bmain, id_resync_root, id_roots, library_indirect_level, true)); + if (lib_override_resync_tagging_finalize_recurse( + bmain, id_resync_root, id_roots, library_indirect_level, true)) { + CLOG_WARN(&LOG, + "Resync root ID still has ancestors tagged for resync, this should not happen " + "at this point." + "\n\tRoot ID: %s" + "\n\tResync root ID: %s", + id_root->name, + id_resync_root->name); + } } BLI_ghashIterator_step(id_roots_iter); } diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 4d6b78e67c4..303f9e99cdf 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -272,7 +272,7 @@ static bool library_foreach_ID_link(Main *bmain, } if (bmain != NULL && bmain->relations != NULL && (flag & IDWALK_READONLY) && - (flag & IDWALK_DO_INTERNAL_RUNTIME_POINTERS) == 0 && + (flag & (IDWALK_DO_INTERNAL_RUNTIME_POINTERS | IDWALK_DO_LIBRARY_POINTER)) == 0 && (((bmain->relations->flag & MAINIDRELATIONS_INCLUDE_UI) == 0) == ((data.flag & IDWALK_INCLUDE_UI) == 0))) { /* Note that this is minor optimization, even in worst cases (like id being an object with @@ -396,7 +396,7 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner) case ID_SCE: return FILTER_ID_OB | FILTER_ID_WO | FILTER_ID_SCE | FILTER_ID_MC | FILTER_ID_MA | FILTER_ID_GR | FILTER_ID_TXT | FILTER_ID_LS | FILTER_ID_MSK | FILTER_ID_SO | - FILTER_ID_GD | FILTER_ID_BR | FILTER_ID_PAL | FILTER_ID_IM | FILTER_ID_NT; + FILTER_ID_GD_LEGACY | FILTER_ID_BR | FILTER_ID_PAL | FILTER_ID_IM | FILTER_ID_NT; case ID_OB: /* Could be more specific, but simpler to just always say 'yes' here. */ return FILTER_ID_ALL; @@ -435,7 +435,7 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner) case ID_PA: return FILTER_ID_OB | FILTER_ID_GR | FILTER_ID_TE; case ID_MC: - return FILTER_ID_GD | FILTER_ID_IM; + return FILTER_ID_GD_LEGACY | FILTER_ID_IM; case ID_MSK: /* WARNING! mask->parent.id, not typed. */ return FILTER_ID_MC; @@ -443,7 +443,7 @@ uint64_t BKE_library_id_can_use_filter_id(const ID *id_owner) return FILTER_ID_TE | FILTER_ID_OB; case ID_LP: return FILTER_ID_IM; - case ID_GD: + case ID_GD_LEGACY: return FILTER_ID_MA; case ID_WS: return FILTER_ID_SCE; diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 4ef3bdabfaa..7376ea3f39a 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -325,20 +325,12 @@ static void libblock_remap_data_preprocess(ID *id_owner, */ static void libblock_remap_data_postprocess_object_update(Main *bmain, Object *old_ob, - Object *new_ob, + Object *UNUSED(new_ob), const bool do_sync_collection) { - if (new_ob == NULL) { - /* In case we unlinked old_ob (new_ob is NULL), the object has already - * been removed from the scenes and their collections. We still have - * to remove the NULL children from collections not used in any scene. */ - BKE_collections_object_remove_nulls(bmain); - } - else { - /* Remapping may have created duplicates of CollectionObject pointing to the same object within - * the same collection. */ - BKE_collections_object_remove_duplicates(bmain); - } + /* Will only effectively process collections that have been tagged with + * #COLLECTION_TAG_COLLECTION_OBJECT_DIRTY. See #collection_foreach_id callback. */ + BKE_collections_object_remove_invalids(bmain); if (do_sync_collection) { BKE_main_collection_sync_remap(bmain); diff --git a/source/blender/blenkernel/intern/lib_remap_test.cc b/source/blender/blenkernel/intern/lib_remap_test.cc index d0175590047..43644eccb90 100644 --- a/source/blender/blenkernel/intern/lib_remap_test.cc +++ b/source/blender/blenkernel/intern/lib_remap_test.cc @@ -20,7 +20,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_remap.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_node.h" #include "BKE_object.h" #include "BKE_scene.h" diff --git a/source/blender/blenkernel/intern/main.c b/source/blender/blenkernel/intern/main.c index 0fb52a531ac..a2c5f7a91af 100644 --- a/source/blender/blenkernel/intern/main.c +++ b/source/blender/blenkernel/intern/main.c @@ -625,7 +625,7 @@ ListBase *which_libbase(Main *bmain, short type) return &(bmain->particles); case ID_WM: return &(bmain->wm); - case ID_GD: + case ID_GD_LEGACY: return &(bmain->gpencils); case ID_MC: return &(bmain->movieclips); @@ -669,7 +669,7 @@ int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/]) lb[INDEX_ID_PAL] = &(bmain->palettes); /* Referenced by nodes, objects, view, scene etc, before to free after. */ - lb[INDEX_ID_GD] = &(bmain->gpencils); + lb[INDEX_ID_GD_LEGACY] = &(bmain->gpencils); lb[INDEX_ID_NT] = &(bmain->nodetrees); lb[INDEX_ID_IM] = &(bmain->images); diff --git a/source/blender/blenkernel/intern/material.cc b/source/blender/blenkernel/intern/material.cc index b34e92837a9..1b44c10bf28 100644 --- a/source/blender/blenkernel/intern/material.cc +++ b/source/blender/blenkernel/intern/material.cc @@ -23,7 +23,7 @@ #include "DNA_curves_types.h" #include "DNA_customdata_types.h" #include "DNA_defaults.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -48,7 +48,7 @@ #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_editmesh.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_icons.h" #include "BKE_idtype.h" #include "BKE_image.h" @@ -56,7 +56,7 @@ #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_node.h" #include "BKE_node_runtime.hh" #include "BKE_object.h" @@ -328,7 +328,7 @@ Material ***BKE_object_material_array_p(Object *ob) MetaBall *mb = static_cast(ob->data); return &(mb->mat); } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = static_cast(ob->data); return &(gpd->mat); } @@ -361,7 +361,7 @@ short *BKE_object_material_len_p(Object *ob) MetaBall *mb = static_cast(ob->data); return &(mb->totcol); } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = static_cast(ob->data); return &(gpd->totcol); } @@ -392,7 +392,7 @@ Material ***BKE_id_material_array_p(ID *id) return &(((Curve *)id)->mat); case ID_MB: return &(((MetaBall *)id)->mat); - case ID_GD: + case ID_GD_LEGACY: return &(((bGPdata *)id)->mat); case ID_CV: return &(((Curves *)id)->mat); @@ -418,7 +418,7 @@ short *BKE_id_material_len_p(ID *id) return &(((Curve *)id)->totcol); case ID_MB: return &(((MetaBall *)id)->totcol); - case ID_GD: + case ID_GD_LEGACY: return &(((bGPdata *)id)->totcol); case ID_CV: return &(((Curves *)id)->totcol); @@ -480,7 +480,7 @@ bool BKE_object_material_slot_used(Object *object, short actcol) case ID_MB: /* Meta-elements don't support materials at the moment. */ return false; - case ID_GD: + case ID_GD_LEGACY: return BKE_gpencil_material_index_used((bGPdata *)ob_data, actcol - 1); default: return false; @@ -1090,7 +1090,7 @@ void BKE_object_material_remap(Object *ob, const uint *remap) else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { BKE_curve_material_remap(static_cast(ob->data), remap, ob->totcol); } - else if (ob->type == OB_GPENCIL) { + else if (ob->type == OB_GPENCIL_LEGACY) { BKE_gpencil_material_remap(static_cast(ob->data), remap, ob->totcol); } else { @@ -1347,7 +1347,7 @@ bool BKE_object_material_slot_remove(Main *bmain, Object *ob) } } /* check indices from gpencil */ - else if (ob->type == OB_GPENCIL) { + else if (ob->type == OB_GPENCIL_LEGACY) { BKE_gpencil_material_index_reassign((bGPdata *)ob->data, ob->totcol, actcol - 1); } diff --git a/source/blender/blenkernel/intern/mball.cc b/source/blender/blenkernel/intern/mball.cc index 3a5e3104b86..14065661367 100644 --- a/source/blender/blenkernel/intern/mball.cc +++ b/source/blender/blenkernel/intern/mball.cc @@ -48,7 +48,7 @@ #include "BKE_material.h" #include "BKE_mball.h" #include "BKE_mball_tessellate.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_scene.h" diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc index 839834a8326..4be58dc1ec3 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.cc +++ b/source/blender/blenkernel/intern/mball_tessellate.cc @@ -30,7 +30,7 @@ #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_mball_tessellate.h" /* own include */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_scene.h" @@ -39,8 +39,8 @@ #include "BLI_strict_flags.h" -/* experimental (faster) normal calculation */ -// #define USE_ACCUM_NORMAL +/* experimental (faster) normal calculation (see #103021) */ +#define USE_ACCUM_NORMAL #define MBALL_ARRAY_LEN_INIT 4096 @@ -1463,15 +1463,15 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, ((ID *)ob->data)->name + 2); mesh->totvert = int(process.curvertex); - CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_ASSIGN, process.co, mesh->totvert, "position"); + CustomData_add_layer_named_with_data( + &mesh->vdata, CD_PROP_FLOAT3, process.co, mesh->totvert, "position"); process.co = nullptr; mesh->totpoly = int(process.curindex); MPoly *polys = static_cast( - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CONSTRUCT, nullptr, mesh->totpoly)); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CONSTRUCT, mesh->totpoly)); MLoop *mloop = static_cast( - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CONSTRUCT, nullptr, mesh->totpoly * 4)); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CONSTRUCT, mesh->totpoly * 4)); int loop_offset = 0; for (int i = 0; i < mesh->totpoly; i++) { @@ -1480,7 +1480,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) const int count = indices[2] != indices[3] ? 4 : 3; polys[i].loopstart = loop_offset; polys[i].totloop = count; - polys[i].flag = ME_SMOOTH; mloop[loop_offset].v = uint32_t(indices[0]); mloop[loop_offset + 1].v = uint32_t(indices[1]); diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 0549bee5a5b..2f94fe9febb 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -50,7 +50,7 @@ #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" @@ -255,20 +255,24 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address Set names_to_skip; if (!BLO_write_is_undo(writer)) { /* When converting to the old mesh format, don't save redundant attributes. */ - names_to_skip.add_multiple_new({".hide_vert", + names_to_skip.add_multiple_new({"position", + ".hide_vert", ".hide_edge", ".hide_poly", - "position", - "material_index", + ".uv_seam", ".select_vert", ".select_edge", - ".select_poly"}); + ".select_poly", + "material_index", + "sharp_face", + "sharp_edge"}); mesh->mvert = BKE_mesh_legacy_convert_positions_to_verts( mesh, temp_arrays_for_legacy_format, vert_layers); BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); BKE_mesh_legacy_convert_selection_layers_to_flags(mesh); BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); + BKE_mesh_legacy_sharp_faces_to_flags(mesh); BKE_mesh_legacy_bevel_weight_from_layers(mesh); BKE_mesh_legacy_edge_crease_from_layers(mesh); BKE_mesh_legacy_sharp_edges_to_flags(mesh); @@ -834,7 +838,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) else { if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { vs = (MVertSkin *)CustomData_add_layer( - &me->vdata, CD_MVERT_SKIN, CD_SET_DEFAULT, nullptr, me->totvert); + &me->vdata, CD_MVERT_SKIN, CD_SET_DEFAULT, me->totvert); /* Mark an arbitrary vertex as root */ if (vs) { @@ -856,7 +860,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) } else { if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, nullptr, me->totpoly); + CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, me->totpoly); changed = true; } } @@ -961,16 +965,16 @@ static void mesh_ensure_cdlayers_primary(Mesh *mesh) { if (!CustomData_get_layer_named(&mesh->vdata, CD_PROP_FLOAT3, "position")) { CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, mesh->totvert, "position"); + &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); } if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_SET_DEFAULT, mesh->totedge); } if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, mesh->totloop); } if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, mesh->totpoly); } } @@ -1090,7 +1094,7 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, * even in cases where the source mesh does not. */ mesh_ensure_cdlayers_primary(me_dst); if (do_tessface && !CustomData_get_layer(&me_dst->fdata, CD_MFACE)) { - CustomData_add_layer(&me_dst->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, me_dst->totface); + CustomData_add_layer(&me_dst->fdata, CD_MFACE, CD_SET_DEFAULT, me_dst->totface); } /* Expect that normals aren't copied at all, since the destination mesh is new. */ @@ -1179,7 +1183,7 @@ static void ensure_orig_index_layer(CustomData &data, const int size) if (CustomData_has_layer(&data, CD_ORIGINDEX)) { return; } - int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, size); + int *indices = (int *)CustomData_add_layer(&data, CD_ORIGINDEX, CD_SET_DEFAULT, size); range_vn_i(indices, size, 0); } @@ -1356,7 +1360,7 @@ void BKE_mesh_orco_ensure(Object *ob, Mesh *mesh) /* Orcos are stored in normalized 0..1 range by convention. */ float(*orcodata)[3] = BKE_mesh_orco_verts_get(ob); BKE_mesh_orco_verts_transform(mesh, orcodata, mesh->totvert, false); - CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_ASSIGN, orcodata, mesh->totvert); + CustomData_add_layer_with_data(&mesh->vdata, CD_ORCO, orcodata, mesh->totvert); } Mesh *BKE_mesh_from_object(Object *ob) @@ -1485,16 +1489,17 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth) { - MutableSpan polys = me->polys_for_write(); + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = me->attributes_for_write(); if (use_smooth) { - for (MPoly &poly : polys) { - poly.flag |= ME_SMOOTH; - } + attributes.remove("sharp_face"); } else { - for (MPoly &poly : polys) { - poly.flag &= ~ME_SMOOTH; - } + SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_only_span( + "sharp_face", ATTR_DOMAIN_FACE); + sharp_faces.span.fill(true); + sharp_faces.finish(); } } @@ -1580,6 +1585,11 @@ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) return true; } +void Mesh::bounds_set_eager(const blender::Bounds &bounds) +{ + this->runtime->bounds_cache.ensure([&](blender::Bounds &r_data) { r_data = bounds; }); +} + void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) { MutableSpan positions = me->vert_positions_for_write(); @@ -1820,7 +1830,7 @@ static float (*ensure_corner_normal_layer(Mesh &mesh))[3] } else { r_loop_normals = (float(*)[3])CustomData_add_layer( - &mesh.ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, mesh.totloop); + &mesh.ldata, CD_NORMAL, CD_SET_DEFAULT, mesh.totloop); CustomData_set_layer_flag(&mesh.ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } return r_loop_normals; @@ -1842,29 +1852,24 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, &mesh->ldata, CD_CUSTOMLOOPNORMAL, mesh->totloop); const bool *sharp_edges = static_cast( CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); - const Span positions = mesh->vert_positions(); - const Span edges = mesh->edges(); - const Span polys = mesh->polys(); - const Span loops = mesh->loops(); - - BKE_mesh_normals_loop_split(reinterpret_cast(positions.data()), - BKE_mesh_vert_normals_ensure(mesh), - positions.size(), - edges.data(), - edges.size(), - loops.data(), - r_corner_normals, - loops.size(), - polys.data(), - BKE_mesh_poly_normals_ensure(mesh), - polys.size(), - use_split_normals, - split_angle, - sharp_edges, - nullptr, - r_lnors_spacearr, - clnors); + blender::bke::mesh::normals_calc_loop( + mesh->vert_positions(), + mesh->edges(), + mesh->polys(), + mesh->loops(), + {}, + mesh->vert_normals(), + mesh->poly_normals(), + sharp_edges, + sharp_faces, + use_split_normals, + split_angle, + clnors, + nullptr, + {reinterpret_cast(r_corner_normals), mesh->totloop}); } void BKE_mesh_calc_normals_split(Mesh *mesh) diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index 44bb0c326e4..089cb6a5332 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -12,7 +12,7 @@ #include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_boolean_convert.hh" #include "BLI_alloca.h" @@ -391,15 +391,12 @@ static void copy_vert_attributes(Mesh *dest_mesh, /* Similar to copy_vert_attributes but for poly attributes. */ static void copy_poly_attributes(Mesh *dest_mesh, - MPoly *poly, - const MPoly *orig_poly, const Mesh *orig_me, int poly_index, int index_in_orig_me, Span material_remap, MutableSpan dst_material_indices) { - poly->flag = orig_poly->flag; CustomData *target_cd = &dest_mesh->pdata; const CustomData *source_cd = &orig_me->pdata; for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) { @@ -550,11 +547,7 @@ static void get_poly2d_cos(const Mesh *me, const Span poly_loops = loops.slice(poly->loopstart, poly->totloop); /* Project coordinates to 2d in cos_2d, using normal as projection axis. */ - float axis_dominant[3]; - BKE_mesh_calc_poly_normal(poly, - &loops[poly->loopstart], - reinterpret_cast(positions.data()), - axis_dominant); + const float3 axis_dominant = bke::mesh::poly_normal_calc(positions, poly_loops); axis_dominant_v3_to_m3(r_axis_mat, axis_dominant); for (const int i : poly_loops.index_range()) { float3 co = positions[poly_loops[i].v]; @@ -751,8 +744,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) } copy_poly_attributes(result, - poly, - orig_poly, orig_me, fi, index_in_orig_me, diff --git a/source/blender/blenkernel/intern/mesh_calc_edges.cc b/source/blender/blenkernel/intern/mesh_calc_edges.cc index f186d89a4e5..0d25de3c33c 100644 --- a/source/blender/blenkernel/intern/mesh_calc_edges.cc +++ b/source/blender/blenkernel/intern/mesh_calc_edges.cc @@ -15,7 +15,7 @@ #include "BKE_attribute.hh" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" namespace blender::bke::calc_edges { @@ -240,7 +240,7 @@ void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select /* Free old CustomData and assign new one. */ CustomData_free(&mesh->edata, mesh->totedge); CustomData_reset(&mesh->edata); - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_ASSIGN, new_edges.data(), new_totedge); + CustomData_add_layer_with_data(&mesh->edata, CD_MEDGE, new_edges.data(), new_totedge); mesh->totedge = new_totedge; if (select_new_edges) { diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 7bd70dcef46..9cb0c766d29 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -40,7 +40,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" @@ -76,6 +76,22 @@ using blender::StringRefNull; static CLG_LogRef LOG = {"bke.mesh_convert"}; +static void poly_edgehash_insert(EdgeHash *ehash, const MPoly *poly, const MLoop *mloop) +{ + const MLoop *ml, *ml_next; + int i = poly->totloop; + + ml_next = mloop; /* first loop */ + ml = &ml_next[i - 1]; /* last loop */ + + while (i-- != 0) { + BLI_edgehash_reinsert(ehash, ml->v, ml_next->v, nullptr); + + ml = ml_next; + ml_next++; + } +} + /** * Specialized function to use when we _know_ existing edges don't overlap with poly edges. */ @@ -90,7 +106,7 @@ static void make_edges_mdata_extend(Mesh &mesh) EdgeHash *eh = BLI_edgehash_new_ex(__func__, eh_reserve); for (const MPoly &poly : polys) { - BKE_mesh_poly_edgehash_insert(eh, &poly, &loops[poly.loopstart]); + poly_edgehash_insert(eh, &poly, &loops[poly.loopstart]); } const int totedge_new = BLI_edgehash_len(eh); @@ -195,8 +211,11 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba MutableAttributeAccessor attributes = mesh->attributes_for_write(); SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_only_span( "material_index", ATTR_DOMAIN_FACE); + SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span( + "sharp_face", ATTR_DOMAIN_FACE); + blender::float2 *mloopuv = static_cast(CustomData_add_layer_named( - &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, mesh->totloop, DATA_("UVMap"))); + &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, mesh->totloop, DATA_("UVMap"))); int dst_vert = 0; int dst_edge = 0; @@ -278,9 +297,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba } } - if (is_smooth) { - polys[dst_poly].flag |= ME_SMOOTH; - } + sharp_faces.span[dst_poly] = !is_smooth; dst_poly++; dst_loop += 3; index += 3; @@ -363,9 +380,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba } } - if (is_smooth) { - polys[dst_poly].flag |= ME_SMOOTH; - } + sharp_faces.span[dst_poly] = !is_smooth; dst_poly++; dst_loop += 4; @@ -383,6 +398,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba } material_indices.finish(); + sharp_faces.finish(); return mesh; } diff --git a/source/blender/blenkernel/intern/mesh_debug.cc b/source/blender/blenkernel/intern/mesh_debug.cc index 6cf237a7c8c..04204f8ed93 100644 --- a/source/blender/blenkernel/intern/mesh_debug.cc +++ b/source/blender/blenkernel/intern/mesh_debug.cc @@ -23,7 +23,7 @@ # include "BKE_customdata.h" -# include "BKE_mesh.h" +# include "BKE_mesh.hh" # include "BLI_dynstr.h" diff --git a/source/blender/blenkernel/intern/mesh_evaluate.cc b/source/blender/blenkernel/intern/mesh_evaluate.cc index dbd39740cbf..979c3f6a064 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.cc +++ b/source/blender/blenkernel/intern/mesh_evaluate.cc @@ -24,10 +24,9 @@ #include "BLI_utildefines.h" #include "BLI_virtual_array.hh" -#include "BKE_customdata.h" - #include "BKE_attribute.hh" -#include "BKE_mesh.h" +#include "BKE_customdata.h" +#include "BKE_mesh.hh" #include "BKE_multires.h" using blender::float3; @@ -39,65 +38,81 @@ using blender::VArray; /** \name Polygon Calculations * \{ */ -static void mesh_calc_ngon_center(const MPoly *poly, - const MLoop *loopstart, - const float (*positions)[3], - float cent[3]) +namespace blender::bke::mesh { + +static float3 poly_center_calc_ngon(const Span vert_positions, + const Span poly_loops) { - const float w = 1.0f / float(poly->totloop); + const float w = 1.0f / float(poly_loops.size()); - zero_v3(cent); - - for (int i = 0; i < poly->totloop; i++) { - madd_v3_v3fl(cent, positions[(loopstart++)->v], w); + float3 center(0); + for (const int i : poly_loops.index_range()) { + center += vert_positions[poly_loops[i].v] * w; } + return center; } -void BKE_mesh_calc_poly_center(const MPoly *poly, - const MLoop *loopstart, +float3 poly_center_calc(const Span vert_positions, const Span poly_loops) +{ + if (poly_loops.size() == 3) { + float3 center; + mid_v3_v3v3v3(center, + vert_positions[poly_loops[0].v], + vert_positions[poly_loops[1].v], + vert_positions[poly_loops[2].v]); + return center; + } + if (poly_loops.size() == 4) { + float3 center; + mid_v3_v3v3v3v3(center, + vert_positions[poly_loops[0].v], + vert_positions[poly_loops[1].v], + vert_positions[poly_loops[2].v], + vert_positions[poly_loops[3].v]); + return center; + } + return poly_center_calc_ngon(vert_positions, poly_loops); +} + +} // namespace blender::bke::mesh + +void BKE_mesh_calc_poly_center(const MLoop *poly_loops, + const int poly_size, const float (*vert_positions)[3], + const int verts_num, float r_cent[3]) { - if (poly->totloop == 3) { - mid_v3_v3v3v3(r_cent, - vert_positions[loopstart[0].v], - vert_positions[loopstart[1].v], - vert_positions[loopstart[2].v]); - } - else if (poly->totloop == 4) { - mid_v3_v3v3v3v3(r_cent, - vert_positions[loopstart[0].v], - vert_positions[loopstart[1].v], - vert_positions[loopstart[2].v], - vert_positions[loopstart[3].v]); - } - else { - mesh_calc_ngon_center(poly, loopstart, vert_positions, r_cent); - } + copy_v3_v3(r_cent, + blender::bke::mesh::poly_center_calc( + {reinterpret_cast(vert_positions), verts_num}, + {poly_loops, poly_size})); } -float BKE_mesh_calc_poly_area(const MPoly *poly, - const MLoop *loopstart, - const float (*vert_positions)[3]) +namespace blender::bke::mesh { + +float poly_area_calc(const Span vert_positions, const Span poly_loops) { - if (poly->totloop == 3) { - return area_tri_v3(vert_positions[loopstart[0].v], - vert_positions[loopstart[1].v], - vert_positions[loopstart[2].v]); + if (poly_loops.size() == 3) { + return area_tri_v3(vert_positions[poly_loops[0].v], + vert_positions[poly_loops[1].v], + vert_positions[poly_loops[2].v]); } - - const MLoop *l_iter = loopstart; - float(*vertexcos)[3] = (float(*)[3])BLI_array_alloca(vertexcos, size_t(poly->totloop)); - - /* pack vertex cos into an array for area_poly_v3 */ - for (int i = 0; i < poly->totloop; i++, l_iter++) { - copy_v3_v3(vertexcos[i], vert_positions[l_iter->v]); + Array poly_coords(poly_loops.size()); + for (const int i : poly_loops.index_range()) { + poly_coords[i] = vert_positions[poly_loops[i].v]; } + return area_poly_v3((const float(*)[3])poly_coords.data(), poly_loops.size()); +} - /* finally calculate the area */ - float area = area_poly_v3((const float(*)[3])vertexcos, uint(poly->totloop)); +} // namespace blender::bke::mesh - return area; +float BKE_mesh_calc_poly_area(const MLoop *poly_loops, + const int poly_size, + const float (*vert_positions)[3], + const int verts_num) +{ + return blender::bke::mesh::poly_area_calc( + {reinterpret_cast(vert_positions), verts_num}, {poly_loops, poly_size}); } float BKE_mesh_calc_area(const Mesh *me) @@ -108,14 +123,14 @@ float BKE_mesh_calc_area(const Mesh *me) float total_area = 0.0f; for (const MPoly &poly : polys) { - total_area += BKE_mesh_calc_poly_area( - &poly, &loops[poly.loopstart], reinterpret_cast(positions.data())); + total_area += blender::bke::mesh::poly_area_calc(positions, + loops.slice(poly.loopstart, poly.totloop)); } return total_area; } -static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *poly, - const MLoop *loopstart, +static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MLoop *poly_loops, + const int poly_size, const float (*positions)[3], float r_cent[3]) { @@ -124,11 +139,11 @@ static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *poly, zero_v3(r_cent); - v_pivot = positions[loopstart[0].v]; - v_step1 = positions[loopstart[1].v]; + v_pivot = positions[poly_loops[0].v]; + v_step1 = positions[poly_loops[1].v]; - for (int i = 2; i < poly->totloop; i++) { - const float *v_step2 = positions[loopstart[i].v]; + for (int i = 2; i < poly_size; i++) { + const float *v_step2 = positions[poly_loops[i].v]; /* Calculate the 6x volume of the tetrahedron formed by the 3 vertices * of the triangle and the origin as the fourth vertex */ @@ -151,26 +166,27 @@ static float UNUSED_FUNCTION(mesh_calc_poly_volume_centroid)(const MPoly *poly, return total_volume; } +namespace blender::bke::mesh { + /** * A version of mesh_calc_poly_volume_centroid that takes an initial reference center, * use this to increase numeric stability as the quality of the result becomes * very low quality as the value moves away from 0.0, see: #65986. */ -static float mesh_calc_poly_volume_centroid_with_reference_center(const MPoly *poly, - const MLoop *loopstart, - const Span positions, - const float reference_center[3], +static float mesh_calc_poly_volume_centroid_with_reference_center(const Span positions, + const Span poly_loops, + const float3 &reference_center, float r_cent[3]) { /* See: mesh_calc_poly_volume_centroid for comments. */ float v_pivot[3], v_step1[3]; float total_volume = 0.0f; zero_v3(r_cent); - sub_v3_v3v3(v_pivot, positions[loopstart[0].v], reference_center); - sub_v3_v3v3(v_step1, positions[loopstart[1].v], reference_center); - for (int i = 2; i < poly->totloop; i++) { + sub_v3_v3v3(v_pivot, positions[poly_loops[0].v], reference_center); + sub_v3_v3v3(v_step1, positions[poly_loops[1].v], reference_center); + for (int i = 2; i < poly_loops.size(); i++) { float v_step2[3]; - sub_v3_v3v3(v_step2, positions[loopstart[i].v], reference_center); + sub_v3_v3v3(v_step2, positions[poly_loops[i].v], reference_center); const float tetra_volume = volume_tri_tetrahedron_signed_v3_6x(v_pivot, v_step1, v_step2); total_volume += tetra_volume; for (uint j = 0; j < 3; j++) { @@ -187,21 +203,22 @@ static float mesh_calc_poly_volume_centroid_with_reference_center(const MPoly *p * - This has the advantage over #mesh_calc_poly_volume_centroid * that it doesn't depend on solid geometry, instead it weights the surface by volume. */ -static float mesh_calc_poly_area_centroid(const MPoly *poly, - const MLoop *loopstart, - const float (*positions)[3], - float r_cent[3]) +static float poly_area_centroid_calc(const Span positions, + const Span poly_loops, + float r_cent[3]) { float total_area = 0.0f; - float v1[3], v2[3], v3[3], normal[3], tri_cent[3]; + float v1[3], v2[3], v3[3], tri_cent[3]; + + const float3 normal = blender::bke::mesh::poly_normal_calc(positions, poly_loops); + + copy_v3_v3(v1, positions[poly_loops[0].v]); + copy_v3_v3(v2, positions[poly_loops[1].v]); - BKE_mesh_calc_poly_normal(poly, loopstart, positions, normal); - copy_v3_v3(v1, positions[loopstart[0].v]); - copy_v3_v3(v2, positions[loopstart[1].v]); zero_v3(r_cent); - for (int i = 2; i < poly->totloop; i++) { - copy_v3_v3(v3, positions[loopstart[i].v]); + for (int i = 2; i < poly_loops.size(); i++) { + copy_v3_v3(v3, positions[poly_loops[i].v]); float tri_area = area_tri_signed_v3(v1, v2, v3, normal); total_area += tri_area; @@ -217,24 +234,23 @@ static float mesh_calc_poly_area_centroid(const MPoly *poly, return total_area; } -void BKE_mesh_calc_poly_angles(const MPoly *poly, - const MLoop *loopstart, - const float (*vert_positions)[3], - float angles[]) +void poly_angles_calc(const Span vert_positions, + const Span poly_loops, + MutableSpan angles) { float nor_prev[3]; float nor_next[3]; - int i_this = poly->totloop - 1; + int i_this = poly_loops.size() - 1; int i_next = 0; sub_v3_v3v3( - nor_prev, vert_positions[loopstart[i_this - 1].v], vert_positions[loopstart[i_this].v]); + nor_prev, vert_positions[poly_loops[i_this - 1].v], vert_positions[poly_loops[i_this].v]); normalize_v3(nor_prev); - while (i_next < poly->totloop) { + while (i_next < poly_loops.size()) { sub_v3_v3v3( - nor_next, vert_positions[loopstart[i_this].v], vert_positions[loopstart[i_next].v]); + nor_next, vert_positions[poly_loops[i_this].v], vert_positions[poly_loops[i_next].v]); normalize_v3(nor_next); angles[i_this] = angle_normalized_v3v3(nor_prev, nor_next); @@ -245,34 +261,7 @@ void BKE_mesh_calc_poly_angles(const MPoly *poly, } } -void BKE_mesh_poly_edgehash_insert(EdgeHash *ehash, const MPoly *poly, const MLoop *mloop) -{ - const MLoop *ml, *ml_next; - int i = poly->totloop; - - ml_next = mloop; /* first loop */ - ml = &ml_next[i - 1]; /* last loop */ - - while (i-- != 0) { - BLI_edgehash_reinsert(ehash, ml->v, ml_next->v, nullptr); - - ml = ml_next; - ml_next++; - } -} - -void BKE_mesh_poly_edgebitmap_insert(uint *edge_bitmap, const MPoly *poly, const MLoop *mloop) -{ - const MLoop *ml; - int i = poly->totloop; - - ml = mloop; - - while (i-- != 0) { - BLI_BITMAP_ENABLE(edge_bitmap, ml->e); - ml++; - } -} +} // namespace blender::bke::mesh /** \} */ @@ -332,7 +321,7 @@ bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3]) float poly_area; float total_area = 0.0f; float poly_cent[3]; - const float(*positions)[3] = BKE_mesh_vert_positions(me); + const Span positions = me->vert_positions(); const blender::Span polys = me->polys(); const blender::Span loops = me->loops(); @@ -340,8 +329,8 @@ bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3]) /* calculate a weighted average of polygon centroids */ for (const int i : polys.index_range()) { - poly_area = mesh_calc_poly_area_centroid( - &polys[i], &loops[polys[i].loopstart], positions, poly_cent); + poly_area = blender::bke::mesh::poly_area_centroid_calc( + positions, loops.slice(polys[i].loopstart, polys[i].totloop), poly_cent); madd_v3_v3fl(r_cent, poly_cent, poly_area); total_area += poly_area; @@ -376,8 +365,8 @@ bool BKE_mesh_center_of_volume(const Mesh *me, float r_cent[3]) /* calculate a weighted average of polyhedron centroids */ for (const int i : polys.index_range()) { - poly_volume = mesh_calc_poly_volume_centroid_with_reference_center( - &polys[i], &loops[polys[i].loopstart], positions, init_cent, poly_cent); + poly_volume = blender::bke::mesh::mesh_calc_poly_volume_centroid_with_reference_center( + positions, loops.slice(polys[i].loopstart, polys[i].totloop), init_cent, poly_cent); /* poly_cent is already volume-weighted, so no need to multiply by the volume */ add_v3_v3(r_cent, poly_cent); diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc index 419be52afe0..b7e5fdc8104 100644 --- a/source/blender/blenkernel/intern/mesh_fair.cc +++ b/source/blender/blenkernel/intern/mesh_fair.cc @@ -16,7 +16,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_fair.h" #include "BKE_mesh_mapping.h" diff --git a/source/blender/blenkernel/intern/mesh_iterators.cc b/source/blender/blenkernel/intern/mesh_iterators.cc index 0dc3d77cb8e..b1a47e176d3 100644 --- a/source/blender/blenkernel/intern/mesh_iterators.cc +++ b/source/blender/blenkernel/intern/mesh_iterators.cc @@ -12,7 +12,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_iterators.h" #include "BLI_bitmap.h" @@ -67,13 +67,14 @@ void BKE_mesh_foreach_mapped_vert( else { const float(*positions)[3] = BKE_mesh_vert_positions(mesh); const int *index = static_cast(CustomData_get_layer(&mesh->vdata, CD_ORIGINDEX)); - const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? - BKE_mesh_vert_normals_ensure(mesh) : - nullptr; + blender::Span vert_normals; + if (flag & MESH_FOREACH_USE_NORMAL) { + vert_normals = mesh->vert_normals(); + } if (index) { for (int i = 0; i < mesh->totvert; i++) { - const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : nullptr; + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr; const int orig = *index++; if (orig == ORIGINDEX_NONE) { continue; @@ -83,7 +84,7 @@ void BKE_mesh_foreach_mapped_vert( } else { for (int i = 0; i < mesh->totvert; i++) { - const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[i] : nullptr; + const float *no = (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[i].x : nullptr; func(userData, i, positions[i], no); } } @@ -233,6 +234,7 @@ void BKE_mesh_foreach_mapped_face_center( void *userData, MeshForeachFlag flag) { + using namespace blender; if (mesh->edit_mesh != nullptr && mesh->runtime->edit_data != nullptr) { BMEditMesh *em = mesh->edit_mesh; BMesh *bm = em->bm; @@ -267,11 +269,9 @@ void BKE_mesh_foreach_mapped_face_center( } } else { - const float(*positions)[3] = BKE_mesh_vert_positions(mesh); + const blender::Span positions = mesh->vert_positions(); const blender::Span polys = mesh->polys(); const blender::Span loops = mesh->loops(); - float _no_buf[3]; - float *no = (flag & MESH_FOREACH_USE_NORMAL) ? _no_buf : nullptr; const int *index = static_cast(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); if (index) { @@ -280,22 +280,28 @@ void BKE_mesh_foreach_mapped_face_center( if (orig == ORIGINDEX_NONE) { continue; } - float cent[3]; - BKE_mesh_calc_poly_center(&polys[i], &loops[polys[i].loopstart], positions, cent); + const Span poly_loops = loops.slice(polys[i].loopstart, polys[i].totloop); + const float3 center = bke::mesh::poly_center_calc(positions, poly_loops); if (flag & MESH_FOREACH_USE_NORMAL) { - BKE_mesh_calc_poly_normal(&polys[i], &loops[polys[i].loopstart], positions, no); + const float3 normal = bke::mesh::poly_normal_calc(positions, poly_loops); + func(userData, orig, center, normal); + } + else { + func(userData, orig, center, nullptr); } - func(userData, orig, cent, no); } } else { for (const int i : polys.index_range()) { - float cent[3]; - BKE_mesh_calc_poly_center(&polys[i], &loops[polys[i].loopstart], positions, cent); + const Span poly_loops = loops.slice(polys[i].loopstart, polys[i].totloop); + const float3 center = bke::mesh::poly_center_calc(positions, poly_loops); if (flag & MESH_FOREACH_USE_NORMAL) { - BKE_mesh_calc_poly_normal(&polys[i], &loops[polys[i].loopstart], positions, no); + const float3 normal = bke::mesh::poly_normal_calc(positions, poly_loops); + func(userData, i, center, normal); + } + else { + func(userData, i, center, nullptr); } - func(userData, i, cent, no); } } } @@ -310,9 +316,10 @@ void BKE_mesh_foreach_mapped_subdiv_face_center( const float(*positions)[3] = BKE_mesh_vert_positions(mesh); const blender::Span polys = mesh->polys(); const blender::Span loops = mesh->loops(); - const float(*vert_normals)[3] = (flag & MESH_FOREACH_USE_NORMAL) ? - BKE_mesh_vert_normals_ensure(mesh) : - nullptr; + blender::Span vert_normals; + if (flag & MESH_FOREACH_USE_NORMAL) { + vert_normals = mesh->vert_normals(); + } const int *index = static_cast(CustomData_get_layer(&mesh->pdata, CD_ORIGINDEX)); const blender::BitSpan facedot_tags = mesh->runtime->subsurf_face_dot_tags; @@ -327,7 +334,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center( func(userData, orig, positions[loop.v], - (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[loop.v] : nullptr); + (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[loop.v].x : nullptr); } } } @@ -339,7 +346,7 @@ void BKE_mesh_foreach_mapped_subdiv_face_center( func(userData, i, positions[loop.v], - (flag & MESH_FOREACH_USE_NORMAL) ? vert_normals[loop.v] : nullptr); + (flag & MESH_FOREACH_USE_NORMAL) ? &vert_normals[loop.v].x : nullptr); } } } diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 46908416325..82179b6204f 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -27,7 +27,7 @@ #include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.h" #include "BKE_multires.h" @@ -228,7 +228,7 @@ void BKE_mesh_calc_edges_legacy(Mesh *me) return; } - edges = (MEdge *)CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, edges, totedge); + edges = (MEdge *)CustomData_add_layer_with_data(&me->edata, CD_MEDGE, edges, totedge); me->totedge = totedge; BKE_mesh_tag_topology_changed(me); @@ -394,19 +394,17 @@ static void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int to for (int i = 0; i < fdata->totlayer; i++) { if (fdata->layers[i].type == CD_MTFACE) { CustomData_add_layer_named( - ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); + ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MCOL) { CustomData_add_layer_named( - ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); + ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MDISPS) { - CustomData_add_layer_named( - ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); + CustomData_add_layer_named(ldata, CD_MDISPS, CD_SET_DEFAULT, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) { - CustomData_add_layer_named( - ldata, CD_NORMAL, CD_SET_DEFAULT, nullptr, totloop, fdata->layers[i].name); + CustomData_add_layer_named(ldata, CD_NORMAL, CD_SET_DEFAULT, totloop, fdata->layers[i].name); } } } @@ -440,12 +438,18 @@ static void convert_mfaces_to_mpolys(ID *id, CustomData_free(pdata, totpoly_i); totpoly = totface_i; - mpoly = (MPoly *)CustomData_add_layer(pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly); + mpoly = (MPoly *)CustomData_add_layer(pdata, CD_MPOLY, CD_SET_DEFAULT, totpoly); int *material_indices = static_cast( CustomData_get_layer_named_for_write(pdata, CD_PROP_INT32, "material_index", totpoly)); if (material_indices == nullptr) { material_indices = static_cast(CustomData_add_layer_named( - pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, totpoly, "material_index")); + pdata, CD_PROP_INT32, CD_SET_DEFAULT, totpoly, "material_index")); + } + bool *sharp_faces = static_cast( + CustomData_get_layer_named_for_write(pdata, CD_PROP_BOOL, "sharp_face", totpoly)); + if (!sharp_faces) { + sharp_faces = static_cast( + CustomData_add_layer_named(pdata, CD_PROP_BOOL, CD_SET_DEFAULT, totpoly, "sharp_face")); } numTex = CustomData_number_of_layers(fdata, CD_MTFACE); @@ -457,7 +461,7 @@ static void convert_mfaces_to_mpolys(ID *id, totloop += mf->v4 ? 4 : 3; } - mloop = (MLoop *)CustomData_add_layer(ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop); + mloop = (MLoop *)CustomData_add_layer(ldata, CD_MLOOP, CD_SET_DEFAULT, totloop); CustomData_to_bmeshpoly(fdata, ldata, totloop); @@ -491,7 +495,7 @@ static void convert_mfaces_to_mpolys(ID *id, poly->totloop = mf->v4 ? 4 : 3; material_indices[i] = mf->mat_nr; - poly->flag = mf->flag; + sharp_faces[i] = (mf->flag & ME_SMOOTH) == 0; #define ML(v1, v2) \ { \ @@ -619,28 +623,25 @@ static void add_mface_layers(Mesh &mesh, CustomData *fdata, CustomData *ldata, i for (int i = 0; i < ldata->totlayer; i++) { if (ldata->layers[i].type == CD_PROP_FLOAT2) { - CustomData_add_layer_named( - fdata, CD_MTFACE, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); + CustomData_add_layer_named(fdata, CD_MTFACE, CD_SET_DEFAULT, total, ldata->layers[i].name); } if (ldata->layers[i].type == CD_PROP_BYTE_COLOR) { - CustomData_add_layer_named( - fdata, CD_MCOL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); + CustomData_add_layer_named(fdata, CD_MCOL, CD_SET_DEFAULT, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) { CustomData_add_layer_named( - fdata, CD_PREVIEW_MCOL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); + fdata, CD_PREVIEW_MCOL, CD_SET_DEFAULT, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) { CustomData_add_layer_named( - fdata, CD_ORIGSPACE, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); + fdata, CD_ORIGSPACE, CD_SET_DEFAULT, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_NORMAL) { CustomData_add_layer_named( - fdata, CD_TESSLOOPNORMAL, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); + fdata, CD_TESSLOOPNORMAL, CD_SET_DEFAULT, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_TANGENT) { - CustomData_add_layer_named( - fdata, CD_TANGENT, CD_SET_DEFAULT, nullptr, total, ldata->layers[i].name); + CustomData_add_layer_named(fdata, CD_TANGENT, CD_SET_DEFAULT, total, ldata->layers[i].name); } } @@ -975,6 +976,8 @@ static int mesh_tessface_calc(Mesh &mesh, mloop = (const MLoop *)CustomData_get_layer(ldata, CD_MLOOP); const int *material_indices = static_cast( CustomData_get_layer_named(pdata, CD_PROP_INT32, "material_index")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(pdata, CD_PROP_BOOL, "sharp_face")); /* Allocate the length of `totfaces`, avoid many small reallocation's, * if all faces are triangles it will be correct, `quads == 2x` allocations. */ @@ -1014,7 +1017,7 @@ static int mesh_tessface_calc(Mesh &mesh, lidx[2] = l3; \ lidx[3] = 0; \ mf->mat_nr = material_indices ? material_indices[poly_index] : 0; \ - mf->flag = poly->flag; \ + mf->flag = (sharp_faces && sharp_faces[poly_index]) ? 0 : ME_SMOOTH; \ mf->edcode = 0; \ (void)0 @@ -1037,7 +1040,7 @@ static int mesh_tessface_calc(Mesh &mesh, lidx[2] = l3; \ lidx[3] = l4; \ mf->mat_nr = material_indices ? material_indices[poly_index] : 0; \ - mf->flag = poly->flag; \ + mf->flag = (sharp_faces && sharp_faces[poly_index]) ? 0 : ME_SMOOTH; \ mf->edcode = TESSFACE_IS_QUAD; \ (void)0 @@ -1123,7 +1126,6 @@ static int mesh_tessface_calc(Mesh &mesh, lidx[3] = 0; mf->mat_nr = material_indices ? material_indices[poly_index] : 0; - mf->flag = poly->flag; mf->edcode = 0; mface_index++; @@ -1150,11 +1152,11 @@ static int mesh_tessface_calc(Mesh &mesh, sizeof(*mface_to_poly_map) * size_t(totface)); } - CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface); + CustomData_add_layer_with_data(fdata, CD_MFACE, mface, totface); /* #CD_ORIGINDEX will contain an array of indices from tessellation-faces to the polygons * they are directly tessellated from. */ - CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, mface_to_poly_map, totface); + CustomData_add_layer_with_data(fdata, CD_ORIGINDEX, mface_to_poly_map, totface); add_mface_layers(mesh, fdata, ldata, totface); /* NOTE: quad detection issue - fourth vertex-index vs fourth loop-index: @@ -1214,6 +1216,57 @@ void BKE_mesh_tessface_ensure(struct Mesh *mesh) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Sharp Edge Conversion + * \{ */ + +void BKE_mesh_legacy_sharp_faces_to_flags(Mesh *mesh) +{ + using namespace blender; + MutableSpan polys = mesh->polys_for_write(); + if (const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"))) { + threading::parallel_for(polys.index_range(), 4096, [&](const IndexRange range) { + for (const int i : range) { + SET_FLAG_FROM_TEST(polys[i].flag_legacy, !sharp_faces[i], ME_SMOOTH); + } + }); + } + else { + for (const int i : polys.index_range()) { + polys[i].flag_legacy |= ME_SMOOTH; + } + } +} + +void BKE_mesh_legacy_sharp_faces_from_flags(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + const Span polys = mesh->polys(); + MutableAttributeAccessor attributes = mesh->attributes_for_write(); + if (attributes.contains("sharp_face")) { + return; + } + if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) { + return !(poly.flag_legacy & ME_SMOOTH); + })) { + SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_only_span( + "sharp_face", ATTR_DOMAIN_FACE); + threading::parallel_for(polys.index_range(), 4096, [&](const IndexRange range) { + for (const int i : range) { + sharp_faces.span[i] = !(polys[i].flag_legacy & ME_SMOOTH); + } + }); + sharp_faces.finish(); + } + else { + attributes.remove("sharp_face"); + } +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Face Set Conversion * \{ */ @@ -1256,8 +1309,8 @@ void BKE_mesh_legacy_face_set_to_generic(Mesh *mesh) } } if (faceset_data != nullptr) { - CustomData_add_layer_named( - &mesh->pdata, CD_PROP_INT32, CD_ASSIGN, faceset_data, mesh->totpoly, ".sculpt_face_set"); + CustomData_add_layer_named_with_data( + &mesh->pdata, CD_PROP_INT32, faceset_data, mesh->totpoly, ".sculpt_face_set"); } } @@ -1307,7 +1360,7 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh) const Span verts(mesh->mvert, mesh->totvert); if (mesh->cd_flag & ME_CDFLAG_VERT_BWEIGHT) { float *weights = static_cast( - CustomData_add_layer(&mesh->vdata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, verts.size())); + CustomData_add_layer(&mesh->vdata, CD_BWEIGHT, CD_CONSTRUCT, verts.size())); for (const int i : verts.index_range()) { weights[i] = verts[i].bweight_legacy / 255.0f; } @@ -1318,7 +1371,7 @@ void BKE_mesh_legacy_bevel_weight_to_layers(Mesh *mesh) if (!CustomData_has_layer(&mesh->edata, CD_BWEIGHT)) { if (mesh->cd_flag & ME_CDFLAG_EDGE_BWEIGHT) { float *weights = static_cast( - CustomData_add_layer(&mesh->edata, CD_BWEIGHT, CD_CONSTRUCT, nullptr, edges.size())); + CustomData_add_layer(&mesh->edata, CD_BWEIGHT, CD_CONSTRUCT, edges.size())); for (const int i : edges.index_range()) { weights[i] = edges[i].bweight_legacy / 255.0f; } @@ -1360,7 +1413,7 @@ void BKE_mesh_legacy_edge_crease_to_layers(Mesh *mesh) const Span edges = mesh->edges(); if (mesh->cd_flag & ME_CDFLAG_EDGE_CREASE) { float *creases = static_cast( - CustomData_add_layer(&mesh->edata, CD_CREASE, CD_CONSTRUCT, nullptr, edges.size())); + CustomData_add_layer(&mesh->edata, CD_CREASE, CD_CONSTRUCT, edges.size())); for (const int i : edges.index_range()) { creases[i] = edges[i].crease_legacy / 255.0f; } @@ -1496,7 +1549,7 @@ void BKE_mesh_legacy_convert_hide_layers_to_flags(Mesh *mesh) ".hide_poly", ATTR_DOMAIN_FACE, false); threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { - SET_FLAG_FROM_TEST(polys[i].flag, hide_poly[i], ME_HIDE); + SET_FLAG_FROM_TEST(polys[i].flag_legacy, hide_poly[i], ME_HIDE); } }); } @@ -1539,13 +1592,14 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh) } const Span polys = mesh->polys(); - if (std::any_of( - polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_HIDE; })) { + if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) { + return poly.flag_legacy & ME_HIDE; + })) { SpanAttributeWriter hide_poly = attributes.lookup_or_add_for_write_only_span( ".hide_poly", ATTR_DOMAIN_FACE); threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { - hide_poly.span[i] = polys[i].flag & ME_HIDE; + hide_poly.span[i] = polys[i].flag_legacy & ME_HIDE; } }); hide_poly.finish(); @@ -1743,32 +1797,29 @@ void BKE_mesh_legacy_convert_uvs_to_generic(Mesh *mesh) }); CustomData_free_layer_named(&mesh->ldata, name.c_str(), mesh->totloop); - CustomData_add_layer_named( - &mesh->ldata, CD_PROP_FLOAT2, CD_ASSIGN, coords, mesh->totloop, name.c_str()); + CustomData_add_layer_named_with_data( + &mesh->ldata, CD_PROP_FLOAT2, coords, mesh->totloop, name.c_str()); char buffer[MAX_CUSTOMDATA_LAYER_NAME]; if (vert_selection) { - CustomData_add_layer_named(&mesh->ldata, - CD_PROP_BOOL, - CD_ASSIGN, - vert_selection, - mesh->totloop, - BKE_uv_map_vert_select_name_get(name.c_str(), buffer)); + CustomData_add_layer_named_with_data(&mesh->ldata, + CD_PROP_BOOL, + vert_selection, + mesh->totloop, + BKE_uv_map_vert_select_name_get(name.c_str(), buffer)); } if (edge_selection) { - CustomData_add_layer_named(&mesh->ldata, - CD_PROP_BOOL, - CD_ASSIGN, - edge_selection, - mesh->totloop, - BKE_uv_map_edge_select_name_get(name.c_str(), buffer)); + CustomData_add_layer_named_with_data(&mesh->ldata, + CD_PROP_BOOL, + edge_selection, + mesh->totloop, + BKE_uv_map_edge_select_name_get(name.c_str(), buffer)); } if (pin) { - CustomData_add_layer_named(&mesh->ldata, - CD_PROP_BOOL, - CD_ASSIGN, - pin, - mesh->totloop, - BKE_uv_map_pin_name_get(name.c_str(), buffer)); + CustomData_add_layer_named_with_data(&mesh->ldata, + CD_PROP_BOOL, + pin, + mesh->totloop, + BKE_uv_map_pin_name_get(name.c_str(), buffer)); } } @@ -1814,7 +1865,7 @@ void BKE_mesh_legacy_convert_selection_layers_to_flags(Mesh *mesh) ".select_poly", ATTR_DOMAIN_FACE, false); threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { - SET_FLAG_FROM_TEST(polys[i].flag, select_poly[i], ME_FACE_SEL); + SET_FLAG_FROM_TEST(polys[i].flag_legacy, select_poly[i], ME_FACE_SEL); } }); } @@ -1858,13 +1909,14 @@ void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh) } const Span polys = mesh->polys(); - if (std::any_of( - polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_FACE_SEL; })) { + if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) { + return poly.flag_legacy & ME_FACE_SEL; + })) { SpanAttributeWriter select_poly = attributes.lookup_or_add_for_write_only_span( ".select_poly", ATTR_DOMAIN_FACE); threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { - select_poly.span[i] = polys[i].flag & ME_FACE_SEL; + select_poly.span[i] = polys[i].flag_legacy & ME_FACE_SEL; } }); select_poly.finish(); @@ -1940,7 +1992,7 @@ void BKE_mesh_legacy_convert_verts_to_positions(Mesh *mesh) mesh->totvert); MutableSpan positions( static_cast(CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, mesh->totvert, "position")), + &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position")), mesh->totvert); threading::parallel_for(verts.index_range(), 2048, [&](IndexRange range) { for (const int i : range) { diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc index fd2452554fa..6ee3d0981b1 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.cc +++ b/source/blender/blenkernel/intern/mesh_mapping.cc @@ -845,11 +845,14 @@ int *BKE_mesh_calc_smoothgroups(const int totedge, const MLoop *mloop, const int totloop, const bool *sharp_edges, + const bool *sharp_faces, int *r_totgroup, const bool use_bitflags) { int *poly_groups = nullptr; + auto poly_is_smooth = [&](const int i) { return !(sharp_faces && sharp_faces[i]); }; + auto poly_is_island_boundary_smooth = [&](const int poly_index, const int /*loop_index*/, const int edge_index, @@ -857,13 +860,13 @@ int *BKE_mesh_calc_smoothgroups(const int totedge, const MeshElemMap &edge_poly_map_elem) { /* Edge is sharp if one of its polys is flat, or edge itself is sharp, * or edge is not used by exactly two polygons. */ - if ((polys[poly_index].flag & ME_SMOOTH) && !(sharp_edges && sharp_edges[edge_index]) && + if ((poly_is_smooth(poly_index)) && !(sharp_edges && sharp_edges[edge_index]) && (edge_user_count == 2)) { /* In that case, edge appears to be smooth, but we need to check its other poly too. */ const int other_poly_index = (poly_index == edge_poly_map_elem.indices[0]) ? edge_poly_map_elem.indices[1] : edge_poly_map_elem.indices[0]; - return (polys[other_poly_index].flag & ME_SMOOTH) == 0; + return !poly_is_smooth(other_poly_index); } return true; }; diff --git a/source/blender/blenkernel/intern/mesh_merge_customdata.cc b/source/blender/blenkernel/intern/mesh_merge_customdata.cc index 6ceedc66082..b0eaa53d345 100644 --- a/source/blender/blenkernel/intern/mesh_merge_customdata.cc +++ b/source/blender/blenkernel/intern/mesh_merge_customdata.cc @@ -15,7 +15,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BLI_memarena.h" @@ -63,7 +63,7 @@ static void merge_uvs_for_vertex(const Span loops_for_vert, Span if (loops_for_vert.size() <= 1) { return; } - /* Manipulate a copy of the loop indices, de-duplicating UVs per layer. */ + /* Manipulate a copy of the loop indices, de-duplicating UVs per layer. */ Vector loops_merge; loops_merge.reserve(loops_for_vert.size()); for (float2 *mloopuv : mloopuv_layers) { diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 1a672d157dd..3d8ea9223a6 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -5,6 +5,7 @@ * \ingroup bke */ +#include "BLI_array.hh" #include "BLI_math.h" #include "DNA_mesh_types.h" @@ -14,7 +15,7 @@ #include "BKE_deform.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mirror.h" #include "BKE_modifier.h" @@ -372,8 +373,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, /* handle custom split normals */ if (ob->type == OB_MESH && (((Mesh *)ob->data)->flag & ME_AUTOSMOOTH) && CustomData_has_layer(&result->ldata, CD_CUSTOMLOOPNORMAL) && result->totpoly > 0) { - float(*loop_normals)[3] = static_cast( - MEM_calloc_arrayN(size_t(result->totloop), sizeof(*loop_normals), __func__)); + blender::Array loop_normals(result_loops.size()); CustomData *ldata = &result->ldata; short(*clnors)[2] = static_cast( CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, result->totloop)); @@ -389,23 +389,22 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, const bool *sharp_edges = static_cast( CustomData_get_layer_named(&result->edata, CD_PROP_BOOL, "sharp_edge")); - BKE_mesh_normals_loop_split(BKE_mesh_vert_positions(result), - BKE_mesh_vert_normals_ensure(result), - result->totvert, - result_edges.data(), - result_edges.size(), - result_loops.data(), - loop_normals, - result_loops.size(), - result_polys.data(), - BKE_mesh_poly_normals_ensure(result), - result_polys.size(), - true, - result->smoothresh, - sharp_edges, - nullptr, - &lnors_spacearr, - clnors); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face")); + blender::bke::mesh::normals_calc_loop(result->vert_positions(), + result_edges, + result_polys, + result_loops, + {}, + result->vert_normals(), + result->poly_normals(), + sharp_edges, + sharp_faces, + true, + result->smoothresh, + clnors, + &lnors_spacearr, + loop_normals); /* mirroring has to account for loops being reversed in polys in second half */ for (const int i : src_polys.index_range()) { @@ -424,7 +423,6 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, } } - MEM_freeN(loop_normals); BKE_lnor_spacearr_free(&lnors_spacearr); } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index ba7eaf00e3d..a302091a065 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -21,7 +21,7 @@ #include "BLI_linklist.h" #include "BLI_linklist_stack.h" #include "BLI_math.h" -#include "BLI_math_vector_types.hh" +#include "BLI_math_vector.hh" #include "BLI_memarena.h" #include "BLI_span.hh" #include "BLI_stack.h" @@ -34,7 +34,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh_cache.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "atomic_ops.h" @@ -100,46 +100,28 @@ static void add_v3_v3_atomic(float r[3], const float a[3]) * Related to managing normals but not directly related to calculating normals. * \{ */ -void BKE_mesh_normals_tag_dirty(Mesh *mesh) -{ - mesh->runtime->vert_normals_dirty = true; - mesh->runtime->poly_normals_dirty = true; -} - float (*BKE_mesh_vert_normals_for_write(Mesh *mesh))[3] { - if (mesh->runtime->vert_normals == nullptr) { - mesh->runtime->vert_normals = (float(*)[3])MEM_malloc_arrayN( - mesh->totvert, sizeof(float[3]), __func__); - } - - BLI_assert(MEM_allocN_len(mesh->runtime->vert_normals) >= sizeof(float[3]) * mesh->totvert); - - return mesh->runtime->vert_normals; + mesh->runtime->vert_normals.reinitialize(mesh->totvert); + return reinterpret_cast(mesh->runtime->vert_normals.data()); } float (*BKE_mesh_poly_normals_for_write(Mesh *mesh))[3] { - if (mesh->runtime->poly_normals == nullptr) { - mesh->runtime->poly_normals = (float(*)[3])MEM_malloc_arrayN( - mesh->totpoly, sizeof(float[3]), __func__); - } - - BLI_assert(MEM_allocN_len(mesh->runtime->poly_normals) >= sizeof(float[3]) * mesh->totpoly); - - return mesh->runtime->poly_normals; + mesh->runtime->poly_normals.reinitialize(mesh->totpoly); + return reinterpret_cast(mesh->runtime->poly_normals.data()); } void BKE_mesh_vert_normals_clear_dirty(Mesh *mesh) { mesh->runtime->vert_normals_dirty = false; - BLI_assert(mesh->runtime->vert_normals || mesh->totvert == 0); + BLI_assert(mesh->runtime->vert_normals.size() == mesh->totvert); } void BKE_mesh_poly_normals_clear_dirty(Mesh *mesh) { mesh->runtime->poly_normals_dirty = false; - BLI_assert(mesh->runtime->poly_normals || mesh->totpoly == 0); + BLI_assert(mesh->runtime->poly_normals.size() == mesh->totpoly); } bool BKE_mesh_vert_normals_are_dirty(const Mesh *mesh) @@ -158,6 +140,8 @@ bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh) /** \name Mesh Normal Calculation (Polygons) * \{ */ +namespace blender::bke::mesh { + /* * COMPUTE POLY NORMAL * @@ -165,88 +149,78 @@ bool BKE_mesh_poly_normals_are_dirty(const Mesh *mesh) * polygon See Graphics Gems for * computing newell normal. */ -static void mesh_calc_ngon_normal(const MPoly *poly, - const MLoop *loopstart, - const float (*positions)[3], - float r_normal[3]) +static float3 normal_calc_ngon(const Span vert_positions, const Span poly_loops) { - const int nverts = poly->totloop; - const float *v_prev = positions[loopstart[nverts - 1].v]; - const float *v_curr; - - zero_v3(r_normal); + float3 normal(0); /* Newell's Method */ - for (int i = 0; i < nverts; i++) { - v_curr = positions[loopstart[i].v]; - add_newell_cross_v3_v3v3(r_normal, v_prev, v_curr); + const float *v_prev = vert_positions[poly_loops.last().v]; + for (const int i : poly_loops.index_range()) { + const float *v_curr = vert_positions[poly_loops[i].v]; + add_newell_cross_v3_v3v3(normal, v_prev, v_curr); v_prev = v_curr; } - if (UNLIKELY(normalize_v3(r_normal) == 0.0f)) { - r_normal[2] = 1.0f; /* other axis set to 0.0 */ + if (UNLIKELY(normalize_v3(normal) == 0.0f)) { + normal[2] = 1.0f; /* other axis set to 0.0 */ } + + return normal; } -void BKE_mesh_calc_poly_normal(const MPoly *poly, - const MLoop *loopstart, +float3 poly_normal_calc(const Span vert_positions, const Span poly_loops) +{ + if (poly_loops.size() > 4) { + return normal_calc_ngon(vert_positions, poly_loops); + } + if (poly_loops.size() == 3) { + return math::normal_tri(vert_positions[poly_loops[0].v], + vert_positions[poly_loops[1].v], + vert_positions[poly_loops[2].v]); + } + if (poly_loops.size() == 4) { + float3 normal; + normal_quad_v3(normal, + vert_positions[poly_loops[0].v], + vert_positions[poly_loops[1].v], + vert_positions[poly_loops[2].v], + vert_positions[poly_loops[3].v]); + return normal; + } + /* horrible, two sided face! */ + return float3(0); +} + +} // namespace blender::bke::mesh + +void BKE_mesh_calc_poly_normal(const MLoop *poly_loops, + const int poly_size, const float (*vert_positions)[3], + const int verts_num, float r_no[3]) { - if (poly->totloop > 4) { - mesh_calc_ngon_normal(poly, loopstart, vert_positions, r_no); - } - else if (poly->totloop == 3) { - normal_tri_v3(r_no, - vert_positions[loopstart[0].v], - vert_positions[loopstart[1].v], - vert_positions[loopstart[2].v]); - } - else if (poly->totloop == 4) { - normal_quad_v3(r_no, - vert_positions[loopstart[0].v], - vert_positions[loopstart[1].v], - vert_positions[loopstart[2].v], - vert_positions[loopstart[3].v]); - } - else { /* horrible, two sided face! */ - r_no[0] = 0.0; - r_no[1] = 0.0; - r_no[2] = 1.0; - } + copy_v3_v3(r_no, + blender::bke::mesh::poly_normal_calc( + {reinterpret_cast(vert_positions), verts_num}, + {poly_loops, poly_size})); } -static void calculate_normals_poly(const Span positions, - const Span polys, - const Span loops, - MutableSpan poly_normals) +namespace blender::bke::mesh { + +void normals_calc_polys(const Span positions, + const Span polys, + const Span loops, + MutableSpan poly_normals) { - using namespace blender; + BLI_assert(polys.size() == poly_normals.size()); threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) { - for (const int poly_i : range) { - const MPoly &poly = polys[poly_i]; - BKE_mesh_calc_poly_normal(&poly, - &loops[poly.loopstart], - reinterpret_cast(positions.data()), - poly_normals[poly_i]); + for (const int i : range) { + const MPoly &poly = polys[i]; + poly_normals[i] = poly_normal_calc(positions, loops.slice(poly.loopstart, poly.totloop)); } }); } -void BKE_mesh_calc_normals_poly(const float (*vert_positions)[3], - const int verts_num, - const MLoop *mloop, - const int mloop_len, - const MPoly *polys, - int polys_len, - float (*r_poly_normals)[3]) -{ - calculate_normals_poly({reinterpret_cast(vert_positions), verts_num}, - {polys, polys_len}, - {mloop, mloop_len}, - {reinterpret_cast(r_poly_normals), polys_len}); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -256,13 +230,12 @@ void BKE_mesh_calc_normals_poly(const float (*vert_positions)[3], * meshes can slow down high-poly meshes. For details on performance, see D11993. * \{ */ -static void calculate_normals_poly_and_vert(const Span positions, - const Span polys, - const Span loops, - MutableSpan poly_normals, - MutableSpan vert_normals) +void normals_calc_poly_vert(const Span positions, + const Span polys, + const Span loops, + MutableSpan poly_normals, + MutableSpan vert_normals) { - using namespace blender; /* Zero the vertex normal array for accumulation. */ { @@ -281,7 +254,7 @@ static void calculate_normals_poly_and_vert(const Span positions, const int i_end = poly.totloop - 1; /* Polygon Normal and edge-vector. */ - /* Inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors. */ + /* Inline version of #poly_normal_calc, also does edge-vectors. */ { zero_v3(pnor); /* Newell's Method */ @@ -346,21 +319,7 @@ static void calculate_normals_poly_and_vert(const Span positions, } } -void BKE_mesh_calc_normals_poly_and_vertex(const float (*vert_positions)[3], - const int mvert_len, - const MLoop *mloop, - const int mloop_len, - const MPoly *polys, - const int polys_len, - float (*r_poly_normals)[3], - float (*r_vert_normals)[3]) -{ - calculate_normals_poly_and_vert({reinterpret_cast(vert_positions), mvert_len}, - {polys, polys_len}, - {mloop, mloop_len}, - {reinterpret_cast(r_poly_normals), polys_len}, - {reinterpret_cast(r_vert_normals), mvert_len}); -} +} // namespace blender::bke::mesh /** \} */ @@ -368,92 +327,73 @@ void BKE_mesh_calc_normals_poly_and_vertex(const float (*vert_positions)[3], /** \name Mesh Normal Calculation * \{ */ -const float (*BKE_mesh_vert_normals_ensure(const Mesh *mesh))[3] +blender::Span Mesh::vert_normals() const { - if (!BKE_mesh_vert_normals_are_dirty(mesh)) { - BLI_assert(mesh->runtime->vert_normals != nullptr || mesh->totvert == 0); - return mesh->runtime->vert_normals; + if (!this->runtime->vert_normals_dirty) { + BLI_assert(this->runtime->vert_normals.size() == this->totvert); + return this->runtime->vert_normals; } - if (mesh->totvert == 0) { - return nullptr; + std::lock_guard lock{this->runtime->normals_mutex}; + if (!this->runtime->vert_normals_dirty) { + BLI_assert(this->runtime->vert_normals.size() == this->totvert); + return this->runtime->vert_normals; } - std::lock_guard lock{mesh->runtime->normals_mutex}; - if (!BKE_mesh_vert_normals_are_dirty(mesh)) { - BLI_assert(mesh->runtime->vert_normals != nullptr); - return mesh->runtime->vert_normals; - } - - float(*vert_normals)[3]; - float(*poly_normals)[3]; - /* Isolate task because a mutex is locked and computing normals is multi-threaded. */ blender::threading::isolate_task([&]() { - Mesh &mesh_mutable = *const_cast(mesh); - const Span positions = mesh_mutable.vert_positions(); - const Span polys = mesh_mutable.polys(); - const Span loops = mesh_mutable.loops(); + const Span positions = this->vert_positions(); + const Span polys = this->polys(); + const Span loops = this->loops(); - vert_normals = BKE_mesh_vert_normals_for_write(&mesh_mutable); - poly_normals = BKE_mesh_poly_normals_for_write(&mesh_mutable); + this->runtime->vert_normals.reinitialize(positions.size()); + this->runtime->poly_normals.reinitialize(polys.size()); + blender::bke::mesh::normals_calc_poly_vert( + positions, polys, loops, this->runtime->poly_normals, this->runtime->vert_normals); - BKE_mesh_calc_normals_poly_and_vertex(reinterpret_cast(positions.data()), - positions.size(), - loops.data(), - loops.size(), - polys.data(), - polys.size(), - poly_normals, - vert_normals); - - BKE_mesh_vert_normals_clear_dirty(&mesh_mutable); - BKE_mesh_poly_normals_clear_dirty(&mesh_mutable); + this->runtime->vert_normals_dirty = false; + this->runtime->poly_normals_dirty = false; }); - return vert_normals; + return this->runtime->vert_normals; +} + +blender::Span Mesh::poly_normals() const +{ + if (!this->runtime->poly_normals_dirty) { + BLI_assert(this->runtime->poly_normals.size() == this->totpoly); + return this->runtime->poly_normals; + } + + std::lock_guard lock{this->runtime->normals_mutex}; + if (!this->runtime->poly_normals_dirty) { + BLI_assert(this->runtime->poly_normals.size() == this->totpoly); + return this->runtime->poly_normals; + } + + /* Isolate task because a mutex is locked and computing normals is multi-threaded. */ + blender::threading::isolate_task([&]() { + const Span positions = this->vert_positions(); + const Span polys = this->polys(); + const Span loops = this->loops(); + + this->runtime->poly_normals.reinitialize(polys.size()); + blender::bke::mesh::normals_calc_polys(positions, polys, loops, this->runtime->poly_normals); + + this->runtime->poly_normals_dirty = false; + }); + + return this->runtime->poly_normals; +} + +const float (*BKE_mesh_vert_normals_ensure(const Mesh *mesh))[3] +{ + return reinterpret_cast(mesh->vert_normals().data()); } const float (*BKE_mesh_poly_normals_ensure(const Mesh *mesh))[3] { - if (!BKE_mesh_poly_normals_are_dirty(mesh)) { - BLI_assert(mesh->runtime->poly_normals != nullptr || mesh->totpoly == 0); - return mesh->runtime->poly_normals; - } - - if (mesh->totpoly == 0) { - return nullptr; - } - - std::lock_guard lock{mesh->runtime->normals_mutex}; - if (!BKE_mesh_poly_normals_are_dirty(mesh)) { - BLI_assert(mesh->runtime->poly_normals != nullptr); - return mesh->runtime->poly_normals; - } - - float(*poly_normals)[3]; - - /* Isolate task because a mutex is locked and computing normals is multi-threaded. */ - blender::threading::isolate_task([&]() { - Mesh &mesh_mutable = *const_cast(mesh); - const Span positions = mesh_mutable.vert_positions(); - const Span polys = mesh_mutable.polys(); - const Span loops = mesh_mutable.loops(); - - poly_normals = BKE_mesh_poly_normals_for_write(&mesh_mutable); - - BKE_mesh_calc_normals_poly(reinterpret_cast(positions.data()), - positions.size(), - loops.data(), - loops.size(), - polys.data(), - polys.size(), - poly_normals); - - BKE_mesh_poly_normals_clear_dirty(&mesh_mutable); - }); - - return poly_normals; + return reinterpret_cast(mesh->vert_normals().data()); } void BKE_mesh_ensure_normals_for_display(Mesh *mesh) @@ -461,8 +401,8 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh) switch (mesh->runtime->wrapper_type) { case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: - BKE_mesh_vert_normals_ensure(mesh); - BKE_mesh_poly_normals_ensure(mesh); + mesh->vert_normals(); + mesh->poly_normals(); break; case ME_WRAPPER_TYPE_BMESH: { BMEditMesh *em = mesh->edit_mesh; @@ -487,10 +427,16 @@ void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, lnors_spacearr->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); } mem = lnors_spacearr->mem; - lnors_spacearr->lspacearr = (MLoopNorSpace **)BLI_memarena_calloc( - mem, sizeof(MLoopNorSpace *) * size_t(numLoops)); - lnors_spacearr->loops_pool = (LinkNode *)BLI_memarena_alloc( - mem, sizeof(LinkNode) * size_t(numLoops)); + if (numLoops > 0) { + lnors_spacearr->lspacearr = (MLoopNorSpace **)BLI_memarena_calloc( + mem, sizeof(MLoopNorSpace *) * size_t(numLoops)); + lnors_spacearr->loops_pool = (LinkNode *)BLI_memarena_alloc( + mem, sizeof(LinkNode) * size_t(numLoops)); + } + else { + lnors_spacearr->lspacearr = nullptr; + lnors_spacearr->loops_pool = nullptr; + } lnors_spacearr->spaces_num = 0; } @@ -782,18 +728,23 @@ struct LoopSplitTaskDataCommon { /* See comment about edge_to_loops below. */ #define IS_EDGE_SHARP(_e2l) ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID) +namespace blender::bke::mesh { + static void mesh_edges_sharp_tag(const Span polys, const Span loops, const Span loop_to_poly_map, const Span poly_normals, + const Span sharp_faces, const Span sharp_edges, const bool check_angle, const float split_angle, MutableSpan edge_to_loops, MutableSpan r_sharp_edges) { - using namespace blender; const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; + auto poly_is_smooth = [&](const int poly_i) { + return sharp_faces.is_empty() || !sharp_faces[poly_i]; + }; for (const int poly_i : polys.index_range()) { const MPoly &poly = polys[poly_i]; @@ -808,7 +759,7 @@ static void mesh_edges_sharp_tag(const Span polys, /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */ e2l[0] = loop_index; /* We have to check this here too, else we might miss some flat faces!!! */ - e2l[1] = (poly.flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID; + e2l[1] = (poly_is_smooth(poly_i)) ? INDEX_UNSET : INDEX_INVALID; } else if (e2l[1] == INDEX_UNSET) { const bool is_angle_sharp = (check_angle && @@ -820,7 +771,7 @@ static void mesh_edges_sharp_tag(const Span polys, * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the * same vertex, or angle between both its polys' normals is above split_angle value. */ - if (!(poly.flag & ME_SMOOTH) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) || + if (!poly_is_smooth(poly_i) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) || vert_i == loops[e2l[0]].v || is_angle_sharp) { /* NOTE: we are sure that loop != 0 here ;). */ e2l[1] = INDEX_INVALID; @@ -850,38 +801,34 @@ static void mesh_edges_sharp_tag(const Span polys, } } -void BKE_edges_sharp_from_angle_set(const int numEdges, - const MLoop *mloops, - const int numLoops, - const MPoly *polys, - const float (*poly_normals)[3], - const int numPolys, - const float split_angle, - bool *sharp_edges) +void edges_sharp_from_angle_set(const Span polys, + const Span loops, + const Span poly_normals, + const bool *sharp_faces, + const float split_angle, + MutableSpan sharp_edges) { - using namespace blender; - using namespace blender::bke; if (split_angle >= float(M_PI)) { /* Nothing to do! */ return; } - /* Mapping edge -> loops. See #BKE_mesh_normals_loop_split for details. */ - Array edge_to_loops(numEdges, int2(0)); + /* Mapping edge -> loops. See #bke::mesh::normals_calc_loop for details. */ + Array edge_to_loops(sharp_edges.size(), int2(0)); /* Simple mapping from a loop to its polygon index. */ - const Array loop_to_poly = mesh_topology::build_loop_to_poly_map({polys, numPolys}, - numLoops); + const Array loop_to_poly = mesh_topology::build_loop_to_poly_map(polys, loops.size()); - mesh_edges_sharp_tag({polys, numPolys}, - {mloops, numLoops}, + mesh_edges_sharp_tag(polys, + loops, loop_to_poly, - {reinterpret_cast(poly_normals), numPolys}, - Span(sharp_edges, numEdges), + poly_normals, + Span(sharp_faces, sharp_faces ? polys.size() : 0), + sharp_edges, true, split_angle, edge_to_loops, - {sharp_edges, numEdges}); + sharp_edges); } static void loop_manifold_fan_around_vert_next(const Span loops, @@ -1292,8 +1239,6 @@ static bool loop_split_generator_check_cyclic_smooth_fan(const Span mloop static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common_data) { - using namespace blender; - using namespace blender::bke; MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; const Span loops = common_data->loops; @@ -1428,26 +1373,21 @@ static void loop_split_generator(TaskPool *pool, LoopSplitTaskDataCommon *common } } -void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], - const float (*vert_normals)[3], - const int numVerts, - const MEdge *edges, - const int numEdges, - const MLoop *mloops, - float (*r_loop_normals)[3], - const int numLoops, - const MPoly *polys, - const float (*poly_normals)[3], - const int numPolys, - const bool use_split_normals, - const float split_angle, - const bool *sharp_edges, - const int *loop_to_poly_map, - MLoopNorSpaceArray *r_lnors_spacearr, - short (*clnors_data)[2]) +void normals_calc_loop(const Span vert_positions, + const Span edges, + const Span polys, + const Span loops, + const Span loop_to_poly_map, + const Span vert_normals, + const Span poly_normals, + const bool *sharp_edges, + const bool *sharp_faces, + bool use_split_normals, + float split_angle, + short (*clnors_data)[2], + MLoopNorSpaceArray *r_lnors_spacearr, + MutableSpan r_loop_normals) { - using namespace blender; - using namespace blender::bke; /* For now this is not supported. * If we do not use split normals, we do not generate anything fancy! */ BLI_assert(use_split_normals || !(r_lnors_spacearr)); @@ -1459,20 +1399,18 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], * since we may want to use loop_normals even when mesh's 'autosmooth' is disabled * (see e.g. mesh mapping code). As usual, we could handle that on case-by-case basis, * but simpler to keep it well confined here. */ - int poly_index; - - for (poly_index = 0; poly_index < numPolys; poly_index++) { - const MPoly &poly = polys[poly_index]; - int ml_index = poly.loopstart; - const int ml_index_end = ml_index + poly.totloop; - const bool is_poly_flat = ((poly.flag & ME_SMOOTH) == 0); + for (const int poly_index : polys.index_range()) { + const MPoly *poly = &polys[poly_index]; + int ml_index = poly->loopstart; + const int ml_index_end = ml_index + poly->totloop; + const bool is_poly_flat = sharp_faces && sharp_faces[poly_index]; for (; ml_index < ml_index_end; ml_index++) { if (is_poly_flat) { copy_v3_v3(r_loop_normals[ml_index], poly_normals[poly_index]); } else { - copy_v3_v3(r_loop_normals[ml_index], vert_normals[mloops[ml_index].v]); + copy_v3_v3(r_loop_normals[ml_index], vert_normals[loops[ml_index].v]); } } } @@ -1493,17 +1431,17 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], * However, if needed, we can store the negated value of loop index instead of INDEX_INVALID * to retrieve the real value later in code). * Note also that loose edges always have both values set to 0! */ - Array edge_to_loops(numEdges, int2(0)); + Array edge_to_loops(edges.size(), int2(0)); /* Simple mapping from a loop to its polygon index. */ Span loop_to_poly; Array local_loop_to_poly_map; - if (loop_to_poly_map) { - loop_to_poly = {loop_to_poly_map, numLoops}; + if (loop_to_poly_map.is_empty()) { + local_loop_to_poly_map = mesh_topology::build_loop_to_poly_map(polys, loops.size()); + loop_to_poly = local_loop_to_poly_map; } else { - local_loop_to_poly_map = mesh_topology::build_loop_to_poly_map({polys, numPolys}, numLoops); - loop_to_poly = local_loop_to_poly_map; + loop_to_poly = loop_to_poly_map; } /* When using custom loop normals, disable the angle feature! */ @@ -1520,28 +1458,27 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], r_lnors_spacearr = &_lnors_spacearr; } if (r_lnors_spacearr) { - BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops, MLNOR_SPACEARR_LOOP_INDEX); + BKE_lnor_spacearr_init(r_lnors_spacearr, loops.size(), MLNOR_SPACEARR_LOOP_INDEX); } - const Span loops(mloops, numLoops); - /* Init data common to all tasks. */ LoopSplitTaskDataCommon common_data; common_data.lnors_spacearr = r_lnors_spacearr; - common_data.loop_normals = {reinterpret_cast(r_loop_normals), numLoops}; - common_data.clnors_data = {reinterpret_cast(clnors_data), clnors_data ? numLoops : 0}; - common_data.positions = {reinterpret_cast(vert_positions), numVerts}; - common_data.edges = {edges, numEdges}; - common_data.polys = {polys, numPolys}; + common_data.loop_normals = r_loop_normals; + common_data.clnors_data = {reinterpret_cast(clnors_data), + clnors_data ? loops.size() : 0}; + common_data.positions = vert_positions; + common_data.edges = edges; + common_data.polys = polys; common_data.loops = loops; common_data.edge_to_loops = edge_to_loops; common_data.loop_to_poly = loop_to_poly; - common_data.poly_normals = {reinterpret_cast(poly_normals), numPolys}; - common_data.vert_normals = {reinterpret_cast(vert_normals), numVerts}; + common_data.poly_normals = poly_normals; + common_data.vert_normals = vert_normals; /* Pre-populate all loop normals as if their verts were all smooth. * This way we don't have to compute those later! */ - threading::parallel_for(IndexRange(numPolys), 1024, [&](const IndexRange range) { + threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) { for (const int poly_i : range) { const MPoly &poly = polys[poly_i]; for (const int loop_i : IndexRange(poly.loopstart, poly.totloop)) { @@ -1551,17 +1488,18 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], }); /* This first loop check which edges are actually smooth, and compute edge vectors. */ - mesh_edges_sharp_tag({polys, numPolys}, + mesh_edges_sharp_tag(polys, loops, loop_to_poly, - {reinterpret_cast(poly_normals), numPolys}, - Span(sharp_edges, sharp_edges ? numEdges : 0), + poly_normals, + Span(sharp_faces, sharp_faces ? polys.size() : 0), + Span(sharp_edges, sharp_edges ? edges.size() : 0), check_angle, split_angle, edge_to_loops, {}); - if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) { + if (loops.size() < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) { /* Not enough loops to be worth the whole threading overhead. */ loop_split_generator(nullptr, &common_data); } @@ -1595,35 +1533,28 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], * r_custom_loop_normals is expected to have normalized normals, or zero ones, * in which case they will be replaced by default loop/vertex normal. */ -static void mesh_normals_loop_custom_set(const float (*positions)[3], - const float (*vert_normals)[3], - const int numVerts, - const MEdge *edges, - const int numEdges, - const MLoop *mloops, - float (*r_custom_loop_normals)[3], - const int numLoops, - const MPoly *polys, - const float (*poly_normals)[3], - const int numPolys, + +static void mesh_normals_loop_custom_set(Span positions, + Span edges, + Span polys, + Span loops, + Span vert_normals, + Span poly_normals, + const bool *sharp_faces, + const bool use_vertices, + MutableSpan r_custom_loop_normals, MutableSpan sharp_edges, - short (*r_clnors_data)[2], - const bool use_vertices) + short (*r_clnors_data)[2]) { - using namespace blender; - using namespace blender::bke; - /* We *may* make that poor #BKE_mesh_normals_loop_split() even more complex by making it handling - * that feature too, would probably be more efficient in absolute. - * However, this function *is not* performance-critical, since it is mostly expected to be called - * by io add-ons when importing custom normals, and modifier - * (and perhaps from some editing tools later?). - * So better to keep some simplicity here, and just call #BKE_mesh_normals_loop_split() twice! */ + /* We *may* make that poor #bke::mesh::normals_calc_loop() even more complex by making it + * handling that feature too, would probably be more efficient in absolute. However, this + * function *is not* performance-critical, since it is mostly expected to be called by io add-ons + * when importing custom normals, and modifier (and perhaps from some editing tools later?). So + * better to keep some simplicity here, and just call #bke::mesh::normals_calc_loop() twice! */ MLoopNorSpaceArray lnors_spacearr = {nullptr}; - BitVector<> done_loops(numLoops, false); - float(*loop_normals)[3] = (float(*)[3])MEM_calloc_arrayN( - size_t(numLoops), sizeof(*loop_normals), __func__); - const Array loop_to_poly = mesh_topology::build_loop_to_poly_map({polys, numPolys}, - numLoops); + BitVector<> done_loops(loops.size(), false); + Array loop_normals(loops.size()); + const Array loop_to_poly = mesh_topology::build_loop_to_poly_map(polys, loops.size()); /* In this case we always consider split nors as ON, * and do not want to use angle to define smooth fans! */ const bool use_split_normals = true; @@ -1632,34 +1563,31 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], BLI_SMALLSTACK_DECLARE(clnors_data, short *); /* Compute current lnor spacearr. */ - BKE_mesh_normals_loop_split(positions, - vert_normals, - numVerts, - edges, - numEdges, - mloops, - loop_normals, - numLoops, - polys, - poly_normals, - numPolys, - use_split_normals, - split_angle, - sharp_edges.data(), - loop_to_poly.data(), - &lnors_spacearr, - nullptr); + normals_calc_loop(positions, + edges, + polys, + loops, + loop_to_poly, + vert_normals, + poly_normals, + sharp_edges.data(), + sharp_faces, + use_split_normals, + split_angle, + r_clnors_data, + &lnors_spacearr, + loop_normals); /* Set all given zero vectors to their default value. */ if (use_vertices) { - for (int i = 0; i < numVerts; i++) { + for (const int i : positions.index_range()) { if (is_zero_v3(r_custom_loop_normals[i])) { copy_v3_v3(r_custom_loop_normals[i], vert_normals[i]); } } } else { - for (int i = 0; i < numLoops; i++) { + for (const int i : loops.index_range()) { if (is_zero_v3(r_custom_loop_normals[i])) { copy_v3_v3(r_custom_loop_normals[i], loop_normals[i]); } @@ -1670,7 +1598,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], /* Now, check each current smooth fan (one lnor space per smooth fan!), * and if all its matching custom loop_normals are not (enough) equal, add sharp edges as needed. - * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans + * This way, next time we run bke::mesh::normals_calc_loop(), we'll get lnor spacearr/smooth fans * matching given custom loop_normals. * Note this code *will never* unsharp edges! And quite obviously, * when we set custom normals per vertices, running this is absolutely useless. */ @@ -1678,7 +1606,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], done_loops.fill(true); } else { - for (int i = 0; i < numLoops; i++) { + for (const int i : loops.index_range()) { if (!lnors_spacearr.lspacearr[i]) { /* This should not happen in theory, but in some rare case (probably ugly geometry) * we can get some nullptr loopspacearr at this point. :/ @@ -1696,7 +1624,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], /* Notes: * - In case of mono-loop smooth fan, we have nothing to do. * - Loops in this linklist are ordered (in reversed order compared to how they were - * discovered by BKE_mesh_normals_loop_split(), but this is not a problem). + * discovered by bke::mesh::normals_calc_loop(), but this is not a problem). * Which means if we find a mismatching clnor, * we know all remaining loops will have to be in a new, different smooth fan/lnor space. * - In smooth fan case, we compare each clnor against a ref one, @@ -1707,13 +1635,13 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], continue; } - LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; + LinkNode *loop_link = lnors_spacearr.lspacearr[i]->loops; const MLoop *prev_ml = nullptr; const float *org_nor = nullptr; - while (loops) { - const int lidx = POINTER_AS_INT(loops->link); - const MLoop *ml = &mloops[lidx]; + while (loop_link) { + const int lidx = POINTER_AS_INT(loop_link->link); + const MLoop *ml = &loops[lidx]; const int nidx = lidx; float *nor = r_custom_loop_normals[nidx]; @@ -1727,14 +1655,14 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], * since we do not allow reversed winding in a same smooth fan. */ const MPoly &poly = polys[loop_to_poly[lidx]]; const MLoop *mlp = - &mloops[(lidx == poly.loopstart) ? poly.loopstart + poly.totloop - 1 : lidx - 1]; + &loops[(lidx == poly.loopstart) ? poly.loopstart + poly.totloop - 1 : lidx - 1]; sharp_edges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e] = true; org_nor = nor; } prev_ml = ml; - loops = loops->next; + loop_link = loop_link->next; done_loops[lidx].set(); } @@ -1742,17 +1670,17 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], * otherwise we may miss some sharp edges here! * This is just a simplified version of above while loop. * See #45984. */ - loops = lnors_spacearr.lspacearr[i]->loops; - if (loops && org_nor) { - const int lidx = POINTER_AS_INT(loops->link); - const MLoop *ml = &mloops[lidx]; + loop_link = lnors_spacearr.lspacearr[i]->loops; + if (loop_link && org_nor) { + const int lidx = POINTER_AS_INT(loop_link->link); + const MLoop *ml = &loops[lidx]; const int nidx = lidx; float *nor = r_custom_loop_normals[nidx]; if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { const MPoly &poly = polys[loop_to_poly[lidx]]; const MLoop *mlp = - &mloops[(lidx == poly.loopstart) ? poly.loopstart + poly.totloop - 1 : lidx - 1]; + &loops[(lidx == poly.loopstart) ? poly.loopstart + poly.totloop - 1 : lidx - 1]; sharp_edges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e] = true; } } @@ -1760,28 +1688,25 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], /* And now, recompute our new auto `loop_normals` and lnor spacearr! */ BKE_lnor_spacearr_clear(&lnors_spacearr); - BKE_mesh_normals_loop_split(positions, - vert_normals, - numVerts, - edges, - numEdges, - mloops, - loop_normals, - numLoops, - polys, - poly_normals, - numPolys, - use_split_normals, - split_angle, - sharp_edges.data(), - loop_to_poly.data(), - &lnors_spacearr, - nullptr); + normals_calc_loop(positions, + edges, + polys, + loops, + loop_to_poly, + vert_normals, + poly_normals, + sharp_edges.data(), + sharp_faces, + use_split_normals, + split_angle, + r_clnors_data, + &lnors_spacearr, + loop_normals); } /* And we just have to convert plain object-space custom normals to our * lnor space-encoded ones. */ - for (int i = 0; i < numLoops; i++) { + for (const int i : loops.index_range()) { if (!lnors_spacearr.lspacearr[i]) { done_loops[i].reset(); if (G.debug & G_DEBUG) { @@ -1795,10 +1720,10 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], /* Note we accumulate and average all custom normals in current smooth fan, * to avoid getting different clnors data (tiny differences in plain custom normals can * give rather huge differences in computed 2D factors). */ - LinkNode *loops = lnors_spacearr.lspacearr[i]->loops; + LinkNode *loop_link = lnors_spacearr.lspacearr[i]->loops; if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { - BLI_assert(POINTER_AS_INT(loops) == i); - const int nidx = use_vertices ? int(mloops[i].v) : i; + BLI_assert(POINTER_AS_INT(loop_link) == i); + const int nidx = use_vertices ? int(loops[i].v) : i; float *nor = r_custom_loop_normals[nidx]; BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]); @@ -1810,16 +1735,16 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], short clnor_data_tmp[2], *clnor_data; zero_v3(avg_nor); - while (loops) { - const int lidx = POINTER_AS_INT(loops->link); - const int nidx = use_vertices ? int(mloops[lidx].v) : lidx; + while (loop_link) { + const int lidx = POINTER_AS_INT(loop_link->link); + const int nidx = use_vertices ? int(loops[lidx].v) : lidx; float *nor = r_custom_loop_normals[nidx]; avg_nor_count++; add_v3_v3(avg_nor, nor); BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]); - loops = loops->next; + loop_link = loop_link->next; done_loops[lidx].reset(); } @@ -1834,74 +1759,59 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], } } - MEM_freeN(loop_normals); BKE_lnor_spacearr_free(&lnors_spacearr); } -void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3], - const float (*vert_normals)[3], - const int numVerts, - const MEdge *edges, - const int numEdges, - const MLoop *mloops, - float (*r_custom_loop_normals)[3], - const int numLoops, - const MPoly *polys, - const float (*poly_normals)[3], - const int numPolys, - bool *sharp_edges, - short (*r_clnors_data)[2]) +void normals_loop_custom_set(const Span vert_positions, + const Span edges, + const Span polys, + const Span loops, + const Span vert_normals, + const Span poly_normals, + const bool *sharp_faces, + MutableSpan sharp_edges, + MutableSpan r_custom_loop_normals, + short (*r_clnors_data)[2]) { mesh_normals_loop_custom_set(vert_positions, - vert_normals, - numVerts, edges, - numEdges, - mloops, - r_custom_loop_normals, - numLoops, polys, + loops, + vert_normals, poly_normals, - numPolys, - {sharp_edges, numEdges}, - r_clnors_data, - false); + sharp_faces, + false, + r_custom_loop_normals, + sharp_edges, + r_clnors_data); } -void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3], - const float (*vert_normals)[3], - float (*r_custom_vert_normals)[3], - const int numVerts, - const MEdge *edges, - const int numEdges, - const MLoop *mloops, - const int numLoops, - const MPoly *polys, - const float (*poly_normals)[3], - const int numPolys, - bool *sharp_edges, - short (*r_clnors_data)[2]) +void normals_loop_custom_set_from_verts(const Span vert_positions, + const Span edges, + const Span polys, + const Span loops, + const Span vert_normals, + const Span poly_normals, + const bool *sharp_faces, + MutableSpan sharp_edges, + MutableSpan r_custom_vert_normals, + short (*r_clnors_data)[2]) { mesh_normals_loop_custom_set(vert_positions, - vert_normals, - numVerts, edges, - numEdges, - mloops, - r_custom_vert_normals, - numLoops, polys, + loops, + vert_normals, poly_normals, - numPolys, - {sharp_edges, numEdges}, - r_clnors_data, - true); + sharp_faces, + true, + r_custom_vert_normals, + sharp_edges, + r_clnors_data); } static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const bool use_vertices) { - using namespace blender; - using namespace blender::bke; short(*clnors)[2]; const int numloops = mesh->totloop; @@ -1912,41 +1822,40 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const } else { clnors = (short(*)[2])CustomData_add_layer( - &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, numloops); + &mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, numloops); } - const Span positions = mesh->vert_positions(); - MutableSpan edges = mesh->edges_for_write(); - const Span polys = mesh->polys(); - const Span loops = mesh->loops(); MutableAttributeAccessor attributes = mesh->attributes_for_write(); SpanAttributeWriter sharp_edges = attributes.lookup_or_add_for_write_span( "sharp_edge", ATTR_DOMAIN_EDGE); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); - mesh_normals_loop_custom_set(reinterpret_cast(positions.data()), - BKE_mesh_vert_normals_ensure(mesh), - positions.size(), - edges.data(), - edges.size(), - loops.data(), - r_custom_nors, - loops.size(), - polys.data(), - BKE_mesh_poly_normals_ensure(mesh), - polys.size(), + mesh_normals_loop_custom_set(mesh->vert_positions(), + mesh->edges(), + mesh->polys(), + mesh->loops(), + mesh->vert_normals(), + mesh->poly_normals(), + sharp_faces, + use_vertices, + {reinterpret_cast(r_custom_nors), + use_vertices ? mesh->totvert : mesh->totloop}, sharp_edges.span, - clnors, - use_vertices); + clnors); + sharp_edges.finish(); } +} // namespace blender::bke::mesh + void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loop_normals)[3]) { - mesh_set_custom_normals(mesh, r_custom_loop_normals, false); + blender::bke::mesh::mesh_set_custom_normals(mesh, r_custom_loop_normals, false); } void BKE_mesh_set_custom_normals_from_verts(Mesh *mesh, float (*r_custom_vert_normals)[3]) { - mesh_set_custom_normals(mesh, r_custom_vert_normals, true); + blender::bke::mesh::mesh_set_custom_normals(mesh, r_custom_vert_normals, true); } void BKE_mesh_normals_loop_to_vertex(const int numVerts, diff --git a/source/blender/blenkernel/intern/mesh_remap.cc b/source/blender/blenkernel/intern/mesh_remap.cc index 361616b67ab..4ccf6a94fc6 100644 --- a/source/blender/blenkernel/intern/mesh_remap.cc +++ b/source/blender/blenkernel/intern/mesh_remap.cc @@ -26,7 +26,7 @@ #include "BKE_bvhutils.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" /* own include */ #include "BKE_mesh_runtime.h" @@ -571,7 +571,7 @@ void BKE_mesh_remap_calc_verts_from_mesh(const int mode, const blender::Span polys_src = me_src->polys(); const blender::Span loops_src = me_src->loops(); float(*vcos_src)[3] = BKE_mesh_vert_coords_alloc(me_src, nullptr); - const float(*vert_normals_dst)[3] = BKE_mesh_vert_normals_ensure(me_dst); + const blender::Span vert_normals_dst = me_dst->vert_normals(); size_t tmp_buff_size = MREMAP_DEFAULT_BUFSIZE; float(*vcos)[3] = static_cast( @@ -937,7 +937,7 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode, BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); - const float(*vert_normals_dst)[3] = BKE_mesh_vert_normals_ensure(me_dst); + const blender::Span vert_normals_dst = me_dst->vert_normals(); for (i = 0; i < numedges_dst; i++) { /* For each dst edge, we sample some rays from it (interpolated from its vertices) @@ -1043,9 +1043,9 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode, static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands, const int island_index, BLI_AStarGraph *as_graph, - const float (*positions)[3], - const MPoly *polys, - const MLoop *loops, + const blender::Span positions, + const blender::Span polys, + const blender::Span loops, const int edge_idx, BLI_bitmap *done_edges, MeshElemMap *edge_to_poly_map, @@ -1075,7 +1075,9 @@ static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands, } if (poly_status[pidx_isld] == POLY_UNSET) { - BKE_mesh_calc_poly_center(&poly, &loops[poly.loopstart], positions, poly_centers[pidx_isld]); + copy_v3_v3(poly_centers[pidx_isld], + blender::bke::mesh::poly_center_calc(positions, + loops.slice(poly.loopstart, poly.totloop))); BLI_astar_node_init(as_graph, pidx_isld, poly_centers[pidx_isld]); poly_status[pidx_isld] = POLY_CENTER_INIT; } @@ -1100,11 +1102,11 @@ static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands, static void mesh_island_to_astar_graph(MeshIslandStore *islands, const int island_index, - const float (*positions)[3], + const blender::Span positions, MeshElemMap *edge_to_poly_map, const int numedges, - const MLoop *loops, - const MPoly *polys, + const blender::Span polys, + const blender::Span loops, const int numpolys, BLI_AStarGraph *r_as_graph) { @@ -1284,12 +1286,13 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, 1) : 0); - const float(*poly_nors_src)[3] = nullptr; - const float(*loop_nors_src)[3] = nullptr; - const float(*poly_nors_dst)[3] = nullptr; - float(*loop_nors_dst)[3] = nullptr; + blender::Span poly_normals_src; + blender::Span loop_normals_src; - float(*poly_cents_src)[3] = nullptr; + blender::Span poly_normals_dst; + blender::float3 *loop_normals_dst; + + blender::Array poly_cents_src; MeshElemMap *vert_to_loop_map_src = nullptr; int *vert_to_loop_map_src_buff = nullptr; @@ -1303,7 +1306,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, /* Unlike above, those are one-to-one mappings, simpler! */ int *loop_to_poly_map_src = nullptr; - const float(*positions_src)[3] = BKE_mesh_vert_positions(me_src); + const blender::Span positions_src = me_src->vert_positions(); const int num_verts_src = me_src->totvert; float(*vcos_src)[3] = nullptr; const blender::Span edges_src = me_src->edges(); @@ -1343,51 +1346,53 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, const bool need_pnors_dst = need_lnors_dst || need_pnors_src; if (need_pnors_dst) { - poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst); + poly_normals_dst = mesh_dst->poly_normals(); } if (need_lnors_dst) { short(*custom_nors_dst)[2] = static_cast( CustomData_get_layer_for_write(ldata_dst, CD_CUSTOMLOOPNORMAL, numloops_dst)); /* Cache loop normals into a temporary custom data layer. */ - loop_nors_dst = static_cast( + loop_normals_dst = static_cast( CustomData_get_layer_for_write(ldata_dst, CD_NORMAL, numloops_dst)); - const bool do_loop_nors_dst = (loop_nors_dst == nullptr); - if (!loop_nors_dst) { - loop_nors_dst = static_cast( - CustomData_add_layer(ldata_dst, CD_NORMAL, CD_SET_DEFAULT, nullptr, numloops_dst)); + + const bool do_loop_normals_dst = (loop_normals_dst == nullptr); + if (!loop_normals_dst) { + loop_normals_dst = static_cast( + CustomData_add_layer(ldata_dst, CD_NORMAL, CD_SET_DEFAULT, numloops_dst)); CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY); } - if (dirty_nors_dst || do_loop_nors_dst) { + if (dirty_nors_dst || do_loop_normals_dst) { const bool *sharp_edges = static_cast( CustomData_get_layer_named(&mesh_dst->edata, CD_PROP_BOOL, "sharp_edge")); - BKE_mesh_normals_loop_split(vert_positions_dst, - BKE_mesh_vert_normals_ensure(mesh_dst), - numverts_dst, - edges_dst, - numedges_dst, - loops_dst, - loop_nors_dst, - numloops_dst, - polys_dst, - poly_nors_dst, - numpolys_dst, - use_split_nors_dst, - split_angle_dst, - sharp_edges, - nullptr, - nullptr, - custom_nors_dst); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh_dst->pdata, CD_PROP_BOOL, "sharp_face")); + blender::bke::mesh::normals_calc_loop( + {reinterpret_cast(vert_positions_dst), numverts_dst}, + {edges_dst, numedges_dst}, + {polys_dst, numpolys_dst}, + {loops_dst, numloops_dst}, + {}, + mesh_dst->vert_normals(), + mesh_dst->poly_normals(), + sharp_edges, + sharp_faces, + use_split_nors_dst, + split_angle_dst, + custom_nors_dst, + nullptr, + {loop_normals_dst, numloops_dst}); } } if (need_pnors_src || need_lnors_src) { if (need_pnors_src) { - poly_nors_src = BKE_mesh_poly_normals_ensure(me_src); + poly_normals_src = me_src->poly_normals(); } if (need_lnors_src) { - loop_nors_src = static_cast( - CustomData_get_layer(&me_src->ldata, CD_NORMAL)); - BLI_assert(loop_nors_src != nullptr); + loop_normals_src = {static_cast( + CustomData_get_layer(&me_src->ldata, CD_NORMAL)), + me_src->totloop}; + BLI_assert(loop_normals_src.data() != nullptr); } } } @@ -1422,8 +1427,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, if (use_from_vert) { loop_to_poly_map_src = static_cast( MEM_mallocN(sizeof(*loop_to_poly_map_src) * size_t(loops_src.size()), __func__)); - poly_cents_src = static_cast( - MEM_mallocN(sizeof(*poly_cents_src) * size_t(polys_src.size()), __func__)); + poly_cents_src.reinitialize(polys_src.size()); for (pidx_src = 0; pidx_src < polys_src.size(); pidx_src++) { const MPoly &poly = polys_src[pidx_src]; ml_src = &loops_src[poly.loopstart]; @@ -1431,7 +1435,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, plidx_src++, lidx_src++) { loop_to_poly_map_src[lidx_src] = pidx_src; } - BKE_mesh_calc_poly_center(&poly, ml_src, positions_src, poly_cents_src[pidx_src]); + poly_cents_src[pidx_src] = blender::bke::mesh::poly_center_calc( + positions_src, loops_src.slice(poly.loopstart, poly.totloop)); } } @@ -1446,7 +1451,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, if (gen_islands_src) { const bool *uv_seams = static_cast( CustomData_get_layer_named(&me_src->edata, CD_PROP_BOOL, ".uv_seam")); - use_islands = gen_islands_src(positions_src, + use_islands = gen_islands_src(reinterpret_cast(positions_src.data()), num_verts_src, edges_src.data(), int(edges_src.size()), @@ -1490,8 +1495,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, positions_src, edge_to_poly_map_src, int(edges_src.size()), - loops_src.data(), - polys_src.data(), + polys_src, + loops_src, int(polys_src.size()), &as_graphdata[tindex]); } @@ -1517,7 +1522,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, } } bvhtree_from_mesh_verts_ex(&treedata[tindex], - positions_src, + reinterpret_cast(positions_src.data()), num_verts_src, verts_active, num_verts_active, @@ -1547,7 +1552,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, } } bvhtree_from_mesh_looptri_ex(&treedata[tindex], - positions_src, + reinterpret_cast(positions_src.data()), loops_src.data(), looptris_src.data(), int(looptris_src.size()), @@ -1577,11 +1582,11 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, /* Only in use_from_vert case, we may need polys' centers as fallback * in case we cannot decide which corner to use from normals only. */ - float pcent_dst[3]; + blender::float3 pcent_dst; bool pcent_dst_valid = false; if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { - copy_v3_v3(pnor_dst, poly_nors_dst[pidx_dst]); + copy_v3_v3(pnor_dst, poly_normals_dst[pidx_dst]); if (space_transform) { BLI_space_transform_apply_normal(space_transform, pnor_dst); } @@ -1614,23 +1619,23 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, if (mesh_remap_bvhtree_query_nearest( tdata, &nearest, tmp_co, max_dist_sq, &hit_dist)) { float(*nor_dst)[3]; - const float(*nors_src)[3]; + blender::Span nors_src; float best_nor_dot = -2.0f; float best_sqdist_fallback = FLT_MAX; int best_index_src = -1; if (mode == MREMAP_MODE_LOOP_NEAREST_LOOPNOR) { - copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]); + copy_v3_v3(tmp_no, loop_normals_dst[plidx_dst + mp_dst->loopstart]); if (space_transform) { BLI_space_transform_apply_normal(space_transform, tmp_no); } nor_dst = &tmp_no; - nors_src = loop_nors_src; + nors_src = loop_normals_src; vert_to_refelem_map_src = vert_to_loop_map_src; } else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */ nor_dst = &pnor_dst; - nors_src = poly_nors_src; + nors_src = poly_normals_src; vert_to_refelem_map_src = vert_to_poly_map_src; } @@ -1665,8 +1670,10 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, ml_src = &loops_src[poly.loopstart]; if (!pcent_dst_valid) { - BKE_mesh_calc_poly_center( - mp_dst, &loops_dst[mp_dst->loopstart], vert_positions_dst, pcent_dst); + pcent_dst = blender::bke::mesh::poly_center_calc( + {reinterpret_cast(vert_positions_dst), + numverts_dst}, + {&loops_dst[mp_dst->loopstart], mp_dst->totloop}); pcent_dst_valid = true; } pcent_src = poly_cents_src[pidx_src]; @@ -1713,7 +1720,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, float w = 1.0f; copy_v3_v3(tmp_co, vert_positions_dst[ml_dst->v]); - copy_v3_v3(tmp_no, loop_nors_dst[plidx_dst + mp_dst->loopstart]); + copy_v3_v3(tmp_no, loop_normals_dst[plidx_dst + mp_dst->loopstart]); /* We do our transform here, since we may do several raycast/nearest queries. */ if (space_transform) { @@ -2136,9 +2143,6 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, if (loop_to_poly_map_src) { MEM_freeN(loop_to_poly_map_src); } - if (poly_cents_src) { - MEM_freeN(poly_cents_src); - } if (vcos_interp) { MEM_freeN(vcos_interp); } @@ -2157,6 +2161,7 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode, const float ray_radius, const Mesh *mesh_dst, const float (*vert_positions_dst)[3], + const int numverts_dst, const MLoop *loops_dst, const MPoly *polys_dst, const int numpolys_dst, @@ -2165,14 +2170,14 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode, { const float full_weight = 1.0f; const float max_dist_sq = max_dist * max_dist; - const float(*poly_nors_dst)[3] = nullptr; - float tmp_co[3], tmp_no[3]; + blender::Span poly_normals_dst; + blender::float3 tmp_co, tmp_no; int i; BLI_assert(mode & MREMAP_MODE_POLY); if (mode & (MREMAP_USE_NORMAL | MREMAP_USE_NORPROJ)) { - poly_nors_dst = BKE_mesh_poly_normals_ensure(mesh_dst); + poly_normals_dst = mesh_dst->poly_normals(); } BKE_mesh_remap_init(r_map, numpolys_dst); @@ -2196,8 +2201,9 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode, for (i = 0; i < numpolys_dst; i++) { const MPoly &poly = polys_dst[i]; - - BKE_mesh_calc_poly_center(&poly, &loops_dst[poly.loopstart], vert_positions_dst, tmp_co); + tmp_co = blender::bke::mesh::poly_center_calc( + {reinterpret_cast(vert_positions_dst), numverts_dst}, + {&loops_dst[poly.loopstart], poly.totloop}); /* Convert the vertex to tree coordinates, if needed. */ if (space_transform) { @@ -2217,13 +2223,13 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode, } } else if (mode == MREMAP_MODE_POLY_NOR) { - BLI_assert(poly_nors_dst); - for (i = 0; i < numpolys_dst; i++) { const MPoly &poly = polys_dst[i]; - BKE_mesh_calc_poly_center(&poly, &loops_dst[poly.loopstart], vert_positions_dst, tmp_co); - copy_v3_v3(tmp_no, poly_nors_dst[i]); + tmp_co = blender::bke::mesh::poly_center_calc( + {reinterpret_cast(vert_positions_dst), numverts_dst}, + {&loops_dst[poly.loopstart], poly.totloop}); + copy_v3_v3(tmp_no, poly_normals_dst[i]); /* Convert the vertex to tree coordinates, if needed. */ if (space_transform) { @@ -2274,7 +2280,7 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode, int tot_rays, done_rays = 0; float poly_area_2d_inv, done_area = 0.0f; - float pcent_dst[3]; + blender::float3 pcent_dst; float to_pnor_2d_mat[3][3], from_pnor_2d_mat[3][3]; float poly_dst_2d_min[2], poly_dst_2d_max[2], poly_dst_2d_z; float poly_dst_2d_size[2]; @@ -2285,9 +2291,11 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode, const int tris_num = poly.totloop - 2; int j; - BKE_mesh_calc_poly_center( - &poly, &loops_dst[poly.loopstart], vert_positions_dst, pcent_dst); - copy_v3_v3(tmp_no, poly_nors_dst[i]); + pcent_dst = blender::bke::mesh::poly_center_calc( + {reinterpret_cast(vert_positions_dst), numverts_dst}, + {&loops_dst[poly.loopstart], poly.totloop}); + + copy_v3_v3(tmp_no, poly_normals_dst[i]); /* We do our transform here, else it'd be redone by raycast helper for each ray, ugh! */ if (space_transform) { diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index 61eb63d00b3..e7af9b326ed 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -30,7 +30,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remesh_voxel.h" /* own include */ #include "BKE_mesh_runtime.h" @@ -290,7 +290,7 @@ void BKE_mesh_remesh_reproject_paint_mask(Mesh *target, const Mesh *source) } else { target_mask = (float *)CustomData_add_layer( - &target->vdata, CD_PAINT_MASK, CD_CONSTRUCT, nullptr, target->totvert); + &target->vdata, CD_PAINT_MASK, CD_CONSTRUCT, target->totvert); } blender::threading::parallel_for(IndexRange(target->totvert), 4096, [&](const IndexRange range) { @@ -338,15 +338,12 @@ void BKE_remesh_reproject_sculpt_face_sets(Mesh *target, const Mesh *source) blender::threading::parallel_for(IndexRange(target->totpoly), 2048, [&](const IndexRange range) { for (const int i : range) { - float from_co[3]; BVHTreeNearest nearest; nearest.index = -1; nearest.dist_sq = FLT_MAX; const MPoly &poly = target_polys[i]; - BKE_mesh_calc_poly_center(&poly, - &target_loops[poly.loopstart], - reinterpret_cast(target_positions.data()), - from_co); + const float3 from_co = mesh::poly_center_calc( + target_positions, target_loops.slice(poly.loopstart, poly.totloop)); BLI_bvhtree_find_nearest( bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree); if (nearest.index != -1) { @@ -387,7 +384,7 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) int elem_num = domain == ATTR_DOMAIN_POINT ? target->totvert : target->totloop; CustomData_add_layer_named( - target_cdata, layer->type, CD_SET_DEFAULT, nullptr, elem_num, layer->name); + target_cdata, eCustomDataType(layer->type), CD_SET_DEFAULT, elem_num, layer->name); layer_i = CustomData_get_named_layer_index(target_cdata, layer->type, layer->name); } diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc index 8a8970b1905..83f3de9c8fe 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.cc +++ b/source/blender/blenkernel/intern/mesh_runtime.cc @@ -20,7 +20,7 @@ #include "BKE_bvhutils.h" #include "BKE_editmesh_cache.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_shrinkwrap.h" #include "BKE_subdiv_ccg.h" @@ -78,10 +78,10 @@ static void free_bvh_cache(MeshRuntime &mesh_runtime) } } -static void free_normals(MeshRuntime &mesh_runtime) +static void reset_normals(MeshRuntime &mesh_runtime) { - MEM_SAFE_FREE(mesh_runtime.vert_normals); - MEM_SAFE_FREE(mesh_runtime.poly_normals); + mesh_runtime.vert_normals.clear_and_shrink(); + mesh_runtime.poly_normals.clear_and_shrink(); mesh_runtime.vert_normals_dirty = true; mesh_runtime.poly_normals_dirty = true; } @@ -101,7 +101,6 @@ MeshRuntime::~MeshRuntime() free_bvh_cache(*this); free_edit_data(*this); free_batch_cache(*this); - free_normals(*this); if (this->shrinkwrap_data) { BKE_shrinkwrap_boundary_data_free(this->shrinkwrap_data); } @@ -152,21 +151,11 @@ blender::Span Mesh::looptris() const r_data.reinitialize(poly_to_tri_count(polys.size(), loops.size())); if (BKE_mesh_poly_normals_are_dirty(this)) { - BKE_mesh_recalc_looptri(loops.data(), - polys.data(), - reinterpret_cast(positions.data()), - loops.size(), - polys.size(), - r_data.data()); + blender::bke::mesh::looptris_calc(positions, polys, loops, r_data); } else { - BKE_mesh_recalc_looptri_with_normals(loops.data(), - polys.data(), - reinterpret_cast(positions.data()), - loops.size(), - polys.size(), - r_data.data(), - BKE_mesh_poly_normals_ensure(this)); + blender::bke::mesh::looptris_calc_with_normals( + positions, polys, loops, this->poly_normals(), r_data); } }); @@ -226,7 +215,7 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh) { /* Tagging shared caches dirty will free the allocated data if there is only one user. */ free_bvh_cache(*mesh->runtime); - free_normals(*mesh->runtime); + reset_normals(*mesh->runtime); free_subdiv_ccg(*mesh->runtime); mesh->runtime->bounds_cache.tag_dirty(); mesh->runtime->loose_edges_cache.tag_dirty(); @@ -244,7 +233,7 @@ void BKE_mesh_tag_edges_split(struct Mesh *mesh) * Face normals didn't change either, but tag those anyway, since there is no API function to * only tag vertex normals dirty. */ free_bvh_cache(*mesh->runtime); - free_normals(*mesh->runtime); + reset_normals(*mesh->runtime); free_subdiv_ccg(*mesh->runtime); mesh->runtime->loose_edges_cache.tag_dirty(); mesh->runtime->subsurf_face_dot_tags.clear_and_shrink(); @@ -256,7 +245,8 @@ void BKE_mesh_tag_edges_split(struct Mesh *mesh) void BKE_mesh_tag_positions_changed(Mesh *mesh) { - BKE_mesh_normals_tag_dirty(mesh); + mesh->runtime->vert_normals_dirty = true; + mesh->runtime->poly_normals_dirty = true; free_bvh_cache(*mesh->runtime); mesh->runtime->looptris_cache.tag_dirty(); mesh->runtime->bounds_cache.tag_dirty(); diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index 316fa41e16f..3fe710d1d69 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -2,7 +2,7 @@ #include "BKE_attribute_math.hh" #include "BKE_bvhutils.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.hh" diff --git a/source/blender/blenkernel/intern/mesh_tangent.cc b/source/blender/blenkernel/intern/mesh_tangent.cc index ab7a5a2579e..c4d8db512a2 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.cc +++ b/source/blender/blenkernel/intern/mesh_tangent.cc @@ -20,7 +20,7 @@ #include "BKE_attribute.hh" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_tangent.h" #include "BKE_report.h" @@ -240,7 +240,7 @@ struct SGLSLMeshToTangent { if (precomputedLoopNormals) { return mikk::float3(precomputedLoopNormals[loop_index]); } - if ((polys[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */ + if (sharp_faces && sharp_faces[lt->poly]) { /* flat */ if (precomputedFaceNormals) { return mikk::float3(precomputedFaceNormals[lt->poly]); } @@ -285,6 +285,7 @@ struct SGLSLMeshToTangent { const float (*vert_normals)[3]; const float (*orco)[3]; float (*tangent)[4]; /* destination */ + const bool *sharp_faces; int numTessFaces; #ifdef USE_LOOPTRI_DETECT_QUADS @@ -310,8 +311,7 @@ void BKE_mesh_add_loop_tangent_named_layer_for_uv(CustomData *uv_data, { if (CustomData_get_named_layer_index(tan_data, CD_TANGENT, layer_name) == -1 && CustomData_get_named_layer_index(uv_data, CD_PROP_FLOAT2, layer_name) != -1) { - CustomData_add_layer_named( - tan_data, CD_TANGENT, CD_SET_DEFAULT, nullptr, numLoopData, layer_name); + CustomData_add_layer_named(tan_data, CD_TANGENT, CD_SET_DEFAULT, numLoopData, layer_name); } } @@ -394,6 +394,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3], const MLoop *mloop, const MLoopTri *looptri, const uint looptri_len, + const bool *sharp_faces, CustomData *loopdata, bool calc_active_tangent, @@ -440,7 +441,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3], if ((tangent_mask & DM_TANGENT_MASK_ORCO) && CustomData_get_named_layer_index(loopdata, CD_TANGENT, "") == -1) { CustomData_add_layer_named( - loopdata_out, CD_TANGENT, CD_SET_DEFAULT, nullptr, int(loopdata_out_len), ""); + loopdata_out, CD_TANGENT, CD_SET_DEFAULT, int(loopdata_out_len), ""); } if (calc_act && act_uv_name[0]) { BKE_mesh_add_loop_tangent_named_layer_for_uv( @@ -498,6 +499,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3], mesh2tangent->polys = polys; mesh2tangent->mloop = mloop; mesh2tangent->looptri = looptri; + mesh2tangent->sharp_faces = sharp_faces; /* NOTE: we assume we do have tessellated loop normals at this point * (in case it is object-enabled), have to check this is valid. */ mesh2tangent->precomputedLoopNormals = loop_normals; @@ -583,12 +585,14 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval, me_eval->loops().data(), looptris.data(), uint(looptris.size()), + static_cast( + CustomData_get_layer_named(&me_eval->pdata, CD_PROP_BOOL, "sharp_face")), &me_eval->ldata, calc_active_tangent, tangent_names, tangent_names_len, - BKE_mesh_vert_normals_ensure(me_eval), - BKE_mesh_poly_normals_ensure(me_eval), + reinterpret_cast(me_eval->vert_normals().data()), + reinterpret_cast(me_eval->poly_normals().data()), static_cast(CustomData_get_layer(&me_eval->ldata, CD_NORMAL)), /* may be nullptr */ static_cast(CustomData_get_layer(&me_eval->vdata, CD_ORCO)), diff --git a/source/blender/blenkernel/intern/mesh_tessellate.cc b/source/blender/blenkernel/intern/mesh_tessellate.cc index 4d3898b70ac..62c69dc9286 100644 --- a/source/blender/blenkernel/intern/mesh_tessellate.cc +++ b/source/blender/blenkernel/intern/mesh_tessellate.cc @@ -10,24 +10,18 @@ * \see bmesh_mesh_tessellate.c for the #BMesh equivalent of this file. */ -#include - -#include "MEM_guardedalloc.h" - -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - +#include "BLI_enumerable_thread_specific.hh" #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_polyfill_2d.h" #include "BLI_task.h" -#include "BLI_utildefines.h" -#include "BKE_customdata.h" -#include "BKE_mesh.h" /* Own include. */ +#include "BKE_mesh.hh" #include "BLI_strict_flags.h" +namespace blender::bke::mesh { + /** Compared against total loops. */ #define MESH_FACE_TESSELLATE_THREADED_LIMIT 4096 @@ -40,9 +34,9 @@ /** * \param face_normal: This will be optimized out as a constant. */ -BLI_INLINE void mesh_calc_tessellation_for_face_impl(const MLoop *mloop, - const MPoly *polys, - const float (*positions)[3], +BLI_INLINE void mesh_calc_tessellation_for_face_impl(const Span mloop, + const Span polys, + const Span positions, uint poly_index, MLoopTri *mlt, MemArena **pf_arena_p, @@ -101,7 +95,7 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const MLoop *mloop, zero_v3(normal); /* Calc normal, flipped: to get a positive 2D cross product. */ - ml = mloop + mp_loopstart; + ml = mloop.data() + mp_loopstart; co_prev = positions[ml[mp_totloop - 1].v]; for (uint j = 0; j < mp_totloop; j++, ml++) { co_curr = positions[ml->v]; @@ -129,7 +123,7 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const MLoop *mloop, float(*projverts)[2] = static_cast( BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(mp_totloop))); - ml = mloop + mp_loopstart; + ml = mloop.data() + mp_loopstart; for (uint j = 0; j < mp_totloop; j++, ml++) { mul_v2_m3v3(projverts[j], axis_mat, positions[ml->v]); } @@ -150,9 +144,9 @@ BLI_INLINE void mesh_calc_tessellation_for_face_impl(const MLoop *mloop, #undef ML_TO_MLT } -static void mesh_calc_tessellation_for_face(const MLoop *mloop, - const MPoly *polys, - const float (*positions)[3], +static void mesh_calc_tessellation_for_face(const Span mloop, + const Span polys, + const Span positions, uint poly_index, MLoopTri *mlt, MemArena **pf_arena_p) @@ -161,9 +155,9 @@ static void mesh_calc_tessellation_for_face(const MLoop *mloop, mloop, polys, positions, poly_index, mlt, pf_arena_p, false, nullptr); } -static void mesh_calc_tessellation_for_face_with_normal(const MLoop *mloop, - const MPoly *polys, - const float (*positions)[3], +static void mesh_calc_tessellation_for_face_with_normal(const Span mloop, + const Span polys, + const Span positions, uint poly_index, MLoopTri *mlt, MemArena **pf_arena_p, @@ -173,16 +167,16 @@ static void mesh_calc_tessellation_for_face_with_normal(const MLoop *mloop, mloop, polys, positions, poly_index, mlt, pf_arena_p, true, normal_precalc); } -static void mesh_recalc_looptri__single_threaded(const MLoop *mloop, - const MPoly *polys, - const float (*positions)[3], +static void mesh_recalc_looptri__single_threaded(const Span mloop, + const Span polys, + const Span positions, int totloop, int totpoly, MLoopTri *mlooptri, const float (*poly_normals)[3]) { MemArena *pf_arena = nullptr; - const MPoly *poly = polys; + const MPoly *poly = polys.data(); uint tri_index = 0; if (poly_normals != nullptr) { @@ -214,12 +208,12 @@ static void mesh_recalc_looptri__single_threaded(const MLoop *mloop, } struct TessellationUserData { - const MLoop *mloop; - const MPoly *polys; - const float (*positions)[3]; + Span mloop; + Span polys; + Span positions; /** Output array. */ - MLoopTri *mlooptri; + MutableSpan mlooptri; /** Optional pre-calculated polygon normals array. */ const float (*poly_normals)[3]; @@ -272,23 +266,31 @@ static void mesh_calc_tessellation_for_face_free_fn(const void *__restrict /*use } } -static void mesh_recalc_looptri__multi_threaded(const MLoop *mloop, - const MPoly *polys, - const float (*positions)[3], - int /*totloop*/, - int totpoly, - MLoopTri *mlooptri, - const float (*poly_normals)[3]) +static void looptris_calc_all(const Span positions, + const Span polys, + const Span loops, + const Span poly_normals, + MutableSpan looptris) { + if (loops.size() < MESH_FACE_TESSELLATE_THREADED_LIMIT) { + mesh_recalc_looptri__single_threaded(loops, + polys, + positions, + int(loops.size()), + int(polys.size()), + looptris.data(), + reinterpret_cast(poly_normals.data())); + return; + } struct TessellationUserTLS tls_data_dummy = {nullptr}; struct TessellationUserData data { }; - data.mloop = mloop; + data.mloop = loops; data.polys = polys; data.positions = positions; - data.mlooptri = mlooptri; - data.poly_normals = poly_normals; + data.mlooptri = looptris; + data.poly_normals = reinterpret_cast(poly_normals.data()); TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); @@ -299,47 +301,46 @@ static void mesh_recalc_looptri__multi_threaded(const MLoop *mloop, settings.func_free = mesh_calc_tessellation_for_face_free_fn; BLI_task_parallel_range(0, - totpoly, + int(polys.size()), &data, - poly_normals ? mesh_calc_tessellation_for_face_with_normal_fn : - mesh_calc_tessellation_for_face_fn, + data.poly_normals ? mesh_calc_tessellation_for_face_with_normal_fn : + mesh_calc_tessellation_for_face_fn, &settings); } +void looptris_calc(const Span vert_positions, + const Span polys, + const Span loops, + MutableSpan looptris) +{ + looptris_calc_all(vert_positions, polys, loops, {}, looptris); +} + +void looptris_calc_with_normals(const Span vert_positions, + const Span polys, + const Span loops, + const Span poly_normals, + MutableSpan looptris) +{ + BLI_assert(!poly_normals.is_empty() || polys.is_empty()); + looptris_calc_all(vert_positions, polys, loops, poly_normals, looptris); +} + +} // namespace blender::bke::mesh + void BKE_mesh_recalc_looptri(const MLoop *mloop, const MPoly *polys, const float (*vert_positions)[3], + int totvert, int totloop, int totpoly, MLoopTri *mlooptri) { - if (totloop < MESH_FACE_TESSELLATE_THREADED_LIMIT) { - mesh_recalc_looptri__single_threaded( - mloop, polys, vert_positions, totloop, totpoly, mlooptri, nullptr); - } - else { - mesh_recalc_looptri__multi_threaded( - mloop, polys, vert_positions, totloop, totpoly, mlooptri, nullptr); - } -} - -void BKE_mesh_recalc_looptri_with_normals(const MLoop *mloop, - const MPoly *polys, - const float (*vert_positions)[3], - int totloop, - int totpoly, - MLoopTri *mlooptri, - const float (*poly_normals)[3]) -{ - BLI_assert(poly_normals != nullptr); - if (totloop < MESH_FACE_TESSELLATE_THREADED_LIMIT) { - mesh_recalc_looptri__single_threaded( - mloop, polys, vert_positions, totloop, totpoly, mlooptri, poly_normals); - } - else { - mesh_recalc_looptri__multi_threaded( - mloop, polys, vert_positions, totloop, totpoly, mlooptri, poly_normals); - } + blender::bke::mesh::looptris_calc( + {reinterpret_cast(vert_positions), totvert}, + {polys, totpoly}, + {mloop, totloop}, + {mlooptri, poly_to_tri_count(totpoly, totloop)}); } /** \} */ diff --git a/source/blender/blenkernel/intern/mesh_validate.cc b/source/blender/blenkernel/intern/mesh_validate.cc index 7f329e2eb68..19e5e525015 100644 --- a/source/blender/blenkernel/intern/mesh_validate.cc +++ b/source/blender/blenkernel/intern/mesh_validate.cc @@ -27,7 +27,7 @@ #include "BKE_attribute.hh" #include "BKE_customdata.h" #include "BKE_deform.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "DEG_depsgraph.h" @@ -299,14 +299,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, recalc_flag.edges = do_fixes; } - const float(*vert_normals)[3] = nullptr; - if (!BKE_mesh_vert_normals_are_dirty(mesh)) { - vert_normals = BKE_mesh_vert_normals_ensure(mesh); - } - for (i = 0; i < totvert; i++) { - bool fix_normal = true; - for (j = 0; j < 3; j++) { if (!isfinite(vert_positions[i][j])) { PRINT_ERR("\tVertex %u: has invalid coordinate", i); @@ -317,31 +310,6 @@ bool BKE_mesh_validate_arrays(Mesh *mesh, fix_flag.verts = true; } } - - if (vert_normals && vert_normals[i][j] != 0.0f) { - fix_normal = false; - break; - } - } - - if (vert_normals && fix_normal) { - /* If the vertex normal accumulates to zero or isn't part of a face, the location is used. - * When the location is also zero, a zero normal warning should not be raised. - * since this is the expected behavior of normal calculation. - * - * This avoids false positives but isn't foolproof as it's possible the vertex - * is part of a polygon that has a normal which this vertex should be using, - * although it's also possible degenerate/opposite faces accumulate to a zero vector. - * To detect this a full normal recalculation would be needed, which is out of scope - * for a basic validity check (see "Vertex Normal" in the doc-string). */ - if (!is_zero_v3(vert_positions[i])) { - PRINT_ERR("\tVertex %u: has zero normal, assuming Z-up normal", i); - if (do_fixes) { - float *normal = (float *)vert_normals[i]; - normal[2] = 1.0f; - fix_flag.verts = true; - } - } } } @@ -1146,13 +1114,6 @@ bool BKE_mesh_is_valid(Mesh *me) do_fixes, &changed); - if (!me->runtime->vert_normals_dirty) { - BLI_assert(me->runtime->vert_normals || me->totvert == 0); - } - if (!me->runtime->poly_normals_dirty) { - BLI_assert(me->runtime->poly_normals || me->totpoly == 0); - } - BLI_assert(changed == false); return is_valid; @@ -1352,8 +1313,8 @@ void BKE_mesh_calc_edges_tessface(Mesh *mesh) /* write new edges into a temporary CustomData */ CustomData edgeData; CustomData_reset(&edgeData); - CustomData_add_layer(&edgeData, CD_MEDGE, CD_SET_DEFAULT, nullptr, numEdges); - CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, numEdges); + CustomData_add_layer(&edgeData, CD_MEDGE, CD_SET_DEFAULT, numEdges); + CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, numEdges); MEdge *ege = (MEdge *)CustomData_get_layer_for_write(&edgeData, CD_MEDGE, mesh->totedge); int *index = (int *)CustomData_get_layer_for_write(&edgeData, CD_ORIGINDEX, mesh->totedge); diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc index a7e5d999cf6..63792623c56 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.cc +++ b/source/blender/blenkernel/intern/mesh_wrapper.cc @@ -34,7 +34,7 @@ #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" diff --git a/source/blender/blenkernel/intern/modifier.cc b/source/blender/blenkernel/intern/modifier.cc index 285cd3207aa..f329ee4124e 100644 --- a/source/blender/blenkernel/intern/modifier.cc +++ b/source/blender/blenkernel/intern/modifier.cc @@ -49,12 +49,12 @@ #include "BKE_effect.h" #include "BKE_fluid.h" #include "BKE_global.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_idtype.h" #include "BKE_key.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_multires.h" #include "BKE_object.h" @@ -735,7 +735,7 @@ ModifierData *BKE_modifiers_get_virtual_modifierlist(const Object *ob, Object *BKE_modifiers_is_deformed_by_armature(Object *ob) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { GpencilVirtualModifierData gpencilvirtualModifierData; ArmatureGpencilModifierData *agmd = nullptr; GpencilModifierData *gmd = BKE_gpencil_modifiers_get_virtual_modifierlist( diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index fc0a29b792e..c91f6c462a9 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -25,7 +25,7 @@ #include "DNA_defaults.h" #include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_movieclip_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc index a2adcfccc94..a2f2c52b9cf 100644 --- a/source/blender/blenkernel/intern/multires.cc +++ b/source/blender/blenkernel/intern/multires.cc @@ -24,7 +24,7 @@ #include "BKE_ccg.h" #include "BKE_cdderivedmesh.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -993,7 +993,7 @@ static void multiresModifier_disp_run( if (!mdisps) { if (op == CALC_DISPLACEMENTS) { mdisps = static_cast( - CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, me->totloop)); + CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, me->totloop)); } else { return; @@ -1528,7 +1528,7 @@ void multires_ensure_external_read(struct Mesh *mesh, int top_level) CustomData_get_layer_for_write(&mesh->ldata, CD_MDISPS, mesh->totloop)); if (mdisps == nullptr) { mdisps = static_cast( - CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, mesh->totloop)); + CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, mesh->totloop)); } const int totloop = mesh->totloop; diff --git a/source/blender/blenkernel/intern/multires_reshape.cc b/source/blender/blenkernel/intern/multires_reshape.cc index d4e842dc10c..d744ada4503 100644 --- a/source/blender/blenkernel/intern/multires_reshape.cc +++ b/source/blender/blenkernel/intern/multires_reshape.cc @@ -14,7 +14,7 @@ #include "BKE_customdata.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -179,8 +179,7 @@ void multiresModifier_subdivide_to_level(Object *object, * are allocated at a proper level and return. */ const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); if (!has_mdisps) { - CustomData_add_layer( - &coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, coarse_mesh->totloop); + CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, coarse_mesh->totloop); } /* NOTE: Subdivision happens from the top level of the existing multires modifier. If it is set diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.cc b/source/blender/blenkernel/intern/multires_reshape_apply_base.cc index e1efb8f0dfd..46a990c6e07 100644 --- a/source/blender/blenkernel/intern/multires_reshape_apply_base.cc +++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.cc @@ -19,7 +19,7 @@ #include "BKE_customdata.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_multires.h" @@ -114,16 +114,10 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape /* Find normal. */ for (int j = 0; j < pmap[i].count; j++) { const MPoly &poly = reshape_context->base_polys[pmap[i].indices[j]]; - MPoly fake_poly; - float no[3]; - /* Set up poly, loops, and coords in order to call BKE_mesh_calc_poly_normal(). */ - fake_poly.totloop = poly.totloop; - fake_poly.loopstart = 0; - MLoop *fake_loops = static_cast( - MEM_malloc_arrayN(poly.totloop, sizeof(MLoop), __func__)); - float(*fake_co)[3] = static_cast( - MEM_malloc_arrayN(poly.totloop, sizeof(float[3]), __func__)); + /* Set up poly, loops, and coords in order to call #bke::mesh::poly_normal_calc(). */ + blender::Array fake_loops(poly.totloop); + blender::Array fake_co(poly.totloop); for (int k = 0; k < poly.totloop; k++) { const int vndx = reshape_context->base_loops[poly.loopstart + k].v; @@ -138,10 +132,7 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape } } - BKE_mesh_calc_poly_normal(&fake_poly, fake_loops, (const float(*)[3])fake_co, no); - MEM_freeN(fake_loops); - MEM_freeN(fake_co); - + const blender::float3 no = blender::bke::mesh::poly_normal_calc(fake_co, fake_loops); add_v3_v3(avg_no, no); } normalize_v3(avg_no); diff --git a/source/blender/blenkernel/intern/multires_reshape_subdivide.cc b/source/blender/blenkernel/intern/multires_reshape_subdivide.cc index d29a820352f..866c35a7a73 100644 --- a/source/blender/blenkernel/intern/multires_reshape_subdivide.cc +++ b/source/blender/blenkernel/intern/multires_reshape_subdivide.cc @@ -14,7 +14,7 @@ #include "BKE_customdata.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -28,7 +28,9 @@ static void multires_subdivide_create_object_space_linear_grids(Mesh *mesh) { - const float(*positions)[3] = BKE_mesh_vert_positions(mesh); + using namespace blender; + using namespace blender::bke; + const Span positions = mesh->vert_positions(); const blender::Span polys = mesh->polys(); const blender::Span loops = mesh->loops(); @@ -36,8 +38,8 @@ static void multires_subdivide_create_object_space_linear_grids(Mesh *mesh) CustomData_get_layer_for_write(&mesh->ldata, CD_MDISPS, mesh->totloop)); for (const int p : polys.index_range()) { const MPoly &poly = polys[p]; - float poly_center[3]; - BKE_mesh_calc_poly_center(&poly, &loops[poly.loopstart], positions, poly_center); + const float3 poly_center = mesh::poly_center_calc(positions, + loops.slice(poly.loopstart, poly.totloop)); for (int l = 0; l < poly.totloop; l++) { const int loop_index = poly.loopstart + l; @@ -72,8 +74,7 @@ void multires_subdivide_create_tangent_displacement_linear_grids(Object *object, const bool has_mdisps = CustomData_has_layer(&coarse_mesh->ldata, CD_MDISPS); if (!has_mdisps) { - CustomData_add_layer( - &coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, coarse_mesh->totloop); + CustomData_add_layer(&coarse_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, coarse_mesh->totloop); } if (new_top_level == 1) { diff --git a/source/blender/blenkernel/intern/multires_reshape_util.cc b/source/blender/blenkernel/intern/multires_reshape_util.cc index c803c5ca478..aea8f8a3ca6 100644 --- a/source/blender/blenkernel/intern/multires_reshape_util.cc +++ b/source/blender/blenkernel/intern/multires_reshape_util.cc @@ -18,7 +18,7 @@ #include "BLI_task.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_multires.h" #include "BKE_subdiv.h" diff --git a/source/blender/blenkernel/intern/multires_subdiv.cc b/source/blender/blenkernel/intern/multires_subdiv.cc index 704d3fde1f1..b4cddcc53bf 100644 --- a/source/blender/blenkernel/intern/multires_subdiv.cc +++ b/source/blender/blenkernel/intern/multires_subdiv.cc @@ -12,7 +12,7 @@ #include "BLI_utildefines.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_subdiv.h" diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.cc b/source/blender/blenkernel/intern/multires_unsubdivide.cc index 49793ce44b6..eac1c869aa5 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.cc +++ b/source/blender/blenkernel/intern/multires_unsubdivide.cc @@ -20,7 +20,7 @@ #include "BKE_customdata.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -903,10 +903,10 @@ static void multires_unsubdivide_add_original_index_datalayers(Mesh *mesh) multires_unsubdivide_free_original_datalayers(mesh); int *l_index = static_cast(CustomData_add_layer_named( - &mesh->ldata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, mesh->totloop, lname)); + &mesh->ldata, CD_PROP_INT32, CD_SET_DEFAULT, mesh->totloop, lname)); int *v_index = static_cast(CustomData_add_layer_named( - &mesh->vdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, mesh->totvert, vname)); + &mesh->vdata, CD_PROP_INT32, CD_SET_DEFAULT, mesh->totvert, vname)); /* Initialize these data-layer with the indices in the current mesh. */ for (int i = 0; i < mesh->totloop; i++) { @@ -1186,8 +1186,8 @@ static void multires_create_grids_in_unsubdivided_base_mesh(MultiresUnsubdivideC if (CustomData_has_layer(&base_mesh->ldata, CD_MDISPS)) { CustomData_free_layers(&base_mesh->ldata, CD_MDISPS, base_mesh->totloop); } - MDisps *mdisps = static_cast(CustomData_add_layer( - &base_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, base_mesh->totloop)); + MDisps *mdisps = static_cast( + CustomData_add_layer(&base_mesh->ldata, CD_MDISPS, CD_SET_DEFAULT, base_mesh->totloop)); const int totdisp = pow_i(BKE_ccg_gridsize(context->num_total_levels), 2); const int totloop = base_mesh->totloop; diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 82589e65e97..c7ab1cffa7e 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -20,7 +20,7 @@ #include "DNA_action_types.h" #include "DNA_anim_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_linestyle_types.h" #include "DNA_material_types.h" diff --git a/source/blender/blenkernel/intern/node_tree_anonymous_attributes.cc b/source/blender/blenkernel/intern/node_tree_anonymous_attributes.cc index d355f6a768c..a3b2465428d 100644 --- a/source/blender/blenkernel/intern/node_tree_anonymous_attributes.cc +++ b/source/blender/blenkernel/intern/node_tree_anonymous_attributes.cc @@ -23,6 +23,11 @@ static const aal::RelationsInNode &get_relations_in_node(const bNode &node, Reso { if (node.is_group()) { if (const bNodeTree *group = reinterpret_cast(node.id)) { + /* Undefined tree types have no relations. */ + if (!ntreeIsRegistered(group)) { + return scope.construct(); + } + BLI_assert(group->runtime->anonymous_attribute_relations); return *group->runtime->anonymous_attribute_relations; } diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 97114c6c624..709981d84a8 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -25,8 +25,8 @@ #include "DNA_dynamicpaint_types.h" #include "DNA_effect_types.h" #include "DNA_fluid_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_light_types.h" @@ -86,9 +86,9 @@ #include "BKE_geometry_set.h" #include "BKE_geometry_set.hh" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" @@ -105,7 +105,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -233,7 +233,7 @@ static void object_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const in BKE_object_facemap_copy_list(&ob_dst->fmaps, &ob_src->fmaps); BKE_constraints_copy_ex(&ob_dst->constraints, &ob_src->constraints, flag_subdata, true); - ob_dst->mode = ob_dst->type != OB_GPENCIL ? OB_MODE_OBJECT : ob_dst->mode; + ob_dst->mode = ob_dst->type != OB_GPENCIL_LEGACY ? OB_MODE_OBJECT : ob_dst->mode; ob_dst->sculpt = nullptr; if (ob_src->pd) { @@ -1489,7 +1489,7 @@ static ParticleSystem *object_copy_modifier_particle_system_ensure(Main *bmain, bool BKE_object_copy_modifier( Main *bmain, Scene *scene, Object *ob_dst, const Object *ob_src, ModifierData *md_src) { - BLI_assert(ob_dst->type != OB_GPENCIL); + BLI_assert(ob_dst->type != OB_GPENCIL_LEGACY); const ModifierTypeInfo *mti = BKE_modifier_get_info((ModifierType)md_src->type); if (!object_modifier_type_copy_check((ModifierType)md_src->type)) { @@ -1587,7 +1587,7 @@ bool BKE_object_copy_modifier( bool BKE_object_copy_gpencil_modifier(struct Object *ob_dst, GpencilModifierData *gmd_src) { - BLI_assert(ob_dst->type == OB_GPENCIL); + BLI_assert(ob_dst->type == OB_GPENCIL_LEGACY); GpencilModifierData *gmd_dst = BKE_gpencil_modifier_new(gmd_src->type); BLI_strncpy(gmd_dst->name, gmd_src->name, sizeof(gmd_dst->name)); @@ -1607,7 +1607,7 @@ bool BKE_object_modifier_stack_copy(Object *ob_dst, const bool do_copy_all, const int flag_subdata) { - if ((ob_dst->type == OB_GPENCIL) != (ob_src->type == OB_GPENCIL)) { + if ((ob_dst->type == OB_GPENCIL_LEGACY) != (ob_src->type == OB_GPENCIL_LEGACY)) { BLI_assert_msg(0, "Trying to copy a modifier stack between a GPencil object and another type."); return false; @@ -1672,7 +1672,8 @@ static void copy_ccg_data(Mesh *mesh_destination, Mesh *mesh_source, int layer_t const int layer_index = CustomData_get_layer_index(data_destination, layer_type); CustomData_free_layer(data_destination, layer_type, num_elements, layer_index); BLI_assert(!CustomData_has_layer(data_destination, layer_type)); - CustomData_add_layer(data_destination, layer_type, CD_SET_DEFAULT, nullptr, num_elements); + CustomData_add_layer( + data_destination, eCustomDataType(layer_type), CD_SET_DEFAULT, num_elements); BLI_assert(CustomData_has_layer(data_destination, layer_type)); CustomData_copy_layer_type_data(data_source, data_destination, layer_type, 0, 0, num_elements); } @@ -1904,7 +1905,7 @@ bool BKE_object_is_in_editmode(const Object *ob) case OB_SURF: case OB_CURVES_LEGACY: return ((Curve *)ob->data)->editnurb != nullptr; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: /* Grease Pencil object has no edit mode data. */ return GPENCIL_EDIT_MODE((bGPdata *)ob->data); case OB_CURVES: @@ -2131,7 +2132,7 @@ static const char *get_obdata_defname(int type) return DATA_("Volume"); case OB_EMPTY: return DATA_("Empty"); - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return DATA_("GPencil"); case OB_LIGHTPROBE: return DATA_("LightProbe"); @@ -2156,7 +2157,7 @@ static void object_init(Object *ob, const short ob_type) ob->upflag = OB_POSY; } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { ob->dtx |= OB_USE_GPENCIL_LIGHTS; } @@ -2196,7 +2197,7 @@ void *BKE_object_obdata_add_from_type(Main *bmain, int type, const char *name) return BKE_speaker_add(bmain, name); case OB_LIGHTPROBE: return BKE_lightprobe_add(bmain, name); - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return BKE_gpencil_data_addnew(bmain, name); case OB_CURVES: return BKE_curves_add(bmain, name); @@ -2230,8 +2231,8 @@ int BKE_object_obdata_to_type(const ID *id) return OB_CAMERA; case ID_LT: return OB_LATTICE; - case ID_GD: - return OB_GPENCIL; + case ID_GD_LEGACY: + return OB_GPENCIL_LEGACY; case ID_AR: return OB_ARMATURE; case ID_LP: @@ -2558,7 +2559,7 @@ Object *BKE_object_pose_armature_get_with_wpaint_check(Object *ob) } break; } - case OB_GPENCIL: { + case OB_GPENCIL_LEGACY: { if ((ob->mode & OB_MODE_WEIGHT_GPENCIL) == 0) { return nullptr; } @@ -2794,7 +2795,7 @@ Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplica id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags); } break; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: if (dupflag & USER_DUP_GPENCIL) { id_new = BKE_id_copy_for_duplicate(bmain, id_old, dupflag, copy_flags); } @@ -3737,7 +3738,7 @@ const BoundBox *BKE_object_boundbox_get(Object *ob) case OB_ARMATURE: bb = BKE_armature_boundbox_get(ob); break; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: bb = BKE_gpencil_boundbox_get(ob); break; case OB_CURVES: @@ -3889,7 +3890,7 @@ void BKE_object_minmax(Object *ob, float r_min[3], float r_max[3], const bool us changed = true; break; } - case OB_GPENCIL: { + case OB_GPENCIL_LEGACY: { const BoundBox bb = *BKE_gpencil_boundbox_get(ob); BKE_boundbox_minmax(&bb, ob->object_to_world, r_min, r_max); changed = true; @@ -4090,7 +4091,7 @@ bool BKE_object_minmax_empty_drawtype(const struct Object *ob, float r_min[3], f max[0] = radius + (ofs[0] * radius); max[1] = radius + (ofs[1] * radius); /* Since the image aspect can shrink the bounds towards the object origin, - * adjust the min/max to account for that. */ + * adjust the min/max to account for that. */ for (int i = 0; i < 2; i++) { CLAMP_MAX(min[i], 0.0f); CLAMP_MIN(max[i], 0.0f); @@ -4190,7 +4191,7 @@ void BKE_object_foreach_display_point(Object *ob, func_cb(co, user_data); } } - else if (ob->type == OB_GPENCIL) { + else if (ob->type == OB_GPENCIL_LEGACY) { GPencilStrokePointIterData iter_data{}; iter_data.obmat = obmat; iter_data.point_func_cb = func_cb; @@ -5118,7 +5119,7 @@ bool BKE_object_supports_material_slots(struct Object *ob) OB_CURVES, OB_POINTCLOUD, OB_VOLUME, - OB_GPENCIL); + OB_GPENCIL_LEGACY); } /** \} */ diff --git a/source/blender/blenkernel/intern/object_deform.c b/source/blender/blenkernel/intern/object_deform.c index c1fe10dca6b..07db35b49e7 100644 --- a/source/blender/blenkernel/intern/object_deform.c +++ b/source/blender/blenkernel/intern/object_deform.c @@ -19,7 +19,7 @@ #include "DNA_armature_types.h" #include "DNA_cloth_types.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -32,7 +32,7 @@ #include "BKE_action.h" #include "BKE_deform.h" #include "BKE_editmesh.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_mesh.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -366,7 +366,7 @@ static void object_defgroup_remove_edit_mode(Object *ob, bDeformGroup *dg) void BKE_object_defgroup_remove(Object *ob, bDeformGroup *defgroup) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { BKE_gpencil_vgroup_remove(ob, defgroup); } else { diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index fb967ac9129..c648a339b0a 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -44,7 +44,7 @@ #include "BKE_instances.hh" #include "BKE_lattice.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_iterators.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -554,7 +554,7 @@ struct VertexDupliData_Mesh { int totvert; Span vert_positions; - const float (*vert_normals)[3]; + Span vert_normals; const float (*orco)[3]; }; @@ -735,7 +735,7 @@ static void make_duplis_verts(const DupliContext *ctx) vdd.params = vdd_params; vdd.totvert = me_eval->totvert; vdd.vert_positions = me_eval->vert_positions(); - vdd.vert_normals = BKE_mesh_vert_normals_ensure(me_eval); + vdd.vert_normals = me_eval->vert_normals(); vdd.orco = (const float(*)[3])CustomData_get_layer(&me_eval->vdata, CD_ORCO); make_child_duplis(ctx, &vdd, make_child_duplis_verts_from_mesh); diff --git a/source/blender/blenkernel/intern/object_update.cc b/source/blender/blenkernel/intern/object_update.cc index e5bb1b529df..1bc58475c3e 100644 --- a/source/blender/blenkernel/intern/object_update.cc +++ b/source/blender/blenkernel/intern/object_update.cc @@ -8,7 +8,7 @@ #include "DNA_anim_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -29,8 +29,8 @@ #include "BKE_displist.h" #include "BKE_editmesh.h" #include "BKE_effect.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_image.h" #include "BKE_key.h" #include "BKE_lattice.h" @@ -38,7 +38,7 @@ #include "BKE_light.h" #include "BKE_material.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_pointcache.h" @@ -181,7 +181,7 @@ void BKE_object_handle_data_update(Depsgraph *depsgraph, Scene *scene, Object *o case OB_LATTICE: BKE_lattice_modifiers_calc(depsgraph, scene, ob); break; - case OB_GPENCIL: { + case OB_GPENCIL_LEGACY: { BKE_gpencil_prepare_eval_data(depsgraph, scene, ob); BKE_gpencil_modifiers_calc(depsgraph, scene, ob); BKE_gpencil_update_layer_transforms(depsgraph, ob); @@ -303,7 +303,7 @@ void BKE_object_batch_cache_dirty_tag(Object *ob) } break; } - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: BKE_gpencil_batch_cache_dirty_tag((struct bGPdata *)ob->data); break; case OB_CURVES: diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 65988217b31..42eb3ceff4a 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -11,7 +11,7 @@ #include "MEM_guardedalloc.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -38,7 +38,7 @@ #include "BKE_context.h" #include "BKE_crazyspace.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_idtype.h" #include "BKE_image.h" #include "BKE_key.h" @@ -46,7 +46,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -1582,7 +1582,7 @@ static MultiresModifierData *sculpt_multires_modifier_get(const Scene *scene, if (mmd->sculptlvl > 0 && !(mmd->flags & eMultiresModifierFlag_UseSculptBaseMesh)) { if (need_mdisps) { - CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, nullptr, me->totloop); + CustomData_add_layer(&me->ldata, CD_MDISPS, CD_SET_DEFAULT, me->totloop); } return mmd; @@ -1976,7 +1976,7 @@ bool *BKE_sculpt_hide_poly_ensure(Mesh *mesh) return hide_poly; } return static_cast(CustomData_add_layer_named( - &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, mesh->totpoly, ".hide_poly")); + &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totpoly, ".hide_poly")); } int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, @@ -2001,8 +2001,8 @@ int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, int gridarea = gridsize * gridsize; int i, j; - gmask = static_cast(CustomData_add_layer( - &me->ldata, CD_GRID_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totloop)); + gmask = static_cast( + CustomData_add_layer(&me->ldata, CD_GRID_PAINT_MASK, CD_SET_DEFAULT, me->totloop)); for (i = 0; i < me->totloop; i++) { GridPaintMask *gpm = &gmask[i]; @@ -2050,7 +2050,7 @@ int BKE_sculpt_mask_layers_ensure(Depsgraph *depsgraph, /* Create vertex paint mask layer if there isn't one already. */ if (!paint_mask) { - CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, nullptr, me->totvert); + CustomData_add_layer(&me->vdata, CD_PAINT_MASK, CD_SET_DEFAULT, me->totvert); /* The evaluated mesh must be updated to contain the new data. */ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); ret |= SCULPT_MASK_LAYER_CALC_VERT; @@ -2188,12 +2188,7 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform, bool MLoopTri *looptri = static_cast( MEM_malloc_arrayN(looptris_num, sizeof(*looptri), __func__)); - BKE_mesh_recalc_looptri(loops.data(), - polys.data(), - reinterpret_cast(positions.data()), - me->totloop, - me->totpoly, - looptri); + blender::bke::mesh::looptris_calc(positions, polys, loops, {looptri, looptris_num}); BKE_pbvh_build_mesh(pbvh, me, @@ -2517,7 +2512,7 @@ static bool sculpt_attribute_create(SculptSession *ss, BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1); - CustomData_add_layer_named(cdata, proptype, CD_SET_DEFAULT, nullptr, totelem, name); + CustomData_add_layer_named(cdata, proptype, CD_SET_DEFAULT, totelem, name); int index = CustomData_get_named_layer_index(cdata, proptype, name); if (!permanent) { @@ -2803,8 +2798,7 @@ static void sculpt_attribute_update_refs(Object *ob) { SculptSession *ss = ob->sculpt; - /* run twice, in case sculpt_attr_update had to recreate a layer and - messed up the bmesh offsets. */ + /* Run twice, in case sculpt_attr_update had to recreate a layer and messed up #BMesh offsets. */ for (int i = 0; i < 2; i++) { for (int j = 0; j < SCULPT_MAX_ATTRIBUTES; j++) { SculptAttribute *attr = ss->temp_attributes + j; diff --git a/source/blender/blenkernel/intern/particle.cc b/source/blender/blenkernel/intern/particle.cc index 48150c7dcaf..5b51e8c6ab1 100644 --- a/source/blender/blenkernel/intern/particle.cc +++ b/source/blender/blenkernel/intern/particle.cc @@ -58,7 +58,7 @@ #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -2160,7 +2160,7 @@ void psys_particle_on_dm(Mesh *mesh_final, } orcodata = static_cast(CustomData_get_layer(&mesh_final->vdata, CD_ORCO)); - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh_final); + const blender::Span vert_normals = mesh_final->vert_normals(); if (from == PART_FROM_VERT) { const float(*vert_positions)[3] = BKE_mesh_vert_positions(mesh_final); @@ -2203,7 +2203,7 @@ void psys_particle_on_dm(Mesh *mesh_final, if (from == PART_FROM_VOLUME) { psys_interpolate_face(mesh_final, vert_positions, - vert_normals, + reinterpret_cast(vert_normals.data()), mface, mtface, orcodata, @@ -2226,7 +2226,7 @@ void psys_particle_on_dm(Mesh *mesh_final, else { psys_interpolate_face(mesh_final, vert_positions, - vert_normals, + reinterpret_cast(vert_normals.data()), mface, mtface, orcodata, diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index cb45736d303..0db48119969 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -20,7 +20,7 @@ #include "BKE_attribute.h" #include "BKE_ccg.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_paint.h" #include "BKE_pbvh.h" @@ -151,19 +151,27 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node) // BB_expand(&node->vb, co); //} -static bool face_materials_match(const PBVH *pbvh, const int a, const int b) +static bool face_materials_match(const PBVH *pbvh, + const bool *sharp_faces, + const int a, + const int b) { if (pbvh->material_indices) { if (pbvh->material_indices[a] != pbvh->material_indices[b]) { return false; } } - return (pbvh->polys[a].flag & ME_SMOOTH) == (pbvh->polys[b].flag & ME_SMOOTH); + if (sharp_faces) { + if (sharp_faces[a] != sharp_faces[b]) { + return false; + } + } + return true; } static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2) { - return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr)); + return (f1->sharp == f2->sharp) && (f1->mat_nr == f2->mat_nr); } /* Adapted from BLI_kdopbvh.c */ @@ -229,7 +237,7 @@ static int partition_indices_grids(int *prim_indices, } /* Returns the index of the first element on the right of the partition */ -static int partition_indices_material(PBVH *pbvh, int lo, int hi) +static int partition_indices_material(PBVH *pbvh, const bool *sharp_faces, int lo, int hi) { const MLoopTri *looptri = pbvh->looptri; const DMFlagMat *flagmats = pbvh->grid_flag_mats; @@ -239,10 +247,10 @@ static int partition_indices_material(PBVH *pbvh, int lo, int hi) for (;;) { if (pbvh->looptri) { const int first = looptri[pbvh->prim_indices[lo]].poly; - for (; face_materials_match(pbvh, first, looptri[indices[i]].poly); i++) { + for (; face_materials_match(pbvh, sharp_faces, first, looptri[indices[i]].poly); i++) { /* pass */ } - for (; !face_materials_match(pbvh, first, looptri[indices[j]].poly); j--) { + for (; !face_materials_match(pbvh, sharp_faces, first, looptri[indices[j]].poly); j--) { /* pass */ } } @@ -450,7 +458,7 @@ static void build_leaf(PBVH *pbvh, int node_index, BBC *prim_bbc, int offset, in /* Return zero if all primitives in the node can be drawn with the * same material (including flat/smooth shading), non-zero otherwise */ -static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count) +static bool leaf_needs_material_split(PBVH *pbvh, const bool *sharp_faces, int offset, int count) { if (count <= 1) { return false; @@ -460,7 +468,7 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count) const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]]; for (int i = offset + count - 1; i > offset; i--) { int prim = pbvh->prim_indices[i]; - if (!face_materials_match(pbvh, first->poly, pbvh->looptri[prim].poly)) { + if (!face_materials_match(pbvh, sharp_faces, first->poly, pbvh->looptri[prim].poly)) { return true; } } @@ -539,6 +547,7 @@ static void test_face_boundaries(PBVH *pbvh) */ static void build_sub(PBVH *pbvh, + const bool *sharp_faces, int node_index, BB *cb, BBC *prim_bbc, @@ -557,7 +566,7 @@ static void build_sub(PBVH *pbvh, /* Decide whether this is a leaf or not */ const bool below_leaf_limit = count <= pbvh->leaf_limit || depth >= STACK_FIXED_DEPTH - 1; if (below_leaf_limit) { - if (!leaf_needs_material_split(pbvh, offset, count)) { + if (!leaf_needs_material_split(pbvh, sharp_faces, offset, count)) { build_leaf(pbvh, node_index, prim_bbc, offset, count); if (node_index == 0) { @@ -610,11 +619,12 @@ static void build_sub(PBVH *pbvh, } else { /* Partition primitives by material */ - end = partition_indices_material(pbvh, offset, offset + count - 1); + end = partition_indices_material(pbvh, sharp_faces, offset, offset + count - 1); } /* Build children */ build_sub(pbvh, + sharp_faces, pbvh->nodes[node_index].children_offset, nullptr, prim_bbc, @@ -623,6 +633,7 @@ static void build_sub(PBVH *pbvh, prim_scratch, depth + 1); build_sub(pbvh, + sharp_faces, pbvh->nodes[node_index].children_offset + 1, nullptr, prim_bbc, @@ -636,7 +647,7 @@ static void build_sub(PBVH *pbvh, } } -static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim) +static void pbvh_build(PBVH *pbvh, const bool *sharp_faces, BB *cb, BBC *prim_bbc, int totprim) { if (totprim != pbvh->totprim) { pbvh->totprim = totprim; @@ -659,7 +670,7 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim) } pbvh->totnode = 1; - build_sub(pbvh, 0, cb, prim_bbc, 0, totprim, nullptr, 0); + build_sub(pbvh, sharp_faces, 0, cb, prim_bbc, 0, totprim, nullptr, 0); } static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node) @@ -834,7 +845,8 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, pbvh->mloop = mloop; pbvh->looptri = looptri; pbvh->vert_positions = vert_positions; - BKE_mesh_vert_normals_ensure(mesh); + /* Make sure cached normals start out calculated. */ + mesh->vert_normals(); pbvh->vert_normals = BKE_mesh_vert_normals_for_write(mesh); pbvh->hide_vert = static_cast(CustomData_get_layer_named_for_write( &mesh->vdata, CD_PROP_BOOL, ".hide_vert", mesh->totvert)); @@ -881,7 +893,9 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, } if (looptri_num) { - pbvh_build(pbvh, &cb, prim_bbc, looptri_num); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, "sharp_face"); + pbvh_build(pbvh, sharp_faces, &cb, prim_bbc, looptri_num); #ifdef TEST_PBVH_FACE_SPLIT test_face_boundaries(pbvh); @@ -968,7 +982,9 @@ void BKE_pbvh_build_grids(PBVH *pbvh, } if (totgrid) { - pbvh_build(pbvh, &cb, prim_bbc, totgrid); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &me->pdata, CD_PROP_BOOL, "sharp_face"); + pbvh_build(pbvh, sharp_faces, &cb, prim_bbc, totgrid); #ifdef TEST_PBVH_FACE_SPLIT test_face_boundaries(pbvh); @@ -1394,7 +1410,7 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata, if (node->flag & PBVH_UpdateNormals) { uint mpoly_prev = UINT_MAX; - float fn[3]; + blender::float3 fn; const int *faces = node->prim_indices; const int totface = node->totprim; @@ -1411,7 +1427,9 @@ static void pbvh_update_normals_accum_task_cb(void *__restrict userdata, /* Face normal and mask */ if (lt->poly != mpoly_prev) { const MPoly &poly = pbvh->polys[lt->poly]; - BKE_mesh_calc_poly_normal(&poly, &pbvh->mloop[poly.loopstart], pbvh->vert_positions, fn); + fn = blender::bke::mesh::poly_normal_calc( + {reinterpret_cast(pbvh->vert_positions), pbvh->totvert}, + {&pbvh->mloop[poly.loopstart], poly.totloop}); mpoly_prev = lt->poly; } @@ -3501,12 +3519,8 @@ bool *BKE_pbvh_get_vert_hide_for_write(PBVH *pbvh) if (pbvh->hide_vert) { return pbvh->hide_vert; } - pbvh->hide_vert = static_cast(CustomData_add_layer_named(&pbvh->mesh->vdata, - CD_PROP_BOOL, - CD_SET_DEFAULT, - nullptr, - pbvh->mesh->totvert, - ".hide_vert")); + pbvh->hide_vert = static_cast(CustomData_add_layer_named( + &pbvh->mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, pbvh->mesh->totvert, ".hide_vert")); return pbvh->hide_vert; } @@ -3872,7 +3886,7 @@ void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh) if (!hide_poly) { hide_poly = static_cast(CustomData_add_layer_named( - &mesh->pdata, CD_PROP_BOOL, CD_CONSTRUCT, nullptr, mesh->totpoly, ".hide_poly")); + &mesh->pdata, CD_PROP_BOOL, CD_CONSTRUCT, mesh->totpoly, ".hide_poly")); } } diff --git a/source/blender/blenkernel/intern/pbvh_colors.cc b/source/blender/blenkernel/intern/pbvh_colors.cc index 03c15b007be..73a32dea777 100644 --- a/source/blender/blenkernel/intern/pbvh_colors.cc +++ b/source/blender/blenkernel/intern/pbvh_colors.cc @@ -21,7 +21,7 @@ #include "BKE_attribute.h" #include "BKE_ccg.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_paint.h" #include "BKE_pbvh.h" diff --git a/source/blender/blenkernel/intern/pbvh_intern.hh b/source/blender/blenkernel/intern/pbvh_intern.hh index a9282629031..cf051e20540 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.hh +++ b/source/blender/blenkernel/intern/pbvh_intern.hh @@ -290,5 +290,4 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode); void pbvh_node_pixels_free(PBVHNode *node); void pbvh_pixels_free(PBVH *pbvh); -void pbvh_pixels_free_brush_test(PBVHNode *node); void pbvh_free_draw_buffers(PBVH *pbvh, PBVHNode *node); diff --git a/source/blender/blenkernel/intern/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc index 4a8f70714fc..0a3f485610f 100644 --- a/source/blender/blenkernel/intern/pbvh_pixels.cc +++ b/source/blender/blenkernel/intern/pbvh_pixels.cc @@ -3,7 +3,7 @@ #include "BKE_attribute.hh" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_pbvh.h" #include "BKE_pbvh_pixels.hh" @@ -23,6 +23,7 @@ #include "bmesh.h" #include "pbvh_intern.hh" +#include "pbvh_pixels_copy.hh" #include "pbvh_uv_islands.hh" namespace blender::bke::pbvh::pixels { @@ -714,6 +715,9 @@ static bool update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image apply_watertight_check(pbvh, image, image_user); } + /* Add solution for non-manifold parts of the model. */ + BKE_pbvh_pixels_copy_update(*pbvh, *image, *image_user, mesh_data); + /* Rebuild the undo regions. */ for (PBVHNode *node : nodes_to_update) { NodeData *node_data = static_cast(node->pixels.node_data); @@ -797,6 +801,13 @@ void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &i node_data->flags.dirty = false; } } + +void BKE_pbvh_pixels_collect_dirty_tiles(PBVHNode &node, Vector &r_dirty_tiles) +{ + NodeData *node_data = static_cast(node.pixels.node_data); + node_data->collect_dirty_tiles(r_dirty_tiles); +} + } // namespace blender::bke::pbvh::pixels using namespace blender::bke::pbvh::pixels; diff --git a/source/blender/blenkernel/intern/pbvh_pixels_copy.cc b/source/blender/blenkernel/intern/pbvh_pixels_copy.cc new file mode 100644 index 00000000000..b09a192ec8b --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_pixels_copy.cc @@ -0,0 +1,577 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +#include "BLI_array.hh" +#include "BLI_bit_vector.hh" +#include "BLI_math.h" +#include "BLI_math_vector.hh" +#include "BLI_task.hh" +#include "BLI_vector.hh" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BKE_image_wrappers.hh" +#include "BKE_pbvh.h" +#include "BKE_pbvh_pixels.hh" + +#include "pbvh_intern.hh" +#include "pbvh_pixels_copy.hh" +#include "pbvh_uv_islands.hh" + +namespace blender::bke::pbvh::pixels { + +const int THREADING_GRAIN_SIZE = 128; + +/** Coordinate space of a coordinate. */ +enum class CoordSpace { + /** + * Coordinate is in UV coordinate space. As in unmodified from mesh data. + */ + UV, + + /** + * Coordinate is in Tile coordinate space. + * + * With tile coordinate space each unit is a single pixel of the tile. + * Range is [0..buffer width]. + */ + Tile, +}; + +template struct Vertex { + float2 coordinate; +}; + +template struct Edge { + Vertex vertex_1; + Vertex vertex_2; +}; + +/** Calculate the bounds of the given edge. */ +static rcti get_bounds(const Edge &tile_edge) +{ + rcti bounds; + BLI_rcti_init_minmax(&bounds); + BLI_rcti_do_minmax_v(&bounds, int2(tile_edge.vertex_1.coordinate)); + BLI_rcti_do_minmax_v(&bounds, int2(tile_edge.vertex_2.coordinate)); + return bounds; +} + +/** Add a margin to the given bounds. */ +static void add_margin(rcti &bounds, int margin) +{ + bounds.xmin -= margin; + bounds.xmax += margin; + bounds.ymin -= margin; + bounds.ymax += margin; +} + +/** Clamp bounds to be between 0,0 and the given resolution. */ +static void clamp(rcti &bounds, int2 resolution) +{ + rcti clamping_bounds; + BLI_rcti_init(&clamping_bounds, 0, resolution.x - 1, 0, resolution.y - 1); + BLI_rcti_isect(&bounds, &clamping_bounds, &bounds); +} + +static const Vertex convert_coord_space(const Vertex &uv_vertex, + const image::ImageTileWrapper image_tile, + const int2 tile_resolution) +{ + return Vertex{(uv_vertex.coordinate - float2(image_tile.get_tile_offset())) * + float2(tile_resolution)}; +} + +static const Edge convert_coord_space(const Edge &uv_edge, + const image::ImageTileWrapper image_tile, + const int2 tile_resolution) +{ + return Edge{ + convert_coord_space(uv_edge.vertex_1, image_tile, tile_resolution), + convert_coord_space(uv_edge.vertex_2, image_tile, tile_resolution), + }; +} + +class NonManifoldTileEdges : public Vector> { +}; + +class NonManifoldUVEdges : public Vector> { + public: + NonManifoldUVEdges(const uv_islands::MeshData &mesh_data) + { + int num_non_manifold_edges = count_non_manifold_edges(mesh_data); + reserve(num_non_manifold_edges); + for (const int primitive_id : mesh_data.looptris.index_range()) { + for (const int edge_id : mesh_data.primitive_to_edge_map[primitive_id]) { + if (is_manifold(mesh_data, edge_id)) { + continue; + } + const MLoopTri &loop_tri = mesh_data.looptris[primitive_id]; + const uv_islands::MeshEdge &mesh_edge = mesh_data.edges[edge_id]; + Edge edge; + + edge.vertex_1.coordinate = find_uv(mesh_data, loop_tri, mesh_edge.vert1); + edge.vertex_2.coordinate = find_uv(mesh_data, loop_tri, mesh_edge.vert2); + append(edge); + } + } + BLI_assert_msg(size() == num_non_manifold_edges, + "Incorrect number of non manifold edges added. "); + } + + NonManifoldTileEdges extract_tile_edges(const image::ImageTileWrapper image_tile, + const int2 tile_resolution) const + { + NonManifoldTileEdges result; + for (const Edge &uv_edge : *this) { + const Edge tile_edge = convert_coord_space( + uv_edge, image_tile, tile_resolution); + result.append(tile_edge); + } + return result; + } + + private: + static int64_t count_non_manifold_edges(const uv_islands::MeshData &mesh_data) + { + int64_t result = 0; + for (const int primitive_id : mesh_data.looptris.index_range()) { + for (const int edge_id : mesh_data.primitive_to_edge_map[primitive_id]) { + if (is_manifold(mesh_data, edge_id)) { + continue; + } + result += 1; + } + } + return result; + } + + static bool is_manifold(const uv_islands::MeshData &mesh_data, const int edge_id) + { + return mesh_data.edge_to_primitive_map[edge_id].size() == 2; + } + + static float2 find_uv(const uv_islands::MeshData &mesh_data, + const MLoopTri &loop_tri, + int vertex_i) + { + for (int i = 0; i < 3; i++) { + int loop_i = loop_tri.tri[i]; + const MLoop &loop = mesh_data.loops[loop_i]; + if (loop.v == vertex_i) { + return mesh_data.uv_map[loop_i]; + } + } + BLI_assert_unreachable(); + return float2(0.0f); + } +}; + +class PixelNodesTileData : public Vector> { + public: + PixelNodesTileData(PBVH &pbvh, const image::ImageTileWrapper &image_tile) + { + reserve(count_nodes(pbvh, image_tile)); + + for (PBVHNode &node : MutableSpan(pbvh.nodes, pbvh.totnode)) { + if (should_add_node(node, image_tile)) { + NodeData &node_data = *static_cast(node.pixels.node_data); + UDIMTilePixels &tile_pixels = *node_data.find_tile_data(image_tile); + append(tile_pixels); + } + } + } + + private: + static bool should_add_node(PBVHNode &node, const image::ImageTileWrapper &image_tile) + { + if ((node.flag & PBVH_Leaf) == 0) { + return false; + } + if (node.pixels.node_data == nullptr) { + return false; + } + NodeData &node_data = *static_cast(node.pixels.node_data); + if (node_data.find_tile_data(image_tile) == nullptr) { + return false; + } + return true; + } + + static int64_t count_nodes(PBVH &pbvh, const image::ImageTileWrapper &image_tile) + { + int64_t result = 0; + for (PBVHNode &node : MutableSpan(pbvh.nodes, pbvh.totnode)) { + if (should_add_node(node, image_tile)) { + result++; + } + } + return result; + } +}; + +/** + * Row contains intermediate data per pixel for a single image row. It is used during updating to + * encode pixels. + */ + +struct Rows { + enum class PixelType { + Undecided, + /** This pixel is directly affected by a brush and doesn't need to be solved. */ + Brush, + SelectedForCloserExamination, + /** This pixel will be copied from another pixel to solve non-manifold edge bleeding. */ + CopyFromClosestEdge, + }; + + struct Pixel { + PixelType type; + float distance; + CopyPixelCommand copy_command; + /** + * Index of the edge in the list of non-manifold edges. + * + * The edge is kept to calculate the mix factor between the two pixels that have chosen to + * be mixed. + */ + int64_t edge_index; + + Pixel() = default; + + void init(int2 coordinate) + { + copy_command.destination = coordinate; + copy_command.source_1 = coordinate; + copy_command.source_2 = coordinate; + copy_command.mix_factor = 0.0f; + type = PixelType::Undecided; + distance = std::numeric_limits::max(); + edge_index = -1; + } + }; + + int2 resolution; + int margin; + Array pixels; + + struct RowView { + int row_number = 0; + /** Not owning pointer into Row.pixels starts at the start of the row.*/ + MutableSpan pixels; + RowView() = delete; + RowView(Rows &rows, int64_t row_number) + : row_number(row_number), + pixels( + MutableSpan(&rows.pixels[row_number * rows.resolution.x], rows.resolution.x)) + { + } + }; + + Rows(int2 resolution, int margin) + : resolution(resolution), margin(margin), pixels(resolution.x * resolution.y) + { + } + + void init_pixels() + { + int64_t index = 0; + for (int y : IndexRange(resolution.y)) { + for (int64_t x : IndexRange(resolution.x)) { + int2 position(x, y); + pixels[index++].init(position); + } + } + } + + /** + * Mark pixels that are painted on by the brush. Those pixels don't need to be updated, but will + * act as a source for other pixels. + */ + void mark_pixels_effected_by_brush(const PixelNodesTileData &nodes_tile_pixels) + { + for (const UDIMTilePixels &tile_pixels : nodes_tile_pixels) { + threading::parallel_for_each( + tile_pixels.pixel_rows, [&](const PackedPixelRow &encoded_pixels) { + for (int x = encoded_pixels.start_image_coordinate.x; + x < encoded_pixels.start_image_coordinate.x + encoded_pixels.num_pixels; + x++) { + int64_t index = encoded_pixels.start_image_coordinate.y * resolution.x + x; + pixels[index].type = PixelType::Brush; + pixels[index].distance = 0.0f; + } + }); + } + } + + /** + * Look for a second source pixel that will be blended with the first source pixel to improve + * the quality of the fix. + * + * - The second source pixel must be a neighbor pixel of the first source, or the same as the + * first source when no second pixel could be found. + * - The second source pixel must be a pixel that is painted on by the brush. + * - The second source pixel must be the second closest pixel , or the first source + * when no second pixel could be found. + */ + int2 find_second_source(int2 destination, int2 first_source) + { + rcti search_bounds; + BLI_rcti_init(&search_bounds, + max_ii(first_source.x - 1, 0), + min_ii(first_source.x + 1, resolution.x - 1), + max_ii(first_source.y - 1, 0), + min_ii(first_source.y + 1, resolution.y - 1)); + /* Initialize to the first source, so when no other source could be found it will use the + * first_source. */ + int2 found_source = first_source; + float found_distance = std::numeric_limits().max(); + for (int sy : IndexRange(search_bounds.ymin, BLI_rcti_size_y(&search_bounds) + 1)) { + for (int sx : IndexRange(search_bounds.xmin, BLI_rcti_size_x(&search_bounds) + 1)) { + int2 source(sx, sy); + /* Skip first source as it should be the closest and already selected. */ + if (source == first_source) { + continue; + } + int pixel_index = sy * resolution.y + sx; + if (pixels[pixel_index].type != PixelType::Brush) { + continue; + } + + float new_distance = blender::math::distance(float2(destination), float2(source)); + if (new_distance < found_distance) { + found_distance = new_distance; + found_source = source; + } + } + } + return found_source; + } + + float determine_mix_factor(const int2 destination, + const int2 source_1, + const int2 source_2, + const Edge &edge) + { + /* Use stable result when both sources are the same. */ + if (source_1 == source_2) { + return 0.0f; + } + + float2 clamped_to_edge; + float destination_lambda = closest_to_line_v2( + clamped_to_edge, float2(destination), edge.vertex_1.coordinate, edge.vertex_2.coordinate); + float source_1_lambda = closest_to_line_v2( + clamped_to_edge, float2(source_1), edge.vertex_1.coordinate, edge.vertex_2.coordinate); + float source_2_lambda = closest_to_line_v2( + clamped_to_edge, float2(source_2), edge.vertex_1.coordinate, edge.vertex_2.coordinate); + + return clamp_f( + (destination_lambda - source_1_lambda) / (source_2_lambda - source_1_lambda), 0.0f, 1.0f); + } + + void find_copy_source(Pixel &pixel, const NonManifoldTileEdges &tile_edges) + { + BLI_assert(pixel.type == PixelType::SelectedForCloserExamination); + + rcti bounds; + BLI_rcti_init(&bounds, + pixel.copy_command.destination.x, + pixel.copy_command.destination.x, + pixel.copy_command.destination.y, + pixel.copy_command.destination.y); + add_margin(bounds, margin); + clamp(bounds, resolution); + + float found_distance = std::numeric_limits().max(); + int2 found_source(0); + + for (int sy : IndexRange(bounds.ymin, BLI_rcti_size_y(&bounds))) { + int pixel_index = sy * resolution.x; + for (int sx : IndexRange(bounds.xmin, BLI_rcti_size_x(&bounds))) { + Pixel &source = pixels[pixel_index + sx]; + if (source.type != PixelType::Brush) { + continue; + } + float new_distance = blender::math::distance(float2(sx, sy), + float2(pixel.copy_command.destination)); + if (new_distance < found_distance) { + found_source = int2(sx, sy); + found_distance = new_distance; + } + } + } + + if (found_distance == std::numeric_limits().max()) { + return; + } + pixel.type = PixelType::CopyFromClosestEdge; + pixel.distance = found_distance; + pixel.copy_command.source_1 = found_source; + pixel.copy_command.source_2 = find_second_source(pixel.copy_command.destination, found_source); + pixel.copy_command.mix_factor = determine_mix_factor(pixel.copy_command.destination, + pixel.copy_command.source_1, + pixel.copy_command.source_2, + tile_edges[pixel.edge_index]); + } + + void find_copy_source(Vector> &selected_pixels, + const NonManifoldTileEdges &tile_edges) + { + threading::parallel_for( + IndexRange(selected_pixels.size()), THREADING_GRAIN_SIZE, [&](IndexRange range) { + for (int selected_pixel_index : range) { + Pixel ¤t_pixel = selected_pixels[selected_pixel_index]; + find_copy_source(current_pixel, tile_edges); + } + }); + } + + Vector> filter_pixels_for_closer_examination( + const NonManifoldTileEdges &tile_edges) + { + Vector> selected_pixels; + selected_pixels.reserve(10000); + + for (int tile_edge_index : tile_edges.index_range()) { + const Edge &tile_edge = tile_edges[tile_edge_index]; + rcti edge_bounds = get_bounds(tile_edge); + add_margin(edge_bounds, margin); + clamp(edge_bounds, resolution); + + for (const int64_t sy : IndexRange(edge_bounds.ymin, BLI_rcti_size_y(&edge_bounds))) { + for (const int64_t sx : IndexRange(edge_bounds.xmin, BLI_rcti_size_x(&edge_bounds))) { + const int64_t index = sy * resolution.x + sx; + Pixel &pixel = pixels[index]; + if (pixel.type == PixelType::Brush) { + continue; + } + BLI_assert_msg(pixel.type != PixelType::CopyFromClosestEdge, + "PixelType::CopyFromClosestEdge isn't allowed to be set as it is set " + "when finding the pixels to copy."); + + const float2 point(sx, sy); + float2 closest_edge_point; + closest_to_line_segment_v2(closest_edge_point, + point, + tile_edge.vertex_1.coordinate, + tile_edge.vertex_2.coordinate); + float distance_to_edge = blender::math::distance(closest_edge_point, point); + if (distance_to_edge < margin && distance_to_edge < pixel.distance) { + if (pixel.type != PixelType::SelectedForCloserExamination) { + selected_pixels.append(std::reference_wrapper(pixel)); + } + pixel.type = PixelType::SelectedForCloserExamination; + pixel.distance = distance_to_edge; + pixel.edge_index = tile_edge_index; + } + } + } + } + return selected_pixels; + } + + void pack_into(const Vector> &selected_pixels, + CopyPixelTile ©_tile) const + { + std::optional> last_group = std::nullopt; + std::optional last_command = std::nullopt; + + for (const Pixel &elem : selected_pixels) { + if (elem.type == PixelType::CopyFromClosestEdge) { + if (!last_command.has_value() || !last_command->can_be_extended(elem.copy_command)) { + CopyPixelGroup new_group = {elem.copy_command.destination - int2(1, 0), + elem.copy_command.source_1, + copy_tile.command_deltas.size(), + 0}; + copy_tile.groups.append(new_group); + last_group = copy_tile.groups.last(); + last_command = CopyPixelCommand(*last_group); + } + + DeltaCopyPixelCommand delta_command = last_command->encode_delta(elem.copy_command); + copy_tile.command_deltas.append(delta_command); + last_group->get().num_deltas++; + last_command = elem.copy_command; + } + } + } + +}; // namespace blender::bke::pbvh::pixels + +void BKE_pbvh_pixels_copy_update(PBVH &pbvh, + Image &image, + ImageUser &image_user, + const uv_islands::MeshData &mesh_data) +{ + PBVHData &pbvh_data = BKE_pbvh_pixels_data_get(pbvh); + pbvh_data.tiles_copy_pixels.clear(); + const NonManifoldUVEdges non_manifold_edges(mesh_data); + if (non_manifold_edges.is_empty()) { + /* Early exit: No non manifold edges detected. */ + return; + } + + ImageUser tile_user = image_user; + LISTBASE_FOREACH (ImageTile *, tile, &image.tiles) { + const image::ImageTileWrapper image_tile = image::ImageTileWrapper(tile); + tile_user.tile = image_tile.get_tile_number(); + + ImBuf *tile_buffer = BKE_image_acquire_ibuf(&image, &tile_user, nullptr); + if (tile_buffer == nullptr) { + continue; + } + const PixelNodesTileData nodes_tile_pixels(pbvh, image_tile); + + int2 tile_resolution(tile_buffer->x, tile_buffer->y); + BKE_image_release_ibuf(&image, tile_buffer, nullptr); + + NonManifoldTileEdges tile_edges = non_manifold_edges.extract_tile_edges(image_tile, + tile_resolution); + CopyPixelTile copy_tile(image_tile.get_tile_number()); + + Rows rows(tile_resolution, image.seam_margin); + rows.init_pixels(); + rows.mark_pixels_effected_by_brush(nodes_tile_pixels); + + Vector> selected_pixels = + rows.filter_pixels_for_closer_examination(tile_edges); + rows.find_copy_source(selected_pixels, tile_edges); + rows.pack_into(selected_pixels, copy_tile); + + copy_tile.print_compression_rate(); + pbvh_data.tiles_copy_pixels.tiles.append(copy_tile); + } +} + +void BKE_pbvh_pixels_copy_pixels(PBVH &pbvh, + Image &image, + ImageUser &image_user, + image::TileNumber tile_number) +{ + PBVHData &pbvh_data = BKE_pbvh_pixels_data_get(pbvh); + std::optional> pixel_tile = + pbvh_data.tiles_copy_pixels.find_tile(tile_number); + if (!pixel_tile.has_value()) { + /* No pixels need to be copied. */ + return; + } + + ImageUser tile_user = image_user; + tile_user.tile = tile_number; + ImBuf *tile_buffer = BKE_image_acquire_ibuf(&image, &tile_user, nullptr); + if (tile_buffer == nullptr) { + /* No tile buffer found to copy. */ + return; + } + + CopyPixelTile &tile = pixel_tile->get(); + threading::parallel_for(tile.groups.index_range(), THREADING_GRAIN_SIZE, [&](IndexRange range) { + tile.copy_pixels(*tile_buffer, range); + }); + + BKE_image_release_ibuf(&image, tile_buffer, nullptr); +} + +} // namespace blender::bke::pbvh::pixels diff --git a/source/blender/blenkernel/intern/pbvh_pixels_copy.hh b/source/blender/blenkernel/intern/pbvh_pixels_copy.hh new file mode 100644 index 00000000000..c235662663e --- /dev/null +++ b/source/blender/blenkernel/intern/pbvh_pixels_copy.hh @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2023 Blender Foundation. All rights reserved. */ + +#include "BLI_math.h" +#include "BLI_math_vector_types.hh" +#include "BLI_vector.hh" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "BKE_image_wrappers.hh" +#include "BKE_pbvh.h" +#include "BKE_pbvh_pixels.hh" + +#include "pbvh_uv_islands.hh" + +namespace blender::bke::pbvh::pixels { + +void BKE_pbvh_pixels_copy_update(PBVH &pbvh, + Image &image, + ImageUser &image_user, + const uv_islands::MeshData &mesh_data); + +} // namespace blender::bke::pbvh::pixels diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 2fee1f4f4d3..93457239348 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -65,7 +65,6 @@ static void pointcloud_init_data(ID *id) CustomData_add_layer_named(&pointcloud->pdata, CD_PROP_FLOAT3, CD_SET_DEFAULT, - nullptr, pointcloud->totpoint, POINTCLOUD_ATTR_POSITION); diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c index f89a44ee024..3499839e03d 100644 --- a/source/blender/blenkernel/intern/rigidbody.c +++ b/source/blender/blenkernel/intern/rigidbody.c @@ -2275,6 +2275,9 @@ void BKE_rigidbody_do_simulation(Depsgraph *depsgraph, Scene *scene, float ctime # if defined(__GNUC__) || defined(__clang__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-parameter" +# elif defined(_MSC_VER) +/* Suppress unreferenced formal parameter warning. */ +# pragma warning(disable : 4100) # endif void BKE_rigidbody_object_copy(Main *bmain, Object *ob_dst, const Object *ob_src, const int flag) diff --git a/source/blender/blenkernel/intern/scene.cc b/source/blender/blenkernel/intern/scene.cc index ccf62a6f899..b5f7d5b68c8 100644 --- a/source/blender/blenkernel/intern/scene.cc +++ b/source/blender/blenkernel/intern/scene.cc @@ -18,7 +18,7 @@ #include "DNA_collection_types.h" #include "DNA_curveprofile_types.h" #include "DNA_defaults.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_linestyle_types.h" #include "DNA_mask_types.h" #include "DNA_material_types.h" @@ -65,7 +65,7 @@ #include "BKE_effect.h" #include "BKE_fcurve.h" #include "BKE_freestyle.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 0f3eccb5bd0..50ac6418ab7 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -20,7 +20,7 @@ #include "DNA_collection_types.h" #include "DNA_defaults.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mask_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -38,7 +38,7 @@ #include "BLT_translation.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" diff --git a/source/blender/blenkernel/intern/shader_fx.c b/source/blender/blenkernel/intern/shader_fx.c index 745bd2a97e6..7b3377e3c6e 100644 --- a/source/blender/blenkernel/intern/shader_fx.c +++ b/source/blender/blenkernel/intern/shader_fx.c @@ -16,14 +16,14 @@ #include "BLT_translation.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_shader_fx_types.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_object.h" diff --git a/source/blender/blenkernel/intern/shrinkwrap.cc b/source/blender/blenkernel/intern/shrinkwrap.cc index 6b010418e11..2b3122f8865 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.cc +++ b/source/blender/blenkernel/intern/shrinkwrap.cc @@ -33,7 +33,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" /* for OMP limits. */ +#include "BKE_mesh.hh" /* for OMP limits. */ #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_subsurf.h" @@ -60,7 +60,7 @@ struct ShrinkwrapCalcData { Object *ob; /* object we are applying shrinkwrap to */ float (*vert_positions)[3]; /* Array of verts being projected. */ - const float (*vert_normals)[3]; + blender::Span vert_normals; /* Vertices being shrink-wrapped. */ float (*vertexCos)[3]; int numVerts; @@ -115,7 +115,9 @@ bool BKE_shrinkwrap_init_tree( data->mesh = mesh; data->polys = mesh->polys().data(); - data->vert_normals = BKE_mesh_vert_normals_ensure(mesh); + data->vert_normals = reinterpret_cast(mesh->vert_normals().data()), + data->sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_face")); if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) { data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2); @@ -134,7 +136,7 @@ bool BKE_shrinkwrap_init_tree( } if (force_normals || BKE_shrinkwrap_needs_normals(shrinkType, shrinkMode)) { - data->poly_normals = BKE_mesh_poly_normals_ensure(mesh); + data->poly_normals = reinterpret_cast(mesh->poly_normals().data()); if ((mesh->flag & ME_AUTOSMOOTH) != 0) { data->clnors = static_cast(CustomData_get_layer(&mesh->ldata, CD_NORMAL)); } @@ -295,7 +297,7 @@ static ShrinkwrapBoundaryData *shrinkwrap_build_boundary_data(Mesh *mesh) MEM_freeN(vert_status); /* Finalize average direction and compute normal. */ - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh); + const blender::Span vert_normals = mesh->vert_normals(); for (int i = 0; i < mesh->totvert; i++) { int bidx = vert_boundary_id[i]; @@ -1175,7 +1177,7 @@ void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree, const float(*vert_normals)[3] = tree->vert_normals; /* Interpolate smooth normals if enabled. */ - if ((tree->polys[tri->poly].flag & ME_SMOOTH) != 0) { + if (!(tree->sharp_faces && tree->sharp_faces[tri->poly])) { const uint32_t vert_indices[3] = {treeData->loop[tri->tri[0]].v, treeData->loop[tri->tri[1]].v, treeData->loop[tri->tri[2]].v}; @@ -1407,7 +1409,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, if (mesh != nullptr && smd->shrinkType == MOD_SHRINKWRAP_PROJECT) { /* Setup arrays to get vertex positions, normals and deform weights */ calc.vert_positions = BKE_mesh_vert_positions_for_write(mesh); - calc.vert_normals = BKE_mesh_vert_normals_ensure(mesh); + calc.vert_normals = mesh->vert_normals(); /* Using vertices positions/normals as if a subsurface was applied */ if (smd->subsurfLevels) { @@ -1568,7 +1570,7 @@ void BKE_shrinkwrap_remesh_target_project(Mesh *src_me, Mesh *target_me, Object calc.smd = &ssmd; calc.numVerts = src_me->totvert; calc.vertexCos = vertexCos; - calc.vert_normals = BKE_mesh_vert_normals_ensure(src_me); + calc.vert_normals = src_me->vert_normals(); calc.vgroup = -1; calc.target = target_me; calc.keepDist = ssmd.keepDist; diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 013574dae10..92beefcbc2d 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2759,7 +2759,8 @@ static void mesh_faces_to_scratch(Object *ob) sb->scratch->totface = poly_to_tri_count(me->totpoly, me->totloop); looptri = lt = MEM_mallocN(sizeof(*looptri) * sb->scratch->totface, __func__); - BKE_mesh_recalc_looptri(loops, polys, vert_positions, me->totloop, me->totpoly, looptri); + BKE_mesh_recalc_looptri( + loops, polys, vert_positions, me->totvert, me->totloop, me->totpoly, looptri); bodyface = sb->scratch->bodyface = MEM_mallocN(sizeof(BodyFace) * sb->scratch->totface, "SB_body_Faces"); diff --git a/source/blender/blenkernel/intern/studiolight.c b/source/blender/blenkernel/intern/studiolight.c index 39e5cf32a86..8b1174535fc 100644 --- a/source/blender/blenkernel/intern/studiolight.c +++ b/source/blender/blenkernel/intern/studiolight.c @@ -48,9 +48,9 @@ static int last_studiolight_id = 0; */ #define STUDIOLIGHT_LOAD_CACHED_FILES -static const char *STUDIOLIGHT_LIGHTS_FOLDER = "studiolights/studio/"; -static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights/world/"; -static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights/matcap/"; +static const char *STUDIOLIGHT_LIGHTS_FOLDER = "studiolights" SEP_STR "studio" SEP_STR; +static const char *STUDIOLIGHT_WORLD_FOLDER = "studiolights" SEP_STR "world" SEP_STR; +static const char *STUDIOLIGHT_MATCAP_FOLDER = "studiolights" SEP_STR "matcap" SEP_STR; static const char *STUDIOLIGHT_WORLD_DEFAULT = "forest.exr"; static const char *STUDIOLIGHT_MATCAP_DEFAULT = "basic_1.exr"; diff --git a/source/blender/blenkernel/intern/subdiv_ccg.cc b/source/blender/blenkernel/intern/subdiv_ccg.cc index 72225f7a364..a1b779d07e6 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.cc +++ b/source/blender/blenkernel/intern/subdiv_ccg.cc @@ -20,7 +20,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_ccg.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_subdiv.h" #include "BKE_subdiv_eval.h" diff --git a/source/blender/blenkernel/intern/subdiv_ccg_mask.cc b/source/blender/blenkernel/intern/subdiv_ccg_mask.cc index 68ad6a2d7f9..5d57378a870 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg_mask.cc +++ b/source/blender/blenkernel/intern/subdiv_ccg_mask.cc @@ -17,7 +17,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_subdiv.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/blenkernel/intern/subdiv_ccg_material.cc b/source/blender/blenkernel/intern/subdiv_ccg_material.cc index 9f03eca889f..a0e450d5697 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg_material.cc +++ b/source/blender/blenkernel/intern/subdiv_ccg_material.cc @@ -5,7 +5,7 @@ * \ingroup bke */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_subdiv_ccg.h" #include "MEM_guardedalloc.h" @@ -15,7 +15,7 @@ struct CCGMaterialFromMeshData { const Mesh *mesh; - blender::Span polys; + const bool *sharp_faces; const int *material_indices; }; @@ -24,9 +24,8 @@ static DMFlagMat subdiv_ccg_material_flags_eval( { CCGMaterialFromMeshData *data = (CCGMaterialFromMeshData *)material_flags_evaluator->user_data; BLI_assert(coarse_face_index < data->mesh->totpoly); - const MPoly &poly = data->polys[coarse_face_index]; DMFlagMat material_flags; - material_flags.flag = poly.flag; + material_flags.sharp = data->sharp_faces && data->sharp_faces[coarse_face_index]; material_flags.mat_nr = data->material_indices ? data->material_indices[coarse_face_index] : 0; return material_flags; } @@ -45,7 +44,8 @@ void BKE_subdiv_ccg_material_flags_init_from_mesh( data->mesh = mesh; data->material_indices = (const int *)CustomData_get_layer_named( &mesh->pdata, CD_PROP_INT32, "material_index"); - data->polys = mesh->polys(); + data->sharp_faces = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, "sharp_face"); material_flags_evaluator->eval_material_flags = subdiv_ccg_material_flags_eval; material_flags_evaluator->free = subdiv_ccg_material_flags_free; material_flags_evaluator->user_data = data; diff --git a/source/blender/blenkernel/intern/subdiv_converter_mesh.cc b/source/blender/blenkernel/intern/subdiv_converter_mesh.cc index aefa53cc04f..b28fe42b1c5 100644 --- a/source/blender/blenkernel/intern/subdiv_converter_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_converter_mesh.cc @@ -16,7 +16,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_subdiv.h" diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.cc b/source/blender/blenkernel/intern/subdiv_displacement_multires.cc index 59309541493..3cd73902d64 100644 --- a/source/blender/blenkernel/intern/subdiv_displacement_multires.cc +++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.cc @@ -18,7 +18,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_multires.h" #include "BKE_subdiv_eval.h" diff --git a/source/blender/blenkernel/intern/subdiv_eval.cc b/source/blender/blenkernel/intern/subdiv_eval.cc index e1e13b10f5c..8dac6807872 100644 --- a/source/blender/blenkernel/intern/subdiv_eval.cc +++ b/source/blender/blenkernel/intern/subdiv_eval.cc @@ -16,7 +16,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_subdiv.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/blenkernel/intern/subdiv_foreach.cc b/source/blender/blenkernel/intern/subdiv_foreach.cc index 3f9126f53e9..8231f0e7ca0 100644 --- a/source/blender/blenkernel/intern/subdiv_foreach.cc +++ b/source/blender/blenkernel/intern/subdiv_foreach.cc @@ -18,7 +18,7 @@ #include "BKE_customdata.h" #include "BKE_key.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_subdiv.h" #include "BKE_subdiv_mesh.hh" diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index 39e10fb03e6..5db8b815b33 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -21,7 +21,7 @@ #include "BKE_customdata.h" #include "BKE_key.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_subdiv.h" #include "BKE_subdiv_eval.h" diff --git a/source/blender/blenkernel/intern/subdiv_modifier.cc b/source/blender/blenkernel/intern/subdiv_modifier.cc index 60d55af215c..504dc8e5b29 100644 --- a/source/blender/blenkernel/intern/subdiv_modifier.cc +++ b/source/blender/blenkernel/intern/subdiv_modifier.cc @@ -11,7 +11,7 @@ #include "DNA_scene_types.h" #include "DNA_userdef_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_subdiv.h" diff --git a/source/blender/blenkernel/intern/subsurf_ccg.cc b/source/blender/blenkernel/intern/subsurf_ccg.cc index cbe26721cc9..3bdf8a27136 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.cc +++ b/source/blender/blenkernel/intern/subsurf_ccg.cc @@ -33,7 +33,7 @@ #include "BKE_ccg.h" #include "BKE_cdderivedmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -1068,20 +1068,17 @@ static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *polys) int gridSize = ccgSubSurf_getGridSize(ss); /* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */ int i = 0, k = 0; - DMFlagMat *faceFlags = ccgdm->faceFlags; totface = ccgSubSurf_getNumFaces(ss); for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - char flag = (faceFlags) ? faceFlags[index].flag : char(ME_SMOOTH); for (S = 0; S < numVerts; S++) { for (y = 0; y < gridSize - 1; y++) { for (x = 0; x < gridSize - 1; x++) { polys[i].loopstart = k; polys[i].totloop = 4; - polys[i].flag = flag; k += 4; i++; @@ -1183,8 +1180,8 @@ static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type) BLI_rw_mutex_lock(&ccgdm->origindex_cache_rwlock, THREAD_LOCK_WRITE); - origindex = static_cast(CustomData_add_layer( - &dm->vertData, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, dm->numVertData)); + origindex = static_cast( + CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_SET_DEFAULT, dm->numVertData)); totorig = ccgSubSurf_getNumVerts(ss); totnone = dm->numVertData - totorig; @@ -1222,8 +1219,8 @@ static void *ccgDM_get_edge_data_layer(DerivedMesh *dm, int type) return origindex; } - origindex = static_cast(CustomData_add_layer( - &dm->edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, dm->numEdgeData)); + origindex = static_cast( + CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_SET_DEFAULT, dm->numEdgeData)); totedge = ccgSubSurf_getNumEdges(ss); totorig = totedge * (edgeSize - 1); @@ -1265,8 +1262,8 @@ static void *ccgDM_get_poly_data_layer(DerivedMesh *dm, int type) return origindex; } - origindex = static_cast(CustomData_add_layer( - &dm->polyData, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, dm->numPolyData)); + origindex = static_cast( + CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_SET_DEFAULT, dm->numPolyData)); totface = ccgSubSurf_getNumFaces(ss); @@ -1541,9 +1538,11 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, gridSideEdges = gridSize - 1; gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; - const MPoly *polys = static_cast(CustomData_get_layer(&dm->polyData, CD_MPOLY)); const int *material_indices = static_cast( CustomData_get_layer_named(&dm->polyData, CD_MPOLY, "material_index")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")); + const int *base_polyOrigIndex = static_cast( CustomData_get_layer(&dm->polyData, CD_ORIGINDEX)); @@ -1569,7 +1568,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, ccgdm->faceMap[index].startEdge = edgeNum; ccgdm->faceMap[index].startFace = faceNum; - faceFlags->flag = polys ? polys[origIndex].flag : 0; + faceFlags->sharp = sharp_faces ? sharp_faces[origIndex] : false; faceFlags->mat_nr = material_indices ? material_indices[origIndex] : 0; faceFlags++; diff --git a/source/blender/blenkernel/intern/tracking.cc b/source/blender/blenkernel/intern/tracking.cc index 6322d2ebc25..0213408eec3 100644 --- a/source/blender/blenkernel/intern/tracking.cc +++ b/source/blender/blenkernel/intern/tracking.cc @@ -15,7 +15,7 @@ #include "DNA_anim_types.h" #include "DNA_camera_types.h" #include "DNA_defaults.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_movieclip_types.h" #include "DNA_object_types.h" /* SELECT */ #include "DNA_scene_types.h" diff --git a/source/blender/blenkernel/intern/tracking_detect.cc b/source/blender/blenkernel/intern/tracking_detect.cc index 259de78c551..f08c9745d2e 100644 --- a/source/blender/blenkernel/intern/tracking_detect.cc +++ b/source/blender/blenkernel/intern/tracking_detect.cc @@ -7,7 +7,7 @@ * This file contains blender-side implementation of feature detection. */ -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_movieclip_types.h" #include "DNA_object_types.h" /* SELECT */ diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc index 1aeedcd04c1..9c64277525c 100644 --- a/source/blender/blenkernel/intern/volume_to_mesh.cc +++ b/source/blender/blenkernel/intern/volume_to_mesh.cc @@ -10,7 +10,7 @@ #include "DNA_meshdata_types.h" #include "DNA_volume_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_volume.h" #ifdef WITH_OPENVDB @@ -180,6 +180,7 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid, mesh->loops_for_write()); BKE_mesh_calc_edges(mesh, false, false); + BKE_mesh_smooth_flag_set(mesh, false); return mesh; } diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c index 1b37bf7db5a..ffafd926785 100644 --- a/source/blender/blenkernel/intern/writeffmpeg.c +++ b/source/blender/blenkernel/intern/writeffmpeg.c @@ -586,7 +586,7 @@ static const AVCodec *get_av1_encoder( } else { /* Is not a square num, set greater side based on longer side, or use a square if both - sides are equal. */ + * sides are equal. */ int sqrt_p2 = power_of_2_min_i(threads_sqrt); if (sqrt_p2 < 2) { /* Ensure a default minimum. */ diff --git a/source/blender/blenlib/BLI_math_angle_types.hh b/source/blender/blenlib/BLI_math_angle_types.hh new file mode 100644 index 00000000000..a46fc43a1a0 --- /dev/null +++ b/source/blender/blenlib/BLI_math_angle_types.hh @@ -0,0 +1,745 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + * + * Classes to represent rotation angles. They can be used as 2D rotation or as building blocks for + * other rotation types. + * + * Each `blender::math::Angle***` implements the same interface and can be swapped easily. + * However, they differ in each operation's efficiency, storage size and the range or group of + * angles that can be stored. + * + * This design allows some function overloads to be more efficient with certain types. + */ + +#include "BLI_math_base.hh" + +namespace blender::math { + +/** + * A `blender::math::AngleRadianBase` is a typical radian angle. + * - Storage : `1 * sizeof(T)` + * - Range : [-inf..inf] + * - Fast : Everything not slow. + * - Slow : `cos()`, `sin()`, `tan()`, `AngleRadian(cos, sin)` + */ +template struct AngleRadianBase { + private: + T value_; + + public: + AngleRadianBase() = default; + + AngleRadianBase(const T &radian) : value_(radian){}; + explicit AngleRadianBase(const T &cos, const T &sin) : value_(math::atan2(sin, cos)){}; + + /** Static functions. */ + + static AngleRadianBase identity() + { + return 0; + } + + static AngleRadianBase from_degree(const T °rees) + { + return degrees * T(M_PI / 180.0); + } + + /** Conversions. */ + + /* Return angle value in radian. */ + explicit operator T() const + { + return value_; + } + + /* Return angle value in degree. */ + T degree() const + { + return value_ * T(180.0 / M_PI); + } + + /* Return angle value in radian. */ + T radian() const + { + return value_; + } + + /** Methods. */ + + /* 'mod_inline(-3, 4)= 1', 'fmod(-3, 4)= -3' */ + static float mod_inline(float a, float b) + { + return a - (b * floorf(a / b)); + } + + /** + * Return the angle wrapped inside [-pi..pi] interval. Basically `(angle + pi) % 2pi - pi`. + */ + AngleRadianBase wrapped() const + { + return math::mod_periodic(value_ + T(M_PI), T(2 * M_PI)) - T(M_PI); + } + + /** + * Return the angle wrapped inside [-pi..pi] interval around a \a reference . + * Basically `(angle - reference + pi) % 2pi - pi + reference` . + * This means the interpolation between the returned value and \a reference will always take the + * shortest path. + */ + AngleRadianBase wrapped_around(const AngleRadianBase &reference) const + { + return reference + (*this - reference).wrapped(); + } + + /** Operators. */ + + friend AngleRadianBase operator+(const AngleRadianBase &a, const AngleRadianBase &b) + { + return a.value_ + b.value_; + } + + friend AngleRadianBase operator-(const AngleRadianBase &a, const AngleRadianBase &b) + { + return a.value_ - b.value_; + } + + friend AngleRadianBase operator*(const AngleRadianBase &a, const AngleRadianBase &b) + { + return a.value_ * b.value_; + } + + friend AngleRadianBase operator/(const AngleRadianBase &a, const AngleRadianBase &b) + { + return a.value_ / b.value_; + } + + friend AngleRadianBase operator-(const AngleRadianBase &a) + { + return -a.value_; + } + + AngleRadianBase &operator+=(const AngleRadianBase &b) + { + value_ += b.value_; + return *this; + } + + AngleRadianBase &operator-=(const AngleRadianBase &b) + { + value_ -= b.value_; + return *this; + } + + AngleRadianBase &operator*=(const AngleRadianBase &b) + { + value_ *= b.value_; + return *this; + } + + AngleRadianBase &operator/=(const AngleRadianBase &b) + { + value_ /= b.value_; + return *this; + } + + friend bool operator==(const AngleRadianBase &a, const AngleRadianBase &b) + { + return a.value_ == b.value_; + } + + friend bool operator!=(const AngleRadianBase &a, const AngleRadianBase &b) + { + return !(a == b); + } + + friend std::ostream &operator<<(std::ostream &stream, const AngleRadianBase &rot) + { + return stream << "AngleRadian(" << rot.value_ << ")"; + } +}; + +/** + * A `blender::math::AngleCartesianBase` stores the angle as cosine + sine tuple. + * - Storage : `2 * sizeof(T)` + * - Range : [-pi..pi] + * - Fast : `cos()`, `sin()`, `tan()`, `AngleCartesian(cos, sin)` + * - Slow : Everything not fast. + * It is only useful for intermediate representation when converting to other rotation types (eg: + * AxisAngle > Quaternion) and for creating rotations from 2D points. In general it offers an + * advantage when trigonometric values of an angle are required but not directly the angle itself. + * It is also a nice shortcut for using the trigonometric identities. + */ +template struct AngleCartesianBase { + private: + T cos_; + T sin_; + + public: + AngleCartesianBase() = default; + + /** + * Create an angle from a (x, y) position on the unit circle. + */ + AngleCartesianBase(const T &x, const T &y) : cos_(x), sin_(y) + { + BLI_assert(math::abs(x * x + y * y - T(1)) < T(1e-4)); + } + + /** + * Create an angle from a radian value. + */ + explicit AngleCartesianBase(const T &radian) + : AngleCartesianBase(math::cos(radian), math::sin(radian)){}; + explicit AngleCartesianBase(const AngleRadianBase &angle) + : AngleCartesianBase(math::cos(angle.radian()), math::sin(angle.radian())){}; + + /** Static functions. */ + + static AngleCartesianBase identity() + { + return {1, 0}; + } + + static AngleCartesianBase from_degree(const T °rees) + { + return AngleCartesianBase(degrees * T(M_PI / 180.0)); + } + + /** + * Create an angle from a (x, y) position on the 2D plane. + * Fallback to identity if (x, y) is origin (0, 0). + */ + static AngleCartesianBase from_point(const T &x, const T &y) + { + T norm = math::sqrt(x * x + y * y); + if (norm == 0) { + return identity(); + } + return AngleCartesianBase(x / norm, y / norm); + } + + /** Conversions. */ + + /* Return angle value in radian. */ + explicit operator T() const + { + return math::atan2(sin_, cos_); + } + + /* Return angle value in degree. */ + T degree() const + { + return T(*this) * T(180.0 / M_PI); + } + + /* Return angle value in radian. */ + T radian() const + { + return T(*this); + } + + /** Methods. */ + + T cos() const + { + return cos_; + } + + T sin() const + { + return sin_; + } + + T tan() const + { + return sin_ / cos_; + } + + /** Operators. */ + + /** + * NOTE: These use the trigonometric identities: + * https://en.wikipedia.org/wiki/List_of_trigonometric_identities + * (see Angle_sum_and_difference_identities, Multiple-angle_formulae and Half-angle_formulae) + * + * There are no identities for (arbitrary) product or quotient of angles. + * Better leave these unimplemented to avoid accidentally using `atan` everywhere (which is the + * purpose of this class). + */ + + friend AngleCartesianBase operator+(const AngleCartesianBase &a, const AngleCartesianBase &b) + { + return {a.cos_ * b.cos_ - a.sin_ * b.sin_, a.sin_ * b.cos_ + a.cos_ * b.sin_}; + } + + friend AngleCartesianBase operator-(const AngleCartesianBase &a, const AngleCartesianBase &b) + { + return {a.cos_ * b.cos_ + a.sin_ * b.sin_, a.sin_ * b.cos_ - a.cos_ * b.sin_}; + } + + friend AngleCartesianBase operator*(const AngleCartesianBase &a, const T &b) + { + if (b == T(2)) { + return {a.cos_ * a.cos_ - a.sin_ * a.sin_, T(2) * a.sin_ * a.cos_}; + } + if (b == T(3)) { + return {T(4) * (a.cos_ * a.cos_ * a.cos_) - T(3) * a.cos_, + T(3) * a.sin_ - T(4) * (a.sin_ * a.sin_ * a.sin_)}; + } + BLI_assert_msg(0, + "Arbitrary angle product isn't supported with AngleCartesianBase for " + "performance reason. Use AngleRadianBase instead."); + return identity(); + } + + friend AngleCartesianBase operator*(const T &b, const AngleCartesianBase &a) + { + return a * b; + } + + friend AngleCartesianBase operator/(const AngleCartesianBase &a, const T &divisor) + { + if (divisor == T(2)) { + /* Still costly but faster than using `atan()`. */ + AngleCartesianBase result = {math::sqrt((T(1) + a.cos_) / T(2)), + math::sqrt((T(1) - a.cos_) / T(2))}; + /* Recover sign only for sine. Cosine of half angle is given to be positive or 0 since the + * angle stored in #AngleCartesianBase is in the range [-pi..pi]. */ + /* TODO(fclem): Could use `copysign` here. */ + if (a.sin_ < T(0)) { + result.sin_ = -result.sin_; + } + return result; + } + BLI_assert_msg(0, + "Arbitrary angle quotient isn't supported with AngleCartesianBase for " + "performance reason. Use AngleRadianBase instead."); + return identity(); + } + + friend AngleCartesianBase operator-(const AngleCartesianBase &a) + { + return {a.cos_, -a.sin_}; + } + + AngleCartesianBase &operator+=(const AngleCartesianBase &b) + { + *this = *this + b; + return *this; + } + + AngleCartesianBase &operator*=(const T &b) + { + *this = *this * b; + return *this; + } + + AngleCartesianBase &operator-=(const AngleCartesianBase &b) + { + *this = *this - b; + return *this; + } + + AngleCartesianBase &operator/=(const T &b) + { + *this = *this / b; + return *this; + } + + friend bool operator==(const AngleCartesianBase &a, const AngleCartesianBase &b) + { + return a.cos_ == b.cos_ && a.sin_ == b.sin_; + } + + friend bool operator!=(const AngleCartesianBase &a, const AngleCartesianBase &b) + { + return !(a == b); + } + + friend std::ostream &operator<<(std::ostream &stream, const AngleCartesianBase &rot) + { + return stream << "AngleCartesian(x=" << rot.cos_ << ", y=" << rot.sin_ << ")"; + } +}; + +/** + * A `blender::math::AngleFraction` stores a radian angle as quotient. + * - Storage : `2 * sizeof(int64_t)` + * - Range : [-INT64_MAX..INT64_MAX] but angle must be expressed as fraction (be in Q subset). + * - Fast : Everything not slow. + * - Slow : `cos()`, `sin()`, `tan()` for angles not optimized. + * + * It offers the best accuracy for fractions of Pi radian angles. For instance + * `sin(AngleFraction::tau() * n - AngleFraction::pi() / 2)` will exactly return `-1` for any `n` + * within [-INT_MAX..INT_MAX]. This holds true even with very high radian values. + * + * Arithmetic operators are relatively cheap (4 operations for addition, 2 for multiplication) but + * not as cheap as a `AngleRadian`. Another nice property is that the `cos()` and `sin()` functions + * give symmetric results around the circle. + * + * NOTE: Prefer converting to `blender::math::AngleCartesianBase` if both `cos()` and `sin()` + * are needed. This will save some computation. + * + * Any operation becomes undefined if either the numerator or the denominator overflows. + * + * The `T` template parameter only serves as type for the computed values like `cos()` or + * `radian()`. + */ +template struct AngleFraction { + private: + /** + * The angle is stored as a fraction of pi. + */ + int64_t numerator_; + int64_t denominator_; + + /** + * Constructor is left private as we do not want the user of this class to create invalid + * fractions. + */ + AngleFraction(int64_t numerator, int64_t denominator = 1) + : numerator_(numerator), denominator_(denominator){}; + + public: + /** Static functions. */ + + static AngleFraction identity() + { + return {0}; + } + + static AngleFraction pi() + { + return {1}; + } + + static AngleFraction tau() + { + return {2}; + } + + /** Conversions. */ + + /* Return angle value in degree. */ + T degree() const + { + return T(numerator_ * 180) / T(denominator_); + } + + /* Return angle value in radian. */ + T radian() const + { + /* This can be refined at will. This tries to reduce the float precision error to a minimum. */ + const bool is_negative = numerator_ < 0; + /* TODO jump table. */ + if (abs(numerator_) == denominator_ * 2) { + return is_negative ? T(-M_PI * 2) : T(M_PI * 2); + } + if (abs(numerator_) == denominator_) { + return is_negative ? T(-M_PI) : T(M_PI); + } + if (numerator_ == 0) { + return T(0); + } + if (abs(numerator_) * 2 == denominator_) { + return is_negative ? T(-M_PI_2) : T(M_PI_2); + } + if (abs(numerator_) * 4 == denominator_) { + return is_negative ? T(-M_PI_4) : T(M_PI_4); + } + /* TODO(fclem): No idea if this is precise or not. Just doing something for now. */ + const int64_t number_of_pi = numerator_ / denominator_; + const int64_t slice_numerator = numerator_ - number_of_pi * denominator_; + T slice_of_pi; + /* Avoid integer overflow. */ + /* TODO(fclem): This is conservative. Could find a better threshold. */ + if (slice_numerator > 0xFFFFFFFF || denominator_ > 0xFFFFFFFF) { + /* Certainly loose precision. */ + slice_of_pi = T(M_PI) * slice_numerator / T(denominator_); + } + else { + /* Pi as a fraction can be expressed as 80143857 / 25510582 with 15th digit of precision. */ + slice_of_pi = T(slice_numerator * 80143857) / T(denominator_ * 25510582); + } + /* If angle is inside [-pi..pi] range, `number_of_pi` is 0 and has no effect on precision. */ + return slice_of_pi + T(M_PI) * number_of_pi; + } + + /** Methods. */ + + /** + * Return the angle wrapped inside [-pi..pi] interval. Basically `(angle + pi) % 2pi - pi`. + */ + AngleFraction wrapped() const + { + if (abs(numerator_) <= denominator_) { + return *this; + } + return {mod_periodic(numerator_ + denominator_, denominator_ * 2) - denominator_, + denominator_}; + } + + /** + * Return the angle wrapped inside [-pi..pi] interval around a \a reference . + * Basically `(angle - reference + pi) % 2pi - pi + reference` . + * This means the interpolation between the returned value and \a reference will always take the + * shortest path. + */ + AngleFraction wrapped_around(const AngleFraction &reference) const + { + return reference + (*this - reference).wrapped(); + } + + /** Operators. */ + + /** + * We only allow operations on fractions of pi. + * So we cannot implement things like `AngleFraction::pi() + 1` or `AngleFraction::pi() * 0.5`. + */ + + friend AngleFraction operator+(const AngleFraction &a, const AngleFraction &b) + { + if (a.denominator_ == b.denominator_) { + return {a.numerator_ + b.numerator_, a.denominator_}; + } + return {(a.numerator_ * b.denominator_) + (b.numerator_ * a.denominator_), + a.denominator_ * b.denominator_}; + } + + friend AngleFraction operator-(const AngleFraction &a, const AngleFraction &b) + { + return a + (-b); + } + + friend AngleFraction operator*(const AngleFraction &a, const AngleFraction &b) + { + return {a.numerator_ * b.numerator_, a.denominator_ * b.denominator_}; + } + + friend AngleFraction operator/(const AngleFraction &a, const AngleFraction &b) + { + return a * AngleFraction(b.denominator_, b.numerator_); + } + + friend AngleFraction operator*(const AngleFraction &a, const int64_t &b) + { + return a * AngleFraction(b); + } + + friend AngleFraction operator/(const AngleFraction &a, const int64_t &b) + { + return a / AngleFraction(b); + } + + friend AngleFraction operator*(const int64_t &a, const AngleFraction &b) + { + return AngleFraction(a) * b; + } + + friend AngleFraction operator/(const int64_t &a, const AngleFraction &b) + { + return AngleFraction(a) / b; + } + + friend AngleFraction operator+(const AngleFraction &a) + { + return a; + } + + friend AngleFraction operator-(const AngleFraction &a) + { + return {-a.numerator_, a.denominator_}; + } + + AngleFraction &operator+=(const AngleFraction &b) + { + return *this = *this + b; + } + + AngleFraction &operator-=(const AngleFraction &b) + { + return *this = *this - b; + } + + AngleFraction &operator*=(const AngleFraction &b) + { + return *this = *this * b; + } + + AngleFraction &operator/=(const AngleFraction &b) + { + return *this = *this / b; + } + + AngleFraction &operator*=(const int64_t &b) + { + return *this = *this * b; + } + + AngleFraction &operator/=(const int64_t &b) + { + return *this = *this / b; + } + + friend bool operator==(const AngleFraction &a, const AngleFraction &b) + { + if (a.numerator_ == 0 && b.numerator_ == 0) { + return true; + } + if (a.denominator_ == b.denominator_) { + return a.numerator_ == b.numerator_; + } + return a.numerator_ * b.denominator_ == b.numerator_ * a.denominator_; + } + + friend bool operator!=(const AngleFraction &a, const AngleFraction &b) + { + return !(a == b); + } + + friend std::ostream &operator<<(std::ostream &stream, const AngleFraction &rot) + { + return stream << "AngleFraction(num=" << rot.numerator_ << ", denom=" << rot.denominator_ + << ")"; + } + + operator AngleCartesianBase() const + { + AngleFraction a = this->wrapped(); + BLI_assert(abs(a.numerator_) <= a.denominator_); + BLI_assert(a.denominator_ > 0); + + /* By default, creating a circle from an integer: calling #sinf & #cosf on the fraction + * doesn't create symmetrical values (because floats can't represent Pi exactly). Resolve this + * when the rotation is calculated from a fraction by mapping the `numerator` to lower values + * so X/Y values for points around a circle are exactly symmetrical, see #87779. + * + * Multiply both the `numerator` and `denominator` by 4 to ensure we can divide the circle + * into 8 octants. For each octant, we then use symmetry and negation to bring the `numerator` + * closer to the origin where precision is highest. + */ + /* Save negative sign so we cane assume unsigned angle for the rest of the computation.. */ + const bool is_negative = a.numerator_ < 0; + /* Multiply numerator the same as denominator. */ + a.numerator_ = abs(a.numerator_) * 4; + /* Determine the octant. */ + const int64_t octant = a.numerator_ / a.denominator_; + const int64_t rest = a.numerator_ - octant * a.denominator_; + /* Ensure denominator is a multiple of 4. */ + a.denominator_ *= 4; + + /* TODO jump table. */ + T x, y; + /* If rest is 0, the angle is an angle with precise value. */ + if (rest == 0) { + switch (octant) { + case 0: + case 4: + x = T(1); + y = T(0); + break; + case 2: + x = T(0); + y = T(1); + break; + case 1: + case 3: + x = y = T(M_SQRT1_2); + break; + default: + BLI_assert_unreachable(); + } + } + else { + switch (octant) { + case 4: + /* -Pi or Pi case. */ + case 0: + /* Primary octant, nothing to do. */ + break; + case 1: + /* Pi / 2 - angle. */ + a.numerator_ = a.denominator_ / 2 - a.numerator_; + break; + case 2: + /* Angle - Pi / 2. */ + a.numerator_ = a.numerator_ - a.denominator_ / 2; + break; + case 3: + /* Pi - angle. */ + a.numerator_ = a.denominator_ - a.numerator_; + break; + default: + BLI_assert_unreachable(); + } + /* Resulting angle should be oscillating in [0..pi/4] range. */ + BLI_assert(a.numerator_ >= 0 && a.numerator_ <= a.denominator_ / 4); + T angle = T(M_PI) * (T(a.numerator_) / T(a.denominator_)); + x = math::cos(angle); + y = math::sin(angle); + /* Diagonal symmetry "unfolding". */ + if (ELEM(octant, 1, 2)) { + std::swap(x, y); + } + } + /* Y axis symmetry. */ + if (octant >= 2) { + x = -x; + } + /* X axis symmetry. */ + if (is_negative) { + y = -y; + } + return AngleCartesianBase(x, y); + } +}; + +template T cos(const AngleRadianBase &a) +{ + return cos(a.radian()); +} +template T sin(const AngleRadianBase &a) +{ + return sin(a.radian()); +} +template T tan(const AngleRadianBase &a) +{ + return tan(a.radian()); +} + +template T cos(const AngleCartesianBase &a) +{ + return a.cos(); +} +template T sin(const AngleCartesianBase &a) +{ + return a.sin(); +} +template T tan(const AngleCartesianBase &a) +{ + return a.tan(); +} + +template T cos(const AngleFraction &a) +{ + return cos(AngleCartesianBase(a)); +} +template T sin(const AngleFraction &a) +{ + return sin(AngleCartesianBase(a)); +} +template T tan(const AngleFraction &a) +{ + return tan(AngleCartesianBase(a)); +} + +using AngleRadian = AngleRadianBase; +using AngleCartesian = AngleCartesianBase; + +} // namespace blender::math + +/** \} */ diff --git a/source/blender/blenlib/BLI_math_axis_angle.hh b/source/blender/blenlib/BLI_math_axis_angle.hh new file mode 100644 index 00000000000..d37d9da5d81 --- /dev/null +++ b/source/blender/blenlib/BLI_math_axis_angle.hh @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + */ + +#include "BLI_math_axis_angle_types.hh" +#include "BLI_math_euler_types.hh" +#include "BLI_math_quaternion_types.hh" + +#include "BLI_math_matrix.hh" +#include "BLI_math_quaternion.hh" + +namespace blender::math { + +/* -------------------------------------------------------------------- */ +/** \name Constructors + * \{ */ + +template +AxisAngleBase::AxisAngleBase(const VecBase &axis, const AngleT &angle) +{ + BLI_assert(is_unit_scale(axis)); + axis_ = axis; + angle_ = angle; +} + +template +AxisAngleBase::AxisAngleBase(const AxisSigned axis, const AngleT &angle) +{ + axis_ = to_vector>(axis); + angle_ = angle; +} + +template +AxisAngleBase::AxisAngleBase(const VecBase &from, const VecBase &to) +{ + BLI_assert(is_unit_scale(from)); + BLI_assert(is_unit_scale(to)); + + T sin; + T cos = dot(from, to); + axis_ = normalize_and_get_length(cross(from, to), sin); + + if (sin <= FLT_EPSILON) { + if (cos > T(0)) { + /* Same vectors, zero rotation... */ + *this = identity(); + return; + } + /* Colinear but opposed vectors, 180 rotation... */ + axis_ = normalize(orthogonal(from)); + sin = T(0); + cos = T(-1); + } + /* Avoid calculating the angle if possible. */ + angle_ = AngleT(cos, sin); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversion to Quaternions + * \{ */ + +template +QuaternionBase to_quaternion(const AxisAngleBase &axis_angle) +{ + BLI_assert(math::is_unit_scale(axis_angle.axis())); + + AngleT half_angle = axis_angle.angle() / 2; + T hs = math::sin(half_angle); + T hc = math::cos(half_angle); + + VecBase xyz = axis_angle.axis() * hs; + return QuaternionBase(hc, xyz.x, xyz.y, xyz.z); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversion to Euler + * \{ */ + +template +Euler3Base to_euler(const AxisAngleBase &axis_angle, EulerOrder order) +{ + /* Use quaternions as intermediate representation for now... */ + return to_euler(to_quaternion(axis_angle), order); +} + +template +EulerXYZBase to_euler(const AxisAngleBase &axis_angle) +{ + /* Check easy and exact conversions first. */ + const VecBase axis = axis_angle.axis(); + if (axis.x == T(1)) { + return EulerXYZBase(T(axis_angle.angle()), T(0), T(0)); + } + else if (axis.y == T(1)) { + return EulerXYZBase(T(0), T(axis_angle.angle()), T(0)); + } + else if (axis.z == T(1)) { + return EulerXYZBase(T(0), T(0), T(axis_angle.angle())); + } + /* Use quaternions as intermediate representation for now... */ + return to_euler(to_quaternion(axis_angle)); +} + +/** \} */ + +} // namespace blender::math diff --git a/source/blender/blenlib/BLI_math_axis_angle_types.hh b/source/blender/blenlib/BLI_math_axis_angle_types.hh new file mode 100644 index 00000000000..68423ac48d1 --- /dev/null +++ b/source/blender/blenlib/BLI_math_axis_angle_types.hh @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + * + * A `blender::math::AxisAngle` represents a rotation around a unit axis. + * + * It is mainly useful for rotating a point around a given axis or quickly getting the rotation + * between 2 vectors. It is cheaper to create than a #Quaternion or a matrix rotation. + * + * If the rotation axis is one of the basis axes (eg: {1,0,0}), then most operations are reduced to + * 2D operations and are thus faster. + * + * Interpolation isn't possible between two `blender::math::AxisAngle`; they must be + * converted to other rotation types for that. Converting to `blender::math::QuaternionBase` is + * the fastest and more correct option. + */ + +#include "BLI_math_angle_types.hh" +#include "BLI_math_base.hh" +#include "BLI_math_basis_types.hh" +#include "BLI_math_vector_types.hh" + +namespace blender::math { + +template struct AxisAngleBase { + using vec3_type = VecBase; + + private: + /** Normalized direction around which we rotate anti-clockwise. */ + vec3_type axis_ = {0, 1, 0}; + AngleT angle_ = AngleT::identity(); + + public: + AxisAngleBase() = default; + + /** + * Create a rotation from a basis axis and an angle. + */ + AxisAngleBase(const AxisSigned axis, const AngleT &angle); + + /** + * Create a rotation from an axis and an angle. + * \note `axis` have to be normalized. + */ + AxisAngleBase(const vec3_type &axis, const AngleT &angle); + + /** + * Create a rotation from 2 normalized vectors. + * \note `from` and `to` must be normalized. + * \note Consider using `AxisAngleCartesian` for faster conversion to other rotation. + */ + AxisAngleBase(const vec3_type &from, const vec3_type &to); + + /** Static functions. */ + + static AxisAngleBase identity() + { + return {}; + } + + /** Methods. */ + + const vec3_type &axis() const + { + return axis_; + } + + const AngleT &angle() const + { + return angle_; + } + + /** Operators. */ + + friend bool operator==(const AxisAngleBase &a, const AxisAngleBase &b) + { + return (a.axis() == b.axis()) && (a.angle() == b.angle()); + } + + friend bool operator!=(const AxisAngleBase &a, const AxisAngleBase &b) + { + return (a != b); + } + + friend std::ostream &operator<<(std::ostream &stream, const AxisAngleBase &rot) + { + return stream << "AxisAngle(axis=" << rot.axis() << ", angle=" << rot.angle() << ")"; + } +}; + +using AxisAngle = AxisAngleBase>; +using AxisAngleCartesian = AxisAngleBase>; + +} // namespace blender::math + +/** \} */ diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh index fdee18840ce..87280eead3a 100644 --- a/source/blender/blenlib/BLI_math_base.hh +++ b/source/blender/blenlib/BLI_math_base.hh @@ -90,6 +90,22 @@ template inline T floor(const T &a) return std::floor(a); } +/** + * Repeats the saw-tooth pattern even on negative numbers. + * ex: `mod_periodic(-3, 4) = 1`, `mod(-3, 4)= -3` + */ +template inline T mod_periodic(const T &a, const T &b) +{ + return a - (b * math::floor(a / b)); +} +template<> inline int64_t mod_periodic(const int64_t &a, const int64_t &b) +{ + int64_t c = (a >= 0) ? a : (-1 - a); + int64_t tmp = c - (b * (c / b)); + /* Negative integers have different rounding that do not match floor(). */ + return (a >= 0) ? tmp : (b - 1 - tmp); +} + template inline T ceil(const T &a) { return std::ceil(a); @@ -130,6 +146,22 @@ template inline T acos(const T &a) return std::acos(a); } +template inline T pow(const T &x, const T &power) +{ + return std::pow(x, power); +} + +template inline T safe_acos(const T &a) +{ + if (UNLIKELY(a <= T(-1))) { + return T(M_PI); + } + else if (UNLIKELY(a >= T(1))) { + return T(0); + } + return math::acos((a)); +} + template inline T asin(const T &a) { return std::asin(a); diff --git a/source/blender/blenlib/BLI_math_basis_types.hh b/source/blender/blenlib/BLI_math_basis_types.hh new file mode 100644 index 00000000000..94732c0266f --- /dev/null +++ b/source/blender/blenlib/BLI_math_basis_types.hh @@ -0,0 +1,473 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + * + * Orthonormal rotation and orientation. + * + * A practical reminder: + * - Forward is typically the positive Y direction in Blender. + * - Up is typically the positive Z direction in Blender. + * - Right is typically the positive X direction in Blender. + * - Blender uses right handedness. + * - For cross product, forward = thumb, up = index, right = middle finger. + * + * The basis changes for each space: + * - Object: X-right, Y-forward, Z-up + * - World: X-right, Y-forward, Z-up + * - Armature Bone: X-right, Y-forward, Z-up (with forward being the root to tip direction) + * - Curve Tangent-Space: X-left, Y-up, Z-forward + */ + +#include "BLI_math_base.hh" +#include "BLI_math_vector_types.hh" + +namespace blender::math { + +/* -------------------------------------------------------------------- */ +/** \name Axes + * \{ */ + +/** + * An enum class representing one of the 3 basis axes. + * This is implemented using a class to allow operators and methods. + * NOTE: While this represents a 3D axis it can still be used to generate 2D basis vectors. + */ +class Axis { + public: + enum class Value : int8_t { + /* Must start at 0. Used as indices in tables and vectors. */ + X = 0, + Y, + Z, + }; + + constexpr static Value X = Value::X; + constexpr static Value Y = Value::Y; + constexpr static Value Z = Value::Z; + + private: + Value axis_; + + public: + Axis() = default; + + constexpr Axis(const Value axis) : axis_(axis){}; + + /** Convert an uppercase axis character 'X', 'Y' or 'Z' to an enum value. */ + constexpr explicit Axis(char axis_char) : axis_(static_cast(axis_char - 'X')) + { + BLI_assert(Value::X <= axis_ && axis_ <= Value::Z); + } + + /** Allow casting from DNA enums stored as short / int. */ + constexpr static Axis from_int(const int axis_int) + { + const Axis axis = static_cast(axis_int); + BLI_assert(Axis::X <= axis && axis <= Axis::Z); + return axis; + } + + /* Allow usage in `switch()` statements and comparisons. */ + constexpr operator Value() const + { + return axis_; + } + + constexpr int as_int() const + { + return int(axis_); + } + + /** Avoid hell. */ + explicit operator bool() const = delete; + + friend std::ostream &operator<<(std::ostream &stream, const Axis axis) + { + switch (axis.axis_) { + default: + BLI_assert_unreachable(); + return stream << "Invalid Axis"; + case Value::X: + return stream << 'X'; + case Value::Y: + return stream << 'Y'; + case Value::Z: + return stream << 'Z'; + } + } +}; + +/** + * An enum class representing one of the 6 axis aligned direction. + * This is implemented using a class to allow operators and methods. + * NOTE: While this represents a 3D axis it can still be used to generate 2D basis vectors. + */ +class AxisSigned { + public: + enum class Value : int8_t { + /* Match #eTrackToAxis_Modes */ + /* Must start at 0. Used as indices in tables and vectors. */ + X_POS = 0, + Y_POS = 1, + Z_POS = 2, + X_NEG = 3, + Y_NEG = 4, + Z_NEG = 5, + }; + + constexpr static Value X_POS = Value::X_POS; + constexpr static Value Y_POS = Value::Y_POS; + constexpr static Value Z_POS = Value::Z_POS; + constexpr static Value X_NEG = Value::X_NEG; + constexpr static Value Y_NEG = Value::Y_NEG; + constexpr static Value Z_NEG = Value::Z_NEG; + + private: + Value axis_; + + public: + AxisSigned() = default; + + constexpr AxisSigned(Value axis) : axis_(axis){}; + constexpr AxisSigned(Axis axis) : axis_(from_int(axis.as_int())){}; + + /** Allow casting from DNA enums stored as short / int. */ + constexpr static AxisSigned from_int(int axis_int) + { + const AxisSigned axis = static_cast(axis_int); + BLI_assert(AxisSigned::X_POS <= axis && axis <= AxisSigned::Z_NEG); + return axis; + } + + /** Return the axis without the sign. It changes the type whereas abs(axis) doesn't. */ + constexpr Axis axis() const + { + return Axis::from_int(this->as_int() % 3); + } + + /** Return the opposing axis. */ + AxisSigned operator-() const + { + return from_int((this->as_int() + 3) % 6); + } + + /** Return next enum value. */ + AxisSigned next_after() const + { + return from_int((this->as_int() + 1) % 6); + } + + /** Allow usage in `switch()` statements and comparisons. */ + constexpr operator Value() const + { + return axis_; + } + + constexpr int as_int() const + { + return int(axis_); + } + + /** Returns -1 if axis is negative, 1 otherwise. */ + constexpr int sign() const + { + return is_negative() ? -1 : 1; + } + + /** Returns true if axis is negative, false otherwise. */ + constexpr bool is_negative() const + { + return int(axis_) > int(Value::Z_POS); + } + + /** Avoid hell. */ + explicit operator bool() const = delete; + + friend std::ostream &operator<<(std::ostream &stream, const AxisSigned axis) + { + switch (axis.axis_) { + default: + BLI_assert_unreachable(); + return stream << "Invalid AxisSigned"; + case Value::X_POS: + case Value::Y_POS: + case Value::Z_POS: + case Value::X_NEG: + case Value::Y_NEG: + case Value::Z_NEG: + return stream << axis.axis() << (axis.sign() == -1 ? '-' : '+'); + } + } +}; + +constexpr static bool operator<=(const Axis::Value a, const Axis::Value b) +{ + return int(a) <= int(b); +} + +constexpr static bool operator<=(const AxisSigned::Value a, const AxisSigned::Value b) +{ + return int(a) <= int(b); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Axes utilities. + * \{ */ + +template<> inline AxisSigned abs(const AxisSigned &axis) +{ + return axis.axis(); +} + +[[nodiscard]] inline int sign(const AxisSigned &axis) +{ + return axis.sign(); +} + +/** + * Returns the cross direction from two basis direction using the right hand rule. + * This is much faster than true cross product if the vectors are basis vectors. + * Any ill-formed case will return a orthogonal axis to \a a but will also trigger an assert. It is + * better to filter these cases upstream. + */ +[[nodiscard]] inline AxisSigned cross(const AxisSigned a, const AxisSigned b) +{ + BLI_assert_msg(abs(a) != abs(b), "Axes must not be colinear."); + switch (a) { + case AxisSigned::X_POS: + switch (b) { + case AxisSigned::X_POS: + break; /* Ill-defined. */ + case AxisSigned::Y_POS: + return AxisSigned::Z_POS; + case AxisSigned::Z_POS: + return AxisSigned::Y_NEG; + case AxisSigned::X_NEG: + break; /* Ill-defined. */ + case AxisSigned::Y_NEG: + return AxisSigned::Z_NEG; + case AxisSigned::Z_NEG: + return AxisSigned::Y_POS; + } + break; + case AxisSigned::Y_POS: + switch (b) { + case AxisSigned::X_POS: + return AxisSigned::Z_NEG; + case AxisSigned::Y_POS: + break; /* Ill-defined. */ + case AxisSigned::Z_POS: + return AxisSigned::X_POS; + case AxisSigned::X_NEG: + return AxisSigned::Z_POS; + case AxisSigned::Y_NEG: + break; /* Ill-defined. */ + case AxisSigned::Z_NEG: + return AxisSigned::X_NEG; + } + break; + case AxisSigned::Z_POS: + switch (b) { + case AxisSigned::X_POS: + return AxisSigned::Y_POS; + case AxisSigned::Y_POS: + return AxisSigned::X_NEG; + case AxisSigned::Z_POS: + break; /* Ill-defined. */ + case AxisSigned::X_NEG: + return AxisSigned::Y_NEG; + case AxisSigned::Y_NEG: + return AxisSigned::X_POS; + case AxisSigned::Z_NEG: + break; /* Ill-defined. */ + } + break; + case AxisSigned::X_NEG: + switch (b) { + case AxisSigned::X_POS: + break; /* Ill-defined. */ + case AxisSigned::Y_POS: + return AxisSigned::Z_NEG; + case AxisSigned::Z_POS: + return AxisSigned::Y_POS; + case AxisSigned::X_NEG: + break; /* Ill-defined. */ + case AxisSigned::Y_NEG: + return AxisSigned::Z_POS; + case AxisSigned::Z_NEG: + return AxisSigned::Y_NEG; + } + break; + case AxisSigned::Y_NEG: + switch (b) { + case AxisSigned::X_POS: + return AxisSigned::Z_POS; + case AxisSigned::Y_POS: + break; /* Ill-defined. */ + case AxisSigned::Z_POS: + return AxisSigned::X_NEG; + case AxisSigned::X_NEG: + return AxisSigned::Z_NEG; + case AxisSigned::Y_NEG: + break; /* Ill-defined. */ + case AxisSigned::Z_NEG: + return AxisSigned::X_POS; + } + break; + case AxisSigned::Z_NEG: + switch (b) { + case AxisSigned::X_POS: + return AxisSigned::Y_NEG; + case AxisSigned::Y_POS: + return AxisSigned::X_POS; + case AxisSigned::Z_POS: + break; /* Ill-defined. */ + case AxisSigned::X_NEG: + return AxisSigned::Y_POS; + case AxisSigned::Y_NEG: + return AxisSigned::X_NEG; + case AxisSigned::Z_NEG: + break; /* Ill-defined. */ + } + break; + } + return a.next_after(); +} + +/** Create basis vector. */ +template T to_vector(const Axis axis) +{ + BLI_assert(axis <= AxisSigned::from_int(T::type_length - 1)); + T vec{}; + vec[axis] = 1; + return vec; +} + +/** Create signed basis vector. */ +template T to_vector(const AxisSigned axis) +{ + BLI_assert(abs(axis) <= AxisSigned::from_int(T::type_length - 1)); + T vec{}; + vec[abs(axis).as_int()] = axis.is_negative() ? -1 : 1; + return vec; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name CartesianBasis + * \{ */ + +/** + * An `blender::math::CartesianBasis` represents an orientation that is aligned with the basis + * axes. This type of rotation is fast, precise and adds more meaning to the code that uses it. + */ +struct CartesianBasis { + VecBase axes = {AxisSigned::X_POS, AxisSigned::Y_POS, AxisSigned::Z_POS}; + + CartesianBasis() = default; + + /** + * Create an arbitrary basis orientation. + * Handedness can be flipped but an axis cannot be present twice. + */ + CartesianBasis(const AxisSigned x, const AxisSigned y, const AxisSigned z) : axes(x, y, z) + { + BLI_assert(abs(x) != abs(y)); + BLI_assert(abs(y) != abs(z)); + BLI_assert(abs(z) != abs(x)); + } + + const AxisSigned &x() const + { + return axes.x; + } + + const AxisSigned &y() const + { + return axes.y; + } + + const AxisSigned &z() const + { + return axes.z; + } + + AxisSigned &x() + { + return axes.x; + } + + AxisSigned &y() + { + return axes.y; + } + + AxisSigned &z() + { + return axes.z; + } + + friend std::ostream &operator<<(std::ostream &stream, const CartesianBasis &rot) + { + return stream << "CartesianBasis" << rot.axes; + } +}; + +/** + * Create an CartesianBasis for converting from \a a orientation to \a b orientation. + * The third axis is chosen by right hand rule to follow blender coordinate system. + * \a forward is Y axis in blender coordinate system. + * \a up is Z axis in blender coordinate system. + * \note \a forward and \a up must be different axes. + */ +[[nodiscard]] inline CartesianBasis from_orthonormal_axes(const AxisSigned forward, + const AxisSigned up) +{ + BLI_assert(math::abs(forward) != math::abs(up)); + return {cross(forward, up), forward, up}; +} + +/** + * Create an CartesianBasis for converting from \a a orientation to \a b orientation. + */ +[[nodiscard]] inline CartesianBasis rotation_between(const CartesianBasis &a, + const CartesianBasis &b) +{ + CartesianBasis basis; + basis.axes[abs(b.x()).as_int()] = (sign(b.x()) != sign(a.x())) ? -abs(a.x()) : abs(a.x()); + basis.axes[abs(b.y()).as_int()] = (sign(b.y()) != sign(a.y())) ? -abs(a.y()) : abs(a.y()); + basis.axes[abs(b.z()).as_int()] = (sign(b.z()) != sign(a.z())) ? -abs(a.z()) : abs(a.z()); + return basis; +} + +/** + * Create an CartesianBasis for converting from an \a a orientation defined only by its forward + * vector to a \a b orientation defined only by its forward vector. + * Rotation is given to be non flipped and deterministic. + */ +[[nodiscard]] inline CartesianBasis rotation_between(const AxisSigned a_forward, + const AxisSigned b_forward) +{ + /* Pick predictable next axis. */ + AxisSigned a_up = abs(a_forward.next_after()); + AxisSigned b_up = abs(b_forward.next_after()); + + if (sign(a_forward) != sign(b_forward)) { + /* Flip both axis (up and right) so resulting rotation matrix sign remains positive. */ + b_up = -b_up; + } + return rotation_between(from_orthonormal_axes(a_forward, a_up), + from_orthonormal_axes(b_forward, b_up)); +} + +/** \} */ + +} // namespace blender::math + +/** \} */ diff --git a/source/blender/blenlib/BLI_math_euler.hh b/source/blender/blenlib/BLI_math_euler.hh new file mode 100644 index 00000000000..3a529023f37 --- /dev/null +++ b/source/blender/blenlib/BLI_math_euler.hh @@ -0,0 +1,114 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + */ + +#include "BLI_math_axis_angle_types.hh" +#include "BLI_math_euler_types.hh" +#include "BLI_math_quaternion_types.hh" + +#include "BLI_math_axis_angle.hh" +#include "BLI_math_matrix.hh" +#include "BLI_math_quaternion.hh" + +namespace blender::math { + +/* -------------------------------------------------------------------- */ +/** \name EulerXYZ + * \{ */ + +template EulerXYZBase EulerXYZBase::wrapped() const +{ + EulerXYZBase result(*this); + result.x() = AngleRadianBase(result.x()).wrapped().radian(); + result.y() = AngleRadianBase(result.y()).wrapped().radian(); + result.z() = AngleRadianBase(result.z()).wrapped().radian(); + return result; +} + +template +EulerXYZBase EulerXYZBase::wrapped_around(const EulerXYZBase &reference) const +{ + EulerXYZBase result(*this); + result.x() = AngleRadianBase(result.x()).wrapped_around(reference.x()).radian(); + result.y() = AngleRadianBase(result.y()).wrapped_around(reference.y()).radian(); + result.z() = AngleRadianBase(result.z()).wrapped_around(reference.z()).radian(); + return result; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversion to Quaternions + * \{ */ + +template QuaternionBase to_quaternion(const EulerXYZBase &eul) +{ + using AngleT = typename EulerXYZBase::AngleT; + const AngleT h_angle_i = eul.x() / 2; + const AngleT h_angle_j = eul.y() / 2; + const AngleT h_angle_k = eul.z() / 2; + const T cos_i = math::cos(h_angle_i); + const T cos_j = math::cos(h_angle_j); + const T cos_k = math::cos(h_angle_k); + const T sin_i = math::sin(h_angle_i); + const T sin_j = math::sin(h_angle_j); + const T sin_k = math::sin(h_angle_k); + const T cos_cos = cos_i * cos_k; + const T cos_sin = cos_i * sin_k; + const T sin_cos = sin_i * cos_k; + const T sin_sin = sin_i * sin_k; + + QuaternionBase quat; + quat.w = cos_j * cos_cos + sin_j * sin_sin; + quat.x = cos_j * sin_cos - sin_j * cos_sin; + quat.y = cos_j * sin_sin + sin_j * cos_cos; + quat.z = cos_j * cos_sin - sin_j * sin_cos; + return quat; +} + +template QuaternionBase to_quaternion(const Euler3Base &eulO) +{ + /* Swizzle to XYZ. */ + EulerXYZBase eul_xyz{eulO.ijk()}; + /* Flip with parity. */ + eul_xyz.y() = eulO.parity() ? -eul_xyz.y() : eul_xyz.y(); + /* Quaternion conversion. */ + QuaternionBase quat = to_quaternion(eul_xyz); + /* Swizzle back from XYZ. */ + VecBase quat_xyz; + quat_xyz[eulO.i_index()] = quat.x; + quat_xyz[eulO.j_index()] = eulO.parity() ? -quat.y : quat.y; + quat_xyz[eulO.k_index()] = quat.z; + + return {quat.w, UNPACK3(quat_xyz)}; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversion to axis angles + * \{ */ + +template +AxisAngleBase to_axis_angle(const EulerXYZBase &euler) +{ + /* Use quaternions as intermediate representation for now... */ + return to_axis_angle(to_quaternion(euler)); +} + +template +AxisAngleBase to_axis_angle(const Euler3Base &euler) +{ + /* Use quaternions as intermediate representation for now... */ + return to_axis_angle(to_quaternion(euler)); +} + +/** \} */ + +} // namespace blender::math + +/** \} */ diff --git a/source/blender/blenlib/BLI_math_euler_types.hh b/source/blender/blenlib/BLI_math_euler_types.hh new file mode 100644 index 00000000000..a7c18e304e3 --- /dev/null +++ b/source/blender/blenlib/BLI_math_euler_types.hh @@ -0,0 +1,441 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + * + * Euler rotations are represented as a triple of angle representing a rotation around each basis + * vector. The order in which the three rotations are applied changes the resulting orientation. + * + * A `blender::math::EulerXYZ` represent an Euler triple with fixed axis order (XYZ). + * A `blender::math::Euler3` represents an Euler triple with arbitrary axis order. + * + * They are prone to gimbal lock and are not suited for many applications. However they are more + * intuitive than other rotation types. Their main use is for converting user facing rotation + * values to other rotation types. + * + * The rotation values can still be reinterpreted like this: + * `Euler3(float3(my_euler3_zyx_rot), EulerOrder::XYZ)` + * This will swap the X and Z rotation order and will likely not produce the same rotation matrix. + * + * If the goal is to convert (keep the same orientation) to `Euler3` then you have to do an + * assignment. + * eg: `Euler3 my_euler(EulerOrder::XYZ); my_euler = my_quaternion:` + */ + +#include "BLI_math_angle_types.hh" +#include "BLI_math_base.hh" +#include "BLI_math_basis_types.hh" + +namespace blender::math { + +/* WARNING: must match the #eRotationModes in `DNA_action_types.h` + * order matters - types are saved to file. */ +enum EulerOrder { + XYZ = 1, + XZY, + YXZ, + YZX, + ZXY, + ZYX, +}; + +std::ostream &operator<<(std::ostream &stream, EulerOrder order); + +/* -------------------------------------------------------------------- */ +/** \name EulerBase + * \{ */ + +template struct EulerBase { + using AngleT = AngleRadianBase; + + protected: + /** + * Container for the rotation values. They are always stored as XYZ order. + * Rotation values are stored without parity flipping. + */ + VecBase xyz_; + + EulerBase() = default; + + EulerBase(const AngleT &x, const AngleT &y, const AngleT &z) : xyz_(x, y, z){}; + + EulerBase(const VecBase &vec) : xyz_(vec){}; + + EulerBase(const VecBase &vec) : xyz_(vec.x, vec.y, vec.z){}; + + public: + /** Static functions. */ + + /** Conversions. */ + + explicit operator VecBase() const + { + return this->xyz_; + } + + explicit operator VecBase() const + { + return {T(x()), T(y()), T(z())}; + } + + /** Methods. */ + + VecBase &xyz() + { + return this->xyz_; + } + const VecBase &xyz() const + { + return this->xyz_; + } + + const AngleT &x() const + { + return this->xyz_.x; + } + + const AngleT &y() const + { + return this->xyz_.y; + } + + const AngleT &z() const + { + return this->xyz_.z; + } + + AngleT &x() + { + return this->xyz_.x; + } + + AngleT &y() + { + return this->xyz_.y; + } + + AngleT &z() + { + return this->xyz_.z; + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name EulerXYZ + * \{ */ + +template struct EulerXYZBase : public EulerBase { + using AngleT = AngleRadianBase; + + public: + EulerXYZBase() = default; + + /** + * Create an euler x,y,z rotation from a triple of radian angle. + */ + template EulerXYZBase(const VecBase &vec) : EulerBase(vec){}; + + EulerXYZBase(const AngleT &x, const AngleT &y, const AngleT &z) : EulerBase(x, y, z){}; + + /** + * Create a rotation from an basis axis and an angle. + * This sets a single component of the euler triple, the others are left to 0. + */ + EulerXYZBase(const Axis axis, const AngleT &angle) + { + *this = identity(); + this->xyz_[axis] = angle; + } + + /** Static functions. */ + + static EulerXYZBase identity() + { + return {AngleRadianBase::identity(), + AngleRadianBase::identity(), + AngleRadianBase::identity()}; + } + + /** Methods. */ + + /** + * Return this euler orientation but with angles wrapped inside [-pi..pi] range. + */ + EulerXYZBase wrapped() const; + + /** + * Return this euler orientation but wrapped around \a reference. + * + * This means the interpolation between the returned value and \a reference will always take the + * shortest path. The angle between them will not be more than pi. + */ + EulerXYZBase wrapped_around(const EulerXYZBase &reference) const; + + /** Operators. */ + + friend EulerXYZBase operator-(const EulerXYZBase &a) + { + return {-a.xyz_.x, -a.xyz_.y, -a.xyz_.z}; + } + + friend bool operator==(const EulerXYZBase &a, const EulerXYZBase &b) + { + return a.xyz_ == b.xyz_; + } + + friend std::ostream &operator<<(std::ostream &stream, const EulerXYZBase &rot) + { + return stream << "EulerXYZ" << static_cast>(rot); + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Euler3 + * \{ */ + +template struct Euler3Base : public EulerBase { + using AngleT = AngleRadianBase; + + private: + /** Axes order from applying the rotation. */ + EulerOrder order_; + + /** + * Swizzle structure allowing to rotation ordered assignment. + */ + class Swizzle { + private: + Euler3Base &eul_; + + public: + explicit Swizzle(Euler3Base &eul) : eul_(eul){}; + + Euler3Base &operator=(const VecBase &angles) + { + eul_.xyz_.x = angles[eul_.i_index()]; + eul_.xyz_.y = angles[eul_.j_index()]; + eul_.xyz_.z = angles[eul_.k_index()]; + return eul_; + } + + operator VecBase() const + { + return {eul_.i(), eul_.j(), eul_.k()}; + } + + explicit operator VecBase() const + { + return {T(eul_.i()), T(eul_.j()), T(eul_.k())}; + } + }; + + public: + Euler3Base() = delete; + + /** + * Create an euler rotation with \a order rotation ordering + * from a triple of radian angles in XYZ order. + * eg: If \a order is `EulerOrder::ZXY` then `angles.z` will be the angle of the first rotation. + */ + template + Euler3Base(const VecBase &angles_xyz, EulerOrder order) + : EulerBase(angles_xyz), order_(order){}; + + Euler3Base(const AngleT &x, const AngleT &y, const AngleT &z, EulerOrder order) + : EulerBase(x, y, z), order_(order){}; + + /** + * Create a rotation around a single euler axis and an angle. + */ + Euler3Base(const Axis axis, AngleT angle, EulerOrder order) : EulerBase(), order_(order) + { + this->xyz_[axis] = angle; + } + + /** + * Defines rotation order but not the rotation values. + * Used for conversion from other rotation types. + */ + Euler3Base(EulerOrder order) : order_(order){}; + + /** Methods. */ + + const EulerOrder &order() const + { + return order_; + } + + /** + * Returns the rotations angle in rotation order. + * eg: if rotation `order` is `YZX` then `i` is the `Y` rotation. + */ + Swizzle ijk() + { + return Swizzle{*this}; + } + const VecBase ijk() const + { + return {i(), j(), k()}; + } + + /** + * Returns the rotations angle in rotation order. + * eg: if rotation `order` is `YZX` then `i` is the `Y` rotation. + */ + const AngleT &i() const + { + return this->xyz_[i_index()]; + } + const AngleT &j() const + { + return this->xyz_[j_index()]; + } + const AngleT &k() const + { + return this->xyz_[k_index()]; + } + AngleT &i() + { + return this->xyz_[i_index()]; + } + AngleT &j() + { + return this->xyz_[j_index()]; + } + AngleT &k() + { + return this->xyz_[k_index()]; + } + + /** + * Return this euler orientation but wrapped around \a reference. + * + * This means the interpolation between the returned value and \a reference will always take the + * shortest path. The angle between them will not be more than pi. + */ + Euler3Base wrapped_around(const Euler3Base &reference) const + { + return {VecBase(EulerXYZBase(this->xyz_).wrapped_around(reference.xyz_)), + order_}; + } + + /** Operators. */ + + friend Euler3Base operator-(const Euler3Base &a) + { + return {-a.xyz_, a.order_}; + } + + friend bool operator==(const Euler3Base &a, const Euler3Base &b) + { + return a.xyz_ == b.xyz_ && a.order_ == b.order_; + } + + friend std::ostream &operator<<(std::ostream &stream, const Euler3Base &rot) + { + return stream << "Euler3_" << rot.order_ << rot.xyz_; + } + + /* Utilities for conversions and functions operating on Euler3. + * This should be private in theory. */ + + /** + * Parity of axis permutation. + * It is considered even if axes are not shuffled (X followed by Y which in turn followed by Z). + * Return `true` if odd (shuffled) and `false` if even (non-shuffled). + */ + bool parity() const + { + switch (order_) { + default: + BLI_assert_unreachable(); + return false; + case XYZ: + case ZXY: + case YZX: + return false; + case XZY: + case YXZ: + case ZYX: + return true; + } + } + + /** + * Source Axis of the 1st axis rotation. + */ + int i_index() const + { + switch (order_) { + default: + BLI_assert_unreachable(); + return 0; + case XYZ: + case XZY: + return 0; + case YXZ: + case YZX: + return 1; + case ZXY: + case ZYX: + return 2; + } + } + + /** + * Source Axis of the 2nd axis rotation. + */ + int j_index() const + { + switch (order_) { + default: + BLI_assert_unreachable(); + return 0; + case YXZ: + case ZXY: + return 0; + case XYZ: + case ZYX: + return 1; + case XZY: + case YZX: + return 2; + } + } + + /** + * Source Axis of the 3rd axis rotation. + */ + int k_index() const + { + switch (order_) { + default: + BLI_assert_unreachable(); + return 0; + case YZX: + case ZYX: + return 0; + case XZY: + case ZXY: + return 1; + case XYZ: + case YXZ: + return 2; + } + } +}; + +/** \} */ + +using EulerXYZ = EulerXYZBase; +using Euler3 = Euler3Base; + +} // namespace blender::math + +/** \} */ diff --git a/source/blender/blenlib/BLI_math_matrix.hh b/source/blender/blenlib/BLI_math_matrix.hh index 5b15920b136..19ed2fe1726 100644 --- a/source/blender/blenlib/BLI_math_matrix.hh +++ b/source/blender/blenlib/BLI_math_matrix.hh @@ -229,6 +229,15 @@ template const VectorT forward, const VectorT up); +/** + * This returns a version of \a mat with orthonormal basis axes. + * This leaves the given \a axis untouched. + * + * In other words this removes the shear of the matrix. However this doesn't properly account for + * volume preservation, and so, the axes keep their respective length. + */ +template [[nodiscard]] MatT orthogonalize(const MatT &mat, const Axis axis); + /** * Construct a transformation that is pivoted around the given origin point. So for instance, * from_origin_transform(from_rotation(M_PI_2), float2(0.0f, 2.0f)) @@ -247,18 +256,48 @@ template * Extract euler rotation from transform matrix. * \return the rotation with the smallest values from the potential candidates. */ -template -[[nodiscard]] inline detail::EulerXYZ to_euler(const MatBase &mat); -template -[[nodiscard]] inline detail::EulerXYZ to_euler(const MatBase &mat); +template [[nodiscard]] inline EulerXYZBase to_euler(const MatBase &mat); +template [[nodiscard]] inline EulerXYZBase to_euler(const MatBase &mat); +template +[[nodiscard]] inline Euler3Base to_euler(const MatBase &mat, EulerOrder order); +template +[[nodiscard]] inline Euler3Base to_euler(const MatBase &mat, EulerOrder order); + +/** + * Extract euler rotation from transform matrix. + * The returned euler triple is given to be the closest from the \a reference. + * It avoids axis flipping for animated f-curves for eg. + * \return the rotation with the smallest values from the potential candidates. + * \note this correspond to the C API "to_compatible" functions. + */ +template +[[nodiscard]] inline EulerXYZBase to_nearest_euler(const MatBase &mat, + const EulerXYZBase &reference); +template +[[nodiscard]] inline EulerXYZBase to_nearest_euler(const MatBase &mat, + const EulerXYZBase &reference); +template +[[nodiscard]] inline Euler3Base to_nearest_euler(const MatBase &mat, + const Euler3Base &reference); +template +[[nodiscard]] inline Euler3Base to_nearest_euler(const MatBase &mat, + const Euler3Base &reference); /** * Extract quaternion rotation from transform matrix. */ -template -[[nodiscard]] inline detail::Quaternion to_quaternion(const MatBase &mat); -template -[[nodiscard]] inline detail::Quaternion to_quaternion(const MatBase &mat); +template +[[nodiscard]] inline QuaternionBase to_quaternion(const MatBase &mat); +template +[[nodiscard]] inline QuaternionBase to_quaternion(const MatBase &mat); + +/** + * Extract quaternion rotation from transform matrix. + * Legacy version of #to_quaternion which has slightly different behavior. + * Keep for particle-system & boids since replacing this will make subtle changes + * that impact hair in existing files. See: D15772. + */ +[[nodiscard]] Quaternion to_quaternion_legacy(const float3x3 &mat); /** * Extract the absolute 3d scale from a transform matrix. @@ -475,16 +514,25 @@ inline bool is_zero(const MatBase &mat) namespace detail { template -[[nodiscard]] MatBase from_rotation(const AngleRadian &rotation); +[[nodiscard]] MatBase from_rotation(const AngleRadianBase &rotation); template -[[nodiscard]] MatBase from_rotation(const EulerXYZ &rotation); +[[nodiscard]] MatBase from_rotation(const EulerXYZBase &rotation); template -[[nodiscard]] MatBase from_rotation(const Quaternion &rotation); +[[nodiscard]] MatBase from_rotation(const Euler3Base &rotation); template -[[nodiscard]] MatBase from_rotation(const AxisAngle &rotation); +[[nodiscard]] MatBase from_rotation(const QuaternionBase &rotation); + +template +[[nodiscard]] MatBase from_rotation(const DualQuaternionBase &rotation); + +template +[[nodiscard]] MatBase from_rotation(const CartesianBasis &rotation); + +template +[[nodiscard]] MatBase from_rotation(const AxisAngleBase &rotation); } // namespace detail @@ -539,14 +587,14 @@ template return result; } -template +template [[nodiscard]] MatBase rotate(const MatBase &mat, - const detail::AxisAngle &rotation) + const AxisAngleBase &rotation) { using MatT = MatBase; using Vec3T = typename MatT::vec3_type; - const T &angle_sin = rotation.angle_sin(); - const T &angle_cos = rotation.angle_cos(); + const T angle_sin = sin(rotation.angle()); + const T angle_cos = cos(rotation.angle()); const Vec3T &axis_vec = rotation.axis(); MatT result = mat; @@ -657,46 +705,78 @@ template namespace detail { template -void normalized_to_eul2(const MatBase &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2) +void normalized_to_eul2(const MatBase &mat, EulerXYZBase &eul1, EulerXYZBase &eul2) { BLI_assert(math::is_unit_scale(mat)); const T cy = math::hypot(mat[0][0], mat[0][1]); if (cy > T(16) * FLT_EPSILON) { - eul1.x = math::atan2(mat[1][2], mat[2][2]); - eul1.y = math::atan2(-mat[0][2], cy); - eul1.z = math::atan2(mat[0][1], mat[0][0]); + eul1.x() = math::atan2(mat[1][2], mat[2][2]); + eul1.y() = math::atan2(-mat[0][2], cy); + eul1.z() = math::atan2(mat[0][1], mat[0][0]); - eul2.x = math::atan2(-mat[1][2], -mat[2][2]); - eul2.y = math::atan2(-mat[0][2], -cy); - eul2.z = math::atan2(-mat[0][1], -mat[0][0]); + eul2.x() = math::atan2(-mat[1][2], -mat[2][2]); + eul2.y() = math::atan2(-mat[0][2], -cy); + eul2.z() = math::atan2(-mat[0][1], -mat[0][0]); } else { - eul1.x = math::atan2(-mat[2][1], mat[1][1]); - eul1.y = math::atan2(-mat[0][2], cy); - eul1.z = 0.0f; + eul1.x() = math::atan2(-mat[2][1], mat[1][1]); + eul1.y() = math::atan2(-mat[0][2], cy); + eul1.z() = 0.0f; eul2 = eul1; } } +template +void normalized_to_eul2(const MatBase &mat, Euler3Base &eul1, Euler3Base &eul2) +{ + BLI_assert(math::is_unit_scale(mat)); + const int i_index = eul1.i_index(); + const int j_index = eul1.j_index(); + const int k_index = eul1.k_index(); + + const T cy = math::hypot(mat[i_index][i_index], mat[i_index][j_index]); + if (cy > T(16) * FLT_EPSILON) { + eul1.i() = math::atan2(mat[j_index][k_index], mat[k_index][k_index]); + eul1.j() = math::atan2(-mat[i_index][k_index], cy); + eul1.k() = math::atan2(mat[i_index][j_index], mat[i_index][i_index]); + + eul2.i() = math::atan2(-mat[j_index][k_index], -mat[k_index][k_index]); + eul2.j() = math::atan2(-mat[i_index][k_index], -cy); + eul2.k() = math::atan2(-mat[i_index][j_index], -mat[i_index][i_index]); + } + else { + eul1.i() = math::atan2(-mat[k_index][j_index], mat[j_index][j_index]); + eul1.j() = math::atan2(-mat[i_index][k_index], cy); + eul1.k() = 0.0f; + + eul2 = eul1; + } + + if (eul1.parity()) { + eul1 = -eul1; + eul2 = -eul2; + } +} /* Using explicit template instantiations in order to reduce compilation time. */ extern template void normalized_to_eul2(const float3x3 &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2); + Euler3Base &eul1, + Euler3Base &eul2); +extern template void normalized_to_eul2(const float3x3 &mat, + EulerXYZBase &eul1, + EulerXYZBase &eul2); extern template void normalized_to_eul2(const double3x3 &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2); + EulerXYZBase &eul1, + EulerXYZBase &eul2); -template detail::Quaternion normalized_to_quat_fast(const MatBase &mat) +template QuaternionBase normalized_to_quat_fast(const MatBase &mat) { BLI_assert(math::is_unit_scale(mat)); /* Caller must ensure matrices aren't negative for valid results, see: #24291, #94231. */ BLI_assert(!math::is_negative(mat)); - detail::Quaternion q; + QuaternionBase q; /* Method outlined by Mike Day, ref: https://math.stackexchange.com/a/3183435/220949 * with an additional `sqrtf(..)` for higher precision result. @@ -710,14 +790,14 @@ template detail::Quaternion normalized_to_quat_fast(const MatBase /* Ensure W is non-negative for a canonical result. */ s = -s; } - q.y = 0.25f * s; + q.x = 0.25f * s; s = 1.0f / s; - q.x = (mat[1][2] - mat[2][1]) * s; - q.z = (mat[0][1] + mat[1][0]) * s; - q.w = (mat[2][0] + mat[0][2]) * s; - if (UNLIKELY((trace == 1.0f) && (q.x == 0.0f && q.z == 0.0f && q.w == 0.0f))) { + q.w = (mat[1][2] - mat[2][1]) * s; + q.y = (mat[0][1] + mat[1][0]) * s; + q.z = (mat[2][0] + mat[0][2]) * s; + if (UNLIKELY((trace == 1.0f) && (q.w == 0.0f && q.y == 0.0f && q.z == 0.0f))) { /* Avoids the need to normalize the degenerate case. */ - q.y = 1.0f; + q.x = 1.0f; } } else { @@ -727,14 +807,14 @@ template detail::Quaternion normalized_to_quat_fast(const MatBase /* Ensure W is non-negative for a canonical result. */ s = -s; } - q.z = 0.25f * s; + q.y = 0.25f * s; s = 1.0f / s; - q.x = (mat[2][0] - mat[0][2]) * s; - q.y = (mat[0][1] + mat[1][0]) * s; - q.w = (mat[1][2] + mat[2][1]) * s; - if (UNLIKELY((trace == 1.0f) && (q.x == 0.0f && q.y == 0.0f && q.w == 0.0f))) { + q.w = (mat[2][0] - mat[0][2]) * s; + q.x = (mat[0][1] + mat[1][0]) * s; + q.z = (mat[1][2] + mat[2][1]) * s; + if (UNLIKELY((trace == 1.0f) && (q.w == 0.0f && q.x == 0.0f && q.z == 0.0f))) { /* Avoids the need to normalize the degenerate case. */ - q.z = 1.0f; + q.y = 1.0f; } } } @@ -746,14 +826,14 @@ template detail::Quaternion normalized_to_quat_fast(const MatBase /* Ensure W is non-negative for a canonical result. */ s = -s; } - q.w = 0.25f * s; + q.z = 0.25f * s; s = 1.0f / s; - q.x = (mat[0][1] - mat[1][0]) * s; - q.y = (mat[2][0] + mat[0][2]) * s; - q.z = (mat[1][2] + mat[2][1]) * s; - if (UNLIKELY((trace == 1.0f) && (q.x == 0.0f && q.y == 0.0f && q.z == 0.0f))) { + q.w = (mat[0][1] - mat[1][0]) * s; + q.x = (mat[2][0] + mat[0][2]) * s; + q.y = (mat[1][2] + mat[2][1]) * s; + if (UNLIKELY((trace == 1.0f) && (q.w == 0.0f && q.x == 0.0f && q.y == 0.0f))) { /* Avoids the need to normalize the degenerate case. */ - q.w = 1.0f; + q.z = 1.0f; } } else { @@ -762,29 +842,28 @@ template detail::Quaternion normalized_to_quat_fast(const MatBase */ const T trace = 1.0f + mat[0][0] + mat[1][1] + mat[2][2]; T s = 2.0f * math::sqrt(trace); - q.x = 0.25f * s; + q.w = 0.25f * s; s = 1.0f / s; - q.y = (mat[1][2] - mat[2][1]) * s; - q.z = (mat[2][0] - mat[0][2]) * s; - q.w = (mat[0][1] - mat[1][0]) * s; - if (UNLIKELY((trace == 1.0f) && (q.y == 0.0f && q.z == 0.0f && q.w == 0.0f))) { + q.x = (mat[1][2] - mat[2][1]) * s; + q.y = (mat[2][0] - mat[0][2]) * s; + q.z = (mat[0][1] - mat[1][0]) * s; + if (UNLIKELY((trace == 1.0f) && (q.x == 0.0f && q.y == 0.0f && q.z == 0.0f))) { /* Avoids the need to normalize the degenerate case. */ - q.x = 1.0f; + q.w = 1.0f; } } } - BLI_assert(!(q.x < 0.0f)); + BLI_assert(!(q.w < 0.0f)); BLI_assert(math::is_unit_scale(VecBase(q))); return q; } -template -detail::Quaternion normalized_to_quat_with_checks(const MatBase &mat) +template QuaternionBase normalized_to_quat_with_checks(const MatBase &mat) { const T det = math::determinant(mat); if (UNLIKELY(!isfinite(det))) { - return detail::Quaternion::identity(); + return QuaternionBase::identity(); } else if (UNLIKELY(det < T(0))) { return normalized_to_quat_fast(-mat); @@ -793,59 +872,85 @@ detail::Quaternion normalized_to_quat_with_checks(const MatBase &mat } /* Using explicit template instantiations in order to reduce compilation time. */ -extern template Quaternion normalized_to_quat_with_checks(const float3x3 &mat); -extern template Quaternion normalized_to_quat_with_checks(const double3x3 &mat); +extern template QuaternionBase normalized_to_quat_with_checks(const float3x3 &mat); +extern template QuaternionBase normalized_to_quat_with_checks(const double3x3 &mat); template -MatBase from_rotation(const EulerXYZ &rotation) +MatBase from_rotation(const EulerXYZBase &rotation) { using MatT = MatBase; using DoublePrecision = typename TypeTraits::DoublePrecision; - DoublePrecision ci = math::cos(rotation.x); - DoublePrecision cj = math::cos(rotation.y); - DoublePrecision ch = math::cos(rotation.z); - DoublePrecision si = math::sin(rotation.x); - DoublePrecision sj = math::sin(rotation.y); - DoublePrecision sh = math::sin(rotation.z); - DoublePrecision cc = ci * ch; - DoublePrecision cs = ci * sh; - DoublePrecision sc = si * ch; - DoublePrecision ss = si * sh; + const DoublePrecision cos_i = math::cos(DoublePrecision(rotation.x().radian())); + const DoublePrecision cos_j = math::cos(DoublePrecision(rotation.y().radian())); + const DoublePrecision cos_k = math::cos(DoublePrecision(rotation.z().radian())); + const DoublePrecision sin_i = math::sin(DoublePrecision(rotation.x().radian())); + const DoublePrecision sin_j = math::sin(DoublePrecision(rotation.y().radian())); + const DoublePrecision sin_k = math::sin(DoublePrecision(rotation.z().radian())); + const DoublePrecision cos_i_cos_k = cos_i * cos_k; + const DoublePrecision cos_i_sin_k = cos_i * sin_k; + const DoublePrecision sin_i_cos_k = sin_i * cos_k; + const DoublePrecision sin_i_sin_k = sin_i * sin_k; MatT mat = MatT::identity(); - mat[0][0] = T(cj * ch); - mat[1][0] = T(sj * sc - cs); - mat[2][0] = T(sj * cc + ss); + mat[0][0] = T(cos_j * cos_k); + mat[1][0] = T(sin_j * sin_i_cos_k - cos_i_sin_k); + mat[2][0] = T(sin_j * cos_i_cos_k + sin_i_sin_k); - mat[0][1] = T(cj * sh); - mat[1][1] = T(sj * ss + cc); - mat[2][1] = T(sj * cs - sc); + mat[0][1] = T(cos_j * sin_k); + mat[1][1] = T(sin_j * sin_i_sin_k + cos_i_cos_k); + mat[2][1] = T(sin_j * cos_i_sin_k - sin_i_cos_k); - mat[0][2] = T(-sj); - mat[1][2] = T(cj * si); - mat[2][2] = T(cj * ci); + mat[0][2] = T(-sin_j); + mat[1][2] = T(cos_j * sin_i); + mat[2][2] = T(cos_j * cos_i); return mat; } template -MatBase from_rotation(const Quaternion &rotation) +MatBase from_rotation(const Euler3Base &rotation) +{ + using MatT = MatBase; + const int i_index = rotation.i_index(); + const int j_index = rotation.j_index(); + const int k_index = rotation.k_index(); +#if 1 /* Reference. */ + EulerXYZBase euler_xyz(rotation.ijk()); + const MatT mat = from_rotation(rotation.parity() ? -euler_xyz : euler_xyz); + MatT result = MatT::identity(); + result[i_index][i_index] = mat[0][0]; + result[j_index][i_index] = mat[1][0]; + result[k_index][i_index] = mat[2][0]; + result[i_index][j_index] = mat[0][1]; + result[j_index][j_index] = mat[1][1]; + result[k_index][j_index] = mat[2][1]; + result[i_index][k_index] = mat[0][2]; + result[j_index][k_index] = mat[1][2]; + result[k_index][k_index] = mat[2][2]; +#else + /* TODO(fclem): Manually inline and check performance difference. */ +#endif + return result; +} + +template +MatBase from_rotation(const QuaternionBase &rotation) { using MatT = MatBase; using DoublePrecision = typename TypeTraits::DoublePrecision; - DoublePrecision q0 = M_SQRT2 * DoublePrecision(rotation.x); - DoublePrecision q1 = M_SQRT2 * DoublePrecision(rotation.y); - DoublePrecision q2 = M_SQRT2 * DoublePrecision(rotation.z); - DoublePrecision q3 = M_SQRT2 * DoublePrecision(rotation.w); + const DoublePrecision q0 = M_SQRT2 * DoublePrecision(rotation.w); + const DoublePrecision q1 = M_SQRT2 * DoublePrecision(rotation.x); + const DoublePrecision q2 = M_SQRT2 * DoublePrecision(rotation.y); + const DoublePrecision q3 = M_SQRT2 * DoublePrecision(rotation.z); - DoublePrecision qda = q0 * q1; - DoublePrecision qdb = q0 * q2; - DoublePrecision qdc = q0 * q3; - DoublePrecision qaa = q1 * q1; - DoublePrecision qab = q1 * q2; - DoublePrecision qac = q1 * q3; - DoublePrecision qbb = q2 * q2; - DoublePrecision qbc = q2 * q3; - DoublePrecision qcc = q3 * q3; + const DoublePrecision qda = q0 * q1; + const DoublePrecision qdb = q0 * q2; + const DoublePrecision qdc = q0 * q3; + const DoublePrecision qaa = q1 * q1; + const DoublePrecision qab = q1 * q2; + const DoublePrecision qac = q1 * q3; + const DoublePrecision qbb = q2 * q2; + const DoublePrecision qbc = q2 * q3; + const DoublePrecision qcc = q3 * q3; MatT mat = MatT::identity(); mat[0][0] = T(1.0 - qbb - qcc); @@ -862,13 +967,54 @@ MatBase from_rotation(const Quaternion &rotation) return mat; } +/* Not technically speaking a simple rotation, but a whole transform. */ template -MatBase from_rotation(const AxisAngle &rotation) +[[nodiscard]] MatBase from_rotation(const DualQuaternionBase &rotation) +{ + using MatT = MatBase; + BLI_assert(is_normalized(rotation)); + /** + * From: + * "Skinning with Dual Quaternions" + * Ladislav Kavan, Steven Collins, Jiri Zara, Carol O'Sullivan + * Trinity College Dublin, Czech Technical University in Prague + */ + /* Follow the paper notation. */ + const QuaternionBase &c0 = rotation.quat; + const QuaternionBase &ce = rotation.trans; + const T &w0 = c0.w, &x0 = c0.x, &y0 = c0.y, &z0 = c0.z; + const T &we = ce.w, &xe = ce.x, &ye = ce.y, &ze = ce.z; + /* Rotation. */ + MatT mat = from_rotation(c0); + /* Translation. */ + mat[3][0] = T(2) * (-we * x0 + xe * w0 - ye * z0 + ze * y0); + mat[3][1] = T(2) * (-we * y0 + xe * z0 + ye * w0 - ze * x0); + mat[3][2] = T(2) * (-we * z0 - xe * y0 + ye * x0 + ze * w0); + /* Scale. */ + if (rotation.scale_weight != T(0)) { + mat.template view<4, 4>() = mat * rotation.scale; + } + return mat; +} + +template +MatBase from_rotation(const CartesianBasis &rotation) +{ + using MatT = MatBase; + MatT mat = MatT::identity(); + mat.x_axis() = to_vector>(rotation.axes.x); + mat.y_axis() = to_vector>(rotation.axes.y); + mat.z_axis() = to_vector>(rotation.axes.z); + return mat; +} + +template +MatBase from_rotation(const AxisAngleBase &rotation) { using MatT = MatBase; using Vec3T = typename MatT::vec3_type; - const T angle_sin = rotation.angle_sin(); - const T angle_cos = rotation.angle_cos(); + const T angle_sin = sin(rotation.angle()); + const T angle_cos = cos(rotation.angle()); const Vec3T &axis = rotation.axis(); BLI_assert(is_unit_scale(axis)); @@ -892,72 +1038,126 @@ MatBase from_rotation(const AxisAngle &rotation) } template -MatBase from_rotation(const AngleRadian &rotation) +MatBase from_rotation(const AngleRadianBase &rotation) { using MatT = MatBase; - T ci = math::cos(rotation.value); - T si = math::sin(rotation.value); + const T cos_i = cos(rotation); + const T sin_i = sin(rotation); MatT mat = MatT::identity(); - mat[0][0] = ci; - mat[1][0] = -si; + mat[0][0] = cos_i; + mat[1][0] = -sin_i; - mat[0][1] = si; - mat[1][1] = ci; + mat[0][1] = sin_i; + mat[1][1] = cos_i; return mat; } /* Using explicit template instantiations in order to reduce compilation time. */ -extern template MatBase from_rotation(const AngleRadian &rotation); -extern template MatBase from_rotation(const AngleRadian &rotation); -extern template MatBase from_rotation(const EulerXYZ &rotation); -extern template MatBase from_rotation(const EulerXYZ &rotation); -extern template MatBase from_rotation(const Quaternion &rotation); -extern template MatBase from_rotation(const Quaternion &rotation); -extern template MatBase from_rotation(const AxisAngle &rotation); -extern template MatBase from_rotation(const AxisAngle &rotation); +extern template MatBase from_rotation(const AngleRadian &rotation); +extern template MatBase from_rotation(const AngleRadian &rotation); +extern template MatBase from_rotation(const EulerXYZ &rotation); +extern template MatBase from_rotation(const EulerXYZ &rotation); +extern template MatBase from_rotation(const Euler3 &rotation); +extern template MatBase from_rotation(const Euler3 &rotation); +extern template MatBase from_rotation(const Quaternion &rotation); +extern template MatBase from_rotation(const Quaternion &rotation); +extern template MatBase from_rotation(const AxisAngle &rotation); +extern template MatBase from_rotation(const AxisAngle &rotation); +extern template MatBase from_rotation(const AxisAngleCartesian &rotation); +extern template MatBase from_rotation(const AxisAngleCartesian &rotation); } // namespace detail -template -[[nodiscard]] inline detail::EulerXYZ to_euler(const MatBase &mat) +template +[[nodiscard]] inline Euler3Base to_euler(const MatBase &mat, EulerOrder order) { - detail::EulerXYZ eul1, eul2; - if constexpr (Normalized) { - detail::normalized_to_eul2(mat, eul1, eul2); - } - else { - detail::normalized_to_eul2(normalize(mat), eul1, eul2); - } - /* Return best, which is just the one with lowest values it in. */ + Euler3Base eul1(order), eul2(order); + detail::normalized_to_eul2(mat, eul1, eul2); + /* Return best, which is just the one with lowest values in it. */ return (length_manhattan(VecBase(eul1)) > length_manhattan(VecBase(eul2))) ? eul2 : eul1; } -template -[[nodiscard]] inline detail::EulerXYZ to_euler(const MatBase &mat) +template [[nodiscard]] inline EulerXYZBase to_euler(const MatBase &mat) { - /* TODO(fclem): Avoid the copy with 3x3 ref. */ - return to_euler(MatBase(mat)); + EulerXYZBase eul1, eul2; + detail::normalized_to_eul2(mat, eul1, eul2); + /* Return best, which is just the one with lowest values in it. */ + return (length_manhattan(VecBase(eul1)) > length_manhattan(VecBase(eul2))) ? eul2 : + eul1; } -template -[[nodiscard]] inline detail::Quaternion to_quaternion(const MatBase &mat) -{ - using namespace math; - if constexpr (Normalized) { - return detail::normalized_to_quat_with_checks(mat); - } - else { - return detail::normalized_to_quat_with_checks(normalize(mat)); - } -} - -template -[[nodiscard]] inline detail::Quaternion to_quaternion(const MatBase &mat) +template +[[nodiscard]] inline Euler3Base to_euler(const MatBase &mat, EulerOrder order) { /* TODO(fclem): Avoid the copy with 3x3 ref. */ - return to_quaternion(MatBase(mat)); + return to_euler(MatBase(mat), order); +} + +template [[nodiscard]] inline EulerXYZBase to_euler(const MatBase &mat) +{ + /* TODO(fclem): Avoid the copy with 3x3 ref. */ + return to_euler(MatBase(mat)); +} + +template +[[nodiscard]] inline Euler3Base to_nearest_euler(const MatBase &mat, + const Euler3Base &reference) +{ + Euler3Base eul1(reference.order()), eul2(reference.order()); + detail::normalized_to_eul2(mat, eul1, eul2); + eul1 = eul1.wrapped_around(reference); + eul2 = eul2.wrapped_around(reference); + /* Return best, which is just the one with lowest values it in. */ + return (length_manhattan(VecBase(eul1) - VecBase(reference)) > + length_manhattan(VecBase(eul2) - VecBase(reference))) ? + eul2 : + eul1; +} + +template +[[nodiscard]] inline EulerXYZBase to_nearest_euler(const MatBase &mat, + const EulerXYZBase &reference) +{ + EulerXYZBase eul1, eul2; + detail::normalized_to_eul2(mat, eul1, eul2); + eul1 = eul1.wrapped_around(reference); + eul2 = eul2.wrapped_around(reference); + /* Return best, which is just the one with lowest values it in. */ + return (length_manhattan(VecBase(eul1) - VecBase(reference)) > + length_manhattan(VecBase(eul2) - VecBase(reference))) ? + eul2 : + eul1; +} + +template +[[nodiscard]] inline Euler3Base to_nearest_euler(const MatBase &mat, + const Euler3Base &reference) +{ + /* TODO(fclem): Avoid the copy with 3x3 ref. */ + return to_euler(MatBase(mat), reference); +} + +template +[[nodiscard]] inline EulerXYZBase to_nearest_euler(const MatBase &mat, + const EulerXYZBase &reference) +{ + /* TODO(fclem): Avoid the copy with 3x3 ref. */ + return to_euler(MatBase(mat), reference); +} + +template +[[nodiscard]] inline QuaternionBase to_quaternion(const MatBase &mat) +{ + return detail::normalized_to_quat_with_checks(mat); +} + +template +[[nodiscard]] inline QuaternionBase to_quaternion(const MatBase &mat) +{ + /* TODO(fclem): Avoid the copy with 3x3 ref. */ + return to_quaternion(MatBase(mat)); } template @@ -987,16 +1187,22 @@ template /* Implementation details. Use `to_euler` and `to_quaternion` instead. */ namespace detail { -template -inline void to_rotation(const MatBase &mat, detail::Quaternion &r_rotation) +template +inline void to_rotation(const MatBase &mat, QuaternionBase &r_rotation) { - r_rotation = to_quaternion(mat); + r_rotation = to_quaternion(mat); } -template -inline void to_rotation(const MatBase &mat, detail::EulerXYZ &r_rotation) +template +inline void to_rotation(const MatBase &mat, EulerXYZBase &r_rotation) { - r_rotation = to_euler(mat); + r_rotation = to_euler(mat); +} + +template +inline void to_rotation(const MatBase &mat, Euler3Base &r_rotation) +{ + r_rotation = to_euler(mat, r_rotation.order()); } } // namespace detail @@ -1013,7 +1219,7 @@ inline void to_rot_scale(const MatBase &mat, r_scale = -r_scale; } } - detail::to_rotation(normalized_mat, r_rotation); + detail::to_rotation(normalized_mat, r_rotation); } template @@ -1084,6 +1290,7 @@ template BLI_assert(is_unit_scale(forward)); BLI_assert(is_unit_scale(up)); + /* TODO(fclem): This is wrong. Forward is Y. */ MatT matrix; matrix.x_axis() = forward; /* Beware of handedness! Blender uses right-handedness. @@ -1104,6 +1311,100 @@ template return matrix; } +template [[nodiscard]] MatT orthogonalize(const MatT &mat, const Axis axis) +{ + using T = typename MatT::base_type; + using Vec3T = VecBase; + Vec3T scale; + MatBase R; + R.x = normalize_and_get_length(mat.x_axis(), scale.x); + R.y = normalize_and_get_length(mat.y_axis(), scale.y); + R.z = normalize_and_get_length(mat.z_axis(), scale.z); + /* NOTE(fclem) This is a direct port from `orthogonalize_m4()`. + * To select the secondary axis, it checks if the candidate axis is not colinear. + * The issue is that the candidate axes are not normalized so this dot product + * check is kind of pointless. + * Because of this, the target axis could still be colinear but pass the check. */ +#if 1 /* Reproduce C API behavior. Do not normalize other axes. */ + switch (axis) { + case Axis::X: + R.y = mat.y_axis(); + R.z = mat.z_axis(); + break; + case Axis::Y: + R.x = mat.x_axis(); + R.z = mat.z_axis(); + break; + case Axis::Z: + R.x = mat.x_axis(); + R.y = mat.y_axis(); + break; + } +#endif + + /** + * The secondary axis is chosen as follow (X->Y, Y->X, Z->X). + * If this axis is co-planar try the third axis. + * If also co-planar, make up an axis by shuffling the primary axis coordinates (XYZ > YZX). + */ + switch (axis) { + case Axis::X: + if (dot(R.x, R.y) < T(1)) { + R.z = normalize(cross(R.x, R.y)); + R.y = cross(R.z, R.x); + } + else if (dot(R.x, R.z) < T(1)) { + R.y = normalize(cross(R.z, R.x)); + R.z = cross(R.x, R.y); + } + else { + R.z = normalize(cross(R.x, Vec3T(R.x.y, R.x.z, R.x.x))); + R.y = cross(R.z, R.x); + } + break; + case Axis::Y: + if (dot(R.y, R.x) < T(1)) { + R.z = normalize(cross(R.x, R.y)); + R.x = cross(R.y, R.z); + } + /* FIXME(fclem): THIS IS WRONG. Should be dot(R.y, R.z). Following C code for now... */ + else if (dot(R.x, R.z) < T(1)) { + R.x = normalize(cross(R.y, R.z)); + R.z = cross(R.x, R.y); + } + else { + R.x = normalize(cross(R.y, Vec3T(R.y.y, R.y.z, R.y.x))); + R.z = cross(R.x, R.y); + } + break; + case Axis::Z: + if (dot(R.z, R.x) < T(1)) { + R.y = normalize(cross(R.z, R.x)); + R.x = cross(R.y, R.z); + } + else if (dot(R.z, R.y) < T(1)) { + R.x = normalize(cross(R.y, R.z)); + R.y = cross(R.z, R.x); + } + else { + R.x = normalize(cross(Vec3T(R.z.y, R.z.z, R.z.x), R.z)); + R.y = cross(R.z, R.x); + } + break; + default: + BLI_assert_unreachable(); + break; + } + /* Reapply the lost scale. */ + R.x *= scale.x; + R.y *= scale.y; + R.z *= scale.z; + + MatT result(R); + result.location() = mat.location(); + return result; +} + template [[nodiscard]] MatT from_origin_transform(const MatT &transform, const VectorT origin) { diff --git a/source/blender/blenlib/BLI_math_quaternion.hh b/source/blender/blenlib/BLI_math_quaternion.hh new file mode 100644 index 00000000000..02383d03d7c --- /dev/null +++ b/source/blender/blenlib/BLI_math_quaternion.hh @@ -0,0 +1,698 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + */ + +#include "BLI_math_axis_angle_types.hh" +#include "BLI_math_euler_types.hh" +#include "BLI_math_quaternion_types.hh" + +#include "BLI_math_matrix.hh" + +namespace blender::math { + +/* -------------------------------------------------------------------- */ +/** \name Quaternion functions. + * \{ */ + +/** + * Dot product between two quaternions. + * Equivalent to vector dot product. + * Equivalent to component wise multiplication followed by summation of the result. + */ +template +[[nodiscard]] inline T dot(const QuaternionBase &a, const QuaternionBase &b); + +/** + * Raise a unit #Quaternion \a q to the real \a y exponent. + * \note This only works on unit quaternions and y != 0. + * \note This is not a per component power. + */ +template [[nodiscard]] QuaternionBase pow(const QuaternionBase &q, const T &y); + +/** + * Return the conjugate of the given quaternion. + * If the quaternion \a q represent the rotation from A to B, + * then the conjugate of \a q represents the rotation from B to A. + */ +template [[nodiscard]] inline QuaternionBase conjugate(const QuaternionBase &a); + +/** + * Negate the quaternion if real component (w) is negative. + */ +template +[[nodiscard]] inline QuaternionBase canonicalize(const QuaternionBase &q); + +/** + * Return invert of \a q or identity if \a q is ill-formed. + * The invert allows quaternion division. + * \note The inverse of \a q isn't the opposite rotation. This would be the conjugate. + */ +template [[nodiscard]] inline QuaternionBase invert(const QuaternionBase &q); + +/** + * Return invert of \a q assuming it is a unit quaternion. + * In this case, the inverse is just the conjugate. `conjugate(q)` could be use directly, + * but this function shows the intent better, and asserts if \a q ever becomes non-unit-length. + */ +template +[[nodiscard]] inline QuaternionBase invert_normalized(const QuaternionBase &q); + +/** + * Return a unit quaternion representing the same rotation as \a q or + * the identity quaternion if \a q is ill-formed. + */ +template [[nodiscard]] inline QuaternionBase normalize(const QuaternionBase &q); +template +[[nodiscard]] inline QuaternionBase normalize_and_get_length(const QuaternionBase &q, + T &out_length); + +/** + * Use spherical interpolation between two quaternions. + * Always interpolate along the shortest angle. + */ +template +[[nodiscard]] inline QuaternionBase interpolate(const QuaternionBase &a, + const QuaternionBase &b, + T t); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform functions. + * \{ */ + +/** + * Transform \a v by rotation using the quaternion \a q . + */ +template +[[nodiscard]] inline VecBase transform_point(const QuaternionBase &q, + const VecBase &v); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Test functions. + * \{ */ + +/** + * Returns true if all components are exactly equal to 0. + */ +template [[nodiscard]] inline bool is_zero(const QuaternionBase &q) +{ + return q.w == T(0) && q.x == T(0) && q.y == T(0) && q.z == T(0); +} + +/** + * Returns true if the quaternions are equal within the given epsilon. Return false otherwise. + */ +template +[[nodiscard]] inline bool is_equal(const QuaternionBase &a, + const QuaternionBase &b, + const T epsilon = T(0)) +{ + return math::abs(a.w - b.w) <= epsilon && math::abs(a.y - b.y) <= epsilon && + math::abs(a.x - b.x) <= epsilon && math::abs(a.z - b.z) <= epsilon; +} + +template [[nodiscard]] inline bool is_unit_scale(const QuaternionBase &q) +{ + /* Checks are flipped so NAN doesn't assert because we're making sure the value was + * normalized and in the case we don't want NAN to be raising asserts since there + * is nothing to be done in that case. */ + const T test_unit = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w; + return (!(math::abs(test_unit - T(1)) >= AssertUnitEpsilon>::value) || + !(math::abs(test_unit) >= AssertUnitEpsilon>::value)); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Quaternion + * \{ */ + +/* -------------- Conversions -------------- */ + +template AngleRadianBase QuaternionBase::twist_angle(const Axis axis) const +{ + /* The calculation requires a canonical quaternion. */ + const VecBase input_vec(canonicalize(*this)); + + return T(2) * AngleRadianBase(input_vec[0], input_vec.yzw()[axis.as_int()]); +} + +template QuaternionBase QuaternionBase::swing(const Axis axis) const +{ + /* The calculation requires a canonical quaternion. */ + const QuaternionBase input = canonicalize(*this); + /* Compute swing by multiplying the original quaternion by inverted twist. */ + QuaternionBase swing = input * invert_normalized(input.twist(axis)); + + BLI_assert(math::abs(VecBase(swing)[axis.as_int() + 1]) < BLI_ASSERT_UNIT_EPSILON); + return swing; +} + +template QuaternionBase QuaternionBase::twist(const Axis axis) const +{ + /* The calculation requires a canonical quaternion. */ + const VecBase input_vec(canonicalize(*this)); + + AngleCartesianBase half_angle = AngleCartesianBase::from_point( + input_vec[0], input_vec.yzw()[axis.as_int()]); + + VecBase twist(half_angle.cos(), T(0), T(0), T(0)); + twist[axis.as_int() + 1] = half_angle.sin(); + return QuaternionBase(twist); +} + +/* -------------- Methods -------------- */ + +template +QuaternionBase QuaternionBase::wrapped_around(const QuaternionBase &reference) const +{ + BLI_assert(is_unit_scale(*this)); + const QuaternionBase &input = *this; + T len; + QuaternionBase reference_normalized = normalize_and_get_length(reference, len); + /* Skips degenerate case. */ + if (len < 1e-4f) { + return input; + } + QuaternionBase result = reference * invert_normalized(reference_normalized) * input; + return (distance_squared(VecBase(-result), VecBase(reference)) < + distance_squared(VecBase(result), VecBase(reference))) ? + -result : + result; +} + +/* -------------- Functions -------------- */ + +template +[[nodiscard]] inline T dot(const QuaternionBase &a, const QuaternionBase &b) +{ + return a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z; +} + +template [[nodiscard]] QuaternionBase pow(const QuaternionBase &q, const T &y) +{ + BLI_assert(is_unit_scale(q)); + /* Reference material: + * https://en.wikipedia.org/wiki/Quaternion + * + * The power of a quaternion raised to an arbitrary (real) exponent y is given by: + * `q^x = ||q||^y * (cos(y * angle * 0.5) + n * sin(y * angle * 0.5))` + * where `n` is the unit vector from the imaginary part of the quaternion and + * where `angle` is the angle of the rotation given by `angle = 2 * acos(q.w)`. + * + * q being a unit quaternion, ||q||^y becomes 1 and is canceled out. + * + * `y * angle * 0.5` expands to `y * 2 * acos(q.w) * 0.5` which simplifies to `y * acos(q.w)`. + */ + const T half_angle = y * math::safe_acos(q.w); + return {math::cos(half_angle), math::sin(half_angle) * normalize(q.imaginary_part())}; +} + +template [[nodiscard]] inline QuaternionBase conjugate(const QuaternionBase &a) +{ + return {a.w, -a.x, -a.y, -a.z}; +} + +template +[[nodiscard]] inline QuaternionBase canonicalize(const QuaternionBase &q) +{ + return (q.w < T(0)) ? -q : q; +} + +template [[nodiscard]] inline QuaternionBase invert(const QuaternionBase &q) +{ + const T length_squared = dot(q, q); + if (length_squared == T(0)) { + return QuaternionBase::identity(); + } + return conjugate(q) * (T(1) / length_squared); +} + +template +[[nodiscard]] inline QuaternionBase invert_normalized(const QuaternionBase &q) +{ + BLI_assert(is_unit_scale(q)); + return conjugate(q); +} + +template +[[nodiscard]] inline QuaternionBase normalize_and_get_length(const QuaternionBase &q, + T &out_length) +{ + out_length = math::sqrt(dot(q, q)); + return (out_length != T(0)) ? (q * (T(1) / out_length)) : QuaternionBase::identity(); +} + +template [[nodiscard]] inline QuaternionBase normalize(const QuaternionBase &q) +{ + T len; + return normalize_and_get_length(q, len); +} + +/** + * Generic function for implementing slerp + * (quaternions and spherical vector coords). + * + * \param t: factor in [0..1] + * \param cosom: dot product from normalized quaternions. + * \return calculated weights. + */ +template +[[nodiscard]] inline VecBase interpolate_dot_slerp(const T t, const T cosom) +{ + const T eps = T(1e-4); + + BLI_assert(IN_RANGE_INCL(cosom, T(-1.0001), T(1.0001))); + + VecBase w; + T abs_cosom = math::abs(cosom); + /* Within [-1..1] range, avoid aligned axis. */ + if (LIKELY(abs_cosom < (T(1) - eps))) { + const T omega = math::acos(abs_cosom); + const T sinom = math::sin(omega); + + w[0] = math::sin((T(1) - t) * omega) / sinom; + w[1] = math::sin(t * omega) / sinom; + } + else { + /* Fallback to lerp */ + w[0] = T(1) - t; + w[1] = t; + } + + /* Rotate around shortest angle. */ + if (cosom < T(0)) { + w[0] = -w[0]; + } + return w; +} + +template +[[nodiscard]] inline QuaternionBase interpolate(const QuaternionBase &a, + const QuaternionBase &b, + T t) +{ + using Vec4T = VecBase; + BLI_assert(is_unit_scale(a)); + BLI_assert(is_unit_scale(b)); + VecBase w = interpolate_dot_slerp(t, dot(a, b)); + return QuaternionBase(w[0] * Vec4T(a) + w[1] * Vec4T(b)); +} + +template +[[nodiscard]] inline VecBase transform_point(const QuaternionBase &q, + const VecBase &v) +{ +#if 0 /* Reference. */ + QuaternionBase V(T(0), UNPACK3(v)); + QuaternionBase R = q * V * conjugate(q); + return {R.x, R.y, R.z}; +#else + /* `S = q * V` */ + QuaternionBase S; + S.w = /* q.w * 0.0 */ -q.x * v.x - q.y * v.y - q.z * v.z; + S.x = q.w * v.x /* + q.x * 0.0 */ + q.y * v.z - q.z * v.y; + S.y = q.w * v.y /* + q.y * 0.0 */ + q.z * v.x - q.x * v.z; + S.z = q.w * v.z /* + q.z * 0.0 */ + q.x * v.y - q.y * v.x; + /* `R = S * conjugate(q)` */ + VecBase R; + /* R.w = S.w * q.w + S.x * q.x + S.y * q.y + S.z * q.z = 0.0; */ + R.x = S.w * -q.x + S.x * q.w - S.y * q.z + S.z * q.y; + R.y = S.w * -q.y + S.y * q.w - S.z * q.x + S.x * q.z; + R.z = S.w * -q.z + S.z * q.w - S.x * q.y + S.y * q.x; + return R; +#endif +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dual-Quaternion + * \{ */ + +/* -------------- Constructors -------------- */ + +template +DualQuaternionBase::DualQuaternionBase(const QuaternionBase &non_dual, + const QuaternionBase &dual) + : quat(non_dual), trans(dual), scale_weight(0), quat_weight(1) +{ + BLI_assert(is_unit_scale(non_dual)); +} + +template +DualQuaternionBase::DualQuaternionBase(const QuaternionBase &non_dual, + const QuaternionBase &dual, + const MatBase &scale_mat) + : quat(non_dual), trans(dual), scale(scale_mat), scale_weight(1), quat_weight(1) +{ + BLI_assert(is_unit_scale(non_dual)); +} + +/* -------------- Operators -------------- */ + +template +DualQuaternionBase &DualQuaternionBase::operator+=(const DualQuaternionBase &b) +{ + DualQuaternionBase &a = *this; + /* Sum rotation and translation. */ + + /* Make sure we interpolate quaternions in the right direction. */ + if (dot(a.quat, b.quat) < 0) { + a.quat.w -= b.quat.w; + a.quat.x -= b.quat.x; + a.quat.y -= b.quat.y; + a.quat.z -= b.quat.z; + + a.trans.w -= b.trans.w; + a.trans.x -= b.trans.x; + a.trans.y -= b.trans.y; + a.trans.z -= b.trans.z; + } + else { + a.quat.w += b.quat.w; + a.quat.x += b.quat.x; + a.quat.y += b.quat.y; + a.quat.z += b.quat.z; + + a.trans.w += b.trans.w; + a.trans.x += b.trans.x; + a.trans.y += b.trans.y; + a.trans.z += b.trans.z; + } + + a.quat_weight += b.quat_weight; + + if (b.scale_weight > T(0)) { + if (a.scale_weight > T(0)) { + /* Weighted sum of scale matrices (sum of components). */ + a.scale += b.scale; + a.scale_weight += b.scale_weight; + } + else { + /* No existing scale. Replace. */ + a.scale = b.scale; + a.scale_weight = b.scale_weight; + } + } + return *this; +} + +template DualQuaternionBase &DualQuaternionBase::operator*=(const T &t) +{ + BLI_assert(t >= 0); + DualQuaternionBase &q = *this; + + q.quat.w *= t; + q.quat.x *= t; + q.quat.y *= t; + q.quat.z *= t; + + q.trans.w *= t; + q.trans.x *= t; + q.trans.y *= t; + q.trans.z *= t; + + q.quat_weight *= t; + + if (q.scale_weight > T(0)) { + q.scale *= t; + q.scale_weight *= t; + } + return *this; +} + +/* -------------- Functions -------------- */ + +/** + * Apply all accumulated weights to the dual-quaternions. + * Also make sure the rotation quaternions is normalized. + * \note The C version of this function does not normalize the quaternion. This makes other + * operations like transform and matrix conversion more complex. + * \note Returns identity #DualQuaternion if degenerate. + */ +template +[[nodiscard]] DualQuaternionBase normalize(const DualQuaternionBase &dual_quat) +{ + const T norm_weighted = math::sqrt(dot(dual_quat.quat, dual_quat.quat)); + /* NOTE(fclem): Should this be an epsilon? */ + if (norm_weighted == T(0)) { + /* The dual-quaternion was zero initialized or is degenerate. Return identity. */ + return DualQuaternionBase::identity(); + } + + const T inv_norm_weighted = T(1) / norm_weighted; + + DualQuaternionBase dq = dual_quat; + dq.quat = dq.quat * inv_norm_weighted; + dq.trans = dq.trans * inv_norm_weighted; + + /* Handle scale if needed. */ + if (dq.scale_weight > T(0)) { + /* Compensate for any dual quaternions added without scale. + * This is an optimization so that we can skip the scale part when not needed. */ + const float missing_uniform_scale = dq.quat_weight - dq.scale_weight; + + if (missing_uniform_scale > T(0)) { + dq.scale[0][0] += missing_uniform_scale; + dq.scale[1][1] += missing_uniform_scale; + dq.scale[2][2] += missing_uniform_scale; + dq.scale[3][3] += missing_uniform_scale; + } + /* Per component scalar product. */ + dq.scale *= T(1) / dq.quat_weight; + dq.scale_weight = T(1); + } + dq.quat_weight = T(1); + return dq; +} + +/** + * Transform \a point using the dual-quaternion \a dq . + * Applying the #DualQuaternion transform can only happen if the #DualQuaternion was normalized + * first. Optionally outputs crazy space matrix. + */ +template +[[nodiscard]] VecBase transform_point(const DualQuaternionBase &dq, + const VecBase &point, + MatBase *r_crazy_space_mat = nullptr) +{ + BLI_assert(is_normalized(dq)); + BLI_assert(is_unit_scale(dq.quat)); + /** + * From: + * "Skinning with Dual Quaternions" + * Ladislav Kavan, Steven Collins, Jiri Zara, Carol O'Sullivan + * Trinity College Dublin, Czech Technical University in Prague + */ + /* Follow the paper notation. */ + const T &w0 = dq.quat.w, &x0 = dq.quat.x, &y0 = dq.quat.y, &z0 = dq.quat.z; + const T &we = dq.trans.w, &xe = dq.trans.x, &ye = dq.trans.y, &ze = dq.trans.z; + /* Part 3.4 - The Final Algorithm. */ + VecBase t; + t[0] = T(2) * (-we * x0 + xe * w0 - ye * z0 + ze * y0); + t[1] = T(2) * (-we * y0 + xe * z0 + ye * w0 - ze * x0); + t[2] = T(2) * (-we * z0 - xe * y0 + ye * x0 + ze * w0); + /* Isolate rotation matrix to easily output crazy-space mat. */ + MatBase M; + M[0][0] = (w0 * w0) + (x0 * x0) - (y0 * y0) - (z0 * z0); /* Same as `1 - 2y0^2 - 2z0^2`. */ + M[0][1] = T(2) * ((x0 * y0) + (w0 * z0)); + M[0][2] = T(2) * ((x0 * z0) - (w0 * y0)); + + M[1][0] = T(2) * ((x0 * y0) - (w0 * z0)); + M[1][1] = (w0 * w0) + (y0 * y0) - (x0 * x0) - (z0 * z0); /* Same as `1 - 2x0^2 - 2z0^2`. */ + M[1][2] = T(2) * ((y0 * z0) + (w0 * x0)); + + M[2][1] = T(2) * ((y0 * z0) - (w0 * x0)); + M[2][2] = (w0 * w0) + (z0 * z0) - (x0 * x0) - (y0 * y0); /* Same as `1 - 2x0^2 - 2y0^2`. */ + M[2][0] = T(2) * ((x0 * z0) + (w0 * y0)); + + VecBase result = point; + /* Apply scaling. */ + if (dq.scale_weight != T(0)) { + /* NOTE(fclem): This is weird that this is also adding translation even if it is marked as + * scale matrix. Follows the old C implementation for now... */ + result = transform_point(dq.scale, result); + } + /* Apply rotation and translation. */ + result = transform_point(M, result) + t; + /* Compute crazy-space correction matrix. */ + if (r_crazy_space_mat != nullptr) { + if (dq.scale_weight) { + *r_crazy_space_mat = M * dq.scale.template view<3, 3>(); + } + else { + *r_crazy_space_mat = M; + } + } + return result; +} + +/** + * Convert transformation \a mat with parent transform \a basemat into a dual-quaternion + * representation. + * + * This allows volume preserving deformation for skinning. + */ +template +[[nodiscard]] DualQuaternionBase to_dual_quaternion(const MatBase &mat, + const MatBase &basemat) +{ + /** + * Conversion routines between (regular quaternion, translation) and dual quaternion. + * + * Version 1.0.0, February 7th, 2007 + * + * SPDX-License-Identifier: Zlib + * Copyright 2006-2007 University of Dublin, Trinity College, All Rights Reserved. + * + * Changes for Blender: + * - renaming, style changes and optimizations + * - added support for scaling + */ + using Mat4T = MatBase; + using Vec3T = VecBase; + + /* Split scaling and rotation. + * There is probably a faster way to do this. It is currently done like this to correctly get + * negative scaling. */ + Mat4T baseRS = mat * basemat; + + Mat4T R, scale; + const bool has_scale = !is_orthonormal(mat) || is_negative(mat) || + length_squared(to_scale(baseRS) - T(1)) > square_f(1e-4f); + if (has_scale) { + /* Extract Rotation and Scale. */ + const Mat4T baseinv = invert(basemat); + + /* Extra orthogonalize, to avoid flipping with stretched bones. */ + QuaternionBase basequat = to_quaternion(normalize(orthogonalize(baseRS, Axis::Y))); + + Mat4T baseR = from_rotation(basequat); + baseR.location() = baseRS.location(); + + R = baseR * baseinv; + + const Mat4T S = invert(baseR) * baseRS; + /* Set scaling part. */ + scale = basemat * S * baseinv; + } + else { + /* Input matrix does not contain scaling. */ + R = mat; + } + + /* Non-dual part. */ + const QuaternionBase q = to_quaternion(normalize(R)); + + /* Dual part. */ + const Vec3T &t = R.location().xyz(); + QuaternionBase d; + d.w = T(-0.5) * (+t.x * q.x + t.y * q.y + t.z * q.z); + d.x = T(+0.5) * (+t.x * q.w + t.y * q.z - t.z * q.y); + d.y = T(+0.5) * (-t.x * q.z + t.y * q.w + t.z * q.x); + d.z = T(+0.5) * (+t.x * q.y - t.y * q.x + t.z * q.w); + + if (has_scale) { + return DualQuaternionBase(q, d, scale); + } + + return DualQuaternionBase(q, d); +} + +/** \} */ + +} // namespace blender::math + +namespace blender::math { + +/* -------------------------------------------------------------------- */ +/** \name Conversion to Euler + * \{ */ + +template +AxisAngleBase to_axis_angle(const QuaternionBase &quat) +{ + BLI_assert(is_unit_scale(quat)); + + VecBase axis = VecBase(quat.x, quat.y, quat.z); + T cos_half_angle = quat.w; + T sin_half_angle = math::length(axis); + /* Prevent division by zero for axis conversion. */ + if (sin_half_angle < T(0.0005)) { + sin_half_angle = T(1); + axis[1] = T(1); + } + /* Normalize the axis. */ + axis /= sin_half_angle; + + /* Leverage AngleT implementation of double angle. */ + AngleT angle = AngleT(cos_half_angle, sin_half_angle) * 2; + + return AxisAngleBase(axis, angle); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversion to Euler + * \{ */ + +template EulerXYZBase to_euler(const QuaternionBase &quat) +{ + using Mat3T = MatBase; + BLI_assert(is_unit_scale(quat)); + Mat3T unit_mat = from_rotation(quat); + return to_euler(unit_mat); +} + +template Euler3Base to_euler(const QuaternionBase &quat, EulerOrder order) +{ + using Mat3T = MatBase; + BLI_assert(is_unit_scale(quat)); + Mat3T unit_mat = from_rotation(quat); + return to_euler(unit_mat, order); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversion from/to Expmap + * \{ */ + +/* Prototype needed to avoid interdependencies of headers. */ +template +QuaternionBase to_quaternion(const AxisAngleBase &axis_angle); + +template QuaternionBase QuaternionBase::expmap(const VecBase &expmap) +{ + using AxisAngleT = AxisAngleBase>; + /* Obtain axis/angle representation. */ + T angle; + const VecBase axis = normalize_and_get_length(expmap, angle); + if (LIKELY(angle != T(0))) { + return to_quaternion(AxisAngleT(axis, angle_wrap_rad(angle))); + } + return QuaternionBase::identity(); +} + +template VecBase QuaternionBase::expmap() const +{ + using AxisAngleT = AxisAngleBase>; + BLI_assert(is_unit_scale(*this)); + const AxisAngleT axis_angle = to_axis_angle(*this); + return axis_angle.axis() * axis_angle.angle().radian(); +} + +/** \} */ + +} // namespace blender::math + +/** \} */ diff --git a/source/blender/blenlib/BLI_math_quaternion_types.hh b/source/blender/blenlib/BLI_math_quaternion_types.hh new file mode 100644 index 00000000000..d06d7cf8e11 --- /dev/null +++ b/source/blender/blenlib/BLI_math_quaternion_types.hh @@ -0,0 +1,310 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +/** \file + * \ingroup bli + */ + +#include "BLI_math_angle_types.hh" +#include "BLI_math_base.hh" +#include "BLI_math_basis_types.hh" +#include "BLI_math_matrix_types.hh" +#include "BLI_math_vector_types.hh" + +namespace blender::math { + +/* -------------------------------------------------------------------- */ +/** \name Quaternion + * \{ */ + +/** + * A `blender::math::QuaternionBase` represents either an orientation or a rotation. + * + * Mainly used for rigging and armature deformations as they have nice mathematical properties + * (eg: smooth shortest path interpolation). A `blender::math::QuaternionBase` is cheaper to + * combine than `MatBase`. However, transforming points is slower. Consider converting to + * a rotation matrix if you are rotating many points. + * + * See this for more information: + * https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Performance_comparisons + */ +template struct QuaternionBase { + T w, x, y, z; + + QuaternionBase() = default; + + QuaternionBase(const T &new_w, const T &new_x, const T &new_y, const T &new_z) + : w(new_w), x(new_x), y(new_y), z(new_z){}; + + /** + * Creates a quaternion from an vector without reordering the components. + * \note Component order must follow the scalar constructor (w, x, y, z). + */ + explicit QuaternionBase(const VecBase &vec) : QuaternionBase(UNPACK4(vec)){}; + + /** + * Creates a quaternion from real (w) and imaginary parts (x, y, z). + */ + QuaternionBase(const T &real, const VecBase &imaginary) + : QuaternionBase(real, UNPACK3(imaginary)){}; + + /** Static functions. */ + + static QuaternionBase identity() + { + return {1, 0, 0, 0}; + } + + /** This is just for convenience. Does not represent a rotation as it is degenerate. */ + static QuaternionBase zero() + { + return {0, 0, 0, 0}; + } + + /** + * Create a quaternion from an exponential map representation. + * An exponential map is basically the rotation axis multiplied by the rotation angle. + */ + static QuaternionBase expmap(const VecBase &expmap); + + /** Conversions. */ + + explicit operator VecBase() const + { + return {this->w, this->x, this->y, this->z}; + } + + /** + * Create an exponential map representation of this quaternion. + * An exponential map is basically the rotation axis multiplied by the rotation angle. + */ + VecBase expmap() const; + + /** + * Returns the full twist angle for a given \a axis direction. + * The twist is the isolated rotation in the plane whose \a axis is normal to. + */ + AngleRadianBase twist_angle(const Axis axis) const; + + /** + * Returns the twist part of this quaternion for the \a axis direction. + * The twist is the isolated rotation in the plane whose \a axis is normal to. + */ + QuaternionBase twist(const Axis axis) const; + + /** + * Returns the swing part of this quaternion for the basis \a axis direction. + * The swing is the original quaternion minus the twist around \a axis. + * So we have the following identity : `q = q.swing(axis) * q.twist(axis)` + */ + QuaternionBase swing(const Axis axis) const; + + /** + * Returns the imaginary part of this quaternion (x, y, z). + */ + const VecBase &imaginary_part() const + { + return *reinterpret_cast *>(&x); + } + VecBase &imaginary_part() + { + return *reinterpret_cast *>(&x); + } + + /** Methods. */ + + /** + * Return this quaternions orientation but wrapped around \a reference. + * + * This means the interpolation between the returned value and \a reference will always take the + * shortest path. The angle between them will not be more than pi. + * + * \note This quaternion is expected to be a unit quaternion. + * \note Works even if \a reference is *not* a unit quaternion. + */ + QuaternionBase wrapped_around(const QuaternionBase &reference) const; + + /** Operators. */ + + friend QuaternionBase operator*(const QuaternionBase &a, const QuaternionBase &b) + { + return {a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z, + a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y, + a.w * b.y + a.y * b.w + a.z * b.x - a.x * b.z, + a.w * b.z + a.z * b.w + a.x * b.y - a.y * b.x}; + } + + QuaternionBase &operator*=(const QuaternionBase &b) + { + *this = *this * b; + return *this; + } + + /* Scalar product. */ + friend QuaternionBase operator*(const QuaternionBase &a, const T &b) + { + return {a.w * b, a.x * b, a.y * b, a.z * b}; + } + + /* Negate the quaternion. */ + friend QuaternionBase operator-(const QuaternionBase &a) + { + return {-a.w, -a.x, -a.y, -a.z}; + } + + friend bool operator==(const QuaternionBase &a, const QuaternionBase &b) + { + return (a.w == b.w) && (a.x == b.x) && (a.y == b.y) && (a.z == b.z); + } + + friend std::ostream &operator<<(std::ostream &stream, const QuaternionBase &rot) + { + return stream << "Quaternion" << static_cast>(rot); + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dual-Quaternion + * \{ */ + +/** + * A `blender::math::DualQuaternionBase` implements dual-quaternion skinning with scale aware + * transformation. It allows volume preserving deformation for skinning. + * + * The type is implemented so that multiple weighted `blender::math::DualQuaternionBase` + * can be aggregated into a final rotation. Calling `normalize(dual_quat)` is mandatory before + * trying to transform points with it. + */ +template struct DualQuaternionBase { + /** Non-dual part. */ + QuaternionBase quat; + /** Dual part. */ + QuaternionBase trans; + + /** + * Scaling is saved separately to handle cases of non orthonormal axes, non uniform scale and + * flipped axes. + */ + /* TODO(fclem): Can this be replaced by a Mat3x3 ? + * It currently holds some translation in some cases. Is this wanted? + * This would save some flops all along the way. */ + MatBase scale; + /** The weight of #DualQuaternionBase.scale. Set to 0 if uniformly scaled to skip `scale` sum. */ + T scale_weight; + /** + * The weight of this dual-quaternion. Used for and summation & normalizing. + * A weight of 0 means the quaternion is not valid. + */ + T quat_weight; + + DualQuaternionBase() = delete; + + /** + * Dual quaternion without scaling. + */ + DualQuaternionBase(const QuaternionBase &non_dual, const QuaternionBase &dual); + + /** + * Dual quaternion with scaling. + */ + DualQuaternionBase(const QuaternionBase &non_dual, + const QuaternionBase &dual, + const MatBase &scale_mat); + + /** Static functions. */ + + static DualQuaternionBase identity() + { + return DualQuaternionBase(QuaternionBase::identity(), QuaternionBase::zero()); + } + + /** Methods. */ + + /** Operators. */ + + /** Apply a scalar weight to a dual quaternion. */ + DualQuaternionBase &operator*=(const T &t); + + /** Add two weighted dual-quaternions rotations. */ + DualQuaternionBase &operator+=(const DualQuaternionBase &b); + + /** Apply a scalar weight to a dual quaternion. */ + friend DualQuaternionBase operator*(const DualQuaternionBase &a, const T &t) + { + DualQuaternionBase dq = a; + dq *= t; + return dq; + } + + /** Apply a scalar weight to a dual quaternion. */ + friend DualQuaternionBase operator*(const T &t, const DualQuaternionBase &a) + { + DualQuaternionBase dq = a; + dq *= t; + return dq; + } + + /** Add two weighted dual-quaternions rotations. */ + friend DualQuaternionBase operator+(const DualQuaternionBase &a, const DualQuaternionBase &b) + { + DualQuaternionBase dq = a; + dq += b; + return dq; + } + + friend bool operator==(const DualQuaternionBase &a, const DualQuaternionBase &b) + { + return (a.quat == b.quat) && (a.trans == b.trans) && (a.quat_weight == b.quat_weight) && + (a.scale_weight == b.scale_weight) && (a.scale == b.scale); + } + + friend std::ostream &operator<<(std::ostream &stream, const DualQuaternionBase &rot) + { + stream << "DualQuaternion(\n"; + stream << " .quat = " << rot.quat << "\n"; + stream << " .trans = " << rot.trans << "\n"; + if (rot.scale_weight != T(0)) { + stream << " .scale = " << rot.scale; + stream << " .scale_weight = " << rot.scale_weight << "\n"; + } + stream << " .quat_weight = " << rot.quat_weight << "\n)\n"; + return stream; + } +}; + +/** + * Returns true if the #DualQuaternion has not been mixed with other #DualQuaternion and needs no + * normalization. + */ +template [[nodiscard]] inline bool is_normalized(const DualQuaternionBase &dq) +{ + return dq.quat_weight == T(1); +} + +/** \} */ + +template struct AssertUnitEpsilon> { + static constexpr U value = AssertUnitEpsilon::value * 10; +}; + +/** + * Intermediate Types. + * + * Some functions need to have higher precision than standard floats for some operations. + */ +template struct TypeTraits { + using DoublePrecision = T; +}; +template<> struct TypeTraits { + using DoublePrecision = double; +}; + +using Quaternion = QuaternionBase; +using DualQuaternion = DualQuaternionBase; + +} // namespace blender::math + +/** \} */ diff --git a/source/blender/blenlib/BLI_math_rotation.hh b/source/blender/blenlib/BLI_math_rotation.hh index cecdec1e90c..9276e2713d6 100644 --- a/source/blender/blenlib/BLI_math_rotation.hh +++ b/source/blender/blenlib/BLI_math_rotation.hh @@ -6,237 +6,475 @@ * \ingroup bli */ -#include "BLI_math_matrix.hh" #include "BLI_math_rotation_types.hh" + +#include "BLI_math_axis_angle.hh" +#include "BLI_math_euler.hh" +#include "BLI_math_matrix.hh" +#include "BLI_math_quaternion.hh" #include "BLI_math_vector.hh" namespace blender::math { +/* -------------------------------------------------------------------- */ +/** \name Rotation helpers + * \{ */ + /** - * Generic function for implementing slerp - * (quaternions and spherical vector coords). + * Rotate \a a by \a b. In other word, insert the \a b rotation before \a a. * - * \param t: factor in [0..1] - * \param cosom: dot product from normalized vectors/quats. - * \param r_w: calculated weights. + * \note Since \a a is a #Quaternion it will cast \a b to a #Quaternion. + * This might introduce some precision loss and have performance implication. */ -template inline VecBase interpolate_dot_slerp(const T t, const T cosom) -{ - const T eps = T(1e-4); +template +[[nodiscard]] QuaternionBase rotate(const QuaternionBase &a, const RotT &b); - BLI_assert(IN_RANGE_INCL(cosom, T(-1.0001), T(1.0001))); +/** + * Rotate \a a by \a b. In other word, insert the \a b rotation before \a a. + * + * \note Since \a a is an #AxisAngle it will cast both \a a and \a b to #Quaternion. + * This might introduce some precision loss and have performance implication. + */ +template +[[nodiscard]] AxisAngleBase rotate(const AxisAngleBase &a, const RotT &b); - VecBase w; - /* Within [-1..1] range, avoid aligned axis. */ - if (LIKELY(math::abs(cosom) < (T(1) - eps))) { - const T omega = math::acos(cosom); - const T sinom = math::sin(omega); +/** + * Rotate \a a by \a b. In other word, insert the \a b rotation before \a a. + * + * \note Since \a a is an #EulerXYZ it will cast both \a a and \a b to #MatBase. + * This might introduce some precision loss and have performance implication. + */ +template +[[nodiscard]] EulerXYZBase rotate(const EulerXYZBase &a, const RotT &b); - w[0] = math::sin((T(1) - t) * omega) / sinom; - w[1] = math::sin(t * omega) / sinom; - } - else { - /* Fallback to lerp */ - w[0] = T(1) - t; - w[1] = t; - } - return w; -} +/** + * Rotate \a a by \a b. In other word, insert the \a b rotation before \a a. + * + * \note Since \a a is an #Euler3 it will cast both \a a and \a b to #MatBase. + * This might introduce some precision loss and have performance implication. + */ +template +[[nodiscard]] Euler3Base rotate(const Euler3Base &a, const RotT &b); +/** + * Return rotation from orientation \a a to orientation \a b into another quaternion. + */ template -inline detail::Quaternion interpolate(const detail::Quaternion &a, - const detail::Quaternion &b, - T t) +[[nodiscard]] QuaternionBase rotation_between(const QuaternionBase &a, + const QuaternionBase &b); + +/** + * Create a orientation from a triangle plane and the axis formed by the segment(v1, v2). + * Takes pre-computed \a normal from the triangle. + * Used for Ngons when their normal is known. + */ +template +[[nodiscard]] QuaternionBase from_triangle(const VecBase &v1, + const VecBase &v2, + const VecBase &v3, + const VecBase &normal); + +/** + * Create a orientation from a triangle plane and the axis formed by the segment(v1, v2). + */ +template +[[nodiscard]] QuaternionBase from_triangle(const VecBase &v1, + const VecBase &v2, + const VecBase &v3); + +/** + * Create a rotation from a vector and a basis rotation. + * Used for tracking. + * \a track_flag is supposed to be #Object.trackflag + * \a up_flag is supposed to be #Object.upflag + */ +template +[[nodiscard]] QuaternionBase from_vector(const VecBase &vector, + const AxisSigned track_flag, + const Axis up_flag); + +/** + * Returns a quaternion for converting local space to tracking space. + * This is slightly different than from_axis_conversion for legacy reasons. + */ +template +[[nodiscard]] QuaternionBase from_tracking(AxisSigned forward_axis, Axis up_axis); + +/** + * Convert euler rotation to gimbal rotation matrix. + */ +template [[nodiscard]] MatBase to_gimbal_axis(const Euler3Base &rotation); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Angles + * \{ */ + +/** + * Extract rotation angle from a unit quaternion. + * Returned angle is in [0..2pi] range. + * + * Unlike the angle between vectors, this does *NOT* return the shortest angle. + * See `angle_of_signed` below for this. + */ +template [[nodiscard]] AngleRadianBase angle_of(const QuaternionBase &q) { - using Vec4T = VecBase; - BLI_assert(is_unit_scale(Vec4T(a))); - BLI_assert(is_unit_scale(Vec4T(b))); - - Vec4T quat = Vec4T(a); - T cosom = dot(Vec4T(a), Vec4T(b)); - /* Rotate around shortest angle. */ - if (cosom < T(0)) { - cosom = -cosom; - quat = -quat; - } - - VecBase w = interpolate_dot_slerp(t, cosom); - - return detail::Quaternion(w[0] * quat + w[1] * Vec4T(b)); + BLI_assert(is_unit_scale(q)); + return T(2) * math::safe_acos(q.w); } -} // namespace blender::math +/** + * Extract rotation angle from a unit quaternion. Always return the shortest angle. + * Returned angle is in [-pi..pi] range. + * + * `angle_of` with quaternion can exceed PI radians. Having signed versions of these functions + * allows to use 'abs(angle_of_signed(...))' to get the shortest angle between quaternions with + * higher precision than subtracting 2pi afterwards. + */ +template [[nodiscard]] AngleRadianBase angle_of_signed(const QuaternionBase &q) +{ + BLI_assert(is_unit_scale(q)); + return T(2) * ((q.w >= T(0)) ? math::safe_acos(q.w) : -math::safe_acos(-q.w)); +} + +/** + * Extract angle between 2 orientations. + * For #Quaternion, the returned angle is in [0..2pi] range. + * For other types, the returned angle is in [0..pi] range. + * See `angle_of` for more detail. + */ +template +[[nodiscard]] AngleRadianBase angle_between(const QuaternionBase &a, + const QuaternionBase &b) +{ + return angle_of(rotation_between(a, b)); +} +template +[[nodiscard]] AngleRadianBase angle_between(const VecBase &a, const VecBase &b) +{ + BLI_assert(is_unit_scale(a)); + BLI_assert(is_unit_scale(b)); + return math::safe_acos(dot(a, b)); +} +template +[[nodiscard]] AngleFraction angle_between(const AxisSigned a, const AxisSigned b) +{ + if (a == b) { + return AngleFraction::identity(); + } + if (abs(a) == abs(b)) { + return AngleFraction::pi(); + } + return AngleFraction::pi() / 2; +} + +/** + * Extract angle between 2 orientations. + * Returned angle is in [-pi..pi] range. + * See `angle_of_signed` for more detail. + */ +template +[[nodiscard]] AngleRadianBase angle_between_signed(const QuaternionBase &a, + const QuaternionBase &b) +{ + return angle_of_signed(rotation_between(a, b)); +} + +/** \} */ /* -------------------------------------------------------------------- */ /** \name Template implementations * \{ */ -namespace blender::math::detail { - -#ifdef DEBUG -# define BLI_ASSERT_UNIT_QUATERNION(_q) \ - { \ - auto rot_vec = static_cast>(_q); \ - T quat_length = math::length_squared(rot_vec); \ - if (!(quat_length == 0 || (math::abs(quat_length - 1) < 0.0001))) { \ - std::cout << "Warning! " << __func__ << " called with non-normalized quaternion: size " \ - << quat_length << " *** report a bug ***\n"; \ - } \ - } -#else -# define BLI_ASSERT_UNIT_QUATERNION(_q) -#endif - -template AxisAngle::AxisAngle(const VecBase &axis, T angle) +template +[[nodiscard]] QuaternionBase rotate(const QuaternionBase &a, const RotT &b) { - T length; - axis_ = math::normalize_and_get_length(axis, length); - if (length > 0.0f) { - angle_cos_ = math::cos(angle); - angle_sin_ = math::sin(angle); - angle_ = angle; - } - else { - *this = identity(); - } + return a * QuaternionBase(b); } -template AxisAngle::AxisAngle(const VecBase &from, const VecBase &to) +template +[[nodiscard]] AxisAngleBase rotate(const AxisAngleBase &a, const RotT &b) { - BLI_assert(is_unit_scale(from)); - BLI_assert(is_unit_scale(to)); - - /* Avoid calculating the angle. */ - angle_cos_ = dot(from, to); - axis_ = normalize_and_get_length(cross(from, to), angle_sin_); - - if (angle_sin_ <= FLT_EPSILON) { - if (angle_cos_ > T(0)) { - /* Same vectors, zero rotation... */ - *this = identity(); - } - else { - /* Colinear but opposed vectors, 180 rotation... */ - axis_ = normalize(orthogonal(from)); - angle_sin_ = T(0); - angle_cos_ = T(-1); - } - } + return AxisAngleBase(QuaternionBase(a) * QuaternionBase(b)); } + +template +[[nodiscard]] EulerXYZBase rotate(const EulerXYZBase &a, const RotT &b) +{ + MatBase tmp = from_rotation>(a) * from_rotation>(b); + return to_euler(tmp); +} + +template +[[nodiscard]] Euler3Base rotate(const Euler3Base &a, const RotT &b) +{ + const MatBase tmp = from_rotation>(a) * + from_rotation>(b); + return to_euler(tmp, a.order()); +} + template -AxisAngleNormalized::AxisAngleNormalized(const VecBase &axis, T angle) : AxisAngle() +[[nodiscard]] QuaternionBase rotation_between(const QuaternionBase &a, + const QuaternionBase &b) { - BLI_assert(is_unit_scale(axis)); - this->axis_ = axis; - this->angle_ = angle; - this->angle_cos_ = math::cos(angle); - this->angle_sin_ = math::sin(angle); + return invert(a) * b; } -template Quaternion::operator EulerXYZ() const +template +[[nodiscard]] QuaternionBase from_triangle(const VecBase &v1, + const VecBase &v2, + const VecBase &v3, + const VecBase &normal) +{ + /* Force to used an unused var to avoid the same function signature as the version without + * `normal` argument. */ + UNUSED_VARS(v3); + + using Vec3T = VecBase; + + /* Move z-axis to face-normal. */ + const Vec3T z_axis = normal; + Vec3T nor = normalize(Vec3T(z_axis.y, -z_axis.x, T(0))); + if (is_zero(nor.xy())) { + nor.x = T(1); + } + + T angle = T(-0.5) * math::safe_acos(z_axis.z); + T si = math::sin(angle); + QuaternionBase q1(math::cos(angle), nor.x * si, nor.y * si, T(0)); + + /* Rotate back line v1-v2. */ + Vec3T line = transform_point(conjugate(q1), (v2 - v1)); + /* What angle has this line with x-axis? */ + line = normalize(Vec3T(line.x, line.y, T(0))); + + angle = T(0.5) * math::atan2(line.y, line.x); + QuaternionBase q2(math::cos(angle), 0.0, 0.0, math::sin(angle)); + + return q1 * q2; +} + +template +[[nodiscard]] QuaternionBase from_triangle(const VecBase &v1, + const VecBase &v2, + const VecBase &v3) +{ + return from_triangle(v1, v2, v3, normal_tri(v1, v2, v3)); +} + +template +[[nodiscard]] QuaternionBase from_vector(const VecBase &vector, + const AxisSigned track_flag, + const Axis up_flag) +{ + using Vec2T = VecBase; + using Vec3T = VecBase; + using Vec4T = VecBase; + + const T vec_len = length(vector); + + if (UNLIKELY(vec_len == 0.0f)) { + return QuaternionBase::identity(); + } + + const Axis axis = track_flag.axis(); + const Vec3T vec = track_flag.is_negative() ? vector : -vector; + + Vec3T rotation_axis; + constexpr T eps = T(1e-4); + T axis_len; + switch (axis) { + case Axis::X: + rotation_axis = normalize_and_get_length(Vec3T(T(0), -vec.z, vec.y), axis_len); + if (axis_len < eps) { + rotation_axis = Vec3T(0, 1, 0); + } + break; + case Axis::Y: + rotation_axis = normalize_and_get_length(Vec3T(vec.z, T(0), -vec.x), axis_len); + if (axis_len < eps) { + rotation_axis = Vec3T(0, 0, 1); + } + break; + default: + case Axis::Z: + rotation_axis = normalize_and_get_length(Vec3T(-vec.y, vec.x, T(0)), axis_len); + if (axis_len < eps) { + rotation_axis = Vec3T(1, 0, 0); + } + break; + } + /* TODO(fclem): Can optimize here by initializing AxisAngle using the cos an sin directly. + * Avoiding the need for safe_acos and deriving sin from cos. */ + const T rotation_angle = math::safe_acos(vec[axis.as_int()] / vec_len); + + const QuaternionBase q1 = to_quaternion( + AxisAngleBase>(rotation_axis, rotation_angle)); + + if (axis == up_flag) { + /* Nothing else to do. */ + return q1; + } + + /* Extract rotation between the up axis of the rotated space and the up axis. */ + /* There might be an easier way to get this angle directly from the quaternion representation. */ + const Vec3T rotated_up = transform_point(q1, Vec3T(0, 0, 1)); + + /* Project using axes index instead of arithmetic. It's much faster and more precise. */ + const AxisSigned y_axis_signed = math::cross(AxisSigned(axis), AxisSigned(up_flag)); + const Axis x_axis = up_flag; + const Axis y_axis = y_axis_signed.axis(); + + Vec2T projected = normalize(Vec2T(rotated_up[x_axis.as_int()], rotated_up[y_axis.as_int()])); + /* Flip sign for flipped axis. */ + if (y_axis_signed.is_negative()) { + projected.y = -projected.y; + } + /* Not sure if this was a bug or not in the previous implementation. + * Carry over this weird behavior to avoid regressions. */ + if (axis == Axis::Z) { + projected = -projected; + } + + const AngleCartesianBase angle(projected.x, projected.y); + const AngleCartesianBase half_angle = angle / T(2); + + const QuaternionBase q2(Vec4T(half_angle.cos(), vec * (half_angle.sin() / vec_len))); + + return q2 * q1; +} + +template +[[nodiscard]] QuaternionBase from_tracking(AxisSigned forward_axis, Axis up_axis) +{ + BLI_assert(forward_axis.axis() != up_axis); + + /* Curve have Z forward, Y up, X left. */ + return QuaternionBase( + rotation_between(from_orthonormal_axes(AxisSigned::Z_POS, AxisSigned::Y_POS), + from_orthonormal_axes(forward_axis, AxisSigned(up_axis)))); +} + +template [[nodiscard]] MatBase to_gimbal_axis(const Euler3Base &rotation) { using Mat3T = MatBase; - const Quaternion &quat = *this; - BLI_ASSERT_UNIT_QUATERNION(quat) - Mat3T unit_mat = math::from_rotation(quat); - return math::to_euler(unit_mat); + using Vec3T = VecBase; + const int i_index = rotation.i_index(); + const int j_index = rotation.j_index(); + const int k_index = rotation.k_index(); + + Mat3T result; + /* First axis is local. */ + result[i_index] = from_rotation(rotation)[i_index]; + /* Second axis is local minus first rotation. */ + Euler3Base tmp_rot = rotation; + tmp_rot.i() = T(0); + result[j_index] = from_rotation(tmp_rot)[j_index]; + /* Last axis is global. */ + result[k_index] = Vec3T(0); + result[k_index][k_index] = T(1); + + return result; } -template EulerXYZ::operator Quaternion() const -{ - const EulerXYZ &eul = *this; - const T ti = eul.x * T(0.5); - const T tj = eul.y * T(0.5); - const T th = eul.z * T(0.5); - const T ci = math::cos(ti); - const T cj = math::cos(tj); - const T ch = math::cos(th); - const T si = math::sin(ti); - const T sj = math::sin(tj); - const T sh = math::sin(th); - const T cc = ci * ch; - const T cs = ci * sh; - const T sc = si * ch; - const T ss = si * sh; - - Quaternion quat; - quat.x = cj * cc + sj * ss; - quat.y = cj * sc - sj * cs; - quat.z = cj * ss + sj * cc; - quat.w = cj * cs - sj * sc; - return quat; -} - -template Quaternion::operator AxisAngle() const -{ - const Quaternion &quat = *this; - BLI_ASSERT_UNIT_QUATERNION(quat) - - /* Calculate angle/2, and sin(angle/2). */ - T ha = math::acos(quat.x); - T si = math::sin(ha); - - /* From half-angle to angle. */ - T angle = ha * 2; - /* Prevent division by zero for axis conversion. */ - if (math::abs(si) < 0.0005) { - si = 1.0f; - } - - VecBase axis = VecBase(quat.y, quat.z, quat.w) / si; - if (math::is_zero(axis)) { - axis[1] = 1.0f; - } - return AxisAngleNormalized(axis, angle); -} - -template AxisAngle::operator Quaternion() const -{ - BLI_assert(math::is_unit_scale(axis_)); - - /** Using half angle identities: sin(angle / 2) = sqrt((1 - angle_cos) / 2) */ - T sine = math::sqrt(T(0.5) - angle_cos_ * T(0.5)); - const T cosine = math::sqrt(T(0.5) + angle_cos_ * T(0.5)); - - if (angle_sin_ < 0.0) { - sine = -sine; - } - - Quaternion quat; - quat.x = cosine; - quat.y = axis_.x * sine; - quat.z = axis_.y * sine; - quat.w = axis_.z * sine; - return quat; -} - -template EulerXYZ::operator AxisAngle() const -{ - /* Use quaternions as intermediate representation for now... */ - return AxisAngle(Quaternion(*this)); -} - -template AxisAngle::operator EulerXYZ() const -{ - /* Use quaternions as intermediate representation for now... */ - return EulerXYZ(Quaternion(*this)); -} - -/* Using explicit template instantiations in order to reduce compilation time. */ -extern template AxisAngle::operator EulerXYZ() const; -extern template AxisAngle::operator Quaternion() const; -extern template EulerXYZ::operator AxisAngle() const; -extern template EulerXYZ::operator Quaternion() const; -extern template Quaternion::operator AxisAngle() const; -extern template Quaternion::operator EulerXYZ() const; - -extern template AxisAngle::operator EulerXYZ() const; -extern template AxisAngle::operator Quaternion() const; -extern template EulerXYZ::operator AxisAngle() const; -extern template EulerXYZ::operator Quaternion() const; -extern template Quaternion::operator AxisAngle() const; -extern template Quaternion::operator EulerXYZ() const; - -} // namespace blender::math::detail - +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversion from Cartesian Basis + * \{ */ + +/** + * Creates a quaternion from an axis triple. + * This is faster and more precise than converting from another representation. + */ +template QuaternionBase to_quaternion(const CartesianBasis &rotation) +{ + /** + * There are only 6 * 4 = 24 possible valid orthonormal orientations. + * We precompute them and store them inside this switch using a key. + * Generated using `generate_axes_to_quaternion_switch_cases()`. + */ + constexpr auto map = [](AxisSigned x, AxisSigned y, AxisSigned z) { + return x.as_int() << 16 | y.as_int() << 8 | z.as_int(); + }; + + switch (map(rotation.axes.x, rotation.axes.y, rotation.axes.z)) { + default: + return QuaternionBase::identity(); + case map(AxisSigned::Z_POS, AxisSigned::X_POS, AxisSigned::Y_POS): + return QuaternionBase{T(0.5), T(-0.5), T(-0.5), T(-0.5)}; + case map(AxisSigned::Y_NEG, AxisSigned::X_POS, AxisSigned::Z_POS): + return QuaternionBase{T(M_SQRT1_2), T(0), T(0), T(-M_SQRT1_2)}; + case map(AxisSigned::Z_NEG, AxisSigned::X_POS, AxisSigned::Y_NEG): + return QuaternionBase{T(0.5), T(0.5), T(0.5), T(-0.5)}; + case map(AxisSigned::Y_POS, AxisSigned::X_POS, AxisSigned::Z_NEG): + return QuaternionBase{T(0), T(M_SQRT1_2), T(M_SQRT1_2), T(0)}; + case map(AxisSigned::Z_NEG, AxisSigned::Y_POS, AxisSigned::X_POS): + return QuaternionBase{T(M_SQRT1_2), T(0), T(M_SQRT1_2), T(0)}; + case map(AxisSigned::Z_POS, AxisSigned::Y_POS, AxisSigned::X_NEG): + return QuaternionBase{T(M_SQRT1_2), T(0), T(-M_SQRT1_2), T(0)}; + case map(AxisSigned::X_NEG, AxisSigned::Y_POS, AxisSigned::Z_NEG): + return QuaternionBase{T(0), T(0), T(1), T(0)}; + case map(AxisSigned::Y_POS, AxisSigned::Z_POS, AxisSigned::X_POS): + return QuaternionBase{T(0.5), T(0.5), T(0.5), T(0.5)}; + case map(AxisSigned::X_NEG, AxisSigned::Z_POS, AxisSigned::Y_POS): + return QuaternionBase{T(0), T(0), T(M_SQRT1_2), T(M_SQRT1_2)}; + case map(AxisSigned::Y_NEG, AxisSigned::Z_POS, AxisSigned::X_NEG): + return QuaternionBase{T(0.5), T(0.5), T(-0.5), T(-0.5)}; + case map(AxisSigned::X_POS, AxisSigned::Z_POS, AxisSigned::Y_NEG): + return QuaternionBase{T(M_SQRT1_2), T(M_SQRT1_2), T(0), T(0)}; + case map(AxisSigned::Z_NEG, AxisSigned::X_NEG, AxisSigned::Y_POS): + return QuaternionBase{T(0.5), T(-0.5), T(0.5), T(0.5)}; + case map(AxisSigned::Y_POS, AxisSigned::X_NEG, AxisSigned::Z_POS): + return QuaternionBase{T(M_SQRT1_2), T(0), T(0), T(M_SQRT1_2)}; + case map(AxisSigned::Z_POS, AxisSigned::X_NEG, AxisSigned::Y_NEG): + return QuaternionBase{T(0.5), T(0.5), T(-0.5), T(0.5)}; + case map(AxisSigned::Y_NEG, AxisSigned::X_NEG, AxisSigned::Z_NEG): + return QuaternionBase{T(0), T(-M_SQRT1_2), T(M_SQRT1_2), T(0)}; + case map(AxisSigned::Z_POS, AxisSigned::Y_NEG, AxisSigned::X_POS): + return QuaternionBase{T(0), T(M_SQRT1_2), T(0), T(M_SQRT1_2)}; + case map(AxisSigned::X_NEG, AxisSigned::Y_NEG, AxisSigned::Z_POS): + return QuaternionBase{T(0), T(0), T(0), T(1)}; + case map(AxisSigned::Z_NEG, AxisSigned::Y_NEG, AxisSigned::X_NEG): + return QuaternionBase{T(0), T(-M_SQRT1_2), T(0), T(M_SQRT1_2)}; + case map(AxisSigned::X_POS, AxisSigned::Y_NEG, AxisSigned::Z_NEG): + return QuaternionBase{T(0), T(1), T(0), T(0)}; + case map(AxisSigned::Y_NEG, AxisSigned::Z_NEG, AxisSigned::X_POS): + return QuaternionBase{T(0.5), T(-0.5), T(0.5), T(-0.5)}; + case map(AxisSigned::X_POS, AxisSigned::Z_NEG, AxisSigned::Y_POS): + return QuaternionBase{T(M_SQRT1_2), T(-M_SQRT1_2), T(0), T(0)}; + case map(AxisSigned::Y_POS, AxisSigned::Z_NEG, AxisSigned::X_NEG): + return QuaternionBase{T(0.5), T(-0.5), T(-0.5), T(0.5)}; + case map(AxisSigned::X_NEG, AxisSigned::Z_NEG, AxisSigned::Y_NEG): + return QuaternionBase{T(0), T(0), T(-M_SQRT1_2), T(M_SQRT1_2)}; + } +} + +/** \} */ + +} // namespace blender::math + +namespace blender::math { + +/* Using explicit template instantiations in order to reduce compilation time. */ +extern template EulerXYZ to_euler(const AxisAngle &); +extern template EulerXYZ to_euler(const AxisAngleCartesian &); +extern template EulerXYZ to_euler(const Quaternion &); +extern template Euler3 to_euler(const AxisAngle &, EulerOrder); +extern template Euler3 to_euler(const AxisAngleCartesian &, EulerOrder); +extern template Euler3 to_euler(const Quaternion &, EulerOrder); +extern template Quaternion to_quaternion(const AxisAngle &); +extern template Quaternion to_quaternion(const AxisAngleCartesian &); +extern template Quaternion to_quaternion(const Euler3 &); +extern template Quaternion to_quaternion(const EulerXYZ &); +extern template AxisAngleCartesian to_axis_angle(const Euler3 &); +extern template AxisAngleCartesian to_axis_angle(const EulerXYZ &); +extern template AxisAngleCartesian to_axis_angle(const Quaternion &); +extern template AxisAngle to_axis_angle(const Euler3 &); +extern template AxisAngle to_axis_angle(const EulerXYZ &); +extern template AxisAngle to_axis_angle(const Quaternion &); + +} // namespace blender::math + /** \} */ diff --git a/source/blender/blenlib/BLI_math_rotation_types.hh b/source/blender/blenlib/BLI_math_rotation_types.hh index 63c02ab9d0a..e639f099357 100644 --- a/source/blender/blenlib/BLI_math_rotation_types.hh +++ b/source/blender/blenlib/BLI_math_rotation_types.hh @@ -4,271 +4,17 @@ /** \file * \ingroup bli - */ - -#include "BLI_math_base.hh" -#include "BLI_math_vector_types.hh" - -namespace blender::math { - -namespace detail { - -/** + * * Rotation Types * - * It gives more semantic information allowing overloaded functions based on the rotation type. - * It also prevent implicit cast from rotation to vector types. + * They give more semantic information and allow overloaded functions based on rotation type. + * They also prevent implicit cast from rotation to vector types. */ -/* Forward declaration. */ -template struct AxisAngle; -template struct Quaternion; - -template struct AngleRadian { - T value; - - AngleRadian() = default; - - AngleRadian(const T &radian) : value(radian){}; - - /** Static functions. */ - - static AngleRadian identity() - { - return 0; - } - - /** Conversions. */ - - explicit operator T() const - { - return value; - } - - /** Operators. */ - - friend std::ostream &operator<<(std::ostream &stream, const AngleRadian &rot) - { - return stream << "AngleRadian(" << rot.value << ")"; - } -}; - -template struct EulerXYZ { - T x, y, z; - - EulerXYZ() = default; - - EulerXYZ(const T &x, const T &y, const T &z) - { - this->x = x; - this->y = y; - this->z = z; - } - - EulerXYZ(const VecBase &vec) : EulerXYZ(UNPACK3(vec)){}; - - /** Static functions. */ - - static EulerXYZ identity() - { - return {0, 0, 0}; - } - - /** Conversions. */ - - explicit operator VecBase() const - { - return {this->x, this->y, this->z}; - } - - explicit operator AxisAngle() const; - - explicit operator Quaternion() const; - - /** Operators. */ - - friend std::ostream &operator<<(std::ostream &stream, const EulerXYZ &rot) - { - return stream << "EulerXYZ" << static_cast>(rot); - } -}; - -template struct Quaternion { - T x, y, z, w; - - Quaternion() = default; - - Quaternion(const T &x, const T &y, const T &z, const T &w) - { - this->x = x; - this->y = y; - this->z = z; - this->w = w; - } - - Quaternion(const VecBase &vec) : Quaternion(UNPACK4(vec)){}; - - /** Static functions. */ - - static Quaternion identity() - { - return {1, 0, 0, 0}; - } - - /** Conversions. */ - - explicit operator VecBase() const - { - return {this->x, this->y, this->z, this->w}; - } - - explicit operator EulerXYZ() const; - - explicit operator AxisAngle() const; - - /** Operators. */ - - const T &operator[](int i) const - { - BLI_assert(i >= 0 && i < 4); - return (&this->x)[i]; - } - - friend std::ostream &operator<<(std::ostream &stream, const Quaternion &rot) - { - return stream << "Quaternion" << static_cast>(rot); - } -}; - -template struct AxisAngle { - using vec3_type = VecBase; - - protected: - vec3_type axis_ = {0, 1, 0}; - /** Store cosine and sine so rotation is cheaper and doesn't require atan2. */ - T angle_cos_ = 1; - T angle_sin_ = 0; - /** - * Source angle for interpolation. - * It might not be computed on creation, so the getter ensures it is updated. - */ - T angle_ = 0; - - /** - * A defaulted constructor would cause zero initialization instead of default initialization, - * and not call the default member initializers. - */ - explicit AxisAngle(){}; - - public: - /** - * Create a rotation from an axis and an angle. - * \note `axis` does not have to be normalized. - * Use `AxisAngleNormalized` instead to skip normalization cost. - */ - AxisAngle(const vec3_type &axis, T angle); - - /** - * Create a rotation from 2 normalized vectors. - * \note `from` and `to` must be normalized. - */ - AxisAngle(const vec3_type &from, const vec3_type &to); - - /** Static functions. */ - - static AxisAngle identity() - { - return AxisAngle(); - } - - /** Getters. */ - - const vec3_type &axis() const - { - return axis_; - } - - const T &angle() const - { - if (UNLIKELY(angle_ == T(0) && angle_cos_ != T(1))) { - /* Angle wasn't computed by constructor. */ - const_cast(this)->angle_ = math::atan2(angle_sin_, angle_cos_); - } - return angle_; - } - - const T &angle_cos() const - { - return angle_cos_; - } - - const T &angle_sin() const - { - return angle_sin_; - } - - /** Conversions. */ - - explicit operator Quaternion() const; - - explicit operator EulerXYZ() const; - - /** Operators. */ - - friend bool operator==(const AxisAngle &a, const AxisAngle &b) - { - return (a.axis == b.axis) && (a.angle == b.angle); - } - - friend bool operator!=(const AxisAngle &a, const AxisAngle &b) - { - return (a != b); - } - - friend std::ostream &operator<<(std::ostream &stream, const AxisAngle &rot) - { - return stream << "AxisAngle(axis=" << rot.axis << ", angle=" << rot.angle << ")"; - } -}; - -/** - * A version of AxisAngle that expects axis to be already normalized. - * Implicitly cast back to AxisAngle. - */ -template struct AxisAngleNormalized : public AxisAngle { - AxisAngleNormalized(const VecBase &axis, T angle); - - operator AxisAngle() const - { - return *this; - } -}; - -/** - * Intermediate Types. - * - * Some functions need to have higher precision than standard floats for some operations. - */ -template struct TypeTraits { - using DoublePrecision = T; -}; -template<> struct TypeTraits { - using DoublePrecision = double; -}; - -}; // namespace detail - -template struct AssertUnitEpsilon> { - static constexpr U value = AssertUnitEpsilon::value * 10; -}; - -/* Most common used types. */ -using AngleRadian = math::detail::AngleRadian; -using EulerXYZ = math::detail::EulerXYZ; -using Quaternion = math::detail::Quaternion; -using AxisAngle = math::detail::AxisAngle; -using AxisAngleNormalized = math::detail::AxisAngleNormalized; - -} // namespace blender::math +#include "BLI_math_angle_types.hh" +#include "BLI_math_axis_angle_types.hh" +#include "BLI_math_basis_types.hh" +#include "BLI_math_euler_types.hh" +#include "BLI_math_quaternion_types.hh" /** \} */ diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh index 6e1e04e65b2..d4a67722abe 100644 --- a/source/blender/blenlib/BLI_math_vector.hh +++ b/source/blender/blenlib/BLI_math_vector.hh @@ -177,6 +177,34 @@ template return result; } +/** + * Return the value of x raised to the y power. + * The result is undefined if x < 0 or if x = 0 and y ≤ 0. + */ +template +[[nodiscard]] inline VecBase pow(const VecBase &x, const T &y) +{ + VecBase result; + for (int i = 0; i < Size; i++) { + result[i] = std::pow(x[i], y); + } + return result; +} + +/** + * Return the value of x raised to the y power. + * The result is undefined if x < 0 or if x = 0 and y ≤ 0. + */ +template +[[nodiscard]] inline VecBase pow(const VecBase &x, const VecBase &y) +{ + VecBase result; + for (int i = 0; i < Size; i++) { + result[i] = std::pow(x[i], y[i]); + } + return result; +} + /** * Returns \a a if it is a multiple of \a b or the next multiple or \a b after \b a . * In other words, it is equivalent to `divide_ceil(a, b) * b`. @@ -460,6 +488,30 @@ template [[nodiscard]] inline VecBase cross_poly(Span +[[nodiscard]] inline VecBase cross_tri(const VecBase &v1, + const VecBase &v2, + const VecBase &v3) +{ + return cross(v1 - v2, v2 - v3); +} + +/** + * Return normal vector to a triangle. + * The result is normalized but can still be degenerate. + */ +template +[[nodiscard]] inline VecBase normal_tri(const VecBase &v1, + const VecBase &v2, + const VecBase &v3) +{ + return normalize(cross_tri(v1, v2, v3)); +} + /** * Per component linear interpolation. * \param t: interpolation factor. Return \a a if equal 0. Return \a b if equal 1. diff --git a/source/blender/blenlib/BLI_math_vector_types.hh b/source/blender/blenlib/BLI_math_vector_types.hh index 89f866a5172..bb7134370e8 100644 --- a/source/blender/blenlib/BLI_math_vector_types.hh +++ b/source/blender/blenlib/BLI_math_vector_types.hh @@ -79,6 +79,9 @@ template uint64_t vector_hash(const T &vec) template struct VecBase : public vec_struct_base { + BLI_STATIC_ASSERT(alignof(T) <= sizeof(T), + "VecBase is not compatible with aligned type for now."); + static constexpr int type_length = Size; using base_type = T; @@ -176,16 +179,36 @@ template struct VecBase : public vec_struct_base /** Swizzling. */ - template= 3)> VecBase xy() const + template= 2)> VecBase xy() const { return *reinterpret_cast *>(this); } - template= 4)> VecBase xyz() const + template= 3)> VecBase yz() const + { + return *reinterpret_cast *>(&((*this)[1])); + } + + template= 4)> VecBase zw() const + { + return *reinterpret_cast *>(&((*this)[2])); + } + + template= 3)> VecBase xyz() const { return *reinterpret_cast *>(this); } + template= 4)> VecBase yzw() const + { + return *reinterpret_cast *>(&((*this)[1])); + } + + template= 4)> VecBase xyzw() const + { + return *reinterpret_cast *>(this); + } + #undef BLI_ENABLE_IF_VEC /** Conversion from pointers (from C-style vectors). */ @@ -622,6 +645,7 @@ template struct AssertUnitEpsilon { } // namespace math +using char2 = blender::VecBase; using char3 = blender::VecBase; using uchar3 = blender::VecBase; diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index 6f119a49f01..a13e3df7877 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -156,7 +156,29 @@ template class AlignedBuffer { */ template class TypedBuffer { private: - BLI_NO_UNIQUE_ADDRESS AlignedBuffer buffer_; + /** Required so that `sizeof(T)` is not required when `Size` is 0. */ + static constexpr size_t get_size() + { + if constexpr (Size == 0) { + return 0; + } + else { + return sizeof(T) * size_t(Size); + } + } + + /** Required so that `alignof(T)` is not required when `Size` is 0. */ + static constexpr size_t get_alignment() + { + if constexpr (Size == 0) { + return 1; + } + else { + return alignof(T); + } + } + + BLI_NO_UNIQUE_ADDRESS AlignedBuffer buffer_; public: operator T *() diff --git a/source/blender/blenlib/BLI_strict_flags.h b/source/blender/blenlib/BLI_strict_flags.h index 26355430f5c..c8131fcf819 100644 --- a/source/blender/blenlib/BLI_strict_flags.h +++ b/source/blender/blenlib/BLI_strict_flags.h @@ -10,7 +10,7 @@ #ifdef __GNUC__ /* NOTE(@ideasman42): CLANG behaves slightly differently to GCC, - * these can be enabled but do so carefully as they can introduce build-errors. */ + * these can be enabled but do so carefully as they can introduce build-errors. */ # if !defined(__clang__) # pragma GCC diagnostic error "-Wsign-compare" # pragma GCC diagnostic error "-Wconversion" diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h index e03bc7ba78a..35e3345f4c2 100644 --- a/source/blender/blenlib/BLI_utildefines.h +++ b/source/blender/blenlib/BLI_utildefines.h @@ -668,6 +668,9 @@ extern bool BLI_memory_is_zero(const void *arr, size_t arr_size); /* UNUSED macro, for function argument */ # if defined(__GNUC__) || defined(__clang__) # define UNUSED(x) UNUSED_##x __attribute__((__unused__)) +# elif defined(_MSC_VER) +/* NOTE: This suppresses the warning for the line, not the attribute. */ +# define UNUSED(x) UNUSED_##x __pragma(warning(suppress : 4100)) # else # define UNUSED(x) UNUSED_##x # endif diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index 6f9a158c1d8..02795689f72 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -108,6 +108,17 @@ class Vector { template friend class Vector; + /** Required in case `T` is an incomplete type. */ + static constexpr bool is_nothrow_move_constructible() + { + if constexpr (InlineBufferCapacity == 0) { + return true; + } + else { + return std::is_nothrow_move_constructible_v; + } + } + public: /** * Create an empty vector. @@ -234,7 +245,7 @@ class Vector { */ template Vector(Vector &&other) noexcept( - std::is_nothrow_move_constructible_v) + is_nothrow_move_constructible()) : Vector(NoExceptConstructor(), other.allocator_) { const int64_t size = other.size(); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index d83fad875a5..1037f820f23 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -262,14 +262,20 @@ set(SRC BLI_map.hh BLI_map_slots.hh BLI_math.h + BLI_math_angle_types.hh + BLI_math_axis_angle.hh + BLI_math_axis_angle_types.hh BLI_math_base.h BLI_math_base.hh BLI_math_base_safe.h + BLI_math_basis_types.hh BLI_math_bits.h BLI_math_boolean.hh BLI_math_color.h BLI_math_color.hh BLI_math_color_blend.h + BLI_math_euler.hh + BLI_math_euler_types.hh BLI_math_geom.h BLI_math_inline.h BLI_math_interp.h @@ -277,6 +283,8 @@ set(SRC BLI_math_matrix.hh BLI_math_matrix_types.hh BLI_math_mpq.hh + BLI_math_quaternion.hh + BLI_math_quaternion_types.hh BLI_math_rotation.h BLI_math_rotation.hh BLI_math_rotation_legacy.hh @@ -498,6 +506,7 @@ if(WITH_GTESTS) tests/BLI_math_matrix_test.cc tests/BLI_math_matrix_types_test.cc tests/BLI_math_rotation_test.cc + tests/BLI_math_rotation_types_test.cc tests/BLI_math_solvers_test.cc tests/BLI_math_time_test.cc tests/BLI_math_vector_test.cc diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index 7dca60128d3..6240c855c99 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -272,6 +272,7 @@ void BLI_filelist_entry_mode_to_string(const struct stat *st, const char *types[8] = {"---", "--x", "-w-", "-wx", "r--", "r-x", "rw-", "rwx"}; #ifdef WIN32 + UNUSED_VARS(st); BLI_strncpy(r_mode1, types[0], sizeof(*r_mode1) * FILELIST_DIRENTRY_MODE_LEN); BLI_strncpy(r_mode2, types[0], sizeof(*r_mode2) * FILELIST_DIRENTRY_MODE_LEN); BLI_strncpy(r_mode3, types[0], sizeof(*r_mode3) * FILELIST_DIRENTRY_MODE_LEN); @@ -315,6 +316,7 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st, char r_owner[FILELIST_DIRENTRY_OWNER_LEN]) { #ifdef WIN32 + UNUSED_VARS(st); strcpy(r_owner, "unknown"); #else struct passwd *pwuser = getpwuid(st->st_uid); diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c index 65518427656..66b68e7a5d3 100644 --- a/source/blender/blenlib/intern/array_store.c +++ b/source/blender/blenlib/intern/array_store.c @@ -105,17 +105,19 @@ * support disabling some parts of this. * \{ */ -/* Scan first chunks (happy path when beginning of the array matches). +/** + * Scan first chunks (happy path when beginning of the array matches). * When the array is a perfect match, we can re-use the entire list. * * Note that disabling makes some tests fail that check for output-size. */ #define USE_FASTPATH_CHUNKS_FIRST -/* Scan last chunks (happy path when end of the array matches). +/** + * Scan last chunks (happy path when end of the array matches). * When the end of the array matches, we can quickly add these chunks. * note that we will add contiguous matching chunks - * so this isn't as useful as USE_FASTPATH_CHUNKS_FIRST, + * so this isn't as useful as #USE_FASTPATH_CHUNKS_FIRST, * however it avoids adding matching chunks into the lookup table, * so creating the lookup table won't be as expensive. */ @@ -123,14 +125,16 @@ # define USE_FASTPATH_CHUNKS_LAST #endif -/* For arrays of matching length, test that *enough* of the chunks are aligned, +/** + * For arrays of matching length, test that *enough* of the chunks are aligned, * and simply step over both arrays, using matching chunks. * This avoids overhead of using a lookup table for cases * when we can assume they're mostly aligned. */ #define USE_ALIGN_CHUNKS_TEST -/* Accumulate hashes from right to left so we can create a hash for the chunk-start. +/** + * Accumulate hashes from right to left so we can create a hash for the chunk-start. * This serves to increase uniqueness and will help when there is many values which are the same. */ #define USE_HASH_TABLE_ACCUMULATE @@ -138,28 +142,48 @@ #ifdef USE_HASH_TABLE_ACCUMULATE /* Number of times to propagate hashes back. * Effectively a 'triangle-number'. - * so 4 -> 7, 5 -> 10, 6 -> 15... etc. + * so 3 -> 7, 4 -> 11, 5 -> 16, 6 -> 22, 7 -> 29, ... etc. + * + * \note additional steps are expensive, so avoid high values unless necessary + * (with low strides, between 1-4) where a low value would cause the hashes to + * be un-evenly distributed. */ -# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS 4 +# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_DEFAULT 3 +# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_32BITS 4 +# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_16BITS 5 +/** + * Singe bytes (or boolean) arrays need a higher number of steps + * because the resulting values are not unique enough to result in evenly distributed values. + * Use more accumulation when the the size of the structs is small, see: #105046. + * + * With 6 -> 22, one byte each - means an array of booleans can be combine into 22 bits + * representing 4,194,303 different combinations. + */ +# define BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_8BITS 6 #else -/* How many items to hash (multiplied by stride) +/** + * How many items to hash (multiplied by stride). + * The more values, the greater the chance this block has a unique hash. */ -# define BCHUNK_HASH_LEN 4 +# define BCHUNK_HASH_LEN 16 #endif -/* Calculate the key once and reuse it +/** + * Calculate the key once and reuse it */ #define USE_HASH_TABLE_KEY_CACHE #ifdef USE_HASH_TABLE_KEY_CACHE -# define HASH_TABLE_KEY_UNSET ((uint64_t)-1) -# define HASH_TABLE_KEY_FALLBACK ((uint64_t)-2) +# define HASH_TABLE_KEY_UNSET ((hash_key)-1) +# define HASH_TABLE_KEY_FALLBACK ((hash_key)-2) #endif -/* How much larger the table is then the total number of chunks. +/** + * How much larger the table is then the total number of chunks. */ #define BCHUNK_HASH_TABLE_MUL 3 -/* Merge too small/large chunks: +/** + * Merge too small/large chunks: * * Using this means chunks below a threshold will be merged together. * Even though short term this uses more memory, @@ -172,19 +196,20 @@ #define USE_MERGE_CHUNKS #ifdef USE_MERGE_CHUNKS -/* Merge chunks smaller then: (chunk_size / BCHUNK_MIN_SIZE_DIV) - */ +/** Merge chunks smaller then: (#BArrayInfo::chunk_byte_size / #BCHUNK_SIZE_MIN_DIV). */ # define BCHUNK_SIZE_MIN_DIV 8 -/* Disallow chunks bigger than the regular chunk size scaled by this value - * NOTE: must be at least 2! +/** + * Disallow chunks bigger than the regular chunk size scaled by this value. + * + * \note must be at least 2! * however, this code runs won't run in tests unless it's ~1.1 ugh. * so lower only to check splitting works. */ # define BCHUNK_SIZE_MAX_MUL 2 #endif /* USE_MERGE_CHUNKS */ -/* slow (keep disabled), but handy for debugging */ +/** Slow (keep disabled), but handy for debugging */ // #define USE_VALIDATE_LIST_SIZE // #define USE_VALIDATE_LIST_DATA_PARTIAL @@ -197,7 +222,7 @@ /** \name Internal Structs * \{ */ -typedef uint64_t hash_key; +typedef uint32_t hash_key; typedef struct BArrayInfo { size_t chunk_stride; @@ -208,7 +233,10 @@ typedef struct BArrayInfo { /* min/max limits (inclusive) */ size_t chunk_byte_size_min; size_t chunk_byte_size_max; - + /** + * The read-ahead value should never exceed `chunk_byte_size`, + * otherwise the hash would be based on values in the next chunk. + */ size_t accum_read_ahead_bytes; #ifdef USE_HASH_TABLE_ACCUMULATE size_t accum_steps; @@ -251,20 +279,23 @@ struct BArrayStore { struct BArrayState { /** linked list in #BArrayStore.states */ struct BArrayState *next, *prev; - - struct BChunkList *chunk_list; /* BChunkList's */ + /** Shared chunk list, this reference must hold a #BChunkList::users. */ + struct BChunkList *chunk_list; }; typedef struct BChunkList { - ListBase chunk_refs; /* BChunkRef's */ - uint chunk_refs_len; /* BLI_listbase_count(chunks), store for reuse. */ - size_t total_size; /* size of all chunks */ + /** List of #BChunkRef's */ + ListBase chunk_refs; + /** Result of `BLI_listbase_count(chunks)`, store for reuse. */ + uint chunk_refs_len; + /** Size of all chunks (expanded). */ + size_t total_expanded_size; - /** number of #BArrayState using this. */ + /** Number of #BArrayState using this. */ int users; } BChunkList; -/* a chunk of an array */ +/** A chunk of memory in an array (unit of de-duplication). */ typedef struct BChunk { const uchar *data; size_t data_len; @@ -353,13 +384,13 @@ static bool bchunk_data_compare(const BChunk *chunk, /** \name Internal BChunkList API * \{ */ -static BChunkList *bchunk_list_new(BArrayMemory *bs_mem, size_t total_size) +static BChunkList *bchunk_list_new(BArrayMemory *bs_mem, size_t total_expanded_size) { BChunkList *chunk_list = BLI_mempool_alloc(bs_mem->chunk_list); BLI_listbase_clear(&chunk_list->chunk_refs); chunk_list->chunk_refs_len = 0; - chunk_list->total_size = total_size; + chunk_list->total_expanded_size = total_expanded_size; chunk_list->users = 0; return chunk_list; } @@ -734,19 +765,19 @@ static void bchunk_list_fill_from_array(const BArrayInfo *info, #define HASH_INIT (5381) -BLI_INLINE uint hash_data_single(const uchar p) +BLI_INLINE hash_key hash_data_single(const uchar p) { - return ((HASH_INIT << 5) + HASH_INIT) + (uint)(*((signed char *)&p)); + return ((HASH_INIT << 5) + HASH_INIT) + (hash_key)(*((signed char *)&p)); } /* hash bytes, from BLI_ghashutil_strhash_n */ -static uint hash_data(const uchar *key, size_t n) +static hash_key hash_data(const uchar *key, size_t n) { const signed char *p; - uint h = HASH_INIT; + hash_key h = HASH_INIT; for (p = (const signed char *)key; n--; p++) { - h = (uint)((h << 5) + h) + (uint)*p; + h = (hash_key)((h << 5) + h) + (hash_key)*p; } return h; @@ -802,6 +833,14 @@ static void hash_array_from_cref(const BArrayInfo *info, BLI_assert(i == hash_array_len); } +BLI_INLINE void hash_accum_impl(hash_key *hash_array, const size_t i_dst, const size_t i_ahead) +{ + /* Tested to give good results when accumulating unique values from an array of booleans. + * (least unused cells in the `BTableRef **table`). */ + BLI_assert(i_dst < i_ahead); + hash_array[i_dst] += ((hash_array[i_ahead] << 3) ^ (hash_array[i_dst] >> 1)); +} + static void hash_accum(hash_key *hash_array, const size_t hash_array_len, size_t iter_steps) { /* _very_ unlikely, can happen if you select a chunk-size of 1 for example. */ @@ -812,8 +851,8 @@ static void hash_accum(hash_key *hash_array, const size_t hash_array_len, size_t const size_t hash_array_search_len = hash_array_len - iter_steps; while (iter_steps != 0) { const size_t hash_offset = iter_steps; - for (uint i = 0; i < hash_array_search_len; i++) { - hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1); + for (size_t i = 0; i < hash_array_search_len; i++) { + hash_accum_impl(hash_array, i, i + hash_offset); } iter_steps -= 1; } @@ -838,7 +877,7 @@ static void hash_accum_single(hash_key *hash_array, const size_t hash_array_len, const size_t hash_array_search_len = hash_array_len - iter_steps_sub; const size_t hash_offset = iter_steps; for (uint i = 0; i < hash_array_search_len; i++) { - hash_array[i] += (hash_array[i + hash_offset]) * ((hash_array[i] & 0xff) + 1); + hash_accum_impl(hash_array, i, i + hash_offset); } iter_steps -= 1; iter_steps_sub += iter_steps; @@ -932,9 +971,9 @@ static const BChunkRef *table_lookup(const BArrayInfo *info, static hash_key key_from_chunk_ref(const BArrayInfo *info, const BChunkRef *cref) { - const size_t data_hash_len = BCHUNK_HASH_LEN * info->chunk_stride; hash_key key; BChunk *chunk = cref->link; + const size_t data_hash_len = MIN2(chunk->data_len, BCHUNK_HASH_LEN * info->chunk_stride); # ifdef USE_HASH_TABLE_KEY_CACHE key = chunk->key; @@ -1012,7 +1051,7 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info, const size_t data_len_original, const BChunkList *chunk_list_reference) { - ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size); + ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_expanded_size); /* ----------------------------------------------------------------------- * Fast-Path for exact match @@ -1045,7 +1084,7 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info, } if (full_match) { - if (chunk_list_reference->total_size == data_len_original) { + if (chunk_list_reference->total_expanded_size == data_len_original) { return (BChunkList *)chunk_list_reference; } } @@ -1135,9 +1174,9 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info, bool use_aligned = false; #ifdef USE_ALIGN_CHUNKS_TEST - if (chunk_list->total_size == chunk_list_reference->total_size) { + if (chunk_list->total_expanded_size == chunk_list_reference->total_expanded_size) { /* if we're already a quarter aligned */ - if (data_len - i_prev <= chunk_list->total_size / 4) { + if (data_len - i_prev <= chunk_list->total_expanded_size / 4) { use_aligned = true; } else { @@ -1219,7 +1258,7 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info, #endif const BChunkRef *cref; - size_t chunk_list_reference_bytes_remaining = chunk_list_reference->total_size - + size_t chunk_list_reference_bytes_remaining = chunk_list_reference->total_expanded_size - chunk_list_reference_skip_bytes; if (cref_match_first) { @@ -1371,7 +1410,7 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info, /* check we're the correct size and that we didn't accidentally modify the reference */ ASSERT_CHUNKLIST_SIZE(chunk_list, data_len_original); - ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_size); + ASSERT_CHUNKLIST_SIZE(chunk_list_reference, chunk_list_reference->total_expanded_size); ASSERT_CHUNKLIST_DATA(chunk_list, data); @@ -1387,6 +1426,8 @@ static BChunkList *bchunk_list_from_data_merge(const BArrayInfo *info, BArrayStore *BLI_array_store_create(uint stride, uint chunk_count) { + BLI_assert(stride > 0 && chunk_count > 0); + BArrayStore *bs = MEM_callocN(sizeof(BArrayStore), __func__); bs->info.chunk_stride = stride; @@ -1399,14 +1440,32 @@ BArrayStore *BLI_array_store_create(uint stride, uint chunk_count) #endif #ifdef USE_HASH_TABLE_ACCUMULATE - bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS - 1; - /* Triangle number, identifying now much read-ahead we need: - * https://en.wikipedia.org/wiki/Triangular_number (+ 1) */ - bs->info.accum_read_ahead_len = - (uint)(((bs->info.accum_steps * (bs->info.accum_steps + 1)) / 2) + 1); + /* One is always subtracted from this `accum_steps`, this is intentional + * as it results in reading ahead the expected amount. */ + if (stride <= sizeof(int8_t)) { + bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_8BITS + 1; + } + else if (stride <= sizeof(int16_t)) { + bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_16BITS + 1; + } + else if (stride <= sizeof(int32_t)) { + bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_32BITS + 1; + } + else { + bs->info.accum_steps = BCHUNK_HASH_TABLE_ACCUMULATE_STEPS_DEFAULT + 1; + } + + do { + bs->info.accum_steps -= 1; + /* Triangle number, identifying now much read-ahead we need: + * https://en.wikipedia.org/wiki/Triangular_number (+ 1) */ + bs->info.accum_read_ahead_len = ((bs->info.accum_steps * (bs->info.accum_steps + 1)) / 2) + 1; + /* Only small chunk counts are likely to exceed the read-ahead length. */ + } while (UNLIKELY(chunk_count < bs->info.accum_read_ahead_len)); + bs->info.accum_read_ahead_bytes = bs->info.accum_read_ahead_len * stride; #else - bs->info.accum_read_ahead_bytes = BCHUNK_HASH_LEN * stride; + bs->info.accum_read_ahead_bytes = MIN2((size_t)BCHUNK_HASH_LEN, chunk_count) * stride; #endif bs->memory.chunk_list = BLI_mempool_create(sizeof(BChunkList), 0, 512, BLI_MEMPOOL_NOP); @@ -1415,6 +1474,8 @@ BArrayStore *BLI_array_store_create(uint stride, uint chunk_count) * (we could loop over all states as an alternative). */ bs->memory.chunk = BLI_mempool_create(sizeof(BChunk), 0, 512, BLI_MEMPOOL_ALLOW_ITER); + BLI_assert(bs->info.accum_read_ahead_bytes <= bs->info.chunk_byte_size); + return bs; } @@ -1470,7 +1531,7 @@ size_t BLI_array_store_calc_size_expanded_get(const BArrayStore *bs) { size_t size_accum = 0; LISTBASE_FOREACH (const BArrayState *, state, &bs->states) { - size_accum += state->chunk_list->total_size; + size_accum += state->chunk_list->total_expanded_size; } return size_accum; } @@ -1556,7 +1617,7 @@ void BLI_array_store_state_remove(BArrayStore *bs, BArrayState *state) size_t BLI_array_store_state_size_get(BArrayState *state) { - return state->chunk_list->total_size; + return state->chunk_list->total_expanded_size; } void BLI_array_store_state_data_get(BArrayState *state, void *data) @@ -1566,7 +1627,7 @@ void BLI_array_store_state_data_get(BArrayState *state, void *data) LISTBASE_FOREACH (BChunkRef *, cref, &state->chunk_list->chunk_refs) { data_test_len += cref->link->data_len; } - BLI_assert(data_test_len == state->chunk_list->total_size); + BLI_assert(data_test_len == state->chunk_list->total_expanded_size); #endif uchar *data_step = (uchar *)data; @@ -1579,9 +1640,9 @@ void BLI_array_store_state_data_get(BArrayState *state, void *data) void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_len) { - void *data = MEM_mallocN(state->chunk_list->total_size, __func__); + void *data = MEM_mallocN(state->chunk_list->total_expanded_size, __func__); BLI_array_store_state_data_get(state, data); - *r_data_len = state->chunk_list->total_size; + *r_data_len = state->chunk_list->total_expanded_size; return data; } @@ -1594,11 +1655,11 @@ void *BLI_array_store_state_data_get_alloc(BArrayState *state, size_t *r_data_le /* only for test validation */ static size_t bchunk_list_size(const BChunkList *chunk_list) { - size_t total_size = 0; + size_t total_expanded_size = 0; LISTBASE_FOREACH (BChunkRef *, cref, &chunk_list->chunk_refs) { - total_size += cref->link->data_len; + total_expanded_size += cref->link->data_len; } - return total_size; + return total_expanded_size; } bool BLI_array_store_is_valid(BArrayStore *bs) @@ -1610,7 +1671,7 @@ bool BLI_array_store_is_valid(BArrayStore *bs) LISTBASE_FOREACH (BArrayState *, state, &bs->states) { BChunkList *chunk_list = state->chunk_list; - if (!(bchunk_list_size(chunk_list) == chunk_list->total_size)) { + if (!(bchunk_list_size(chunk_list) == chunk_list->total_expanded_size)) { return false; } @@ -1620,7 +1681,7 @@ bool BLI_array_store_is_valid(BArrayStore *bs) #ifdef USE_MERGE_CHUNKS /* ensure we merge all chunks that could be merged */ - if (chunk_list->total_size > bs->info.chunk_byte_size_min) { + if (chunk_list->total_expanded_size > bs->info.chunk_byte_size_min) { LISTBASE_FOREACH (BChunkRef *, cref, &chunk_list->chunk_refs) { if (cref->link->data_len < bs->info.chunk_byte_size_min) { return false; diff --git a/source/blender/blenlib/intern/array_store_utils.c b/source/blender/blenlib/intern/array_store_utils.c index 51b5ce0519f..51d853d85b3 100644 --- a/source/blender/blenlib/intern/array_store_utils.c +++ b/source/blender/blenlib/intern/array_store_utils.c @@ -54,8 +54,8 @@ void BLI_array_store_at_size_clear(struct BArrayStore_AtSize *bs_stride) } } - MEM_freeN(bs_stride->stride_table); - bs_stride->stride_table = NULL; + /* It's possible this table was never used. */ + MEM_SAFE_FREE(bs_stride->stride_table); bs_stride->stride_table_len = 0; } diff --git a/source/blender/blenlib/intern/math_matrix.cc b/source/blender/blenlib/intern/math_matrix.cc index f215b460001..a266313d506 100644 --- a/source/blender/blenlib/intern/math_matrix.cc +++ b/source/blender/blenlib/intern/math_matrix.cc @@ -339,9 +339,9 @@ MatBase interpolate(const MatBase &A, const MatBase & P_B = -P_B; } - detail::Quaternion quat_A = math::to_quaternion(U_A); - detail::Quaternion quat_B = math::to_quaternion(U_B); - detail::Quaternion quat = math::interpolate(quat_A, quat_B, t); + QuaternionBase quat_A = math::to_quaternion(normalize(U_A)); + QuaternionBase quat_B = math::to_quaternion(normalize(U_B)); + QuaternionBase quat = math::interpolate(quat_A, quat_B, t); Mat3T U = from_rotation(quat); Mat3T P = interpolate_linear(P_A, P_B, t); @@ -372,7 +372,7 @@ template double4x4 interpolate(const double4x4 &a, const double4x4 &b, double t) template MatBase interpolate_fast(const MatBase &a, const MatBase &b, T t) { - using QuaternionT = detail::Quaternion; + using QuaternionT = QuaternionBase; using Vec3T = typename MatBase::vec3_type; Vec3T a_scale, b_scale; @@ -391,7 +391,7 @@ template double3x3 interpolate_fast(const double3x3 &a, const double3x3 &b, doub template MatBase interpolate_fast(const MatBase &a, const MatBase &b, T t) { - using QuaternionT = detail::Quaternion; + using QuaternionT = QuaternionBase; using Vec3T = typename MatBase::vec3_type; Vec3T a_loc, b_loc; @@ -411,6 +411,35 @@ template double4x4 interpolate_fast(const double4x4 &a, const double4x4 &b, doub /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Legacy + * \{ */ + +Quaternion to_quaternion_legacy(const float3x3 &mat) +{ + float3x3 n_mat = normalize(mat); + /* Rotate z-axis of matrix to z-axis. */ + float3 z_axis = n_mat.z_axis(); + + /* Cross product with (0,0,1). */ + float3 nor = normalize(float3(z_axis.y, -z_axis.x, 0.0f)); + + float ha = 0.5f * math::safe_acos(z_axis.z); + /* `nor` negative here, but why? */ + Quaternion q1(math::cos(ha), -nor * math::sin(ha)); + + /* Rotate back x-axis from mat, using inverse q1. */ + float3 x_axis = transform_point(conjugate(q1), n_mat.x_axis()); + + /* And align x-axes. */ + float ha2 = 0.5f * math::atan2(x_axis.y, x_axis.x); + Quaternion q2(math::cos(ha2), 0.0f, 0.0f, math::sin(ha2)); + + return q1 * q2; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Template instantiation * \{ */ @@ -418,23 +447,30 @@ template double4x4 interpolate_fast(const double4x4 &a, const double4x4 &b, doub namespace detail { template void normalized_to_eul2(const float3x3 &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2); + Euler3Base &eul1, + Euler3Base &eul2); +template void normalized_to_eul2(const float3x3 &mat, + EulerXYZBase &eul1, + EulerXYZBase &eul2); template void normalized_to_eul2(const double3x3 &mat, - detail::EulerXYZ &eul1, - detail::EulerXYZ &eul2); + EulerXYZBase &eul1, + EulerXYZBase &eul2); -template detail::Quaternion normalized_to_quat_with_checks(const float3x3 &mat); -template detail::Quaternion normalized_to_quat_with_checks(const double3x3 &mat); +template QuaternionBase normalized_to_quat_with_checks(const float3x3 &mat); +template QuaternionBase normalized_to_quat_with_checks(const double3x3 &mat); -template MatBase from_rotation(const detail::AngleRadian &rotation); -template MatBase from_rotation(const detail::AngleRadian &rotation); -template MatBase from_rotation(const detail::EulerXYZ &rotation); -template MatBase from_rotation(const detail::EulerXYZ &rotation); -template MatBase from_rotation(const detail::Quaternion &rotation); -template MatBase from_rotation(const detail::Quaternion &rotation); -template MatBase from_rotation(const detail::AxisAngle &rotation); -template MatBase from_rotation(const detail::AxisAngle &rotation); +template MatBase from_rotation(const AngleRadian &rotation); +template MatBase from_rotation(const AngleRadian &rotation); +template MatBase from_rotation(const EulerXYZ &rotation); +template MatBase from_rotation(const EulerXYZ &rotation); +template MatBase from_rotation(const Euler3 &rotation); +template MatBase from_rotation(const Euler3 &rotation); +template MatBase from_rotation(const Quaternion &rotation); +template MatBase from_rotation(const Quaternion &rotation); +template MatBase from_rotation(const AxisAngle &rotation); +template MatBase from_rotation(const AxisAngle &rotation); +template MatBase from_rotation(const AxisAngleCartesian &rotation); +template MatBase from_rotation(const AxisAngleCartesian &rotation); } // namespace detail diff --git a/source/blender/blenlib/intern/math_rotation.cc b/source/blender/blenlib/intern/math_rotation.cc index 968d5bc57c0..a6918556240 100644 --- a/source/blender/blenlib/intern/math_rotation.cc +++ b/source/blender/blenlib/intern/math_rotation.cc @@ -11,26 +11,100 @@ #include "BLI_math_vector.h" #include "BLI_math_vector.hh" -namespace blender::math::detail { - -template AxisAngle::operator EulerXYZ() const; -template AxisAngle::operator Quaternion() const; -template EulerXYZ::operator AxisAngle() const; -template EulerXYZ::operator Quaternion() const; -template Quaternion::operator AxisAngle() const; -template Quaternion::operator EulerXYZ() const; - -template AxisAngle::operator EulerXYZ() const; -template AxisAngle::operator Quaternion() const; -template EulerXYZ::operator AxisAngle() const; -template EulerXYZ::operator Quaternion() const; -template Quaternion::operator AxisAngle() const; -template Quaternion::operator EulerXYZ() const; - -} // namespace blender::math::detail - namespace blender::math { +template EulerXYZ to_euler(const AxisAngle &); +template EulerXYZ to_euler(const AxisAngleCartesian &); +template EulerXYZ to_euler(const Quaternion &); +template Euler3 to_euler(const AxisAngle &, EulerOrder); +template Euler3 to_euler(const AxisAngleCartesian &, EulerOrder); +template Euler3 to_euler(const Quaternion &, EulerOrder); +template Quaternion to_quaternion(const AxisAngle &); +template Quaternion to_quaternion(const AxisAngleCartesian &); +template Quaternion to_quaternion(const Euler3 &); +template Quaternion to_quaternion(const EulerXYZ &); +template AxisAngleCartesian to_axis_angle(const Euler3 &); +template AxisAngleCartesian to_axis_angle(const EulerXYZ &); +template AxisAngleCartesian to_axis_angle(const Quaternion &); +template AxisAngle to_axis_angle(const Euler3 &); +template AxisAngle to_axis_angle(const EulerXYZ &); +template AxisAngle to_axis_angle(const Quaternion &); + +#if 0 /* Only for reference. */ +void generate_axes_to_quaternion_switch_cases() +{ + std::cout << "default: *this = identity(); break;" << std::endl; + /* Go through all 32 cases. Only 23 valid and 1 is identity. */ + for (int i : IndexRange(6)) { + for (int j : IndexRange(6)) { + const AxisSigned forward = AxisSigned(i); + const AxisSigned up = AxisSigned(j); + /* Filter the 12 invalid cases. Fall inside the default case. */ + if (Axis(forward) == Axis(up)) { + continue; + } + /* Filter the identity case. Fall inside the default case. */ + if (forward == AxisSigned::Y_POS && up == AxisSigned::Z_POS) { + continue; + } + + VecBase axes{cross(forward, up), forward, up}; + + float3x3 mat; + mat.x_axis() = float3(axes.x); + mat.y_axis() = float3(axes.y); + mat.z_axis() = float3(axes.z); + + math::Quaternion q = to_quaternion(mat); + /* Create a integer value out of the 4 possible component values (+sign). */ + int4 p = int4(round(sign(float4(q)) * min(pow(float4(q), 2.0f), float4(0.75)) * 4.0)); + + auto format_component = [](int value) { + switch (abs(value)) { + default: + case 0: + return "T(0)"; + case 1: + return (value > 0) ? "T(0.5)" : "T(-0.5)"; + case 2: + return (value > 0) ? "T(M_SQRT1_2)" : "T(-M_SQRT1_2)"; + case 3: + return (value > 0) ? "T(1)" : "T(-1)"; + } + }; + auto format_axis = [](AxisSigned axis) { + switch (axis) { + default: + case AxisSigned::X_POS: + return "AxisSigned::X_POS"; + case AxisSigned::Y_POS: + return "AxisSigned::Y_POS"; + case AxisSigned::Z_POS: + return "AxisSigned::Z_POS"; + case AxisSigned::X_NEG: + return "AxisSigned::X_NEG"; + case AxisSigned::Y_NEG: + return "AxisSigned::Y_NEG"; + case AxisSigned::Z_NEG: + return "AxisSigned::Z_NEG"; + } + }; + /* Use same code function as in the switch case. */ + std::cout << "case "; + std::cout << format_axis(axes.x) << " << 16 | "; + std::cout << format_axis(axes.y) << " << 8 | "; + std::cout << format_axis(axes.z); + std::cout << ": *this = {"; + std::cout << format_component(p.x) << ", "; + std::cout << format_component(p.y) << ", "; + std::cout << format_component(p.z) << ", "; + std::cout << format_component(p.w) << "}; break;"; + std::cout << std::endl; + } + } +} +#endif + float3 rotate_direction_around_axis(const float3 &direction, const float3 &axis, const float angle) { BLI_ASSERT_UNIT_V3(direction); @@ -56,4 +130,23 @@ float3 rotate_around_axis(const float3 &vector, return result + center; } +std::ostream &operator<<(std::ostream &stream, EulerOrder order) +{ + switch (order) { + default: + case XYZ: + return stream << "XYZ"; + case XZY: + return stream << "XZY"; + case YXZ: + return stream << "YXZ"; + case YZX: + return stream << "YZX"; + case ZXY: + return stream << "ZXY"; + case ZYX: + return stream << "ZYX"; + } +} + } // namespace blender::math diff --git a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc index cc6bae0ea0e..2ed1786f9e0 100644 --- a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc +++ b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc @@ -58,16 +58,9 @@ TEST(linear_allocator, CopyString) blender::AlignedBuffer<256, 1> buffer; allocator.provide_buffer(buffer); - /* False positive warning with GCC 12.2, - * considers assignment outside of array bounds (`char [0]`). */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Warray-bounds" - StringRefNull ref1 = allocator.copy_string("Hello"); StringRefNull ref2 = allocator.copy_string("World"); -#pragma GCC diagnostic pop - EXPECT_EQ(ref1, "Hello"); EXPECT_EQ(ref2, "World"); EXPECT_EQ(ref2.data() - ref1.data(), 6); diff --git a/source/blender/blenlib/tests/BLI_math_matrix_test.cc b/source/blender/blenlib/tests/BLI_math_matrix_test.cc index e04625c4163..2e08472ed44 100644 --- a/source/blender/blenlib/tests/BLI_math_matrix_test.cc +++ b/source/blender/blenlib/tests/BLI_math_matrix_test.cc @@ -4,6 +4,7 @@ #include "BLI_math_matrix.h" #include "BLI_math_matrix.hh" +#include "BLI_math_rotation.h" #include "BLI_math_rotation.hh" TEST(math_matrix, interp_m4_m4m4_regular) @@ -229,8 +230,8 @@ TEST(math_matrix, MatrixInit) {-0.909297, -0.350175, -0.224845, 0}, {0, 0, 0, 1})); EulerXYZ euler(1, 2, 3); - Quaternion quat(euler); - AxisAngle axis_angle(euler); + Quaternion quat = to_quaternion(euler); + AxisAngle axis_angle = to_axis_angle(euler); m = from_rotation(euler); EXPECT_M3_NEAR(m, expect, 1e-5); m = from_rotation(quat); @@ -238,6 +239,14 @@ TEST(math_matrix, MatrixInit) m = from_rotation(axis_angle); EXPECT_M3_NEAR(m, expect, 1e-5); + expect = transpose(float4x4({0.823964, -1.66748, -0.735261, 3.28334}, + {-0.117453, -0.853835, 1.80476, 5.44925}, + {-1.81859, -0.700351, -0.44969, -0.330972}, + {0, 0, 0, 1})); + DualQuaternion dual_quat(quat, Quaternion(0.5f, 0.5f, 0.5f, 1.5f), float4x4::diagonal(2.0f)); + m = from_rotation(dual_quat); + EXPECT_M3_NEAR(m, expect, 1e-5); + m = from_scale(float4(1, 2, 3, 4)); expect = float4x4({1, 0, 0, 0}, {0, 2, 0, 0}, {0, 0, 3, 0}, {0, 0, 0, 4}); EXPECT_TRUE(is_equal(m, expect, 0.00001f)); @@ -317,6 +326,19 @@ TEST(math_matrix, MatrixCompareTest) EXPECT_FALSE(is_negative(m6)); } +TEST(math_matrix, MatrixToNearestEuler) +{ + EulerXYZ eul1 = EulerXYZ(225.08542, -1.12485, -121.23738); + Euler3 eul2 = Euler3(float3{4.06112, 100.561928, -18.9063}, EulerOrder::ZXY); + + float3x3 mat = {{0.808309, -0.578051, -0.111775}, + {0.47251, 0.750174, -0.462572}, + {0.351241, 0.321087, 0.879507}}; + + EXPECT_V3_NEAR(float3(to_nearest_euler(mat, eul1)), float3(225.71, 0.112009, -120.001), 1e-3); + EXPECT_V3_NEAR(float3(to_nearest_euler(mat, eul2)), float3(5.95631, 100.911, -19.5061), 1e-3); +} + TEST(math_matrix, MatrixMethods) { float4x4 m = float4x4({0, 3, 0, 0}, {2, 0, 0, 0}, {0, 0, 2, 0}, {0, 1, 0, 1}); @@ -325,8 +347,6 @@ TEST(math_matrix, MatrixMethods) float3 expect_scale = float3(3, 2, 2); float3 expect_location = float3(0, 1, 0); - EXPECT_V3_NEAR(float3(to_euler(m)), float3(expect_eul), 0.0002f); - EXPECT_V4_NEAR(float4(to_quaternion(m)), float4(expect_qt), 0.0002f); EXPECT_EQ(to_scale(m), expect_scale); float4 expect_sz = {3, 2, 2, M_SQRT2}; @@ -338,6 +358,9 @@ TEST(math_matrix, MatrixMethods) float4x4 m2 = normalize(m); EXPECT_TRUE(is_unit_scale(m2)); + EXPECT_V3_NEAR(float3(to_euler(m1)), float3(expect_eul), 0.0002f); + EXPECT_V4_NEAR(float4(to_quaternion(m1)), float4(expect_qt), 0.0002f); + EulerXYZ eul; Quaternion qt; float3 scale; @@ -356,6 +379,17 @@ TEST(math_matrix, MatrixMethods) EXPECT_V3_NEAR(float3(eul), float3(expect_eul), 0.0002f); } +TEST(math_matrix, MatrixToQuaternionLegacy) +{ + float3x3 mat = {{0.808309, -0.578051, -0.111775}, + {0.47251, 0.750174, -0.462572}, + {0.351241, 0.321087, 0.879507}}; + + EXPECT_V4_NEAR(float4(to_quaternion_legacy(mat)), + float4(0.927091f, -0.211322f, 0.124857f, -0.283295f), + 1e-5f); +} + TEST(math_matrix, MatrixTranspose) { float4x4 m({1, 2, 3, 4}, {5, 6, 7, 8}, {9, 1, 2, 3}, {2, 5, 6, 7}); diff --git a/source/blender/blenlib/tests/BLI_math_rotation_test.cc b/source/blender/blenlib/tests/BLI_math_rotation_test.cc index 2d74b40a90d..497adc93456 100644 --- a/source/blender/blenlib/tests/BLI_math_rotation_test.cc +++ b/source/blender/blenlib/tests/BLI_math_rotation_test.cc @@ -281,9 +281,9 @@ TEST(math_rotation, DefaultConstructor) EXPECT_EQ(quat.w, 0.0f); EulerXYZ eul{}; - EXPECT_EQ(eul.x, 0.0f); - EXPECT_EQ(eul.y, 0.0f); - EXPECT_EQ(eul.z, 0.0f); + EXPECT_EQ(eul.x(), 0.0f); + EXPECT_EQ(eul.y(), 0.0f); + EXPECT_EQ(eul.z(), 0.0f); } TEST(math_rotation, RotateDirectionAroundAxis) @@ -304,39 +304,532 @@ TEST(math_rotation, RotateDirectionAroundAxis) TEST(math_rotation, AxisAngleConstructors) { - AxisAngle a({0.0f, 0.0f, 2.0f}, M_PI_2); + AxisAngle a({0.0f, 0.0f, 1.0f}, M_PI_2); EXPECT_V3_NEAR(a.axis(), float3(0, 0, 1), 1e-4); - EXPECT_NEAR(a.angle(), M_PI_2, 1e-4); + EXPECT_NEAR(float(a.angle()), M_PI_2, 1e-4); + EXPECT_NEAR(sin(a.angle()), 1.0f, 1e-4); + EXPECT_NEAR(cos(a.angle()), 0.0f, 1e-4); - AxisAngleNormalized b({0.0f, 0.0f, 1.0f}, M_PI_2); + AxisAngleCartesian b({0.0f, 0.0f, 1.0f}, AngleCartesian(AngleRadian(M_PI_2))); EXPECT_V3_NEAR(b.axis(), float3(0, 0, 1), 1e-4); - EXPECT_NEAR(b.angle(), M_PI_2, 1e-4); + EXPECT_NEAR(float(b.angle()), M_PI_2, 1e-4); + EXPECT_NEAR(b.angle().sin(), 1.0f, 1e-4); + EXPECT_NEAR(b.angle().cos(), 0.0f, 1e-4); + + AxisAngle axis_angle_basis = AxisAngle(AxisSigned::Y_NEG, M_PI); + EXPECT_EQ(axis_angle_basis.axis(), float3(0.0f, -1.0f, 0.0f)); + EXPECT_EQ(axis_angle_basis.angle(), M_PI); AxisAngle c({1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}); EXPECT_V3_NEAR(c.axis(), float3(0, 0, 1), 1e-4); - EXPECT_NEAR(c.angle(), M_PI_2, 1e-4); + EXPECT_NEAR(float(c.angle()), M_PI_2, 1e-4); AxisAngle d({1.0f, 0.0f, 0.0f}, {0.0f, -1.0f, 0.0f}); EXPECT_V3_NEAR(d.axis(), float3(0, 0, -1), 1e-4); - EXPECT_NEAR(d.angle(), M_PI_2, 1e-4); + EXPECT_NEAR(float(d.angle()), M_PI_2, 1e-4); } -TEST(math_rotation, TypeConversion) +TEST(math_rotation, QuaternionDot) { - EulerXYZ euler(0, 0, M_PI_2); - Quaternion quat(M_SQRT1_2, 0.0f, 0.0f, M_SQRT1_2); - AxisAngle axis_angle({0.0f, 0.0f, 2.0f}, M_PI_2); + Quaternion q1(1.0f, 2.0f, 3.0f, 4.0f); + Quaternion q2(2.0f, -3.0f, 5.0f, 100.0f); + EXPECT_EQ(math::dot(q1, q2), 411.0f); +} - EXPECT_V4_NEAR(float4(Quaternion(euler)), float4(quat), 1e-4); - EXPECT_V3_NEAR(AxisAngle(euler).axis(), axis_angle.axis(), 1e-4); - EXPECT_NEAR(AxisAngle(euler).angle(), axis_angle.angle(), 1e-4); +TEST(math_rotation, QuaternionConjugate) +{ + Quaternion q1(1.0f, 2.0f, 3.0f, 4.0f); + EXPECT_EQ(float4(conjugate(q1)), float4(1.0f, -2.0f, -3.0f, -4.0f)); +} - EXPECT_V3_NEAR(float3(EulerXYZ(quat)), float3(euler), 1e-4); - EXPECT_V3_NEAR(AxisAngle(quat).axis(), axis_angle.axis(), 1e-4); - EXPECT_NEAR(AxisAngle(quat).angle(), axis_angle.angle(), 1e-4); +TEST(math_rotation, QuaternionNormalize) +{ + Quaternion q1(1.0f, 2.0f, 3.0f, 4.0f); + EXPECT_V4_NEAR(float4(normalize(q1)), + float4(0.1825741827, 0.3651483654, 0.5477225780, 0.7302967309), + 1e-6f); +} - EXPECT_V3_NEAR(float3(EulerXYZ(axis_angle)), float3(euler), 1e-4); - EXPECT_V4_NEAR(float4(Quaternion(axis_angle)), float4(quat), 1e-4); +TEST(math_rotation, QuaternionInvert) +{ + Quaternion q1(1.0f, 2.0f, 3.0f, 4.0f); + EXPECT_V4_NEAR(float4(invert(q1)), float4(0.0333333f, -0.0666667f, -0.1f, -0.133333f), 1e-4f); + + Quaternion q2(0.927091f, 0.211322f, -0.124857f, 0.283295f); + Quaternion result = invert_normalized(normalize(q2)); + EXPECT_V4_NEAR(float4(result), float4(0.927091f, -0.211322f, 0.124857f, -0.283295f), 1e-4f); +} + +TEST(math_rotation, QuaternionCanonicalize) +{ + EXPECT_V4_NEAR(float4(canonicalize(Quaternion(0.5f, 2.0f, 3.0f, 4.0f))), + float4(0.5f, 2.0f, 3.0f, 4.0f), + 1e-4f); + EXPECT_V4_NEAR(float4(canonicalize(Quaternion(-0.5f, 2.0f, 3.0f, 4.0f))), + float4(0.5f, -2.0f, -3.0f, -4.0f), + 1e-4f); +} + +TEST(math_rotation, QuaternionAngleBetween) +{ + Quaternion q1 = normalize(Quaternion(0.927091f, 0.211322f, -0.124857f, 0.283295f)); + Quaternion q2 = normalize(Quaternion(-0.083377f, -0.051681f, 0.498261f, -0.86146f)); + Quaternion q3 = rotation_between(q1, q2); + EXPECT_V4_NEAR(float4(q3), float4(-0.394478f, 0.00330195f, 0.284119f, -0.873872f), 1e-4f); + EXPECT_NEAR(float(angle_of(q1)), 0.76844f, 1e-4f); + EXPECT_NEAR(float(angle_of(q2)), 3.30854f, 1e-4f); + EXPECT_NEAR(float(angle_of(q3)), 3.95259f, 1e-4f); + EXPECT_NEAR(float(angle_of_signed(q1)), 0.76844f, 1e-4f); + EXPECT_NEAR(float(angle_of_signed(q2)), 3.30854f - 2 * M_PI, 1e-4f); + EXPECT_NEAR(float(angle_of_signed(q3)), 3.95259f - 2 * M_PI, 1e-4f); + EXPECT_NEAR(float(angle_between(q1, q2)), 3.95259f, 1e-4f); + EXPECT_NEAR(float(angle_between_signed(q1, q2)), 3.95259f - 2 * M_PI, 1e-4f); +} + +TEST(math_rotation, QuaternionPower) +{ + Quaternion q1 = normalize(Quaternion(0.927091f, 0.211322f, -0.124857f, 0.283295f)); + Quaternion q2 = normalize(Quaternion(-0.083377f, -0.051681f, 0.498261f, -0.86146f)); + + EXPECT_V4_NEAR( + float4(math::pow(q1, -2.5f)), float4(0.573069, -0.462015, 0.272976, -0.61937), 1e-4); + EXPECT_V4_NEAR( + float4(math::pow(q1, -0.5f)), float4(0.981604, -0.107641, 0.0635985, -0.144302), 1e-4); + EXPECT_V4_NEAR( + float4(math::pow(q1, 0.5f)), float4(0.981604, 0.107641, -0.0635985, 0.144302), 1e-4); + EXPECT_V4_NEAR( + float4(math::pow(q1, 2.5f)), float4(0.573069, 0.462015, -0.272976, 0.61937), 1e-4); + EXPECT_V4_NEAR( + float4(math::pow(q2, -2.5f)), float4(-0.545272, -0.0434735, 0.419131, -0.72465), 1e-4); + EXPECT_V4_NEAR( + float4(math::pow(q2, -0.5f)), float4(0.676987, 0.0381699, -0.367999, 0.636246), 1e-4); + EXPECT_V4_NEAR( + float4(math::pow(q2, 0.5f)), float4(0.676987, -0.0381699, 0.367999, -0.636246), 1e-4); + EXPECT_V4_NEAR( + float4(math::pow(q2, 2.5f)), float4(-0.545272, 0.0434735, -0.419131, 0.72465), 1e-4); +} + +TEST(math_rotation, QuaternionFromTriangle) +{ + float3 v1(0.927091f, 0.211322f, -0.124857f); + float3 v2(-0.051681f, 0.498261f, -0.86146f); + float3 v3(0.211322f, -0.124857f, 0.283295f); + EXPECT_V4_NEAR(float4(from_triangle(v1, v2, v3)), + float4(0.255566f, -0.213799f, 0.454253f, 0.826214f), + 1e-5f); + EXPECT_V4_NEAR(float4(from_triangle(v1, v3, v2)), + float4(0.103802f, 0.295067f, -0.812945f, 0.491204f), + 1e-5f); +} + +TEST(math_rotation, QuaternionFromVector) +{ + float3 v1(0.927091f, 0.211322f, -0.124857f); + float3 v2(-0.051681f, 0.498261f, -0.86146f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::X_POS, Axis::X)), + float4(0.129047, 0, -0.50443, -0.853755), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::X_POS, Axis::Y)), + float4(0.12474, 0.0330631, -0.706333, -0.696017), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::X_POS, Axis::Z)), + float4(0.111583, -0.0648251, -0.00729451, -0.991612), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Y_POS, Axis::X)), + float4(0.476074, 0.580363, -0.403954, 0.522832), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Y_POS, Axis::Y)), + float4(0.62436, 0.104259, 0, 0.774148), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Y_POS, Axis::Z)), + float4(0.622274, 0.0406802, 0.0509963, 0.780077), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Z_POS, Axis::X)), + float4(0.747014, 0.0737433, -0.655337, 0.0840594), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Z_POS, Axis::Z)), + float4(0.751728, 0.146562, -0.642981, 0), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Z_POS, Axis::Z)), + float4(0.751728, 0.146562, -0.642981, 0), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::X_NEG, Axis::X)), + float4(0.991638, 0, 0.0656442, 0.111104), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::X_NEG, Axis::Y)), + float4(0.706333, 0.696017, 0.12474, 0.0330631), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::X_NEG, Axis::Z)), + float4(0.991612, -0.0072946, 0.0648251, 0.111583), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Y_NEG, Axis::X)), + float4(0.580363, -0.476074, -0.522832, -0.403954), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Y_NEG, Axis::Y)), + float4(0.781137, -0.083334, 0, -0.618774), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Y_NEG, Axis::Z)), + float4(0.780077, -0.0509963, 0.0406802, -0.622274), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Z_NEG, Axis::X)), + float4(0.0737433, -0.747014, -0.0840594, -0.655337), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Z_NEG, Axis::Z)), + float4(0.659473, -0.167065, 0.732929, 0), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v1, AxisSigned::Z_NEG, Axis::Z)), + float4(0.659473, -0.167065, 0.732929, 0), + 1e-5f); + + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::X_POS, Axis::X)), + float4(0.725211, 0, -0.596013, -0.344729), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::X_POS, Axis::Y)), + float4(0.691325, 0.219092, -0.672309, -0.148561), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::X_POS, Axis::Z)), + float4(0.643761, -0.333919, -0.370346, -0.580442), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Y_POS, Axis::X)), + float4(0.320473, 0.593889, 0.383792, 0.630315), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Y_POS, Axis::Y)), + float4(0.499999, 0.864472, 0, -0.0518617), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Y_POS, Axis::Z)), + float4(0.0447733, 0.0257574, -0.49799, -0.865643), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Z_POS, Axis::X)), + float4(0.646551, 0.193334, -0.174318, 0.717082), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Z_POS, Axis::Z)), + float4(0.965523, 0.258928, 0.0268567, 0), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Z_POS, Axis::Z)), + float4(0.965523, 0.258928, 0.0268567, 0), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::X_NEG, Axis::X)), + float4(0.688527, 0, 0.627768, 0.363095), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::X_NEG, Axis::Y)), + float4(0.672309, 0.148561, 0.691325, 0.219092), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::X_NEG, Axis::Z)), + float4(0.580442, -0.370345, 0.333919, 0.643761), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Y_NEG, Axis::X)), + float4(0.593889, -0.320473, -0.630315, 0.383792), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Y_NEG, Axis::Y)), + float4(0.866026, -0.499102, 0, 0.0299423), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Y_NEG, Axis::Z)), + float4(0.865643, -0.49799, -0.0257574, 0.0447733), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Z_NEG, Axis::X)), + float4(0.193334, -0.646551, -0.717082, -0.174318), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Z_NEG, Axis::Z)), + float4(0.260317, -0.960371, -0.0996123, 0), + 1e-5f); + EXPECT_V4_NEAR(float4(from_vector(v2, AxisSigned::Z_NEG, Axis::Z)), + float4(0.260317, -0.960371, -0.0996123, 0), + 1e-5f); +} + +TEST(math_rotation, QuaternionWrappedAround) +{ + Quaternion q1 = normalize(Quaternion(0.927091f, 0.211322f, -0.124857f, 0.283295f)); + Quaternion q2 = normalize(Quaternion(-0.083377f, -0.051681f, 0.498261f, -0.86146f)); + Quaternion q_malformed = Quaternion(0.0f, 0.0f, 0.0f, 0.0f); + EXPECT_V4_NEAR(float4(q1.wrapped_around(q2)), float4(-q1), 1e-4f); + EXPECT_V4_NEAR(float4(q1.wrapped_around(-q2)), float4(q1), 1e-4f); + EXPECT_V4_NEAR(float4(q1.wrapped_around(q_malformed)), float4(q1), 1e-4f); +} + +TEST(math_rotation, QuaternionFromTracking) +{ + for (int i : IndexRange(6)) { + for (int j : IndexRange(3)) { + AxisSigned forward_axis = AxisSigned::from_int(i); + Axis up_axis = Axis::from_int(j); + + if (forward_axis.axis() == up_axis) { + continue; + } + + Quaternion expect = Quaternion::identity(); + quat_apply_track(&expect.w, forward_axis.as_int(), up_axis.as_int()); + + /* This is the expected axis conversion for curve tangent space to tracked object space. */ + CartesianBasis axes = rotation_between( + from_orthonormal_axes(AxisSigned::Z_POS, AxisSigned::Y_POS), + from_orthonormal_axes(forward_axis, AxisSigned(up_axis))); + Quaternion result = to_quaternion(axes); + + EXPECT_V4_NEAR(float4(result), float4(expect), 1e-5f); + } + } +} + +TEST(math_rotation, EulerWrappedAround) +{ + EulerXYZ eul1 = EulerXYZ(2.08542, -1.12485, -1.23738); + EulerXYZ eul2 = EulerXYZ(4.06112, 0.561928, -18.9063); + EXPECT_V3_NEAR(float3(eul1.wrapped_around(eul2)), float3(2.08542, -1.12485, -20.0869), 1e-4f); + EXPECT_V3_NEAR(float3(eul2.wrapped_around(eul1)), float3(4.06112, 0.561928, -0.0567436), 1e-4f); +} + +TEST(math_rotation, Euler3ToGimbal) +{ + /* All the same rotation. */ + float3 ijk{0.350041, -0.358896, 0.528994}; + Euler3 euler3_xyz(ijk, EulerOrder::XYZ); + Euler3 euler3_xzy(ijk, EulerOrder::XZY); + Euler3 euler3_yxz(ijk, EulerOrder::YXZ); + Euler3 euler3_yzx(ijk, EulerOrder::YZX); + Euler3 euler3_zxy(ijk, EulerOrder::ZXY); + Euler3 euler3_zyx(ijk, EulerOrder::ZYX); + + float3x3 mat_xyz = transpose( + float3x3({0.808309, -0.504665, 0}, {0.47251, 0.863315, 0}, {0.351241, 0, 1})); + float3x3 mat_xzy = transpose( + float3x3({0.808309, 0, -0.351241}, {0.504665, 1, -0}, {0.303232, 0, 0.936285})); + float3x3 mat_yxz = transpose( + float3x3({0.863315, -0.474062, 0}, {0.504665, 0.810963, 0}, {-0, 0.342936, 1})); + float3x3 mat_yzx = transpose( + float3x3({1, -0.504665, 0}, {0, 0.810963, -0.342936}, {0, 0.296062, 0.939359})); + float3x3 mat_zxy = transpose( + float3x3({0.936285, 0, -0.329941}, {0, 1, -0.342936}, {0.351241, 0, 0.879508})); + float3x3 mat_zyx = transpose( + float3x3({1, -0, -0.351241}, {0, 0.939359, -0.321086}, {0, 0.342936, 0.879508})); + + EXPECT_M3_NEAR(to_gimbal_axis(euler3_xyz), mat_xyz, 1e-4); + EXPECT_M3_NEAR(to_gimbal_axis(euler3_xzy), mat_xzy, 1e-4); + EXPECT_M3_NEAR(to_gimbal_axis(euler3_yxz), mat_yxz, 1e-4); + EXPECT_M3_NEAR(to_gimbal_axis(euler3_yzx), mat_yzx, 1e-4); + EXPECT_M3_NEAR(to_gimbal_axis(euler3_zxy), mat_zxy, 1e-4); + EXPECT_M3_NEAR(to_gimbal_axis(euler3_zyx), mat_zyx, 1e-4); +} + +TEST(math_rotation, CartesianBasis) +{ + for (int i : IndexRange(6)) { + for (int j : IndexRange(6)) { + for (int k : IndexRange(6)) { + for (int l : IndexRange(6)) { + AxisSigned src_forward = AxisSigned::from_int(i); + AxisSigned src_up = AxisSigned::from_int(j); + AxisSigned dst_forward = AxisSigned::from_int(k); + AxisSigned dst_up = AxisSigned::from_int(l); + + if ((abs(src_forward) == abs(src_up)) || (abs(dst_forward) == abs(dst_up))) { + /* Assertion expected. */ + continue; + } + + float3x3 expect; + if (src_forward == dst_forward && src_up == dst_up) { + expect = float3x3::identity(); + } + else { + /* TODO: Find a way to test without resorting to old C API. */ + mat3_from_axis_conversion(src_forward.as_int(), + src_up.as_int(), + dst_forward.as_int(), + dst_up.as_int(), + expect.ptr()); + } + + EXPECT_EQ(from_rotation( + rotation_between(from_orthonormal_axes(src_forward, src_up), + from_orthonormal_axes(dst_forward, dst_up))), + expect); + + if (src_forward == dst_forward) { + expect = float3x3::identity(); + } + else { + /* TODO: Find a way to test without resorting to old C API. */ + mat3_from_axis_conversion_single( + src_forward.as_int(), dst_forward.as_int(), expect.ptr()); + } + + EXPECT_EQ(from_rotation(rotation_between(src_forward, dst_forward)), expect); + } + } + } + } +} + +TEST(math_rotation, Transform) +{ + Quaternion q(0.927091f, 0.211322f, -0.124857f, 0.283295f); + + float3 p(0.576f, -0.6546f, 46.354f); + p = transform_point(q, p); + EXPECT_V3_NEAR(p, float3(-4.33722f, -21.661f, 40.7608f), 1e-4f); +} + +TEST(math_rotation, DualQuaternionNormalize) +{ + DualQuaternion sum = DualQuaternion(Quaternion(0, 0, 1, 0), Quaternion(0, 1, 0, 1)) * 2.0f; + sum += DualQuaternion(Quaternion(1, 0, 0, 0), Quaternion(1, 1, 1, 1), float4x4::identity()) * + 4.0f; + sum += DualQuaternion(Quaternion(1, 0, 0, 0), Quaternion(1, 0, 0, 0), float4x4::identity()) * + 3.0f; + + sum = normalize(sum); + + /* The difference with the C API. */ + float len = length(float4(0.777778, 0, 0.222222, 0)); + + EXPECT_V4_NEAR(float4(sum.quat), (float4(0.777778, 0, 0.222222, 0) / len), 1e-4f); + EXPECT_V4_NEAR(float4(sum.trans), (float4(0.777778, 0.666667, 0.444444, 0.666667) / len), 1e-4f); + EXPECT_EQ(sum.scale, float4x4::identity()); + EXPECT_EQ(sum.scale_weight, 1.0f); + EXPECT_EQ(sum.quat_weight, 1.0f); +} + +TEST(math_rotation, DualQuaternionFromMatrix) +{ + { + float4x4 mat{transpose(float4x4({-2.14123, -0.478481, -1.38296, -2.26029}, + {-1.28264, 2.87361, 0.0230992, 12.8871}, + {3.27343, 0.812993, -0.895575, -13.5216}, + {0, 0, 0, 1}))}; + float4x4 basemat{transpose(float4x4({0.0988318, 0.91328, 0.39516, 7.73971}, + {0.16104, -0.406549, 0.899324, 22.8871}, + {0.981987, -0.0252451, -0.187255, -3.52155}, + {0, 0, 0, 1}))}; + float4x4 expected_scale_mat{transpose(float4x4({4.08974, 0.306437, -0.0853435, -31.2277}, + {-0.445021, 2.97151, -0.250095, -42.5586}, + {0.146173, 0.473002, 1.62645, -9.75092}, + {0, 0, 0, 1}))}; + + DualQuaternion dq = to_dual_quaternion(mat, basemat); + EXPECT_V4_NEAR(float4(dq.quat), float4(0.502368, 0.0543716, -0.854483, -0.120535), 1e-4f); + EXPECT_V4_NEAR(float4(dq.trans), float4(22.674, -0.878616, 11.2762, 14.167), 1e-4f); + EXPECT_M4_NEAR(dq.scale, expected_scale_mat, 1e-4f); + EXPECT_EQ(dq.scale_weight, 1.0f); + EXPECT_EQ(dq.quat_weight, 1.0f); + } + { + float4x4 mat{transpose(float4x4({-0.0806635, -1.60529, 2.44763, 26.823}, + {-1.04583, -0.150756, -0.385074, -22.2225}, + {-0.123402, 2.32698, 1.66357, 5.397}, + {0, 0, 0, 1}))}; + float4x4 basemat{transpose(float4x4({0.0603774, 0.904674, 0.421806, 36.823}, + {-0.271734, 0.421514, -0.865151, -12.2225}, + {-0.960477, -0.0623834, 0.27128, 15.397}, + {0, 0, 0, 1}))}; + float4x4 expected_scale_mat{transpose(float4x4({0.248852, 2.66363, -0.726295, 71.3985}, + {0.971507, -0.382422, 1.09917, -69.5943}, + {-0.331274, 0.8794, 2.67787, -2.88715}, + {0, 0, 0, 1}))}; + + DualQuaternion dq = to_dual_quaternion(mat, basemat); + EXPECT_V4_NEAR(float4(dq.quat), float4(0.149898, -0.319339, -0.0441496, -0.934668), 1e-4f); + EXPECT_V4_NEAR(float4(dq.trans), float4(-2.20019, 39.6236, 49.052, -16.2077), 1e-4f); + EXPECT_M4_NEAR(dq.scale, expected_scale_mat, 1e-4f); + EXPECT_EQ(dq.scale_weight, 1.0f); + EXPECT_EQ(dq.quat_weight, 1.0f); + } + +#if 0 /* Generate random matrices. */ + for (int i = 0; i < 1000; i++) { + auto frand = []() { return (std::rand() - RAND_MAX / 2) / float(RAND_MAX); }; + float4x4 mat = from_loc_rot_scale( + float3{frand(), frand(), frand()} * 100.0f, + EulerXYZ{frand() * 10.0f, frand() * 10.0f, frand() * 10.0f}, + float3{frand(), frand(), frand()} * 10.0f); + float4x4 basemat = from_loc_rot( + mat.location() + 10, EulerXYZ{frand() * 10.0f, frand() * 10.0f, frand() * 10.0f}); + + DualQuaternion expect; + mat4_to_dquat((DualQuat *)&expect.quat.w, basemat.ptr(), mat.ptr()); + + DualQuaternion dq = to_dual_quaternion(mat, basemat); + EXPECT_V4_NEAR(float4(dq.quat), float4(expect.quat), 1e-4f); + EXPECT_V4_NEAR(float4(dq.trans), float4(expect.trans), 1e-4f); + EXPECT_M4_NEAR(dq.scale, expect.scale, 2e-4f); + EXPECT_EQ(dq.scale_weight, expect.scale_weight); + } +#endif +} + +TEST(math_rotation, DualQuaternionTransform) +{ + { + float4x4 scale_mat{transpose(float4x4({4.08974, 0.306437, -0.0853435, -31.2277}, + {-0.445021, 2.97151, -0.250095, -42.5586}, + {0.146173, 0.473002, 1.62645, -9.75092}, + {0, 0, 0, 1}))}; + + DualQuaternion dq({0.502368, 0.0543716, -0.854483, -0.120535}, + {22.674, -0.878616, 11.2762, 14.167}, + scale_mat); + + float3 p0{51.0f, 1647.0f, 12.0f}; + float3 p1{58.0f, 0.0054f, 10.0f}; + float3 p2{0.0f, 7854.0f, 111.0f}; + + float3x3 crazy_space_mat; + float3 p0_expect = p0; + float3 p1_expect = p1; + float3 p2_expect = p2; + mul_v3m3_dq(p0_expect, crazy_space_mat.ptr(), (DualQuat *)&dq); + mul_v3m3_dq(p1_expect, crazy_space_mat.ptr(), (DualQuat *)&dq); + mul_v3m3_dq(p2_expect, crazy_space_mat.ptr(), (DualQuat *)&dq); + + float3 p0_result = transform_point(dq, p0); + float3 p1_result = transform_point(dq, p1); + float3 p2_result = transform_point(dq, p2, &crazy_space_mat); + + float4x4 expected_crazy_space_mat{transpose(float3x3({-2.14123, -0.478481, -1.38296}, + {-1.28264, 2.87361, 0.0230978}, + {3.27343, 0.812991, -0.895574}))}; + + EXPECT_V3_NEAR(p0_result, p0_expect, 1e-2f); + EXPECT_V3_NEAR(p1_result, p1_expect, 1e-2f); + EXPECT_V3_NEAR(p2_result, p2_expect, 1e-2f); + EXPECT_M3_NEAR(crazy_space_mat, expected_crazy_space_mat, 1e-4f); + } + { + float4x4 scale_mat{transpose(float4x4({0.248852, 2.66363, -0.726295, 71.3985}, + {0.971507, -0.382422, 1.09917, -69.5943}, + {-0.331274, 0.8794, 2.67787, -2.88715}, + {0, 0, 0, 1}))}; + + DualQuaternion dq({0.149898, -0.319339, -0.0441496, -0.934668}, + {-2.20019, 39.6236, 49.052, -16.207}, + scale_mat); + + float3 p0{51.0f, 1647.0f, 12.0f}; + float3 p1{58.0f, 0.0054f, 10.0f}; + float3 p2{0.0f, 7854.0f, 111.0f}; + + float3x3 crazy_space_mat; + float3 p0_expect = p0; + float3 p1_expect = p1; + float3 p2_expect = p2; + mul_v3m3_dq(p0_expect, crazy_space_mat.ptr(), (DualQuat *)&dq); + mul_v3m3_dq(p1_expect, crazy_space_mat.ptr(), (DualQuat *)&dq); + mul_v3m3_dq(p2_expect, crazy_space_mat.ptr(), (DualQuat *)&dq); + + float3 p0_result = transform_point(dq, p0); + float3 p1_result = transform_point(dq, p1); + float3 p2_result = transform_point(dq, p2, &crazy_space_mat); + + float4x4 expected_crazy_space_mat{transpose(float3x3({-0.0806647, -1.60529, 2.44763}, + {-1.04583, -0.150754, -0.385079}, + {-0.123401, 2.32698, 1.66357}))}; + + EXPECT_V3_NEAR(p0_result, float3(-2591.83, -328.472, 3851.6), 1e-2f); + EXPECT_V3_NEAR(p1_result, float3(46.6121, -86.7318, 14.8882), 1e-2f); + EXPECT_V3_NEAR(p2_result, float3(-12309.5, -1248.99, 18466.1), 6e-2f); + EXPECT_M3_NEAR(crazy_space_mat, expected_crazy_space_mat, 1e-4f); + } } } // namespace blender::math::tests diff --git a/source/blender/blenlib/tests/BLI_math_rotation_types_test.cc b/source/blender/blenlib/tests/BLI_math_rotation_types_test.cc new file mode 100644 index 00000000000..e6a0576c7dd --- /dev/null +++ b/source/blender/blenlib/tests/BLI_math_rotation_types_test.cc @@ -0,0 +1,440 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "testing/testing.h" + +#include "DNA_action_types.h" + +#include "BLI_math_rotation.h" +#include "BLI_math_rotation.hh" +#include "BLI_math_rotation_types.hh" + +namespace blender::tests { + +using namespace blender::math; + +TEST(math_rotation_types, AxisSignedCross) +{ + auto test_fn = [](AxisSigned a, AxisSigned b) { + return to_vector(cross(a, b)) == cross(to_vector(a), to_vector(b)); + }; + EXPECT_TRUE(test_fn(AxisSigned::X_POS, AxisSigned::Y_POS)); + EXPECT_TRUE(test_fn(AxisSigned::X_POS, AxisSigned::Z_POS)); + EXPECT_TRUE(test_fn(AxisSigned::X_POS, AxisSigned::Y_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::X_POS, AxisSigned::Z_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::Y_POS, AxisSigned::X_POS)); + EXPECT_TRUE(test_fn(AxisSigned::Y_POS, AxisSigned::Z_POS)); + EXPECT_TRUE(test_fn(AxisSigned::Y_POS, AxisSigned::X_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::Y_POS, AxisSigned::Z_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::Z_POS, AxisSigned::X_POS)); + EXPECT_TRUE(test_fn(AxisSigned::Z_POS, AxisSigned::Y_POS)); + EXPECT_TRUE(test_fn(AxisSigned::Z_POS, AxisSigned::X_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::Z_POS, AxisSigned::Y_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::X_NEG, AxisSigned::Y_POS)); + EXPECT_TRUE(test_fn(AxisSigned::X_NEG, AxisSigned::Z_POS)); + EXPECT_TRUE(test_fn(AxisSigned::X_NEG, AxisSigned::Y_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::X_NEG, AxisSigned::Z_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::Y_NEG, AxisSigned::X_POS)); + EXPECT_TRUE(test_fn(AxisSigned::Y_NEG, AxisSigned::Z_POS)); + EXPECT_TRUE(test_fn(AxisSigned::Y_NEG, AxisSigned::X_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::Y_NEG, AxisSigned::Z_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::Z_NEG, AxisSigned::X_POS)); + EXPECT_TRUE(test_fn(AxisSigned::Z_NEG, AxisSigned::Y_POS)); + EXPECT_TRUE(test_fn(AxisSigned::Z_NEG, AxisSigned::X_NEG)); + EXPECT_TRUE(test_fn(AxisSigned::Z_NEG, AxisSigned::Y_NEG)); +} + +TEST(math_rotation_types, AxisSignedConvertToVec) +{ + EXPECT_EQ(to_vector(AxisSigned::X_POS), float3(1, 0, 0)); + EXPECT_EQ(to_vector(AxisSigned::Y_POS), float3(0, 1, 0)); + EXPECT_EQ(to_vector(AxisSigned::Z_POS), float3(0, 0, 1)); + EXPECT_EQ(to_vector(AxisSigned::X_NEG), float3(-1, 0, 0)); + EXPECT_EQ(to_vector(AxisSigned::Y_NEG), float3(0, -1, 0)); + EXPECT_EQ(to_vector(AxisSigned::Z_NEG), float3(0, 0, -1)); + + EXPECT_EQ(to_vector(AxisSigned::X_POS), float2(1, 0)); + EXPECT_EQ(to_vector(AxisSigned::Y_POS), float2(0, 1)); + EXPECT_EQ(to_vector(AxisSigned::X_NEG), float2(-1, 0)); + EXPECT_EQ(to_vector(AxisSigned::Y_NEG), float2(0, -1)); +} + +TEST(math_rotation_types, Euler3Order) +{ + /* Asserts those match. + * Do not do it in the header to avoid including the DNA header everywhere. + */ + BLI_STATIC_ASSERT(int(EulerOrder::XYZ) == int(eRotationModes::ROT_MODE_XYZ), ""); + BLI_STATIC_ASSERT(int(EulerOrder::XZY) == int(eRotationModes::ROT_MODE_XZY), ""); + BLI_STATIC_ASSERT(int(EulerOrder::YXZ) == int(eRotationModes::ROT_MODE_YXZ), ""); + BLI_STATIC_ASSERT(int(EulerOrder::YZX) == int(eRotationModes::ROT_MODE_YZX), ""); + BLI_STATIC_ASSERT(int(EulerOrder::ZXY) == int(eRotationModes::ROT_MODE_ZXY), ""); + BLI_STATIC_ASSERT(int(EulerOrder::ZYX) == int(eRotationModes::ROT_MODE_ZYX), ""); + + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::XYZ).ijk()), float3(0, 1, 2)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::XZY).ijk()), float3(0, 2, 1)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::YXZ).ijk()), float3(1, 0, 2)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::YZX).ijk()), float3(1, 2, 0)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::ZXY).ijk()), float3(2, 0, 1)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::ZYX).ijk()), float3(2, 1, 0)); + + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::XYZ).xyz()), float3(0, 1, 2)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::XZY).xyz()), float3(0, 1, 2)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::YXZ).xyz()), float3(0, 1, 2)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::YZX).xyz()), float3(0, 1, 2)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::ZXY).xyz()), float3(0, 1, 2)); + EXPECT_EQ(float3(Euler3(0, 1, 2, EulerOrder::ZYX).xyz()), float3(0, 1, 2)); + + EXPECT_EQ(float3(Euler3(EulerOrder::XYZ).ijk() = {0, 1, 2}), float3(0, 1, 2)); + EXPECT_EQ(float3(Euler3(EulerOrder::XZY).ijk() = {0, 1, 2}), float3(0, 2, 1)); + EXPECT_EQ(float3(Euler3(EulerOrder::YXZ).ijk() = {0, 1, 2}), float3(1, 0, 2)); + EXPECT_EQ(float3(Euler3(EulerOrder::YZX).ijk() = {0, 1, 2}), float3(1, 2, 0)); + EXPECT_EQ(float3(Euler3(EulerOrder::ZXY).ijk() = {0, 1, 2}), float3(2, 0, 1)); + EXPECT_EQ(float3(Euler3(EulerOrder::ZYX).ijk() = {0, 1, 2}), float3(2, 1, 0)); +} + +TEST(math_rotation_types, DualQuaternionUniformScaleConstructor) +{ + DualQuaternion q = {Quaternion::identity(), Quaternion::zero()}; + EXPECT_EQ(q.quat, Quaternion::identity()); + EXPECT_EQ(q.trans, Quaternion::zero()); + EXPECT_EQ(q.scale_weight, 0.0f); + EXPECT_EQ(q.quat_weight, 1.0f); +} + +TEST(math_rotation_types, DualQuaternionNonUniformScaleConstructor) +{ + DualQuaternion q = {Quaternion::identity(), Quaternion::zero(), float4x4::identity()}; + EXPECT_EQ(q.quat, Quaternion::identity()); + EXPECT_EQ(q.trans, Quaternion::zero()); + EXPECT_EQ(q.scale, float4x4::identity()); + EXPECT_EQ(q.scale_weight, 1.0f); + EXPECT_EQ(q.quat_weight, 1.0f); +} + +TEST(math_rotation_types, DualQuaternionOperators) +{ + DualQuaternion sum = DualQuaternion(Quaternion(0, 0, 1, 0), Quaternion(0, 1, 0, 1)) * 2.0f; + + EXPECT_EQ(sum.quat, Quaternion(0, 0, 2, 0)); + EXPECT_EQ(sum.trans, Quaternion(0, 2, 0, 2)); + EXPECT_EQ(sum.scale_weight, 0.0f); + EXPECT_EQ(sum.quat_weight, 2.0f); + + sum += DualQuaternion(Quaternion(1, 0, 0, 0), Quaternion(1, 1, 1, 1), float4x4::identity()) * + 4.0f; + + EXPECT_EQ(sum.quat, Quaternion(4, 0, 2, 0)); + EXPECT_EQ(sum.trans, Quaternion(4, 6, 4, 6)); + EXPECT_EQ(sum.scale, float4x4::identity() * 4.0f); + EXPECT_EQ(sum.scale_weight, 4.0f); + EXPECT_EQ(sum.quat_weight, 6.0f); + + sum += 3.0f * + DualQuaternion(Quaternion(1, 0, 0, 0), Quaternion(1, 0, 0, 0), float4x4::identity()); + + EXPECT_EQ(sum.quat, Quaternion(7, 0, 2, 0)); + EXPECT_EQ(sum.trans, Quaternion(7, 6, 4, 6)); + EXPECT_EQ(sum.scale, float4x4::identity() * 7.0f); + EXPECT_EQ(sum.scale_weight, 7.0f); + EXPECT_EQ(sum.quat_weight, 9.0f); +} + +TEST(math_rotation_types, QuaternionDefaultConstructor) +{ + Quaternion q{}; + EXPECT_EQ(q.w, 0.0f); + EXPECT_EQ(q.x, 0.0f); + EXPECT_EQ(q.y, 0.0f); + EXPECT_EQ(q.z, 0.0f); +} + +TEST(math_rotation_types, QuaternionStaticConstructor) +{ + Quaternion q = Quaternion::identity(); + EXPECT_EQ(q.w, 1.0f); + EXPECT_EQ(q.x, 0.0f); + EXPECT_EQ(q.y, 0.0f); + EXPECT_EQ(q.z, 0.0f); +} + +TEST(math_rotation_types, QuaternionVectorConstructor) +{ + Quaternion q{1.0f, 2.0f, 3.0f, 4.0f}; + EXPECT_EQ(q.w, 1.0f); + EXPECT_EQ(q.x, 2.0f); + EXPECT_EQ(q.y, 3.0f); + EXPECT_EQ(q.z, 4.0f); +} + +TEST(math_rotation_types, QuaternionProduct) +{ + Quaternion q1{1.0f, 2.0f, 3.0f, 4.0f}; + Quaternion q2{3.0f, 4.0f, 5.0f, 6.0f}; + Quaternion result = q1 * q2; + EXPECT_EQ(result.w, -44.0f); + EXPECT_EQ(result.x, 8.0f); + EXPECT_EQ(result.y, 18.0f); + EXPECT_EQ(result.z, 16.0f); + + Quaternion result2 = q1 * 4.0f; + EXPECT_EQ(result2.w, 4.0f); + EXPECT_EQ(result2.x, 8.0f); + EXPECT_EQ(result2.y, 12.0f); + EXPECT_EQ(result2.z, 16.0f); +} + +TEST(math_rotation_types, QuaternionUnaryMinus) +{ + Quaternion q{1.0f, 2.0f, 3.0f, 4.0f}; + Quaternion result = -q; + EXPECT_EQ(result.w, -1.0f); + EXPECT_EQ(result.x, -2.0f); + EXPECT_EQ(result.y, -3.0f); + EXPECT_EQ(result.z, -4.0f); +} + +TEST(math_rotation_types, QuaternionExpmap) +{ + Quaternion q(0.927091f, 0.211322f, -0.124857f, 0.283295f); + float3 expmap = normalize(q).expmap(); + EXPECT_V3_NEAR(expmap, float3(0.433225f, -0.255966f, 0.580774f), 1e-4f); + EXPECT_V4_NEAR(float4(Quaternion::expmap(expmap)), float4(q), 1e-4f); +} + +TEST(math_rotation_types, QuaternionTwistSwing) +{ + Quaternion q(0.927091f, 0.211322f, -0.124857f, 0.283295f); + EXPECT_NEAR(float(q.twist_angle(Axis::X)), 0.448224, 1e-4); + EXPECT_NEAR(float(q.twist_angle(Axis::Y)), -0.267741, 1e-4); + EXPECT_NEAR(float(q.twist_angle(Axis::Z)), 0.593126, 1e-4); + + EXPECT_V4_NEAR(float4(q.twist(Axis::X)), float4(0.974992, 0.222241, 0, 0), 1e-4); + EXPECT_V4_NEAR(float4(q.twist(Axis::Y)), float4(0.991053, 0, -0.133471, 0), 1e-4); + EXPECT_V4_NEAR(float4(q.twist(Axis::Z)), float4(0.956347, 0, 0, 0.292235), 1e-4); + EXPECT_V4_NEAR(float4(q.swing(Axis::X)), float4(0.950871, 0, -0.184694, 0.248462), 1e-4); + EXPECT_V4_NEAR(float4(q.swing(Axis::Y)), float4(0.935461, 0.17162, 0, 0.308966), 1e-4); + EXPECT_V4_NEAR(float4(q.swing(Axis::Z)), float4(0.969409, 0.238585, -0.0576509, 0), 1e-4); + EXPECT_V4_NEAR(float4(q.swing(Axis::Z) * q.twist(Axis::Z)), float4(q), 1e-4); +} + +TEST(math_rotation_types, AngleMethods) +{ + EXPECT_NEAR(float(AngleRadian(M_PI * -2.5).wrapped()), -M_PI * 0.5, 1e-4f); + EXPECT_NEAR(float(AngleRadian(M_PI * -1.5).wrapped()), M_PI * 0.5, 1e-4f); + EXPECT_NEAR(float(AngleRadian(M_PI * -0.5).wrapped()), -M_PI * 0.5, 1e-4f); + EXPECT_NEAR(float(AngleRadian(M_PI * 0.5).wrapped()), M_PI * 0.5, 1e-4f); + EXPECT_NEAR(float(AngleRadian(M_PI * 2.0).wrapped()), 0.0, 1e-4f); + EXPECT_NEAR(float(AngleRadian(M_PI * 2.5).wrapped()), M_PI * 0.5, 1e-4f); + EXPECT_NEAR(float(AngleRadian(M_PI * 1.5).wrapped()), M_PI * -0.5, 1e-4f); + EXPECT_NEAR(float(AngleRadian(M_PI * 0.5).wrapped_around(-M_PI)), -M_PI * 1.5, 1e-4f); + EXPECT_NEAR(float(AngleRadian(M_PI * 1.0).wrapped_around(M_PI * 0.5)), M_PI, 1e-4f); +} + +TEST(math_rotation_types, AngleFraction) +{ + using T = float; + using AngleFraction = AngleFraction; + auto pi = AngleFraction::pi(); + auto tau = AngleFraction::tau(); + EXPECT_EQ(AngleFraction::identity().radian(), 0); + EXPECT_EQ(pi.radian(), T(M_PI)); + EXPECT_EQ(tau.radian(), T(M_PI * 2)); + /* Doesn't work with standard float angles. */ + EXPECT_EQ((pi / 5 + pi * 4 / 5).radian(), T(M_PI)); + EXPECT_EQ((pi * 2 / 3).radian(), T(M_PI * 2 / 3)); + EXPECT_EQ(cos(pi * 2 / 3), cos(2 * pi + pi * 2 / 3)); + EXPECT_EQ(sin(pi * 3 / 2), T(-1)); + EXPECT_EQ(sin(pi * 1574051 / 2), T(-1)); + EXPECT_EQ((-pi * 4 / 2).wrapped(), (+pi * 0 / 2)); + EXPECT_EQ((-pi * 3 / 2).wrapped(), (+pi * 1 / 2)); + EXPECT_EQ((-pi * 2 / 2).wrapped(), (-pi * 2 / 2)); + EXPECT_EQ((-pi * 1 / 2).wrapped(), (-pi * 1 / 2)); + EXPECT_EQ((+pi * 0 / 2).wrapped(), (+pi * 0 / 2)); + EXPECT_EQ((+pi * 1 / 2).wrapped(), (+pi * 1 / 2)); + EXPECT_EQ((+pi * 2 / 2).wrapped(), (+pi * 2 / 2)); + EXPECT_EQ((+pi * 3 / 2).wrapped(), (-pi * 1 / 2)); + EXPECT_EQ((+pi * 4 / 2).wrapped(), (-pi * 0 / 2)); + EXPECT_EQ((+pi * 0 / 2).wrapped_around(pi), (+pi * 0 / 2)); + EXPECT_EQ((+pi * 1 / 2).wrapped_around(pi), (+pi * 1 / 2)); + EXPECT_EQ((+pi * 2 / 2).wrapped_around(pi), (+pi * 2 / 2)); + EXPECT_EQ((+pi * 3 / 2).wrapped_around(pi), (+pi * 3 / 2)); + EXPECT_EQ((+pi * 4 / 2).wrapped_around(pi), (+pi * 4 / 2)); + + for (int i = 0; i < 32; i++) { + AngleCartesian angle(+pi * i / 16); + EXPECT_NEAR(angle.cos(), cos((T(M_PI) * i) / 16), 1e-6f); + EXPECT_NEAR(angle.sin(), sin((T(M_PI) * i) / 16), 1e-6f); + + /* Ensure symmetry. */ + AngleCartesian angle_opposite(pi + pi * i / 16); + EXPECT_EQ(angle.cos(), -angle_opposite.cos()); + EXPECT_EQ(angle.sin(), -angle_opposite.sin()); + + AngleCartesian angle_phase(pi / 2 + pi * i / 16); + EXPECT_EQ(angle.cos(), angle_phase.sin()); + EXPECT_EQ(angle.sin(), -angle_phase.cos()); + + /* Ensure Periodicity. */ + AngleCartesian angle_per(tau + pi * i / 16); + EXPECT_EQ(angle.cos(), angle_per.cos()); + EXPECT_EQ(angle.sin(), angle_per.sin()); + } + /* Ensure exact values. */ + EXPECT_EQ(AngleCartesian(+pi * 0 / 2).cos(), +1.0f); + EXPECT_EQ(AngleCartesian(+pi * 1 / 2).cos(), +0.0f); + EXPECT_EQ(AngleCartesian(+pi * 2 / 2).cos(), -1.0f); + EXPECT_EQ(AngleCartesian(+pi * 3 / 2).cos(), +0.0f); + EXPECT_EQ(AngleCartesian(+pi * 4 / 2).cos(), +1.0f); + + EXPECT_EQ(AngleCartesian(+pi * 0 / 2).sin(), +0.0f); + EXPECT_EQ(AngleCartesian(+pi * 1 / 2).sin(), +1.0f); + EXPECT_EQ(AngleCartesian(+pi * 2 / 2).sin(), +0.0f); + EXPECT_EQ(AngleCartesian(+pi * 3 / 2).sin(), -1.0f); + EXPECT_EQ(AngleCartesian(+pi * 4 / 2).sin(), +0.0f); + + EXPECT_EQ(AngleCartesian(+pi * 1 / 4).cos(), T(M_SQRT1_2)); + EXPECT_EQ(AngleCartesian(+pi * 3 / 4).cos(), T(-M_SQRT1_2)); + EXPECT_EQ(AngleCartesian(-pi * 1 / 4).cos(), T(M_SQRT1_2)); + EXPECT_EQ(AngleCartesian(-pi * 3 / 4).cos(), T(-M_SQRT1_2)); + + EXPECT_EQ(AngleCartesian(+pi * 1 / 4).sin(), T(M_SQRT1_2)); + EXPECT_EQ(AngleCartesian(+pi * 3 / 4).sin(), T(M_SQRT1_2)); + EXPECT_EQ(AngleCartesian(-pi * 1 / 4).sin(), T(-M_SQRT1_2)); + EXPECT_EQ(AngleCartesian(-pi * 3 / 4).sin(), T(-M_SQRT1_2)); +} + +TEST(math_rotation_types, TypeConversion) +{ + /* All the same rotation. */ + Quaternion quaternion(0.927091f, 0.211322f, -0.124857f, 0.283295f); + EulerXYZ euler_xyz(AngleRadian::from_degree(20.0559), + AngleRadian::from_degree(-20.5632f), + AngleRadian::from_degree(30.3091f)); + AxisAngle axis_angle(normalize(float3{0.563771, -0.333098, 0.755783}), + AngleRadian::from_degree(44.0284f)); + + EXPECT_V4_NEAR(float4(to_quaternion(euler_xyz)), float4(quaternion), 1e-4); + EXPECT_V3_NEAR(to_axis_angle(euler_xyz).axis(), axis_angle.axis(), 1e-4); + EXPECT_NEAR(float(to_axis_angle(euler_xyz).angle()), float(axis_angle.angle()), 1e-4); + + EXPECT_V3_NEAR(float3(to_euler(quaternion)), float3(euler_xyz), 1e-4); + EXPECT_V3_NEAR(to_axis_angle(quaternion).axis(), axis_angle.axis(), 1e-4); + EXPECT_NEAR(float(to_axis_angle(quaternion).angle()), float(axis_angle.angle()), 1e-4); + + EXPECT_V3_NEAR(float3(to_euler(axis_angle)), float3(euler_xyz), 1e-4); + EXPECT_V4_NEAR(float4(to_quaternion(axis_angle)), float4(quaternion), 1e-4); +} + +TEST(math_rotation_types, Euler3Conversion) +{ + /* All the same rotation. */ + float3 xyz{0.350041, -0.358896, 0.528994}; + Euler3 euler3_xyz(xyz, EulerOrder::XYZ); + Euler3 euler3_xzy(xyz, EulerOrder::XZY); + Euler3 euler3_yxz(xyz, EulerOrder::YXZ); + Euler3 euler3_yzx(xyz, EulerOrder::YZX); + Euler3 euler3_zxy(xyz, EulerOrder::ZXY); + Euler3 euler3_zyx(xyz, EulerOrder::ZYX); + + Quaternion quat_xyz(0.927091f, 0.211322f, -0.124857f, 0.283295f); + Quaternion quat_xzy(0.943341f, 0.119427f, -0.124857f, 0.283295f); + Quaternion quat_yxz(0.943341f, 0.211322f, -0.124857f, 0.223297f); + Quaternion quat_yzx(0.927091f, 0.211322f, -0.214438f, 0.223297f); + Quaternion quat_zxy(0.927091f, 0.119427f, -0.214438f, 0.283295f); + Quaternion quat_zyx(0.943341f, 0.119427f, -0.214438f, 0.223297f); + + float3x3 mat_xyz = transpose(float3x3{{0.80831, -0.57805, -0.111775}, + {0.47251, 0.750174, -0.462572}, + {0.35124, 0.321087, 0.879508}}); + float3x3 mat_xzy = transpose(float3x3{{0.80831, -0.56431, -0.167899}, + {0.504665, 0.810963, -0.296063}, + {0.303231, 0.154577, 0.940296}}); + float3x3 mat_yxz = transpose(float3x3{{0.869098, -0.474061, -0.14119}, + {0.368521, 0.810963, -0.454458}, + {0.329941, 0.342937, 0.879508}}); + float3x3 mat_yzx = transpose(float3x3{{0.80831, -0.504665, -0.303231}, + {0.323403, 0.810963, -0.487596}, + {0.491982, 0.296063, 0.818719}}); + float3x3 mat_zxy = transpose(float3x3{{0.747521, -0.576499, -0.329941}, + {0.474061, 0.810963, -0.342937}, + {0.465272, 0.0999405, 0.879508}}); + float3x3 mat_zyx = transpose(float3x3{{0.80831, -0.47251, -0.35124}, + {0.370072, 0.871751, -0.321087}, + {0.457911, 0.129553, 0.879508}}); + + EXPECT_V4_NEAR(float4(to_quaternion(euler3_xyz)), float4(quat_xyz), 1e-4); + EXPECT_V4_NEAR(float4(to_quaternion(euler3_xzy)), float4(quat_xzy), 1e-4); + EXPECT_V4_NEAR(float4(to_quaternion(euler3_yxz)), float4(quat_yxz), 1e-4); + EXPECT_V4_NEAR(float4(to_quaternion(euler3_yzx)), float4(quat_yzx), 1e-4); + EXPECT_V4_NEAR(float4(to_quaternion(euler3_zxy)), float4(quat_zxy), 1e-4); + EXPECT_V4_NEAR(float4(to_quaternion(euler3_zyx)), float4(quat_zyx), 1e-4); + + EXPECT_V3_NEAR(float3(to_euler(quat_xyz, EulerOrder::XYZ).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(quat_xzy, EulerOrder::XZY).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(quat_yxz, EulerOrder::YXZ).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(quat_yzx, EulerOrder::YZX).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(quat_zxy, EulerOrder::ZXY).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(quat_zyx, EulerOrder::ZYX).xyz()), xyz, 1e-4); + + EXPECT_M3_NEAR(from_rotation(euler3_xyz), mat_xyz, 1e-4); + EXPECT_M3_NEAR(from_rotation(euler3_xzy), mat_xzy, 1e-4); + EXPECT_M3_NEAR(from_rotation(euler3_yxz), mat_yxz, 1e-4); + EXPECT_M3_NEAR(from_rotation(euler3_yzx), mat_yzx, 1e-4); + EXPECT_M3_NEAR(from_rotation(euler3_zxy), mat_zxy, 1e-4); + EXPECT_M3_NEAR(from_rotation(euler3_zyx), mat_zyx, 1e-4); + + EXPECT_V3_NEAR(float3(to_euler(mat_xyz, EulerOrder::XYZ).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(mat_xzy, EulerOrder::XZY).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(mat_yxz, EulerOrder::YXZ).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(mat_yzx, EulerOrder::YZX).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(mat_zxy, EulerOrder::ZXY).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(mat_zyx, EulerOrder::ZYX).xyz()), xyz, 1e-4); + + AxisAngle axis_angle_xyz = {normalize(float3{0.563771, -0.333098, 0.755783}), 0.76844f}; + AxisAngle axis_angle_xzy = {normalize(float3{0.359907, -0.376274, 0.853747}), 0.676476f}; + AxisAngle axis_angle_yxz = {normalize(float3{0.636846, -0.376274, 0.672937}), 0.676476f}; + AxisAngle axis_angle_yzx = {normalize(float3{0.563771, -0.572084, 0.59572}), 0.76844f}; + AxisAngle axis_angle_zxy = {normalize(float3{0.318609, -0.572084, 0.755783}), 0.76844f}; + AxisAngle axis_angle_zyx = {normalize(float3{0.359907, -0.646237, 0.672937}), 0.676476f}; + + EXPECT_V3_NEAR(to_axis_angle(euler3_xyz).axis(), axis_angle_xyz.axis(), 1e-4); + EXPECT_V3_NEAR(to_axis_angle(euler3_xzy).axis(), axis_angle_xzy.axis(), 1e-4); + EXPECT_V3_NEAR(to_axis_angle(euler3_yxz).axis(), axis_angle_yxz.axis(), 1e-4); + EXPECT_V3_NEAR(to_axis_angle(euler3_yzx).axis(), axis_angle_yzx.axis(), 1e-4); + EXPECT_V3_NEAR(to_axis_angle(euler3_zxy).axis(), axis_angle_zxy.axis(), 1e-4); + EXPECT_V3_NEAR(to_axis_angle(euler3_zyx).axis(), axis_angle_zyx.axis(), 1e-4); + + EXPECT_NEAR(float(to_axis_angle(euler3_xyz).angle()), float(axis_angle_xyz.angle()), 1e-4); + EXPECT_NEAR(float(to_axis_angle(euler3_xzy).angle()), float(axis_angle_xzy.angle()), 1e-4); + EXPECT_NEAR(float(to_axis_angle(euler3_yxz).angle()), float(axis_angle_yxz.angle()), 1e-4); + EXPECT_NEAR(float(to_axis_angle(euler3_yzx).angle()), float(axis_angle_yzx.angle()), 1e-4); + EXPECT_NEAR(float(to_axis_angle(euler3_zxy).angle()), float(axis_angle_zxy.angle()), 1e-4); + EXPECT_NEAR(float(to_axis_angle(euler3_zyx).angle()), float(axis_angle_zyx.angle()), 1e-4); + + EXPECT_V3_NEAR(float3(to_euler(axis_angle_xyz, EulerOrder::XYZ).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(axis_angle_xzy, EulerOrder::XZY).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(axis_angle_yxz, EulerOrder::YXZ).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(axis_angle_yzx, EulerOrder::YZX).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(axis_angle_zxy, EulerOrder::ZXY).xyz()), xyz, 1e-4); + EXPECT_V3_NEAR(float3(to_euler(axis_angle_zyx, EulerOrder::ZYX).xyz()), xyz, 1e-4); +} + +TEST(math_rotation_types, AngleSinCosOperators) +{ + AngleCartesian(M_PI_2); + EXPECT_NEAR((AngleCartesian(M_PI_2) + AngleCartesian(M_PI)).radian(), + AngleRadian(M_PI_2 + M_PI).wrapped().radian(), + 1e-4); + EXPECT_NEAR((AngleCartesian(M_PI_2) - AngleCartesian(M_PI)).radian(), + AngleRadian(M_PI_2 - M_PI).wrapped().radian(), + 1e-4); + EXPECT_NEAR((-AngleCartesian(M_PI_2)).radian(), AngleRadian(-M_PI_2).radian(), 1e-4); + EXPECT_NEAR((AngleCartesian(M_PI_4) * 2).radian(), AngleRadian(M_PI_4 * 2).radian(), 1e-4); + EXPECT_NEAR((AngleCartesian(M_PI_4) * 3).radian(), AngleRadian(M_PI_4 * 3).radian(), 1e-4); + EXPECT_NEAR((AngleCartesian(-M_PI_4) * 2).radian(), AngleRadian(-M_PI_4 * 2).radian(), 1e-4); + EXPECT_NEAR((AngleCartesian(-M_PI_4) * 3).radian(), AngleRadian(-M_PI_4 * 3).radian(), 1e-4); + EXPECT_NEAR((AngleCartesian(M_PI_4) / 2).radian(), AngleRadian(M_PI_4 / 2).radian(), 1e-4); + EXPECT_NEAR((AngleCartesian(-M_PI_4) / 2).radian(), AngleRadian(-M_PI_4 / 2).radian(), 1e-4); +} + +} // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_math_vector_types_test.cc b/source/blender/blenlib/tests/BLI_math_vector_types_test.cc index 2a5884fb282..2677d2785d6 100644 --- a/source/blender/blenlib/tests/BLI_math_vector_types_test.cc +++ b/source/blender/blenlib/tests/BLI_math_vector_types_test.cc @@ -259,4 +259,25 @@ TEST(math_vec_types, DivideFloatByVectorSmall) EXPECT_FLOAT_EQ(result.y, 1.0f); } +TEST(math_vec_types, SwizzleReinterpret) +{ + const float2 v01(0, 1); + const float2 v12(1, 2); + const float2 v23(2, 3); + const float3 v012(0, 1, 2); + const float3 v123(1, 2, 3); + const float4 v0123(0, 1, 2, 3); + /* Identity. */ + EXPECT_EQ(v01.xy(), v01); + EXPECT_EQ(v012.xyz(), v012); + EXPECT_EQ(v0123.xyzw(), v0123); + /* Masking. */ + EXPECT_EQ(v012.xy(), v01); + EXPECT_EQ(v0123.xyz(), v012); + /* Offset. */ + EXPECT_EQ(v0123.yz(), v12); + EXPECT_EQ(v0123.zw(), v23); + EXPECT_EQ(v0123.yzw(), v123); +} + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc index 29bf6c0cfb1..fc8090a2cb1 100644 --- a/source/blender/blenlib/tests/BLI_vector_test.cc +++ b/source/blender/blenlib/tests/BLI_vector_test.cc @@ -859,4 +859,14 @@ TEST(vector, RemoveChunkExceptions) EXPECT_EQ(vec.size(), 7); } +struct RecursiveType { + Vector my_vector; +}; + +TEST(vector, RecursiveStructure) +{ + RecursiveType my_recursive_type; + my_recursive_type.my_vector.append({}); +} + } // namespace blender::tests diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index e28688b6bab..58896d432a8 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -313,27 +313,6 @@ void BLO_read_invalidate_message(BlendHandle *bh, struct Main *bmain, const char #define BLO_GROUP_MAX 32 #define BLO_EMBEDDED_STARTUP_BLEND "" -/** - * Check whether given path ends with a blend file compatible extension - * (`.blend`, `.ble` or `.blend.gz`). - * - * \param str: The path to check. - * \return true is this path ends with a blender file extension. - */ -bool BLO_has_bfile_extension(const char *str); -/** - * Try to explode given path into its 'library components' - * (i.e. a .blend file, id type/group, and data-block itself). - * - * \param path: the full path to explode. - * \param r_dir: the string that'll contain path up to blend file itself ('library' path). - * WARNING! Must be #FILE_MAX_LIBEXTRA long (it also stores group and name strings)! - * \param r_group: the string that'll contain 'group' part of the path, if any. May be NULL. - * \param r_name: the string that'll contain data's name part of the path, if any. May be NULL. - * \return true if path contains a blend file. - */ -bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name); - /* -------------------------------------------------------------------- */ /** \name BLO Blend File Linking API * \{ */ diff --git a/source/blender/blenloader/intern/readfile.cc b/source/blender/blenloader/intern/readfile.cc index 891a9f81358..74c8442c212 100644 --- a/source/blender/blenloader/intern/readfile.cc +++ b/source/blender/blenloader/intern/readfile.cc @@ -75,7 +75,7 @@ #include "BKE_main.h" /* for Main */ #include "BKE_main_idmap.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_node.h" /* for tree type defines */ #include "BKE_object.h" @@ -1306,76 +1306,6 @@ void blo_filedata_free(FileData *fd) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Public Utilities - * \{ */ - -bool BLO_has_bfile_extension(const char *str) -{ - const char *ext_test[4] = {".blend", ".ble", ".blend.gz", nullptr}; - return BLI_path_extension_check_array(str, ext_test); -} - -bool BLO_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name) -{ - /* We might get some data names with slashes, - * so we have to go up in path until we find blend file itself, - * then we know next path item is group, and everything else is data name. */ - char *slash = nullptr, *prev_slash = nullptr, c = '\0'; - - r_dir[0] = '\0'; - if (r_group) { - *r_group = nullptr; - } - if (r_name) { - *r_name = nullptr; - } - - /* if path leads to an existing directory, we can be sure we're not (in) a library */ - if (BLI_is_dir(path)) { - return false; - } - - strcpy(r_dir, path); - - while ((slash = (char *)BLI_path_slash_rfind(r_dir))) { - char tc = *slash; - *slash = '\0'; - if (BLO_has_bfile_extension(r_dir) && BLI_is_file(r_dir)) { - break; - } - if (STREQ(r_dir, BLO_EMBEDDED_STARTUP_BLEND)) { - break; - } - - if (prev_slash) { - *prev_slash = c; - } - prev_slash = slash; - c = tc; - } - - if (!slash) { - return false; - } - - if (slash[1] != '\0') { - BLI_assert(strlen(slash + 1) < BLO_GROUP_MAX); - if (r_group) { - *r_group = slash + 1; - } - } - - if (prev_slash && (prev_slash[1] != '\0')) { - BLI_assert(strlen(prev_slash + 1) < MAX_ID_NAME - 2); - if (r_name) { - *r_name = prev_slash + 1; - } - } - - return true; -} - BlendThumbnail *BLO_thumbnail_from_file(const char *filepath) { FileData *fd; @@ -2963,7 +2893,7 @@ static const char *dataname(short id_code) return "Data from PAL"; case ID_PC: return "Data from PCRV"; - case ID_GD: + case ID_GD_LEGACY: return "Data from GD"; case ID_WM: return "Data from WM"; diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index fb806a0b124..094ec062381 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -431,7 +431,7 @@ static void versions_gpencil_add_main(Main *bmain, ListBase *lb, ID *id, const c BLI_addtail(lb, id); id->us = 1; id->flag = LIB_FAKEUSER; - *((short *)id->name) = ID_GD; + *((short *)id->name) = ID_GD_LEGACY; BKE_id_new_name_validate(bmain, lb, id, name, false); /* alphabetic insertion: is in BKE_id_new_name_validate */ diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index 3278309641d..0b93f193bff 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -20,7 +20,7 @@ #include "DNA_cloth_types.h" #include "DNA_constraint_types.h" #include "DNA_fluid_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_linestyle_types.h" #include "DNA_mask_types.h" diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 17b833b56b7..250f9725526 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -29,8 +29,8 @@ #include "DNA_fluid_types.h" #include "DNA_freestyle_types.h" #include "DNA_genfile.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_gpu_types.h" #include "DNA_key_types.h" #include "DNA_layer_types.h" @@ -65,9 +65,9 @@ #include "BKE_fcurve_driver.h" #include "BKE_freestyle.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_idprop.h" #include "BKE_key.h" #include "BKE_layer.h" @@ -4665,7 +4665,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) /* Fix Grease Pencil VFX and modifiers. */ LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->type != OB_GPENCIL) { + if (ob->type != OB_GPENCIL_LEGACY) { continue; } diff --git a/source/blender/blenloader/intern/versioning_290.cc b/source/blender/blenloader/intern/versioning_290.cc index 646dd089daf..c71becf5606 100644 --- a/source/blender/blenloader/intern/versioning_290.cc +++ b/source/blender/blenloader/intern/versioning_290.cc @@ -20,8 +20,8 @@ #include "DNA_curves_types.h" #include "DNA_fluid_types.h" #include "DNA_genfile.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -45,10 +45,10 @@ #include "BKE_cryptomatte.h" #include "BKE_curve.h" #include "BKE_fcurve.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_multires.h" #include "BKE_node.h" @@ -553,7 +553,7 @@ void do_versions_after_linking_290(FileData * /*fd*/, Main *bmain) Scene *scene = static_cast(bmain->scenes.first); if (scene != nullptr) { LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->type != OB_GPENCIL) { + if (ob->type != OB_GPENCIL_LEGACY) { continue; } bGPdata *gpd = static_cast(ob->data); diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index 0eb71f7d7c8..62751661645 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -14,6 +14,7 @@ #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_multi_value_map.hh" #include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_string_utils.h" @@ -62,7 +63,7 @@ #include "BKE_lib_override.h" #include "BKE_main.h" #include "BKE_main_namemap.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_node.h" #include "BKE_screen.h" @@ -76,6 +77,7 @@ #include "readfile.h" #include "SEQ_channels.h" +#include "SEQ_effects.h" #include "SEQ_iterator.h" #include "SEQ_retiming.h" #include "SEQ_sequencer.h" @@ -384,7 +386,7 @@ static void assert_sorted_ids(Main *bmain) static void move_vertex_group_names_to_object_data(Main *bmain) { LISTBASE_FOREACH (Object *, object, &bmain->objects) { - if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL_LEGACY)) { ListBase *new_defbase = BKE_object_defgroup_list_mutable(object); /* Choose the longest vertex group name list among all linked duplicates. */ @@ -939,6 +941,139 @@ static void version_geometry_nodes_primitive_uv_maps(bNodeTree &ntree) } } +/** + * When extruding from loose edges, the extrude geometry node used to create flat faces due to the + * default of the old "shade_smooth" attribute. Since the "false" value has changed with the + * "sharp_face" attribute, add nodes to propagate the new attribute in its inverted "smooth" form. + */ +static void version_geometry_nodes_extrude_smooth_propagation(bNodeTree &ntree) +{ + using namespace blender; + Vector new_nodes; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) { + if (node->idname != StringRef("GeometryNodeExtrudeMesh")) { + continue; + } + if (static_cast(node->storage)->mode != + GEO_NODE_EXTRUDE_MESH_EDGES) { + continue; + } + bNodeSocket *geometry_in_socket = nodeFindSocket(node, SOCK_IN, "Mesh"); + bNodeSocket *geometry_out_socket = nodeFindSocket(node, SOCK_OUT, "Mesh"); + + Map in_links_per_socket; + MultiValueMap out_links_per_socket; + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + in_links_per_socket.add(link->tosock, link); + out_links_per_socket.add(link->fromsock, link); + } + + bNodeLink *geometry_in_link = in_links_per_socket.lookup_default(geometry_in_socket, nullptr); + Span geometry_out_links = out_links_per_socket.lookup(geometry_out_socket); + if (!geometry_in_link || geometry_out_links.is_empty()) { + continue; + } + + const bool versioning_already_done = [&]() { + if (geometry_in_link->fromnode->idname != StringRef("GeometryNodeCaptureAttribute")) { + return false; + } + bNode *capture_node = geometry_in_link->fromnode; + const NodeGeometryAttributeCapture &capture_storage = + *static_cast(capture_node->storage); + if (capture_storage.data_type != CD_PROP_BOOL || + capture_storage.domain != ATTR_DOMAIN_FACE) { + return false; + } + bNodeSocket *capture_in_socket = nodeFindSocket(capture_node, SOCK_IN, "Value_003"); + bNodeLink *capture_in_link = in_links_per_socket.lookup_default(capture_in_socket, nullptr); + if (!capture_in_link) { + return false; + } + if (capture_in_link->fromnode->idname != StringRef("GeometryNodeInputShadeSmooth")) { + return false; + } + if (geometry_out_links.size() != 1) { + return false; + } + bNodeLink *geometry_out_link = geometry_out_links.first(); + if (geometry_out_link->tonode->idname != StringRef("GeometryNodeSetShadeSmooth")) { + return false; + } + bNode *set_smooth_node = geometry_out_link->tonode; + bNodeSocket *smooth_in_socket = nodeFindSocket(set_smooth_node, SOCK_IN, "Shade Smooth"); + bNodeLink *connecting_link = in_links_per_socket.lookup_default(smooth_in_socket, nullptr); + if (!connecting_link) { + return false; + } + if (connecting_link->fromnode != capture_node) { + return false; + } + return true; + }(); + if (versioning_already_done) { + continue; + } + + bNode *capture_node = nodeAddNode(nullptr, &ntree, "GeometryNodeCaptureAttribute"); + capture_node->parent = node->parent; + capture_node->locx = node->locx - 25; + capture_node->locy = node->locy; + new_nodes.append(capture_node); + static_cast(capture_node->storage)->data_type = CD_PROP_BOOL; + static_cast(capture_node->storage)->domain = ATTR_DOMAIN_FACE; + + bNode *is_smooth_node = nodeAddNode(nullptr, &ntree, "GeometryNodeInputShadeSmooth"); + is_smooth_node->parent = node->parent; + is_smooth_node->locx = capture_node->locx - 25; + is_smooth_node->locy = capture_node->locy; + new_nodes.append(is_smooth_node); + nodeAddLink(&ntree, + is_smooth_node, + nodeFindSocket(is_smooth_node, SOCK_OUT, "Smooth"), + capture_node, + nodeFindSocket(capture_node, SOCK_IN, "Value_003")); + nodeAddLink(&ntree, + capture_node, + nodeFindSocket(capture_node, SOCK_OUT, "Geometry"), + capture_node, + geometry_in_socket); + geometry_in_link->tonode = capture_node; + geometry_in_link->tosock = nodeFindSocket(capture_node, SOCK_IN, "Geometry"); + + bNode *set_smooth_node = nodeAddNode(nullptr, &ntree, "GeometryNodeSetShadeSmooth"); + set_smooth_node->parent = node->parent; + set_smooth_node->locx = node->locx + 25; + set_smooth_node->locy = node->locy; + new_nodes.append(set_smooth_node); + nodeAddLink(&ntree, + node, + geometry_out_socket, + set_smooth_node, + nodeFindSocket(set_smooth_node, SOCK_IN, "Geometry")); + + bNodeSocket *smooth_geometry_out = nodeFindSocket(set_smooth_node, SOCK_OUT, "Geometry"); + for (bNodeLink *link : geometry_out_links) { + link->fromnode = set_smooth_node; + link->fromsock = smooth_geometry_out; + } + nodeAddLink(&ntree, + capture_node, + nodeFindSocket(capture_node, SOCK_OUT, "Attribute_003"), + set_smooth_node, + nodeFindSocket(set_smooth_node, SOCK_IN, "Shade Smooth")); + } + + /* Move nodes to the front so that they are drawn behind existing nodes. */ + for (bNode *node : new_nodes) { + BLI_remlink(&ntree.nodes, node); + BLI_addhead(&ntree.nodes, node); + } + if (!new_nodes.is_empty()) { + nodeRebuildIDVector(&ntree); + } +} + void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain) { if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) { @@ -1043,7 +1178,7 @@ void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain) if (!MAIN_VERSION_ATLEAST(bmain, 300, 33)) { /* This was missing from #move_vertex_group_names_to_object_data. */ LISTBASE_FOREACH (Object *, object, &bmain->objects) { - if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + if (ELEM(object->type, OB_MESH, OB_LATTICE, OB_GPENCIL_LEGACY)) { /* This uses the fact that the active vertex group index starts counting at 1. */ if (BKE_object_defgroup_active_index_get(object) == 0) { BKE_object_defgroup_active_index_set(object, object->actdef); @@ -1637,6 +1772,16 @@ static bool version_fix_delete_flag(Sequence *seq, void * /*user_data*/) return true; } +static bool version_set_seq_single_frame_content(Sequence *seq, void * /*user_data*/) +{ + if ((seq->len == 1) && + (seq->type == SEQ_TYPE_IMAGE || + ((seq->type & SEQ_TYPE_EFFECT) && SEQ_effect_get_num_inputs(seq->type) == 0))) { + seq->flag |= SEQ_SINGLE_FRAME_CONTENT; + } + return true; +} + /* Those `version_liboverride_rnacollections_*` functions mimic the old, pre-3.0 code to find * anchor and source items in the given list of modifiers, constraints etc., using only the * `subitem_local` data of the override property operation. @@ -2336,7 +2481,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) } } } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { if (md->type == eGpencilModifierType_Lineart) { LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md; @@ -2531,7 +2676,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) if (!DNA_struct_elem_find( fd->filesdna, "LineartGpencilModifierData", "bool", "use_crease_on_smooth")) { LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { if (md->type == eGpencilModifierType_Lineart) { LineartGpencilModifierData *lmd = (LineartGpencilModifierData *)md; @@ -4003,16 +4148,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) } } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #blo_do_versions_userdef - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { + if (!MAIN_VERSION_ATLEAST(bmain, 306, 3)) { /* Z bias for retopology overlay. */ if (!DNA_struct_elem_find(fd->filesdna, "View3DOverlay", "float", "retopology_offset")) { LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { @@ -4027,6 +4163,32 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) } } + /* Use `SEQ_SINGLE_FRAME_CONTENT` flag instead of weird function to check if strip has multiple + * frames. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + Editing *ed = SEQ_editing_get(scene); + if (ed != nullptr) { + SEQ_for_each_callback(&ed->seqbase, version_set_seq_single_frame_content, nullptr); + } + } + + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + if (ntree->type == NTREE_GEOMETRY) { + version_geometry_nodes_extrude_smooth_propagation(*ntree); + } + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #blo_do_versions_userdef + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { /* Keep this block, even when empty. */ } } diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index e482fbe1d9f..b7465e37186 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -31,6 +31,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh) BKE_mesh_legacy_convert_flags_to_hide_layers(&mesh); BKE_mesh_legacy_convert_uvs_to_generic(&mesh); BKE_mesh_legacy_convert_mpoly_to_material_indices(&mesh); + BKE_mesh_legacy_sharp_faces_from_flags(&mesh); BKE_mesh_legacy_bevel_weight_to_layers(&mesh); BKE_mesh_legacy_sharp_edges_from_flags(&mesh); BKE_mesh_legacy_face_set_to_generic(&mesh); diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc index d19616223cd..abdda14bb72 100644 --- a/source/blender/blenloader/intern/versioning_defaults.cc +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -22,7 +22,7 @@ #include "DNA_camera_types.h" #include "DNA_curveprofile_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_mask_types.h" #include "DNA_material_types.h" @@ -42,14 +42,14 @@ #include "BKE_colortools.h" #include "BKE_curveprofile.h" #include "BKE_customdata.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_main_namemap.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_node.h" #include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" @@ -464,7 +464,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) Object *ob = static_cast( BLI_findstring(&bmain->objects, "Stroke", offsetof(ID, name) + 2)); - if (ob && ob->type == OB_GPENCIL) { + if (ob && ob->type == OB_GPENCIL_LEGACY) { ob->dtx |= OB_USE_GPENCIL_LIGHTS; } } @@ -550,7 +550,7 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) if (app_template && STREQ(app_template, "2D_Animation")) { LISTBASE_FOREACH (Object *, object, &bmain->objects) { - if (object->type == OB_GPENCIL) { + if (object->type == OB_GPENCIL_LEGACY) { /* Set grease pencil object in drawing mode */ bGPdata *gpd = (bGPdata *)object->data; object->mode = OB_MODE_PAINT_GPENCIL; diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c index 63fc349ca39..25304b68e40 100644 --- a/source/blender/blenloader/intern/versioning_legacy.c +++ b/source/blender/blenloader/intern/versioning_legacy.c @@ -273,27 +273,27 @@ static void customdata_version_242(Mesh *me) int a, mtfacen, mcoln; if (!me->vdata.totlayer) { - CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, me->mvert, me->totvert); + CustomData_add_layer_with_data(&me->vdata, CD_MVERT, me->mvert, me->totvert); if (me->dvert) { - CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_ASSIGN, me->dvert, me->totvert); + CustomData_add_layer_with_data(&me->vdata, CD_MDEFORMVERT, me->dvert, me->totvert); } } if (!me->edata.totlayer) { - CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, me->medge, me->totedge); + CustomData_add_layer_with_data(&me->edata, CD_MEDGE, me->medge, me->totedge); } if (!me->fdata.totlayer) { - CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, me->mface, me->totface); + CustomData_add_layer_with_data(&me->fdata, CD_MFACE, me->mface, me->totface); if (me->tface) { if (me->mcol) { MEM_freeN(me->mcol); } - me->mcol = CustomData_add_layer(&me->fdata, CD_MCOL, CD_SET_DEFAULT, NULL, me->totface); - me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_SET_DEFAULT, NULL, me->totface); + me->mcol = CustomData_add_layer(&me->fdata, CD_MCOL, CD_SET_DEFAULT, me->totface); + me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_SET_DEFAULT, me->totface); mtf = me->mtface; mcol = me->mcol; @@ -308,7 +308,7 @@ static void customdata_version_242(Mesh *me) me->tface = NULL; } else if (me->mcol) { - me->mcol = CustomData_add_layer(&me->fdata, CD_MCOL, CD_ASSIGN, me->mcol, me->totface); + CustomData_add_layer_with_data(&me->fdata, CD_MCOL, me->mcol, me->totface); } } @@ -1307,7 +1307,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain) /* Cannot call stuff now (pointers!), done in #setup_app_data. */ ob->id.recalc |= ID_RECALC_ALL; - /* new generic xray option */ + /* New generic X-ray option. */ arm = blo_do_versions_newlibadr(fd, lib, ob->data); enum { ARM_DRAWXRAY = (1 << 1) }; if (arm->flag & ARM_DRAWXRAY) { diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 4b2acfa7205..a6e55f7b12d 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -89,6 +89,10 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) btheme->tui.wcol_view_item = U_theme_default.tui.wcol_view_item; } + if (!USER_VERSION_ATLEAST(306, 3)) { + FROM_DEFAULT_V4_UCHAR(space_view3d.face_retopology); + } + /** * Versioning code until next subversion bump goes here. * @@ -783,6 +787,17 @@ void blo_do_versions_userdef(UserDef *userdef) } } + if (!USER_VERSION_ATLEAST(306, 2)) { + userdef->animation_flag |= USER_ANIM_HIGH_QUALITY_DRAWING; + } + + if (!USER_VERSION_ATLEAST(306, 4)) { + /* Increase the number of recently-used files if using the old default value. */ + if (userdef->recent_files == 10) { + userdef->recent_files = 20; + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blentranslation/BLT_translation.h b/source/blender/blentranslation/BLT_translation.h index eb884a91412..ded3539eb1c 100644 --- a/source/blender/blentranslation/BLT_translation.h +++ b/source/blender/blentranslation/BLT_translation.h @@ -201,7 +201,7 @@ typedef struct { BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_CONSTRAINT, "constraint"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_COLOR, "color"), \ BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_AMOUNT, "amount"), \ - BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_UNIT, "unit"), \ + BLT_I18NCONTEXTS_ITEM(BLT_I18NCONTEXT_UNIT, "unit"), \ { \ NULL, NULL, NULL \ } \ diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index a724a8783d4..6449d442276 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -378,6 +378,8 @@ typedef struct BMesh { * This allows save invalidation of a #BMesh when it's freed, * so the Python object will report it as having been removed, * instead of crashing on invalid memory access. + * + * Doesn't hold a #PyObject reference, cleared when the last object is de-referenced. */ void *py_handle; } BMesh; diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index b549580f354..397c576a773 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -591,8 +591,7 @@ void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst, const int size = *(&allocsize->totvert + i); for (int l = 0; l < src->totlayer; l++) { - CustomData_add_layer_named( - dst, src->layers[l].type, CD_SET_DEFAULT, NULL, 0, src->layers[l].name); + CustomData_add_layer_named(dst, src->layers[l].type, CD_SET_DEFAULT, 0, src->layers[l].name); } CustomData_bmesh_init_pool(dst, size, htypes[i]); } diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c index 8f21ed63df2..e755bd4e5b0 100644 --- a/source/blender/bmesh/intern/bmesh_interp.c +++ b/source/blender/bmesh/intern/bmesh_interp.c @@ -841,7 +841,7 @@ void BM_data_layer_add(BMesh *bm, CustomData *data, int type) /* The pool is now owned by `olddata` and must not be shared. */ data->pool = NULL; - CustomData_add_layer(data, type, CD_SET_DEFAULT, NULL, 0); + CustomData_add_layer(data, type, CD_SET_DEFAULT, 0); update_data_blocks(bm, &olddata, data); if (olddata.layers) { @@ -856,7 +856,7 @@ void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char * /* The pool is now owned by `olddata` and must not be shared. */ data->pool = NULL; - CustomData_add_layer_named(data, type, CD_SET_DEFAULT, NULL, 0, name); + CustomData_add_layer_named(data, type, CD_SET_DEFAULT, 0, name); update_data_blocks(bm, &olddata, data); if (olddata.layers) { diff --git a/source/blender/bmesh/intern/bmesh_mesh.cc b/source/blender/bmesh/intern/bmesh_mesh.cc index d8fe0c36108..db70182fa27 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.cc +++ b/source/blender/bmesh/intern/bmesh_mesh.cc @@ -16,7 +16,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "bmesh.h" diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index c2484e30bf2..0b8ad1970b9 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -85,11 +85,12 @@ #include "BLI_span.hh" #include "BLI_string_ref.hh" #include "BLI_task.hh" +#include "BLI_timeit.hh" #include "BLI_vector.hh" #include "BKE_attribute.hh" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_multires.h" @@ -113,18 +114,6 @@ using blender::Span; using blender::StringRef; using blender::Vector; -static char bm_face_flag_from_mflag(const char mflag) -{ - return ((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0); -} - -static char bm_face_flag_to_mflag(const BMFace *f) -{ - const char hflag = f->head.hflag; - - return ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0); -} - bool BM_attribute_stored_in_bmesh_builtin(const StringRef name) { return ELEM(name, @@ -137,10 +126,10 @@ bool BM_attribute_stored_in_bmesh_builtin(const StringRef name) ".select_edge", ".select_poly", "material_index", + "sharp_face", "sharp_edge"); } -/* Static function for alloc (duplicate in modifiers_bmesh.c) */ static BMFace *bm_face_create_from_mpoly(BMesh &bm, Span loops, Span vtable, @@ -244,22 +233,19 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar BKE_uv_map_vert_select_name_get( CustomData_get_layer_name(&mesh_ldata, CD_PROP_FLOAT2, layer_index), name); if (CustomData_get_named_layer_index(&mesh_ldata, CD_PROP_BOOL, name) < 0) { - CustomData_add_layer_named( - &mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me->totloop, name); + CustomData_add_layer_named(&mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, me->totloop, name); temporary_layers_to_delete.append(std::string(name)); } BKE_uv_map_edge_select_name_get( CustomData_get_layer_name(&mesh_ldata, CD_PROP_FLOAT2, layer_index), name); if (CustomData_get_named_layer_index(&mesh_ldata, CD_PROP_BOOL, name) < 0) { - CustomData_add_layer_named( - &mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me->totloop, name); + CustomData_add_layer_named(&mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, me->totloop, name); temporary_layers_to_delete.append(std::string(name)); } BKE_uv_map_pin_name_get(CustomData_get_layer_name(&mesh_ldata, CD_PROP_FLOAT2, layer_index), name); if (CustomData_get_named_layer_index(&mesh_ldata, CD_PROP_BOOL, name) < 0) { - CustomData_add_layer_named( - &mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me->totloop, name); + CustomData_add_layer_named(&mesh_ldata, CD_PROP_BOOL, CD_SET_DEFAULT, me->totloop, name); temporary_layers_to_delete.append(std::string(name)); } } @@ -291,9 +277,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar return; } - const float(*vert_normals)[3] = nullptr; + blender::Span vert_normals; if (params->calc_vert_normal) { - vert_normals = BKE_mesh_vert_normals_ensure(me); + vert_normals = me->vert_normals(); } if (is_new) { @@ -352,7 +338,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar if (is_new) { if (tot_shape_keys || params->add_key_index) { - CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_ASSIGN, nullptr, 0); + CustomData_add_layer(&bm->vdata, CD_SHAPE_KEYINDEX, CD_SET_DEFAULT, 0); } } @@ -385,7 +371,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar for (i = 0, block = static_cast(me->key->block.first); i < tot_shape_keys; block = block->next, i++) { if (is_new) { - CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_ASSIGN, nullptr, 0, block->name); + CustomData_add_layer_named(&bm->vdata, CD_SHAPEKEY, CD_SET_DEFAULT, 0, block->name); int j = CustomData_get_layer_index_n(&bm->vdata, CD_SHAPEKEY, i); bm->vdata.layers[j].uid = block->uid; } @@ -426,6 +412,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar &me->pdata, CD_PROP_BOOL, ".hide_poly"); const int *material_indices = (const int *)CustomData_get_layer_named( &me->pdata, CD_PROP_INT32, "material_index"); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &me->pdata, CD_PROP_BOOL, "sharp_face"); const bool *sharp_edges = (const bool *)CustomData_get_layer_named( &me->edata, CD_PROP_BOOL, "sharp_edge"); const bool *uv_seams = (const bool *)CustomData_get_layer_named( @@ -445,7 +433,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar BM_vert_select_set(bm, v, true); } - if (vert_normals) { + if (!vert_normals.is_empty()) { copy_v3_v3(v->no, vert_normals[i]); } @@ -527,7 +515,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar BM_elem_index_set(f, bm->totface - 1); /* set_ok */ /* Transfer flag. */ - f->head.hflag = bm_face_flag_from_mflag(polys[i].flag); + if (!(sharp_faces && sharp_faces[i])) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } if (hide_poly && hide_poly[i]) { BM_elem_flag_enable(f, BM_ELEM_HIDDEN); } @@ -600,7 +590,7 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar /** * \brief BMesh -> Mesh */ -static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert) +static BMVert **bm_to_mesh_vertex_map(BMesh *bm, const int old_verts_num) { const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX); BMVert **vertMap = nullptr; @@ -609,13 +599,13 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert) BMIter iter; /* Caller needs to ensure this. */ - BLI_assert(ototvert > 0); + BLI_assert(old_verts_num > 0); - vertMap = static_cast(MEM_callocN(sizeof(*vertMap) * ototvert, "vertMap")); + vertMap = static_cast(MEM_callocN(sizeof(*vertMap) * old_verts_num, "vertMap")); if (cd_shape_keyindex_offset != -1) { BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { const int keyi = BM_ELEM_CD_GET_INT(eve, cd_shape_keyindex_offset); - if ((keyi != ORIGINDEX_NONE) && (keyi < ototvert) && + if ((keyi != ORIGINDEX_NONE) && (keyi < old_verts_num) && /* Not fool-proof, but chances are if we have many verts with the same index, * we will want to use the first one, * since the second is more likely to be a duplicate. */ @@ -626,7 +616,7 @@ static BMVert **bm_to_mesh_vertex_map(BMesh *bm, int ototvert) } else { BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - if (i < ototvert) { + if (i < old_verts_num) { vertMap[i] = eve; } else { @@ -956,23 +946,6 @@ static void bm_to_mesh_shape(BMesh *bm, /** \} */ -template -static void write_fn_to_attribute(blender::bke::MutableAttributeAccessor attributes, - const StringRef attribute_name, - const eAttrDomain domain, - const GetFn &get_fn) -{ - using namespace blender; - bke::SpanAttributeWriter attribute = attributes.lookup_or_add_for_write_only_span( - attribute_name, domain); - threading::parallel_for(attribute.span.index_range(), 4096, [&](IndexRange range) { - for (const int i : range) { - attribute.span[i] = get_fn(i); - } - }); - attribute.finish(); -} - static void assert_bmesh_has_no_mesh_only_attributes(const BMesh &bm) { (void)bm; /* Unused in the release builds. */ @@ -988,68 +961,70 @@ static void assert_bmesh_has_no_mesh_only_attributes(const BMesh &bm) BLI_assert(CustomData_get_layer_named(&bm.pdata, CD_PROP_BOOL, ".select_poly") == nullptr); } -static void convert_bmesh_hide_flags_to_mesh_attributes(BMesh &bm, - const bool need_hide_vert, - const bool need_hide_edge, - const bool need_hide_poly, - Mesh &mesh) +static void bmesh_to_mesh_calc_object_remap(Main &bmain, + Mesh &me, + BMesh &bm, + const int old_totvert) { - using namespace blender; - /* The "hide" attributes are stored as flags on #BMesh. */ - assert_bmesh_has_no_mesh_only_attributes(bm); + BMVert **vertMap = nullptr; + BMVert *eve; - if (!(need_hide_vert || need_hide_edge || need_hide_poly)) { - return; + LISTBASE_FOREACH (Object *, ob, &bmain.objects) { + if ((ob->parent) && (ob->parent->data == &me) && ELEM(ob->partype, PARVERT1, PARVERT3)) { + + if (vertMap == nullptr) { + vertMap = bm_to_mesh_vertex_map(&bm, old_totvert); + } + + if (ob->par1 < old_totvert) { + eve = vertMap[ob->par1]; + if (eve) { + ob->par1 = BM_elem_index_get(eve); + } + } + if (ob->par2 < old_totvert) { + eve = vertMap[ob->par2]; + if (eve) { + ob->par2 = BM_elem_index_get(eve); + } + } + if (ob->par3 < old_totvert) { + eve = vertMap[ob->par3]; + if (eve) { + ob->par3 = BM_elem_index_get(eve); + } + } + } + if (ob->data == &me) { + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type == eModifierType_Hook) { + HookModifierData *hmd = (HookModifierData *)md; + + if (vertMap == nullptr) { + vertMap = bm_to_mesh_vertex_map(&bm, old_totvert); + } + int i, j; + for (i = j = 0; i < hmd->indexar_num; i++) { + if (hmd->indexar[i] < old_totvert) { + eve = vertMap[hmd->indexar[i]]; + + if (eve) { + hmd->indexar[j++] = BM_elem_index_get(eve); + } + } + else { + j++; + } + } + + hmd->indexar_num = j; + } + } + } } - bke::MutableAttributeAccessor attributes = mesh.attributes_for_write(); - BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE); - - if (need_hide_vert) { - write_fn_to_attribute(attributes, ".hide_vert", ATTR_DOMAIN_POINT, [&](const int i) { - return BM_elem_flag_test(BM_vert_at_index(&bm, i), BM_ELEM_HIDDEN); - }); - } - if (need_hide_edge) { - write_fn_to_attribute(attributes, ".hide_edge", ATTR_DOMAIN_EDGE, [&](const int i) { - return BM_elem_flag_test(BM_edge_at_index(&bm, i), BM_ELEM_HIDDEN); - }); - } - if (need_hide_poly) { - write_fn_to_attribute(attributes, ".hide_poly", ATTR_DOMAIN_FACE, [&](const int i) { - return BM_elem_flag_test(BM_face_at_index(&bm, i), BM_ELEM_HIDDEN); - }); - } -} - -static void convert_bmesh_selection_flags_to_mesh_attributes(BMesh &bm, - const bool need_select_vert, - const bool need_select_edge, - const bool need_select_poly, - Mesh &mesh) -{ - using namespace blender; - if (!(need_select_vert || need_select_edge || need_select_poly)) { - return; - } - - bke::MutableAttributeAccessor attributes = mesh.attributes_for_write(); - BM_mesh_elem_table_ensure(&bm, BM_VERT | BM_EDGE | BM_FACE); - - if (need_select_vert) { - write_fn_to_attribute(attributes, ".select_vert", ATTR_DOMAIN_POINT, [&](const int i) { - return BM_elem_flag_test(BM_vert_at_index(&bm, i), BM_ELEM_SELECT); - }); - } - if (need_select_edge) { - write_fn_to_attribute(attributes, ".select_edge", ATTR_DOMAIN_EDGE, [&](const int i) { - return BM_elem_flag_test(BM_edge_at_index(&bm, i), BM_ELEM_SELECT); - }); - } - if (need_select_poly) { - write_fn_to_attribute(attributes, ".select_poly", ATTR_DOMAIN_FACE, [&](const int i) { - return BM_elem_flag_test(BM_face_at_index(&bm, i), BM_ELEM_SELECT); - }); + if (vertMap) { + MEM_freeN(vertMap); } } @@ -1102,381 +1077,6 @@ static Vector bm_to_mesh_copy_info_calc(const CustomData & return infos; } -static void bmesh_block_copy_to_mesh_attributes(const Span copy_info, - const int mesh_index, - const void *block) -{ - for (const BMeshToMeshLayerInfo &info : copy_info) { - CustomData_data_copy_value(info.type, - POINTER_OFFSET(block, info.bmesh_offset), - POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index)); - } -} - -void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) -{ - using namespace blender; - BMVert *v, *eve; - BMEdge *e; - BMFace *f; - BMIter iter; - int i, j; - - const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, CD_SHAPE_KEYINDEX); - - const int ototvert = me->totvert; - - blender::Vector ldata_layers_marked_nocopy; - - /* Free custom data. */ - CustomData_free(&me->vdata, me->totvert); - CustomData_free(&me->edata, me->totedge); - CustomData_free(&me->fdata, me->totface); - CustomData_free(&me->ldata, me->totloop); - CustomData_free(&me->pdata, me->totpoly); - - BKE_mesh_runtime_clear_geometry(me); - - /* Add new custom data. */ - me->totvert = bm->totvert; - me->totedge = bm->totedge; - me->totloop = bm->totloop; - me->totpoly = bm->totface; - /* Will be overwritten with a valid value if 'dotess' is set, otherwise we - * end up with 'me->totface' and `me->mface == nullptr` which can crash #28625. */ - me->totface = 0; - me->act_face = -1; - - /* Mark UV selection layers which are all false as 'nocopy'. */ - for (const int layer_index : - IndexRange(CustomData_number_of_layers(&bm->ldata, CD_PROP_FLOAT2))) { - char const *layer_name = CustomData_get_layer_name(&bm->ldata, CD_PROP_FLOAT2, layer_index); - char sub_layer_name[MAX_CUSTOMDATA_LAYER_NAME]; - int vertsel_layer_index = CustomData_get_named_layer_index( - &bm->ldata, CD_PROP_BOOL, BKE_uv_map_vert_select_name_get(layer_name, sub_layer_name)); - int edgesel_layer_index = CustomData_get_named_layer_index( - &bm->ldata, CD_PROP_BOOL, BKE_uv_map_edge_select_name_get(layer_name, sub_layer_name)); - int pin_layer_index = CustomData_get_named_layer_index( - &bm->ldata, CD_PROP_BOOL, BKE_uv_map_pin_name_get(layer_name, sub_layer_name)); - - /* If ever the uv map associated bool layers become optional in BMesh as well (like in Mesh) - * this assert needs to be removed. For now it is a bug if they don't exist. */ - BLI_assert(vertsel_layer_index >= 0 && edgesel_layer_index >= 0 && pin_layer_index >= 0); - - int vertsel_offset = vertsel_layer_index >= 0 ? bm->ldata.layers[vertsel_layer_index].offset : - -1; - int edgesel_offset = edgesel_layer_index >= 0 ? bm->ldata.layers[edgesel_layer_index].offset : - -1; - int pin_offset = pin_layer_index >= 0 ? bm->ldata.layers[pin_layer_index].offset : -1; - - bool need_vertsel = false; - bool need_edgesel = false; - bool need_pin = false; - - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BMIter liter; - BMLoop *l; - if (vertsel_layer_index >= 0) { - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - need_vertsel |= BM_ELEM_CD_GET_BOOL(l, vertsel_offset); - } - } - if (edgesel_layer_index >= 0) { - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - need_edgesel |= BM_ELEM_CD_GET_BOOL(l, edgesel_offset); - } - } - if (pin_layer_index >= 0) { - BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - need_pin |= BM_ELEM_CD_GET_BOOL(l, pin_offset); - } - } - } - - if (need_vertsel) { - bm->ldata.layers[vertsel_layer_index].flag &= ~CD_FLAG_NOCOPY; - } - else { - bm->ldata.layers[vertsel_layer_index].flag |= CD_FLAG_NOCOPY; - ldata_layers_marked_nocopy.append(vertsel_layer_index); - } - if (need_edgesel) { - bm->ldata.layers[edgesel_layer_index].flag &= ~CD_FLAG_NOCOPY; - } - else { - bm->ldata.layers[edgesel_layer_index].flag |= CD_FLAG_NOCOPY; - ldata_layers_marked_nocopy.append(edgesel_layer_index); - } - if (need_pin) { - bm->ldata.layers[pin_layer_index].flag &= ~CD_FLAG_NOCOPY; - } - else { - bm->ldata.layers[pin_layer_index].flag |= CD_FLAG_NOCOPY; - ldata_layers_marked_nocopy.append(pin_layer_index); - } - } - - { - CustomData_MeshMasks mask = CD_MASK_MESH; - CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); - CustomData_copy(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); - CustomData_copy(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); - CustomData_copy(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); - CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); - } - - const Vector vert_info = bm_to_mesh_copy_info_calc(bm->vdata, me->vdata); - const Vector edge_info = bm_to_mesh_copy_info_calc(bm->edata, me->edata); - const Vector poly_info = bm_to_mesh_copy_info_calc(bm->pdata, me->pdata); - const Vector loop_info = bm_to_mesh_copy_info_calc(bm->ldata, me->ldata); - - /* Clear the CD_FLAG_NOCOPY flags for the layers they were temporarily set on */ - for (const int i : ldata_layers_marked_nocopy) { - bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY; - } - - CustomData_add_layer_named( - &me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, me->totvert, "position"); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, me->totedge); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, me->totloop); - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, me->totpoly); - MutableSpan positions = me->vert_positions_for_write(); - MutableSpan edges = me->edges_for_write(); - MutableSpan polys = me->polys_for_write(); - MutableSpan mloop = me->loops_for_write(); - - bool need_select_vert = false; - bool need_select_edge = false; - bool need_select_poly = false; - bool need_hide_vert = false; - bool need_hide_edge = false; - bool need_hide_poly = false; - bool need_material_index = false; - bool need_sharp_edge = false; - bool need_uv_seam = false; - - i = 0; - BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - copy_v3_v3(positions[i], v->co); - - if (BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { - need_hide_vert = true; - } - if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { - need_select_vert = true; - } - - BM_elem_index_set(v, i); /* set_inline */ - - bmesh_block_copy_to_mesh_attributes(vert_info, i, v->head.data); - - i++; - - BM_CHECK_ELEMENT(v); - } - bm->elem_index_dirty &= ~BM_VERT; - - i = 0; - BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - edges[i].v1 = BM_elem_index_get(e->v1); - edges[i].v2 = BM_elem_index_get(e->v2); - - if (BM_elem_flag_test(e, BM_ELEM_SEAM)) { - need_uv_seam = true; - } - if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - need_hide_edge = true; - } - if (BM_elem_flag_test(e, BM_ELEM_SELECT)) { - need_select_edge = true; - } - if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) { - need_sharp_edge = true; - } - - BM_elem_index_set(e, i); /* set_inline */ - - bmesh_block_copy_to_mesh_attributes(edge_info, i, e->head.data); - - i++; - BM_CHECK_ELEMENT(e); - } - bm->elem_index_dirty &= ~BM_EDGE; - - i = 0; - j = 0; - BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - BMLoop *l_iter, *l_first; - polys[i].loopstart = j; - polys[i].totloop = f->len; - if (f->mat_nr != 0) { - need_material_index = true; - } - polys[i].flag = bm_face_flag_to_mflag(f); - if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { - need_hide_poly = true; - } - if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { - need_select_poly = true; - } - - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - mloop[j].e = BM_elem_index_get(l_iter->e); - mloop[j].v = BM_elem_index_get(l_iter->v); - - bmesh_block_copy_to_mesh_attributes(loop_info, j, l_iter->head.data); - - j++; - BM_CHECK_ELEMENT(l_iter); - BM_CHECK_ELEMENT(l_iter->e); - BM_CHECK_ELEMENT(l_iter->v); - } while ((l_iter = l_iter->next) != l_first); - - if (f == bm->act_face) { - me->act_face = i; - } - - bmesh_block_copy_to_mesh_attributes(poly_info, i, f->head.data); - - i++; - BM_CHECK_ELEMENT(f); - } - - if (need_material_index) { - BM_mesh_elem_table_ensure(bm, BM_FACE); - write_fn_to_attribute(me->attributes_for_write(), - "material_index", - ATTR_DOMAIN_FACE, - [&](const int i) { return int(BM_face_at_index(bm, i)->mat_nr); }); - } - if (need_sharp_edge) { - BM_mesh_elem_table_ensure(bm, BM_EDGE); - write_fn_to_attribute( - me->attributes_for_write(), "sharp_edge", ATTR_DOMAIN_EDGE, [&](const int i) { - return !BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SMOOTH); - }); - } - if (need_uv_seam) { - BM_mesh_elem_table_ensure(bm, BM_EDGE); - write_fn_to_attribute( - me->attributes_for_write(), ".uv_seam", ATTR_DOMAIN_EDGE, [&](const int i) { - return BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SEAM); - }); - } - - /* Patch hook indices and vertex parents. */ - if (params->calc_object_remap && (ototvert > 0)) { - BLI_assert(bmain != nullptr); - BMVert **vertMap = nullptr; - - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if ((ob->parent) && (ob->parent->data == me) && ELEM(ob->partype, PARVERT1, PARVERT3)) { - - if (vertMap == nullptr) { - vertMap = bm_to_mesh_vertex_map(bm, ototvert); - } - - if (ob->par1 < ototvert) { - eve = vertMap[ob->par1]; - if (eve) { - ob->par1 = BM_elem_index_get(eve); - } - } - if (ob->par2 < ototvert) { - eve = vertMap[ob->par2]; - if (eve) { - ob->par2 = BM_elem_index_get(eve); - } - } - if (ob->par3 < ototvert) { - eve = vertMap[ob->par3]; - if (eve) { - ob->par3 = BM_elem_index_get(eve); - } - } - } - if (ob->data == me) { - LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { - if (md->type == eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData *)md; - - if (vertMap == nullptr) { - vertMap = bm_to_mesh_vertex_map(bm, ototvert); - } - - for (i = j = 0; i < hmd->indexar_num; i++) { - if (hmd->indexar[i] < ototvert) { - eve = vertMap[hmd->indexar[i]]; - - if (eve) { - hmd->indexar[j++] = BM_elem_index_get(eve); - } - } - else { - j++; - } - } - - hmd->indexar_num = j; - } - } - } - } - - if (vertMap) { - MEM_freeN(vertMap); - } - } - - convert_bmesh_hide_flags_to_mesh_attributes( - *bm, need_hide_vert, need_hide_edge, need_hide_poly, *me); - convert_bmesh_selection_flags_to_mesh_attributes( - *bm, need_select_vert, need_select_edge, need_select_poly, *me); - - { - me->totselect = BLI_listbase_count(&(bm->selected)); - - MEM_SAFE_FREE(me->mselect); - if (me->totselect != 0) { - me->mselect = static_cast( - MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history")); - } - - LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) { - if (selected->htype == BM_VERT) { - me->mselect[i].type = ME_VSEL; - } - else if (selected->htype == BM_EDGE) { - me->mselect[i].type = ME_ESEL; - } - else if (selected->htype == BM_FACE) { - me->mselect[i].type = ME_FSEL; - } - - me->mselect[i].index = BM_elem_index_get(selected->ele); - } - } - - if (me->key) { - bm_to_mesh_shape(bm, me->key, positions, params->active_shapekey_to_mvert); - } - - /* Run this even when shape keys aren't used since it may be used for hooks or vertex parents. */ - if (params->update_shapekey_indices) { - /* We have written a new shape key, if this mesh is _not_ going to be freed, - * update the shape key indices to match the newly updated. */ - if (cd_shape_keyindex_offset != -1) { - BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { - BM_ELEM_CD_SET_INT(eve, cd_shape_keyindex_offset, i); - } - } - } - - /* Topology could be changed, ensure #CD_MDISPS are ok. */ - multires_topology_changed(me); -} - namespace blender { static void bm_vert_table_build(BMesh &bm, @@ -1492,6 +1092,7 @@ static void bm_vert_table_build(BMesh &bm, BM_elem_index_set(vert, i); /* set_inline */ table[i] = vert; hflag |= vert->head.hflag; + BM_CHECK_ELEMENT(vert); } need_select_vert = (hflag & BM_ELEM_SELECT) != 0; need_hide_vert = (hflag & BM_ELEM_HIDDEN) != 0; @@ -1512,6 +1113,7 @@ static void bm_edge_table_build(BMesh &bm, BM_elem_index_set(edge, i); /* set_inline */ table[i] = edge; hflag |= edge->head.hflag; + BM_CHECK_ELEMENT(edge); } need_select_edge = (hflag & BM_ELEM_SELECT) != 0; need_hide_edge = (hflag & BM_ELEM_HIDDEN) != 0; @@ -1519,13 +1121,54 @@ static void bm_edge_table_build(BMesh &bm, need_uv_seams = (hflag & BM_ELEM_SEAM) != 0; } +/** + * UV map vertex and edge selection, and UV pinning are all stored in separate boolean layers. On + * #Mesh they are only meant to exist if they have a true value, but on #BMesh they currently + * always exist. To avoid creating unnecessary mesh attributes, mark the UV helper layers with no + * true values with the "no copy" flag. + */ static void bm_face_loop_table_build(BMesh &bm, MutableSpan face_table, MutableSpan loop_table, bool &need_select_poly, bool &need_hide_poly, - bool &need_material_index) + bool &need_sharp_face, + bool &need_material_index, + Vector &ldata_layers_marked_nocopy) { + const CustomData &ldata = bm.ldata; + Vector vert_sel_layers; + Vector edge_sel_layers; + Vector pin_layers; + for (const int i : IndexRange(CustomData_number_of_layers(&ldata, CD_PROP_FLOAT2))) { + char const *layer_name = CustomData_get_layer_name(&ldata, CD_PROP_FLOAT2, i); + char sub_layer_name[MAX_CUSTOMDATA_LAYER_NAME]; + auto add_bool_layer = [&](Vector &layers, const char *name) { + const int layer_index = CustomData_get_named_layer_index(&ldata, CD_PROP_BOOL, name); + if (layer_index != -1) { + layers.append(layer_index); + } + }; + add_bool_layer(vert_sel_layers, BKE_uv_map_vert_select_name_get(layer_name, sub_layer_name)); + add_bool_layer(edge_sel_layers, BKE_uv_map_edge_select_name_get(layer_name, sub_layer_name)); + add_bool_layer(pin_layers, BKE_uv_map_pin_name_get(layer_name, sub_layer_name)); + } + Array vert_sel_offsets(vert_sel_layers.size()); + Array edge_sel_offsets(edge_sel_layers.size()); + Array pin_offsets(pin_layers.size()); + for (const int i : vert_sel_layers.index_range()) { + vert_sel_offsets[i] = ldata.layers[vert_sel_layers[i]].offset; + } + for (const int i : edge_sel_layers.index_range()) { + edge_sel_offsets[i] = ldata.layers[edge_sel_layers[i]].offset; + } + for (const int i : pin_layers.index_range()) { + pin_offsets[i] = ldata.layers[pin_layers[i]].offset; + } + + Array need_vert_sel(vert_sel_layers.size(), false); + Array need_edge_sel(edge_sel_layers.size(), false); + Array need_pin(pin_layers.size(), false); char hflag = 0; BMIter iter; int face_i = 0; @@ -1535,18 +1178,66 @@ static void bm_face_loop_table_build(BMesh &bm, BM_elem_index_set(face, face_i); /* set_inline */ face_table[face_i] = face; hflag |= face->head.hflag; + need_sharp_face |= (face->head.hflag & BM_ELEM_SMOOTH) == 0; need_material_index |= face->mat_nr != 0; + BM_CHECK_ELEMENT(face); BMLoop *loop = BM_FACE_FIRST_LOOP(face); for ([[maybe_unused]] const int i : IndexRange(face->len)) { BM_elem_index_set(loop, loop_i); /* set_inline */ loop_table[loop_i] = loop; + for (const int i : vert_sel_offsets.index_range()) { + if (BM_ELEM_CD_GET_BOOL(loop, vert_sel_offsets[i])) { + need_vert_sel[i] = true; + } + } + for (const int i : edge_sel_offsets.index_range()) { + if (BM_ELEM_CD_GET_BOOL(loop, edge_sel_offsets[i])) { + need_edge_sel[i] = true; + } + } + for (const int i : pin_offsets.index_range()) { + if (BM_ELEM_CD_GET_BOOL(loop, pin_offsets[i])) { + need_pin[i] = true; + } + } + BM_CHECK_ELEMENT(loop); loop = loop->next; loop_i++; } } need_select_poly = (hflag & BM_ELEM_SELECT) != 0; need_hide_poly = (hflag & BM_ELEM_HIDDEN) != 0; + + for (const int i : vert_sel_layers.index_range()) { + if (!need_vert_sel[i]) { + ldata.layers[vert_sel_layers[i]].flag |= CD_FLAG_NOCOPY; + ldata_layers_marked_nocopy.append(vert_sel_layers[i]); + } + } + for (const int i : edge_sel_layers.index_range()) { + if (!need_edge_sel[i]) { + ldata.layers[edge_sel_layers[i]].flag |= CD_FLAG_NOCOPY; + ldata_layers_marked_nocopy.append(edge_sel_layers[i]); + } + } + for (const int i : pin_layers.index_range()) { + if (!need_pin[i]) { + ldata.layers[pin_layers[i]].flag |= CD_FLAG_NOCOPY; + ldata_layers_marked_nocopy.append(pin_layers[i]); + } + } +} + +static void bmesh_block_copy_to_mesh_attributes(const Span copy_info, + const int mesh_index, + const void *block) +{ + for (const BMeshToMeshLayerInfo &info : copy_info) { + CustomData_data_copy_value(info.type, + POINTER_OFFSET(block, info.bmesh_offset), + POINTER_OFFSET(info.mesh_data, info.elem_size * mesh_index)); + } } static void bm_to_mesh_verts(const BMesh &bm, @@ -1555,6 +1246,7 @@ static void bm_to_mesh_verts(const BMesh &bm, MutableSpan select_vert, MutableSpan hide_vert) { + CustomData_add_layer_named(&mesh.vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh.totvert, "position"); const Vector info = bm_to_mesh_copy_info_calc(bm.vdata, mesh.vdata); MutableSpan dst_vert_positions = mesh.vert_positions_for_write(); threading::parallel_for(dst_vert_positions.index_range(), 1024, [&](const IndexRange range) { @@ -1584,6 +1276,7 @@ static void bm_to_mesh_edges(const BMesh &bm, MutableSpan sharp_edge, MutableSpan uv_seams) { + CustomData_add_layer(&mesh.edata, CD_MEDGE, CD_SET_DEFAULT, mesh.totedge); const Vector info = bm_to_mesh_copy_info_calc(bm.edata, mesh.edata); MutableSpan dst_edges = mesh.edges_for_write(); threading::parallel_for(dst_edges.index_range(), 512, [&](const IndexRange range) { @@ -1622,8 +1315,10 @@ static void bm_to_mesh_faces(const BMesh &bm, Mesh &mesh, MutableSpan select_poly, MutableSpan hide_poly, + MutableSpan sharp_faces, MutableSpan material_indices) { + CustomData_add_layer(&mesh.pdata, CD_MPOLY, CD_CONSTRUCT, mesh.totpoly); const Vector info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata); MutableSpan dst_polys = mesh.polys_for_write(); threading::parallel_for(dst_polys.index_range(), 1024, [&](const IndexRange range) { @@ -1632,7 +1327,6 @@ static void bm_to_mesh_faces(const BMesh &bm, MPoly &dst_poly = dst_polys[face_i]; dst_poly.totloop = src_face.len; dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face)); - dst_poly.flag = bm_face_flag_to_mflag(&src_face); bmesh_block_copy_to_mesh_attributes(info, face_i, src_face.head.data); } if (!select_poly.is_empty()) { @@ -1650,11 +1344,17 @@ static void bm_to_mesh_faces(const BMesh &bm, material_indices[face_i] = bm_faces[face_i]->mat_nr; } } + if (!sharp_faces.is_empty()) { + for (const int face_i : range) { + sharp_faces[face_i] = !BM_elem_flag_test(bm_faces[face_i], BM_ELEM_SMOOTH); + } + } }); } static void bm_to_mesh_loops(const BMesh &bm, const Span bm_loops, Mesh &mesh) { + CustomData_add_layer(&mesh.ldata, CD_MLOOP, CD_SET_DEFAULT, mesh.totloop); const Vector info = bm_to_mesh_copy_info_calc(bm.ldata, mesh.ldata); MutableSpan dst_loops = mesh.loops_for_write(); threading::parallel_for(dst_loops.index_range(), 1024, [&](const IndexRange range) { @@ -1670,16 +1370,16 @@ static void bm_to_mesh_loops(const BMesh &bm, const Span bm_loop } // namespace blender -/* NOTE: The function is called from multiple threads with the same input BMesh and different - * mesh objects. */ -void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra) +void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params) { using namespace blender; + const int old_verts_num = me->totvert; - /* Must be an empty mesh. */ - BLI_assert(me->totvert == 0); - BLI_assert(cd_mask_extra == nullptr || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0); - /* Just in case, clear the derived geometry caches from the input mesh. */ + CustomData_free(&me->vdata, me->totvert); + CustomData_free(&me->edata, me->totedge); + CustomData_free(&me->fdata, me->totface); + CustomData_free(&me->ldata, me->totloop); + CustomData_free(&me->pdata, me->totpoly); BKE_mesh_runtime_clear_geometry(me); me->totvert = bm->totvert; @@ -1687,32 +1387,17 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * me->totface = 0; me->totloop = bm->totloop; me->totpoly = bm->totface; + me->act_face = -1; - if (!CustomData_get_layer_named(&me->vdata, CD_PROP_FLOAT3, "position")) { - CustomData_add_layer_named( - &me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, bm->totvert, "position"); + { + CustomData_MeshMasks mask = CD_MASK_MESH; + CustomData_MeshMasks_update(&mask, ¶ms->cd_mask_extra); + CustomData_copy(&bm->vdata, &me->vdata, mask.vmask, CD_SET_DEFAULT, me->totvert); + CustomData_copy(&bm->edata, &me->edata, mask.emask, CD_SET_DEFAULT, me->totedge); + CustomData_copy(&bm->ldata, &me->ldata, mask.lmask, CD_SET_DEFAULT, me->totloop); + CustomData_copy(&bm->pdata, &me->pdata, mask.pmask, CD_SET_DEFAULT, me->totpoly); } - CustomData_add_layer(&me->edata, CD_MEDGE, CD_CONSTRUCT, nullptr, bm->totedge); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_CONSTRUCT, nullptr, bm->totloop); - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_CONSTRUCT, nullptr, bm->totface); - /* Don't process shape-keys, we only feed them through the modifier stack as needed, - * e.g. for applying modifiers or the like. */ - CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH; - if (cd_mask_extra != nullptr) { - CustomData_MeshMasks_update(&mask, cd_mask_extra); - } - mask.vmask &= ~CD_MASK_SHAPEKEY; - CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); - CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); - CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); - CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); - - me->runtime->deformed_only = true; - - /* In a first pass, update indices of BMesh elements and build tables for easy iteration later. - * Also check if some optional mesh attributes should be added in the next step. Since each - * domain has no effect on others, process the independent domains on separate threads. */ bool need_select_vert = false; bool need_select_edge = false; bool need_select_poly = false; @@ -1721,11 +1406,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * bool need_hide_poly = false; bool need_material_index = false; bool need_sharp_edge = false; + bool need_sharp_face = false; bool need_uv_seams = false; Array vert_table; Array edge_table; Array face_table; Array loop_table; + Vector ldata_layers_marked_nocopy; threading::parallel_invoke( me->totface > 1024, [&]() { @@ -1740,8 +1427,14 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * [&]() { face_table.reinitialize(bm->totface); loop_table.reinitialize(bm->totloop); - bm_face_loop_table_build( - *bm, face_table, loop_table, need_select_poly, need_hide_poly, need_material_index); + bm_face_loop_table_build(*bm, + face_table, + loop_table, + need_select_poly, + need_hide_poly, + need_sharp_face, + need_material_index, + ldata_layers_marked_nocopy); }); bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP); @@ -1756,6 +1449,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * bke::SpanAttributeWriter uv_seams; bke::SpanAttributeWriter select_poly; bke::SpanAttributeWriter hide_poly; + bke::SpanAttributeWriter sharp_face; bke::SpanAttributeWriter material_index; if (need_select_vert) { select_vert = attrs.lookup_or_add_for_write_only_span(".select_vert", ATTR_DOMAIN_POINT); @@ -1781,6 +1475,227 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * if (need_hide_poly) { hide_poly = attrs.lookup_or_add_for_write_only_span(".hide_poly", ATTR_DOMAIN_FACE); } + if (need_sharp_face) { + sharp_face = attrs.lookup_or_add_for_write_only_span("sharp_face", ATTR_DOMAIN_FACE); + } + if (need_material_index) { + material_index = attrs.lookup_or_add_for_write_only_span("material_index", + ATTR_DOMAIN_FACE); + } + + /* Loop over all elements in parallel, copying attributes and building the Mesh topology. */ + threading::parallel_invoke( + me->totvert > 1024, + [&]() { + bm_to_mesh_verts(*bm, vert_table, *me, select_vert.span, hide_vert.span); + if (me->key) { + bm_to_mesh_shape( + bm, me->key, me->vert_positions_for_write(), params->active_shapekey_to_mvert); + } + }, + [&]() { + bm_to_mesh_edges(*bm, + edge_table, + *me, + select_edge.span, + hide_edge.span, + sharp_edge.span, + uv_seams.span); + }, + [&]() { + bm_to_mesh_faces(*bm, + face_table, + *me, + select_poly.span, + hide_poly.span, + sharp_face.span, + material_index.span); + if (bm->act_face) { + me->act_face = BM_elem_index_get(bm->act_face); + } + }, + [&]() { + bm_to_mesh_loops(*bm, loop_table, *me); + /* Topology could be changed, ensure #CD_MDISPS are ok. */ + multires_topology_changed(me); + for (const int i : ldata_layers_marked_nocopy) { + bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY; + } + }, + [&]() { + /* Patch hook indices and vertex parents. */ + if (params->calc_object_remap && (old_verts_num > 0)) { + bmesh_to_mesh_calc_object_remap(*bmain, *me, *bm, old_verts_num); + } + }, + [&]() { + me->totselect = BLI_listbase_count(&(bm->selected)); + + MEM_SAFE_FREE(me->mselect); + if (me->totselect != 0) { + me->mselect = static_cast( + MEM_mallocN(sizeof(MSelect) * me->totselect, "Mesh selection history")); + } + int i; + LISTBASE_FOREACH_INDEX (BMEditSelection *, selected, &bm->selected, i) { + if (selected->htype == BM_VERT) { + me->mselect[i].type = ME_VSEL; + } + else if (selected->htype == BM_EDGE) { + me->mselect[i].type = ME_ESEL; + } + else if (selected->htype == BM_FACE) { + me->mselect[i].type = ME_FSEL; + } + + me->mselect[i].index = BM_elem_index_get(selected->ele); + } + }, + [&]() { + /* Run this even when shape keys aren't used since it may be used for hooks or vertex + * parents. */ + if (params->update_shapekey_indices) { + /* We have written a new shape key, if this mesh is _not_ going to be freed, + * update the shape key indices to match the newly updated. */ + const int cd_shape_keyindex_offset = CustomData_get_offset(&bm->vdata, + CD_SHAPE_KEYINDEX); + if (cd_shape_keyindex_offset != -1) { + BMIter iter; + BMVert *vert; + int i; + BM_ITER_MESH_INDEX (vert, &iter, bm, BM_VERTS_OF_MESH, i) { + BM_ELEM_CD_SET_INT(vert, cd_shape_keyindex_offset, i); + } + } + } + }); + + select_vert.finish(); + hide_vert.finish(); + select_edge.finish(); + hide_edge.finish(); + sharp_edge.finish(); + uv_seams.finish(); + select_poly.finish(); + hide_poly.finish(); + sharp_face.finish(); + material_index.finish(); +} + +/* NOTE: The function is called from multiple threads with the same input BMesh and different + * mesh objects. */ +void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra) +{ + using namespace blender; + /* Must be an empty mesh. */ + BLI_assert(me->totvert == 0); + BLI_assert(cd_mask_extra == nullptr || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0); + /* Just in case, clear the derived geometry caches from the input mesh. */ + BKE_mesh_runtime_clear_geometry(me); + + me->totvert = bm->totvert; + me->totedge = bm->totedge; + me->totface = 0; + me->totloop = bm->totloop; + me->totpoly = bm->totface; + + /* Don't process shape-keys. We only feed them through the modifier stack as needed, + * e.g. for applying modifiers or the like. */ + CustomData_MeshMasks mask = CD_MASK_DERIVEDMESH; + if (cd_mask_extra != nullptr) { + CustomData_MeshMasks_update(&mask, cd_mask_extra); + } + mask.vmask &= ~CD_MASK_SHAPEKEY; + CustomData_merge(&bm->vdata, &me->vdata, mask.vmask, CD_CONSTRUCT, me->totvert); + CustomData_merge(&bm->edata, &me->edata, mask.emask, CD_CONSTRUCT, me->totedge); + CustomData_merge(&bm->ldata, &me->ldata, mask.lmask, CD_CONSTRUCT, me->totloop); + CustomData_merge(&bm->pdata, &me->pdata, mask.pmask, CD_CONSTRUCT, me->totpoly); + + me->runtime->deformed_only = true; + + /* In a first pass, update indices of BMesh elements and build tables for easy iteration later. + * Also check if some optional mesh attributes should be added in the next step. Since each + * domain has no effect on others, process the independent domains on separate threads. */ + bool need_select_vert = false; + bool need_select_edge = false; + bool need_select_poly = false; + bool need_hide_vert = false; + bool need_hide_edge = false; + bool need_hide_poly = false; + bool need_material_index = false; + bool need_sharp_edge = false; + bool need_sharp_face = false; + bool need_uv_seams = false; + Array vert_table; + Array edge_table; + Array face_table; + Array loop_table; + Vector ldata_layers_marked_nocopy; + threading::parallel_invoke( + me->totface > 1024, + [&]() { + vert_table.reinitialize(bm->totvert); + bm_vert_table_build(*bm, vert_table, need_select_vert, need_hide_vert); + }, + [&]() { + edge_table.reinitialize(bm->totedge); + bm_edge_table_build( + *bm, edge_table, need_select_edge, need_hide_edge, need_sharp_edge, need_uv_seams); + }, + [&]() { + face_table.reinitialize(bm->totface); + loop_table.reinitialize(bm->totloop); + bm_face_loop_table_build(*bm, + face_table, + loop_table, + need_select_poly, + need_hide_poly, + need_sharp_face, + need_material_index, + ldata_layers_marked_nocopy); + }); + bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP); + + /* Add optional mesh attributes before parallel iteration. */ + assert_bmesh_has_no_mesh_only_attributes(*bm); + bke::MutableAttributeAccessor attrs = me->attributes_for_write(); + bke::SpanAttributeWriter select_vert; + bke::SpanAttributeWriter hide_vert; + bke::SpanAttributeWriter select_edge; + bke::SpanAttributeWriter hide_edge; + bke::SpanAttributeWriter sharp_edge; + bke::SpanAttributeWriter uv_seams; + bke::SpanAttributeWriter select_poly; + bke::SpanAttributeWriter hide_poly; + bke::SpanAttributeWriter sharp_face; + bke::SpanAttributeWriter material_index; + if (need_select_vert) { + select_vert = attrs.lookup_or_add_for_write_only_span(".select_vert", ATTR_DOMAIN_POINT); + } + if (need_hide_vert) { + hide_vert = attrs.lookup_or_add_for_write_only_span(".hide_vert", ATTR_DOMAIN_POINT); + } + if (need_select_edge) { + select_edge = attrs.lookup_or_add_for_write_only_span(".select_edge", ATTR_DOMAIN_EDGE); + } + if (need_sharp_edge) { + sharp_edge = attrs.lookup_or_add_for_write_only_span("sharp_edge", ATTR_DOMAIN_EDGE); + } + if (need_uv_seams) { + uv_seams = attrs.lookup_or_add_for_write_only_span(".uv_seam", ATTR_DOMAIN_EDGE); + } + if (need_hide_edge) { + hide_edge = attrs.lookup_or_add_for_write_only_span(".hide_edge", ATTR_DOMAIN_EDGE); + } + if (need_select_poly) { + select_poly = attrs.lookup_or_add_for_write_only_span(".select_poly", ATTR_DOMAIN_FACE); + } + if (need_hide_poly) { + hide_poly = attrs.lookup_or_add_for_write_only_span(".hide_poly", ATTR_DOMAIN_FACE); + } + if (need_sharp_face) { + sharp_face = attrs.lookup_or_add_for_write_only_span("sharp_face", ATTR_DOMAIN_FACE); + } if (need_material_index) { material_index = attrs.lookup_or_add_for_write_only_span("material_index", ATTR_DOMAIN_FACE); @@ -1800,10 +1715,20 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * uv_seams.span); }, [&]() { - bm_to_mesh_faces( - *bm, face_table, *me, select_poly.span, hide_poly.span, material_index.span); + bm_to_mesh_faces(*bm, + face_table, + *me, + select_poly.span, + hide_poly.span, + sharp_face.span, + material_index.span); }, - [&]() { bm_to_mesh_loops(*bm, loop_table, *me); }); + [&]() { + bm_to_mesh_loops(*bm, loop_table, *me); + for (const int i : ldata_layers_marked_nocopy) { + bm->ldata.layers[i].flag &= ~CD_FLAG_NOCOPY; + } + }); select_vert.finish(); hide_vert.finish(); @@ -1813,5 +1738,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * uv_seams.finish(); select_poly.finish(); hide_poly.finish(); + sharp_face.finish(); material_index.finish(); } diff --git a/source/blender/bmesh/intern/bmesh_mesh_normals.cc b/source/blender/bmesh/intern/bmesh_mesh_normals.cc index 28164eaec7a..6f0f7af7a6b 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_normals.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_normals.cc @@ -22,7 +22,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "intern/bmesh_private.h" @@ -1053,7 +1053,7 @@ static void bm_mesh_loops_calc_normals_for_vert_without_clnors( } /** - * BMesh version of BKE_mesh_normals_loop_split() in `mesh_evaluate.cc` + * BMesh version of bke::mesh::normals_calc_loop() in `mesh_evaluate.cc` * Will use first clnors_data array, and fallback to cd_loop_clnors_offset * (use nullptr and -1 to not use clnors). * @@ -1404,7 +1404,7 @@ static bool bm_mesh_loops_split_lnor_fans(BMesh *bm, /* Notes: * * In case of mono-loop smooth fan, we have nothing to do. * * Loops in this linklist are ordered (in reversed order compared to how they were - * discovered by BKE_mesh_normals_loop_split(), but this is not a problem). + * discovered by bke::mesh::normals_calc_loop(), but this is not a problem). * Which means if we find a mismatching clnor, * we know all remaining loops will have to be in a new, different smooth fan/lnor space. * * In smooth fan case, we compare each clnor against a ref one, diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c index a1c69da6f7a..98de2ea60bd 100644 --- a/source/blender/bmesh/intern/bmesh_opdefines.c +++ b/source/blender/bmesh/intern/bmesh_opdefines.c @@ -274,7 +274,7 @@ static BMOpDefine bmo_reverse_faces_def = { * Flip Quad Tessellation * * Flip the tessellation direction of the selected quads. -*/ + */ static BMOpDefine bmo_flip_quad_tessellation_def = { "flip_quad_tessellation", /* slot_in */ diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index b4cfeb43c8f..de1ab723b9c 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -261,6 +261,8 @@ static bool bm_face_split_edgenet_find_loop_walk(BMVert *v_init, const uint edge_order_len, BMEdge *e_pair[2]) { + UNUSED_VARS_NDEBUG(edge_order_len); + /* fast-path for the common case (avoid push-pop). * Also avoids tagging as visited since we know we * can't reach these verts some other way */ diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index 8d4ba5c11f8..9109a8eda42 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -573,27 +573,28 @@ void bmo_reverse_uvs_exec(BMesh *bm, BMOperator *op) /**************************************************************************** * * Cycle colors for a face **************************************************************************** */ + static void bmo_get_loop_color_ref(BMesh *bm, int index, int *r_cd_color_offset, int *r_cd_color_type) { Mesh me_query; - - BKE_id_attribute_copy_domains_temp( - ID_ME, &bm->vdata, NULL, &bm->ldata, NULL, NULL, &me_query.id); + memset(&me_query, 0, sizeof(Mesh)); + CustomData_reset(&me_query.vdata); + CustomData_reset(&me_query.edata); + CustomData_reset(&me_query.pdata); + me_query.ldata = bm->ldata; + *((short *)me_query.id.name) = ID_ME; CustomDataLayer *layer = BKE_id_attribute_from_index( - &me_query.id, index, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); - - if (!layer || BKE_id_attribute_domain(&me_query.id, layer) != ATTR_DOMAIN_CORNER) { + &me_query.id, index, ATTR_DOMAIN_MASK_CORNER, CD_MASK_COLOR_ALL); + if (!layer) { *r_cd_color_offset = -1; return; } - int layer_i = CustomData_get_layer_index(&bm->ldata, layer->type); - - *r_cd_color_offset = bm->ldata.layers[layer_i].offset; + *r_cd_color_offset = layer->offset; *r_cd_color_type = layer->type; } diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.h b/source/blender/compositor/operations/COM_BokehImageOperation.h index e3ae3ef922b..e9e6262e1c7 100644 --- a/source/blender/compositor/operations/COM_BokehImageOperation.h +++ b/source/blender/compositor/operations/COM_BokehImageOperation.h @@ -30,7 +30,7 @@ namespace blender::compositor { * - Distance between the center of the image and the pixel to be evaluated. * - Distance between the center of the image and the outer-edge. * - Distance between the center of the image and the inner-edge. - + * * With a simple compare it can be detected if the evaluated pixel is between the outer and inner * edge. */ diff --git a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc index 75b2249b6a7..cd0327f1c9e 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc +++ b/source/blender/compositor/operations/COM_GaussianAlphaBlurBaseOperation.cc @@ -102,7 +102,7 @@ void GaussianAlphaBlurBaseOperation::update_memory_buffer_partial(MemoryBuffer * const int coord_min = max_ii(coord - filtersize_, min_input_coord); const int coord_max = min_ii(coord + filtersize_ + 1, max_input_coord); - /* *** This is the main part which is different to #GaussianBlurBaseOperation. *** */ + /* *** This is the main part which is different to #GaussianBlurBaseOperation. *** */ /* Gauss. */ float alpha_accum = 0.0f; float multiplier_accum = 0.0f; diff --git a/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc b/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc index c9ea395cfa6..5f0ddf6719a 100644 --- a/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc +++ b/source/blender/compositor/realtime_compositor/intern/realize_on_domain_operation.cc @@ -76,13 +76,25 @@ void RealizeOnDomainOperation::execute() GPUShader *RealizeOnDomainOperation::get_realization_shader() { - switch (get_result().type()) { - case ResultType::Color: - return shader_manager().get("compositor_realize_on_domain_color"); - case ResultType::Vector: - return shader_manager().get("compositor_realize_on_domain_vector"); - case ResultType::Float: - return shader_manager().get("compositor_realize_on_domain_float"); + if (get_input().get_realization_options().interpolation == Interpolation::Bicubic) { + switch (get_result().type()) { + case ResultType::Color: + return shader_manager().get("compositor_realize_on_domain_bicubic_color"); + case ResultType::Vector: + return shader_manager().get("compositor_realize_on_domain_bicubic_vector"); + case ResultType::Float: + return shader_manager().get("compositor_realize_on_domain_bicubic_float"); + } + } + else { + switch (get_result().type()) { + case ResultType::Color: + return shader_manager().get("compositor_realize_on_domain_color"); + case ResultType::Vector: + return shader_manager().get("compositor_realize_on_domain_vector"); + case ResultType::Float: + return shader_manager().get("compositor_realize_on_domain_float"); + } } BLI_assert_unreachable(); diff --git a/source/blender/compositor/realtime_compositor/shaders/compositor_realize_on_domain.glsl b/source/blender/compositor/realtime_compositor/shaders/compositor_realize_on_domain.glsl index 4ae6e2fb700..604783d54eb 100644 --- a/source/blender/compositor/realtime_compositor/shaders/compositor_realize_on_domain.glsl +++ b/source/blender/compositor/realtime_compositor/shaders/compositor_realize_on_domain.glsl @@ -1,3 +1,4 @@ +#pragma BLENDER_REQUIRE(gpu_shader_bicubic_sampler_lib.glsl) #pragma BLENDER_REQUIRE(gpu_shader_compositor_texture_utilities.glsl) void main() @@ -25,5 +26,5 @@ void main() * the sampler's expected [0, 1] range. */ vec2 normalized_coordinates = (coordinates - offset) / vec2(input_size); - imageStore(domain_img, texel, texture(input_tx, normalized_coordinates)); + imageStore(domain_img, texel, SAMPLER_FUNCTION(input_tx, normalized_coordinates)); } diff --git a/source/blender/compositor/realtime_compositor/shaders/infos/compositor_realize_on_domain_info.hh b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_realize_on_domain_info.hh index 4528649ae98..2de84e1ba75 100644 --- a/source/blender/compositor/realtime_compositor/shaders/infos/compositor_realize_on_domain_info.hh +++ b/source/blender/compositor/realtime_compositor/shaders/infos/compositor_realize_on_domain_info.hh @@ -8,17 +8,40 @@ GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_shared) .sampler(0, ImageType::FLOAT_2D, "input_tx") .compute_source("compositor_realize_on_domain.glsl"); -GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_color) +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_standard_shared) .additional_info("compositor_realize_on_domain_shared") + .define("SAMPLER_FUNCTION", "texture"); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_shared) + .additional_info("compositor_realize_on_domain_shared") + .define("SAMPLER_FUNCTION", "texture_bicubic"); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_color) + .additional_info("compositor_realize_on_domain_standard_shared") .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") .do_static_compilation(true); GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_vector) - .additional_info("compositor_realize_on_domain_shared") + .additional_info("compositor_realize_on_domain_standard_shared") .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") .do_static_compilation(true); GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_float) - .additional_info("compositor_realize_on_domain_shared") + .additional_info("compositor_realize_on_domain_standard_shared") + .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_color) + .additional_info("compositor_realize_on_domain_bicubic_shared") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_vector) + .additional_info("compositor_realize_on_domain_bicubic_shared") + .image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") + .do_static_compilation(true); + +GPU_SHADER_CREATE_INFO(compositor_realize_on_domain_bicubic_float) + .additional_info("compositor_realize_on_domain_bicubic_shared") .image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "domain_img") .do_static_compilation(true); diff --git a/source/blender/compositor/realtime_compositor/shaders/library/gpu_shader_compositor_luminance_matte.glsl b/source/blender/compositor/realtime_compositor/shaders/library/gpu_shader_compositor_luminance_matte.glsl index 3647ac583fe..c3e28723237 100644 --- a/source/blender/compositor/realtime_compositor/shaders/library/gpu_shader_compositor_luminance_matte.glsl +++ b/source/blender/compositor/realtime_compositor/shaders/library/gpu_shader_compositor_luminance_matte.glsl @@ -8,7 +8,7 @@ void node_composite_luminance_matte(vec4 color, out float matte) { float luminance = get_luminance(color.rgb, luminance_coefficients); - float alpha = clamp(0.0, 1.0, (luminance - low) / (high - low)); + float alpha = clamp((luminance - low) / (high - low), 0.0, 1.0); matte = min(alpha, color.a); result = color * matte; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_key.h b/source/blender/depsgraph/intern/builder/deg_builder_key.h index 2d08e231114..526cbe82050 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_key.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_key.h @@ -155,7 +155,7 @@ struct PersistentOperationKey : public OperationKey { component_name_storage_ = component_node->name; name_storage_ = operation_node->name; - /* Assign fields used by the #OperationKey API. */ + /* Assign fields used by the #OperationKey API. */ id = id_node->id_orig; component_type = component_node->type; component_name = component_name_storage_.c_str(); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 9c02d8045c0..de153347342 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -28,7 +28,7 @@ #include "DNA_curve_types.h" #include "DNA_curves_types.h" #include "DNA_effect_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_light_types.h" #include "DNA_lightprobe_types.h" @@ -61,8 +61,8 @@ #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_fcurve_driver.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_image.h" @@ -75,7 +75,7 @@ #include "BKE_mask.h" #include "BKE_material.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_movieclip.h" #include "BKE_node.h" @@ -604,7 +604,7 @@ void DepsgraphNodeBuilder::build_id(ID *id) case ID_MB: case ID_CU_LEGACY: case ID_LT: - case ID_GD: + case ID_GD_LEGACY: case ID_CV: case ID_PT: case ID_VO: @@ -933,7 +933,7 @@ void DepsgraphNodeBuilder::build_object_data(Object *object) case OB_SURF: case OB_MBALL: case OB_LATTICE: - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: case OB_CURVES: case OB_POINTCLOUD: case OB_VOLUME: @@ -1616,7 +1616,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata) break; } - case ID_GD: { + case ID_GD_LEGACY: { /* GPencil evaluation operations. */ op_node = add_operation_node(obdata, NodeType::GEOMETRY, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index b1f5b86ff76..31023b8ca4a 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -29,7 +29,7 @@ #include "DNA_curve_types.h" #include "DNA_curves_types.h" #include "DNA_effect_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_light_types.h" #include "DNA_lightprobe_types.h" @@ -63,7 +63,7 @@ #include "BKE_curve.h" #include "BKE_effect.h" #include "BKE_fcurve_driver.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_idprop.h" #include "BKE_image.h" #include "BKE_key.h" @@ -224,8 +224,14 @@ OperationCode bone_target_opcode(ID *target, bool object_have_geometry_component(const Object *object) { - return ELEM( - object->type, OB_MESH, OB_CURVES_LEGACY, OB_FONT, OB_SURF, OB_MBALL, OB_LATTICE, OB_GPENCIL); + return ELEM(object->type, + OB_MESH, + OB_CURVES_LEGACY, + OB_FONT, + OB_SURF, + OB_MBALL, + OB_LATTICE, + OB_GPENCIL_LEGACY); } } // namespace @@ -542,7 +548,7 @@ void DepsgraphRelationBuilder::build_id(ID *id) case ID_CV: case ID_PT: case ID_VO: - case ID_GD: + case ID_GD_LEGACY: build_object_data_geometry_datablock(id); break; case ID_SPK: @@ -942,7 +948,7 @@ void DepsgraphRelationBuilder::build_object_data(Object *object) case OB_SURF: case OB_MBALL: case OB_LATTICE: - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: case OB_CURVES: case OB_POINTCLOUD: case OB_VOLUME: { @@ -2435,7 +2441,7 @@ void DepsgraphRelationBuilder::build_object_data_geometry_datablock(ID *obdata) } case ID_LT: break; - case ID_GD: /* Grease Pencil */ + case ID_GD_LEGACY: /* Grease Pencil */ { bGPdata *gpd = (bGPdata *)obdata; diff --git a/source/blender/depsgraph/intern/depsgraph_registry.cc b/source/blender/depsgraph/intern/depsgraph_registry.cc index 96336167b5a..dea87550542 100644 --- a/source/blender/depsgraph/intern/depsgraph_registry.cc +++ b/source/blender/depsgraph/intern/depsgraph_registry.cc @@ -5,6 +5,9 @@ * \ingroup depsgraph */ +#include +#include + #include "intern/depsgraph_registry.h" #include "BLI_utildefines.h" @@ -13,7 +16,19 @@ namespace blender::deg { -using GraphRegistry = Map
>; +/* Global registry for dependency graphs associated with a main database. + * + * Threads may add or remove depsgraphs for different mains concurrently + * (for example for preview rendering), but not the same main. */ + +/* Use pointer for map value to ensure span returned by get_all_registered_graphs + * remains unchanged as other mains are added or removed. */ +typedef std::unique_ptr> GraphSetPtr; +struct GraphRegistry { + Map
map; + std::mutex mutex; +}; + static GraphRegistry &get_graph_registry() { static GraphRegistry graph_registry; @@ -22,28 +37,37 @@ static GraphRegistry &get_graph_registry() void register_graph(Depsgraph *depsgraph) { + GraphRegistry &graph_registry = get_graph_registry(); Main *bmain = depsgraph->bmain; - get_graph_registry().lookup_or_add_default(bmain).add_new(depsgraph); + + std::lock_guard lock{graph_registry.mutex}; + graph_registry.map + .lookup_or_add_cb(bmain, []() { return std::make_unique>(); }) + ->add_new(depsgraph); } void unregister_graph(Depsgraph *depsgraph) { Main *bmain = depsgraph->bmain; GraphRegistry &graph_registry = get_graph_registry(); - VectorSet &graphs = graph_registry.lookup(bmain); - graphs.remove(depsgraph); + + std::lock_guard lock{graph_registry.mutex}; + GraphSetPtr &graphs = graph_registry.map.lookup(bmain); + graphs->remove(depsgraph); /* If this was the last depsgraph associated with the main, remove the main entry as well. */ - if (graphs.is_empty()) { - graph_registry.remove(bmain); + if (graphs->is_empty()) { + graph_registry.map.remove(bmain); } } Span get_all_registered_graphs(Main *bmain) { - VectorSet *graphs = get_graph_registry().lookup_ptr(bmain); - if (graphs != nullptr) { - return *graphs; + GraphRegistry &graph_registry = get_graph_registry(); + std::lock_guard lock{graph_registry.mutex}; + GraphSetPtr *graphs = graph_registry.map.lookup_ptr(bmain); + if (graphs) { + return **graphs; } return {}; } diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 2df65bf15aa..21d9cf60870 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -71,7 +71,7 @@ void depsgraph_geometry_tag_to_component(const ID *id, NodeType *component_type) bool is_selectable_data_id_type(const ID_Type id_type) { - return ELEM(id_type, ID_ME, ID_CU_LEGACY, ID_MB, ID_LT, ID_GD, ID_CV, ID_PT, ID_VO); + return ELEM(id_type, ID_ME, ID_CU_LEGACY, ID_MB, ID_LT, ID_GD_LEGACY, ID_CV, ID_PT, ID_VO); } void depsgraph_select_tag_to_component_opcode(const ID *id, @@ -585,7 +585,7 @@ NodeType geometry_tag_to_component(const ID *id) case OB_FONT: case OB_LATTICE: case OB_MBALL: - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: case OB_CURVES: case OB_POINTCLOUD: case OB_VOLUME: @@ -609,7 +609,7 @@ NodeType geometry_tag_to_component(const ID *id) return NodeType::UNDEFINED; case ID_LP: return NodeType::PARAMETERS; - case ID_GD: + case ID_GD_LEGACY: return NodeType::GEOMETRY; case ID_PAL: /* Palettes */ return NodeType::PARAMETERS; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 4d2a9a7e850..a896e4eb245 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -26,8 +26,8 @@ #include "BKE_curve.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_update_cache.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_update_cache_legacy.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -41,7 +41,7 @@ #include "DNA_ID.h" #include "DNA_anim_types.h" #include "DNA_armature_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mesh_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -739,7 +739,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, } /* FIXME: This is a temporary fix to update the runtime pointers properly, see #96216. Should * be removed at some point. */ - case ID_GD: { + case ID_GD_LEGACY: { bGPdata *gpd_cow = (bGPdata *)id_cow; bGPDlayer *gpl = (bGPDlayer *)(gpd_cow->layers.first); if (gpl != nullptr && gpl->runtime.gpl_orig == nullptr) { @@ -892,8 +892,8 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph, const IDNode } /* In case we don't need to do a copy-on-write, we can use the update cache of the grease * pencil data to do an update-on-write. */ - if (id_type == ID_GD && BKE_gpencil_can_avoid_full_copy_on_write( - (const ::Depsgraph *)depsgraph, (bGPdata *)id_orig)) { + if (id_type == ID_GD_LEGACY && BKE_gpencil_can_avoid_full_copy_on_write( + (const ::Depsgraph *)depsgraph, (bGPdata *)id_orig)) { BKE_gpencil_update_on_write((bGPdata *)id_orig, (bGPdata *)id_cow); return id_cow; } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc index 9ccd7ed447b..79f764ddb12 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup.cc @@ -60,7 +60,7 @@ void RuntimeBackup::init_from_id(ID *id) case ID_VO: volume_backup.init_from_volume(reinterpret_cast(id)); break; - case ID_GD: + case ID_GD_LEGACY: gpencil_backup.init_from_gpencil(reinterpret_cast(id)); break; default: @@ -103,7 +103,7 @@ void RuntimeBackup::restore_to_id(ID *id) case ID_VO: volume_backup.restore_to_volume(reinterpret_cast(id)); break; - case ID_GD: + case ID_GD_LEGACY: gpencil_backup.restore_to_gpencil(reinterpret_cast(id)); break; default: diff --git a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.cc b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.cc index e3d7593eb3c..be37d8b7ebe 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_runtime_backup_gpencil.cc @@ -8,10 +8,10 @@ #include "intern/eval/deg_eval_runtime_backup_gpencil.h" #include "intern/depsgraph.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_update_cache.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_update_cache_legacy.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" namespace blender::deg { diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 5c4a07a6cb8..e1aad7d4280 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -144,6 +144,7 @@ set(SRC engines/eevee_next/eevee_film.cc engines/eevee_next/eevee_hizbuffer.cc engines/eevee_next/eevee_instance.cc + engines/eevee_next/eevee_irradiance_cache.cc engines/eevee_next/eevee_light.cc engines/eevee_next/eevee_material.cc engines/eevee_next/eevee_motion_blur.cc @@ -275,6 +276,7 @@ set(SRC engines/eevee_next/eevee_film.hh engines/eevee_next/eevee_hizbuffer.hh engines/eevee_next/eevee_instance.hh + engines/eevee_next/eevee_irradiance_cache.hh engines/eevee_next/eevee_light.hh engines/eevee_next/eevee_material.hh engines/eevee_next/eevee_motion_blur.hh @@ -425,6 +427,8 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_colorspace_lib.glsl engines/eevee_next/shaders/eevee_cryptomatte_lib.glsl engines/eevee_next/shaders/eevee_transparency_lib.glsl + engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl + engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl engines/eevee_next/shaders/eevee_depth_of_field_accumulator_lib.glsl engines/eevee_next/shaders/eevee_depth_of_field_bokeh_lut_comp.glsl engines/eevee_next/shaders/eevee_depth_of_field_downsample_comp.glsl @@ -467,6 +471,7 @@ set(GLSL_SRC engines/eevee_next/shaders/eevee_sampling_lib.glsl engines/eevee_next/shaders/eevee_shadow_debug_frag.glsl engines/eevee_next/shaders/eevee_shadow_lib.glsl + engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl engines/eevee_next/shaders/eevee_shadow_page_allocate_comp.glsl engines/eevee_next/shaders/eevee_shadow_page_clear_comp.glsl engines/eevee_next/shaders/eevee_shadow_page_defrag_comp.glsl @@ -822,7 +827,6 @@ if(WITH_GTESTS) tests/draw_pass_test.cc tests/draw_testing.cc tests/eevee_test.cc - tests/shaders_test.cc tests/draw_testing.hh ) diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index a4bd789438d..1d31c5fdeed 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -107,14 +107,14 @@ void EEVEE_lookdev_init(EEVEE_Data *vedata) /* Make the viewport width scale the lookdev spheres a bit. * Scale between 1000px and 2000px. */ const float viewport_scale = clamp_f( - BLI_rcti_size_x(rect) / (2000.0f * U.dpi_fac), 0.5f, 1.0f); - const int sphere_size = U.lookdev_sphere_size * U.dpi_fac * viewport_scale; + BLI_rcti_size_x(rect) / (2000.0f * UI_SCALE_FAC), 0.5f, 1.0f); + const int sphere_size = U.lookdev_sphere_size * UI_SCALE_FAC * viewport_scale; if (sphere_size != effects->sphere_size || rect->xmax != effects->anchor[0] || rect->ymin != effects->anchor[1]) { /* Make sphere resolution adaptive to viewport_scale, DPI and #U.lookdev_sphere_size. */ float res_scale = clamp_f( - (U.lookdev_sphere_size / 400.0f) * viewport_scale * U.dpi_fac, 0.1f, 1.0f); + (U.lookdev_sphere_size / 400.0f) * viewport_scale * UI_SCALE_FAC, 0.1f, 1.0f); if (res_scale > 0.7f) { effects->sphere_lod = DRW_LOD_HIGH; diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 6f47007c3c5..1be0901085e 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -607,7 +607,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl GPU_framebuffer_bind(fbl->main_fb); GPU_framebuffer_clear_color_depth_stencil(fbl->main_fb, clear_col, clear_depth, clear_stencil); - /* Depth prepass */ + /* Depth pre-pass. */ DRW_draw_pass(psl->depth_ps); /* Create minmax texture */ EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); diff --git a/source/blender/draw/engines/eevee/shaders/infos/eevee_legacy_effects_info.hh b/source/blender/draw/engines/eevee/shaders/infos/eevee_legacy_effects_info.hh index 3c9169e34c5..6e4ea28b814 100644 --- a/source/blender/draw/engines/eevee/shaders/infos/eevee_legacy_effects_info.hh +++ b/source/blender/draw/engines/eevee/shaders/infos/eevee_legacy_effects_info.hh @@ -227,7 +227,7 @@ GPU_SHADER_CREATE_INFO(eevee_legacy_effect_reflection_resolve) .auto_resource_location(true) .do_static_compilation(true); -/* Split reflection resolve support for Intel-based MacBooks.*/ +/* Split reflection resolve support for Intel-based MacBooks. */ GPU_SHADER_CREATE_INFO(eevee_legacy_effect_reflection_resolve_probe) .define("RESOLVE_PROBE") .additional_info("eevee_legacy_effect_reflection_resolve") diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index 5ee020358b5..6bd9d222420 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -101,6 +101,7 @@ SSR_INTERFACE # if defined(USE_BARYCENTRICS) && !defined(HAIR_SHADER) vec3 barycentric_distances_get() { +# if defined(GPU_OPENGL) /* NOTE: No need to undo perspective divide since it is not applied yet. */ vec3 pos0 = (ProjectionMatrixInverse * gpu_position_at_vertex(0)).xyz; vec3 pos1 = (ProjectionMatrixInverse * gpu_position_at_vertex(1)).xyz; @@ -119,6 +120,17 @@ vec3 barycentric_distances_get() d = dot(d10, edge21); dists.z = sqrt(dot(edge21, edge21) - d * d); return dists.xyz; +# elif defined(GPU_METAL) + /* Calculate Barycentric distances from available parameters in Metal. */ + float3 wp_delta = (length(dfdx(worldPosition.xyz)) + length(dfdy(worldPosition.xyz))); + float3 bc_delta = (length(dfdx(gpu_BaryCoord)) + length(dfdy(gpu_BaryCoord))); + float3 rate_of_change = wp_delta / bc_delta; + vec3 dists; + dists.x = length(rate_of_change * (1.0 - gpu_BaryCoord.x)); + dists.y = length(rate_of_change * (1.0 - gpu_BaryCoord.y)); + dists.z = length(rate_of_change * (1.0 - gpu_BaryCoord.z)); + return dists.xyz; +# endif } # endif diff --git a/source/blender/draw/engines/eevee_next/eevee_defines.hh b/source/blender/draw/engines/eevee_next/eevee_defines.hh index 72470ab7060..bc778dc874d 100644 --- a/source/blender/draw/engines/eevee_next/eevee_defines.hh +++ b/source/blender/draw/engines/eevee_next/eevee_defines.hh @@ -54,6 +54,7 @@ #define SHADOW_PAGE_PER_ROW 64 #define SHADOW_ATLAS_SLOT 5 #define SHADOW_BOUNDS_GROUP_SIZE 64 +#define SHADOW_CLIPMAP_GROUP_SIZE 64 #define SHADOW_VIEW_MAX 64 /* Must match DRW_VIEW_MAX. */ /* Ray-tracing. */ diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.cc b/source/blender/draw/engines/eevee_next/eevee_instance.cc index f57e15bd422..491190334e1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.cc +++ b/source/blender/draw/engines/eevee_next/eevee_instance.cc @@ -70,6 +70,7 @@ void Instance::init(const int2 &output_res, shadows.init(); motion_blur.init(); main_view.init(); + irradiance_cache.init(); } void Instance::set_time(float time) @@ -117,6 +118,7 @@ void Instance::begin_sync() main_view.sync(); world.sync(); film.sync(); + irradiance_cache.sync(); } void Instance::scene_sync() @@ -136,7 +138,7 @@ void Instance::scene_sync() void Instance::object_sync(Object *ob) { - const bool is_renderable_type = ELEM(ob->type, OB_CURVES, OB_GPENCIL, OB_MESH, OB_LAMP); + const bool is_renderable_type = ELEM(ob->type, OB_CURVES, OB_GPENCIL_LEGACY, OB_MESH, OB_LAMP); const int ob_visibility = DRW_object_visibility_in_active_context(ob); const bool partsys_is_visible = (ob_visibility & OB_VISIBLE_PARTICLES) != 0 && (ob->type == OB_MESH); @@ -174,7 +176,7 @@ void Instance::object_sync(Object *ob) case OB_CURVES: sync.sync_curves(ob, ob_handle, res_handle); break; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: sync.sync_gpencil(ob, ob_handle, res_handle); break; default: diff --git a/source/blender/draw/engines/eevee_next/eevee_instance.hh b/source/blender/draw/engines/eevee_next/eevee_instance.hh index ba17289604c..6bb54a37a2c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_instance.hh +++ b/source/blender/draw/engines/eevee_next/eevee_instance.hh @@ -20,6 +20,7 @@ #include "eevee_depth_of_field.hh" #include "eevee_film.hh" #include "eevee_hizbuffer.hh" +#include "eevee_irradiance_cache.hh" #include "eevee_light.hh" #include "eevee_material.hh" #include "eevee_motion_blur.hh" @@ -60,6 +61,7 @@ class Instance { RenderBuffers render_buffers; MainView main_view; World world; + IrradianceCache irradiance_cache; /** Input data. */ Depsgraph *depsgraph; @@ -103,7 +105,8 @@ class Instance { film(*this), render_buffers(*this), main_view(*this), - world(*this){}; + world(*this), + irradiance_cache(*this){}; ~Instance(){}; void init(const int2 &output_res, diff --git a/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.cc b/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.cc new file mode 100644 index 00000000000..890ef35c3b5 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.cc @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "BLI_rand.hh" +#include "eevee_instance.hh" + +#include "eevee_irradiance_cache.hh" + +namespace blender::eevee { + +void IrradianceCache::generate_random_surfels() +{ + const int surfels_len = 256; + debug_surfels.resize(surfels_len); + + RandomNumberGenerator rng; + rng.seed(0); + + for (DebugSurfel &surfel : debug_surfels) { + float3 random = rng.get_unit_float3(); + surfel.position = random * 3.0f; + surfel.normal = random; + surfel.color = float4(rng.get_float(), rng.get_float(), rng.get_float(), 1.0f); + } + + debug_surfels.push_update(); +} + +void IrradianceCache::init() +{ + if (debug_surfels_sh_ == nullptr) { + debug_surfels_sh_ = inst_.shaders.static_shader_get(DEBUG_SURFELS); + } + + /* TODO: Remove this. */ + generate_random_surfels(); +} + +void IrradianceCache::sync() +{ + debug_pass_sync(); +} + +void IrradianceCache::debug_pass_sync() +{ + if (inst_.debug_mode == eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS) { + debug_surfels_ps_.init(); + debug_surfels_ps_.state_set(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | + DRW_STATE_DEPTH_LESS_EQUAL); + debug_surfels_ps_.shader_set(debug_surfels_sh_); + debug_surfels_ps_.bind_ssbo("surfels_buf", debug_surfels); + debug_surfels_ps_.push_constant("surfel_radius", 0.25f); + debug_surfels_ps_.draw_procedural(GPU_PRIM_TRI_STRIP, debug_surfels.size(), 4); + } +} + +void IrradianceCache::debug_draw(View &view, GPUFrameBuffer *view_fb) +{ + if (inst_.debug_mode == eDebugMode::DEBUG_IRRADIANCE_CACHE_SURFELS) { + inst_.info = "Debug Mode: Irradiance Cache Surfels"; + GPU_framebuffer_bind(view_fb); + inst_.manager->submit(debug_surfels_ps_, view); + } +} + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.hh b/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.hh new file mode 100644 index 00000000000..bc5be19332f --- /dev/null +++ b/source/blender/draw/engines/eevee_next/eevee_irradiance_cache.hh @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include "eevee_shader_shared.hh" + +namespace blender::eevee { + +class Instance; + +class IrradianceCache { + private: + Instance &inst_; + + DebugSurfelBuf debug_surfels; + PassSimple debug_surfels_ps_ = {"IrradianceCache.Debug"}; + GPUShader *debug_surfels_sh_ = nullptr; + + /* TODO: Remove this. */ + void generate_random_surfels(); + + public: + IrradianceCache(Instance &inst) : inst_(inst){}; + ~IrradianceCache(){}; + + void init(); + void sync(); + + void debug_pass_sync(); + void debug_draw(View &view, GPUFrameBuffer *view_fb); +}; + +} // namespace blender::eevee diff --git a/source/blender/draw/engines/eevee_next/eevee_material.hh b/source/blender/draw/engines/eevee_next/eevee_material.hh index c85ff5f8665..0546c2e06bb 100644 --- a/source/blender/draw/engines/eevee_next/eevee_material.hh +++ b/source/blender/draw/engines/eevee_next/eevee_material.hh @@ -99,7 +99,7 @@ static inline eMaterialGeometry to_material_geometry(const Object *ob) return MAT_GEOM_CURVES; case OB_VOLUME: return MAT_GEOM_VOLUME; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return MAT_GEOM_GPENCIL; default: return MAT_GEOM_MESH; diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.cc b/source/blender/draw/engines/eevee_next/eevee_shader.cc index 0207a2574b2..4d9ac75687c 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shader.cc @@ -98,6 +98,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_motion_blur_tiles_flatten_render"; case MOTION_BLUR_TILE_FLATTEN_VIEWPORT: return "eevee_motion_blur_tiles_flatten_viewport"; + case DEBUG_SURFELS: + return "eevee_debug_surfels"; case DOF_BOKEH_LUT: return "eevee_depth_of_field_bokeh_lut"; case DOF_DOWNSAMPLE: @@ -142,6 +144,8 @@ const char *ShaderModule::static_shader_create_info_name_get(eShaderType shader_ return "eevee_light_culling_tile"; case LIGHT_CULLING_ZBIN: return "eevee_light_culling_zbin"; + case SHADOW_CLIPMAP_CLEAR: + return "eevee_shadow_clipmap_clear"; case SHADOW_DEBUG: return "eevee_shadow_debug"; case SHADOW_PAGE_ALLOCATE: diff --git a/source/blender/draw/engines/eevee_next/eevee_shader.hh b/source/blender/draw/engines/eevee_next/eevee_shader.hh index df689bb2717..173dc7bfa86 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader.hh @@ -30,6 +30,8 @@ enum eShaderType { FILM_COMP, FILM_CRYPTOMATTE_POST, + DEBUG_SURFELS, + DOF_BOKEH_LUT, DOF_DOWNSAMPLE, DOF_FILTER, @@ -62,6 +64,7 @@ enum eShaderType { MOTION_BLUR_TILE_FLATTEN_RENDER, MOTION_BLUR_TILE_FLATTEN_VIEWPORT, + SHADOW_CLIPMAP_CLEAR, SHADOW_DEBUG, SHADOW_PAGE_ALLOCATE, SHADOW_PAGE_CLEAR, diff --git a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh index fb8b355c38f..3b4345c3a2b 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shader_shared.hh @@ -48,6 +48,10 @@ enum eDebugMode : uint32_t { * Show incorrectly downsample tiles in red. */ DEBUG_HIZ_VALIDATION = 2u, + /** + * Display IrradianceCache surfels. + */ + DEBUG_IRRADIANCE_CACHE_SURFELS = 3u, /** * Show tiles depending on their status. */ @@ -821,6 +825,21 @@ static inline ShadowTileDataPacked shadow_tile_pack(ShadowTileData tile) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Debug + * \{ */ + +struct DebugSurfel { + packed_float3 position; + int _pad0; + packed_float3 normal; + int _pad1; + float4 color; +}; +BLI_STATIC_ASSERT_ALIGN(DebugSurfel, 16) + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Hierarchical-Z Buffer * \{ */ @@ -928,6 +947,7 @@ using DepthOfFieldDataBuf = draw::UniformBuffer; using DepthOfFieldScatterListBuf = draw::StorageArrayBuffer; using DrawIndirectBuf = draw::StorageBuffer; using FilmDataBuf = draw::UniformBuffer; +using DebugSurfelBuf = draw::StorageArrayBuffer; using HiZDataBuf = draw::UniformBuffer; using LightCullingDataBuf = draw::StorageBuffer; using LightCullingKeyBuf = draw::StorageArrayBuffer; diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.cc b/source/blender/draw/engines/eevee_next/eevee_shadow.cc index 5b5eec04d9a..81e84d12961 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.cc +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.cc @@ -722,7 +722,7 @@ void ShadowModule::begin_sync() PassMain::Sub &sub = pass.sub("Transparent"); /* WORKAROUND: The DRW_STATE_WRITE_STENCIL is here only to avoid enabling the rasterizer * discard inside draw manager. */ - sub.state_set(DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_WRITE_STENCIL); + sub.state_set(DRW_STATE_CULL_FRONT | DRW_STATE_WRITE_STENCIL); sub.state_stencil(0, 0, 0); sub.framebuffer_set(&usage_tag_fb); sub.shader_set(inst_.shaders.static_shader_get(SHADOW_TILEMAP_TAG_USAGE_TRANSPARENT)); @@ -730,6 +730,10 @@ void ShadowModule::begin_sync() sub.bind_ssbo("tiles_buf", &tilemap_pool.tiles_data); sub.bind_ssbo("bounds_buf", &manager.bounds_buf.current()); sub.push_constant("tilemap_projection_ratio", &tilemap_projection_ratio_); + sub.push_constant("pixel_world_radius", &pixel_world_radius_); + sub.push_constant("fb_resolution", &usage_tag_fb_resolution_); + sub.push_constant("fb_lod", &usage_tag_fb_lod_); + inst_.hiz_buffer.bind_resources(&sub); inst_.lights.bind_resources(&sub); box_batch_ = DRW_cache_cube_get(); @@ -831,20 +835,8 @@ void ShadowModule::end_sync() /* Clear tiles to not reference any page. */ tilemap_pool.tiles_data.clear_to_zero(); - /* Clear tile-map clip buffer. */ - union { - ShadowTileMapClip clip; - int4 i; - } u; - u.clip.clip_near_stored = 0.0f; - u.clip.clip_far_stored = 0.0f; - u.clip.clip_near = int(0xFF7FFFFFu ^ 0x7FFFFFFFu); /* floatBitsToOrderedInt(-FLT_MAX) */ - u.clip.clip_far = 0x7F7FFFFF; /* floatBitsToOrderedInt(FLT_MAX) */ - GPU_storagebuf_clear(tilemap_pool.tilemaps_clip, GPU_RGBA32I, GPU_DATA_INT, &u.i); - /* Clear cached page buffer. */ - int2 data = {-1, -1}; - GPU_storagebuf_clear(pages_cached_data_, GPU_RG32I, GPU_DATA_INT, &data); + GPU_storagebuf_clear(pages_cached_data_, -1); /* Reset info to match new state. */ pages_infos_data_.page_free_count = shadow_page_len_; @@ -863,6 +855,17 @@ void ShadowModule::end_sync() PassSimple &pass = tilemap_setup_ps_; pass.init(); + { + /** Clear tile-map clip buffer. */ + PassSimple::Sub &sub = pass.sub("ClearClipmap"); + sub.shader_set(inst_.shaders.static_shader_get(SHADOW_CLIPMAP_CLEAR)); + sub.bind_ssbo("tilemaps_clip_buf", tilemap_pool.tilemaps_clip); + sub.push_constant("tilemaps_clip_buf_len", int(tilemap_pool.tilemaps_clip.size())); + sub.dispatch(int3( + divide_ceil_u(tilemap_pool.tilemaps_clip.size(), SHADOW_CLIPMAP_GROUP_SIZE), 1, 1)); + sub.barrier(GPU_BARRIER_SHADER_STORAGE); + } + { /** Compute near/far clip distances for directional shadows based on casters bounds. */ PassSimple::Sub &sub = pass.sub("DirectionalBounds"); @@ -1092,12 +1095,17 @@ void ShadowModule::set_view(View &view) int3 target_size = inst_.render_buffers.depth_tx.size(); dispatch_depth_scan_size_ = math::divide_ceil(target_size, int3(SHADOW_DEPTH_SCAN_GROUP_SIZE)); - tilemap_projection_ratio_ = tilemap_pixel_radius() / - screen_pixel_radius(view, int2(target_size)); + pixel_world_radius_ = screen_pixel_radius(view, int2(target_size)); + tilemap_projection_ratio_ = tilemap_pixel_radius() / pixel_world_radius_; + + usage_tag_fb_resolution_ = math::divide_ceil(int2(target_size), + int2(std::exp2(usage_tag_fb_lod_))); + usage_tag_fb.ensure(usage_tag_fb_resolution_); - usage_tag_fb.ensure(int2(target_size)); render_fb_.ensure(int2(SHADOW_TILEMAP_RES * shadow_page_size_)); + inst_.hiz_buffer.update(); + bool tile_update_remains = true; while (tile_update_remains) { DRW_stats_group_start("Shadow"); diff --git a/source/blender/draw/engines/eevee_next/eevee_shadow.hh b/source/blender/draw/engines/eevee_next/eevee_shadow.hh index 01501ad4627..c343a8502e5 100644 --- a/source/blender/draw/engines/eevee_next/eevee_shadow.hh +++ b/source/blender/draw/engines/eevee_next/eevee_shadow.hh @@ -216,6 +216,9 @@ class ShadowModule { int3 dispatch_depth_scan_size_; /* Ratio between tile-map pixel world "radius" and film pixel world "radius". */ float tilemap_projection_ratio_; + float pixel_world_radius_; + int2 usage_tag_fb_resolution_; + int usage_tag_fb_lod_ = 5; /* Statistics that are read back to CPU after a few frame (to avoid stall). */ SwapChain statistics_buf_; diff --git a/source/blender/draw/engines/eevee_next/eevee_sync.cc b/source/blender/draw/engines/eevee_next/eevee_sync.cc index fa09edce8d4..b340280cdfc 100644 --- a/source/blender/draw/engines/eevee_next/eevee_sync.cc +++ b/source/blender/draw/engines/eevee_next/eevee_sync.cc @@ -10,11 +10,11 @@ #include "eevee_engine.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_object.h" #include "DEG_depsgraph_query.h" #include "DNA_curves_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_modifier_types.h" #include "DNA_particle_types.h" diff --git a/source/blender/draw/engines/eevee_next/eevee_view.cc b/source/blender/draw/engines/eevee_next/eevee_view.cc index d7cb4985a9b..8037af78db1 100644 --- a/source/blender/draw/engines/eevee_next/eevee_view.cc +++ b/source/blender/draw/engines/eevee_next/eevee_view.cc @@ -136,6 +136,8 @@ void ShadingView::render() inst_.hiz_buffer.debug_draw(render_view_new_, combined_fb_); inst_.shadows.debug_draw(render_view_new_, combined_fb_); + inst_.irradiance_cache.debug_draw(render_view_new_, combined_fb_); + GPUTexture *combined_final_tx = render_postfx(rbufs.combined_tx); inst_.film.accumulate(sub_view_, combined_final_tx); diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl new file mode 100644 index 00000000000..ed6bfc8f87f --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_debug_surfels_frag.glsl @@ -0,0 +1,21 @@ + +void main() +{ + DebugSurfel surfel = surfels_buf[surfel_index]; + out_color = surfel.color; + + /* Display surfels as circles. */ + if (distance(P, surfel.position) > surfel_radius) { + discard; + return; + } + + /* Display backfacing surfels with a transparent checkerboard grid. */ + if (!gl_FrontFacing) { + ivec2 grid_uv = ivec2(gl_FragCoord) / 5; + if ((grid_uv.x + grid_uv.y) % 2 == 0) { + discard; + return; + } + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl new file mode 100644 index 00000000000..fc08f418827 --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_debug_surfels_vert.glsl @@ -0,0 +1,38 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl) + +void main() +{ + surfel_index = gl_InstanceID; + DebugSurfel surfel = surfels_buf[surfel_index]; + + vec3 lP; + + switch (gl_VertexID) { + case 0: + lP = vec3(-1, 1, 0); + break; + case 1: + lP = vec3(-1, -1, 0); + break; + case 2: + lP = vec3(1, 1, 0); + break; + case 3: + lP = vec3(1, -1, 0); + break; + } + + vec3 N = surfel.normal; + vec3 T, B; + make_orthonormal_basis(N, T, B); + + mat4 model_matrix = mat4(vec4(T * surfel_radius, 0), + vec4(B * surfel_radius, 0), + vec4(N * surfel_radius, 0), + vec4(surfel.position, 1)); + + P = (model_matrix * vec4(lP, 1)).xyz; + + gl_Position = point_world_to_ndc(P); +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl new file mode 100644 index 00000000000..bd5560accec --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_clipmap_clear_comp.glsl @@ -0,0 +1,13 @@ + +#pragma BLENDER_REQUIRE(gpu_shader_utildefines_lib.glsl) + +void main() +{ + int index = int(gl_GlobalInvocationID.x); + if (index < tilemaps_clip_buf_len) { + tilemaps_clip_buf[index].clip_near_stored = 0; + tilemaps_clip_buf[index].clip_far_stored = 0; + tilemaps_clip_buf[index].clip_near = floatBitsToOrderedInt(-FLT_MAX); + tilemaps_clip_buf[index].clip_far = floatBitsToOrderedInt(FLT_MAX); + } +} diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl index 23f78106ac2..dd946ffb637 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_frag.glsl @@ -3,13 +3,120 @@ * Virtual shadowmapping: Usage tagging * * Shadow pages are only allocated if they are visible. - * This pass scan the depth buffer and tag all tiles that are needed for light shadowing as - * needed. + * This ray-marches the current fragment along the bounds depth and tags all the intersected shadow + * tiles. */ #pragma BLENDER_REQUIRE(eevee_shadow_tag_usage_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + +#pragma BLENDER_REQUIRE(common_debug_shape_lib.glsl) + +float ray_aabb(vec3 ray_origin, vec3 ray_direction, vec3 aabb_min, vec3 aabb_max) +{ + /* https://gdbooks.gitbooks.io/3dcollisions/content/Chapter3/raycast_aabb.html */ + vec3 t_mins = (aabb_min - ray_origin) / ray_direction; + vec3 t_maxs = (aabb_max - ray_origin) / ray_direction; + + float t_min = max_v3(min(t_mins, t_maxs)); + float t_max = min_v3(max(t_mins, t_maxs)); + + /* AABB is in the opposite direction. */ + if (t_max < 0.0) { + return -1.0; + } + /* No intersection. */ + if (t_min > t_max) { + return -1.0; + } + /* The ray origin is inside the aabb. */ + if (t_min < 0.0) { + /* For regular ray casting we would return t_max here, + * but we want to ray cast against the box volume, not just the surface. */ + return 0.0; + } + return t_min; +} + +float pixel_size_at(float linear_depth) +{ + float pixel_size = pixel_world_radius; + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + if (is_persp) { + pixel_size *= max(0.01, linear_depth); + } + return pixel_size * exp2(fb_lod); +} + +void step_bounding_sphere(vec3 vs_near_plane, + vec3 vs_view_direction, + float near_t, + float far_t, + out vec3 sphere_center, + out float sphere_radius) +{ + float near_pixel_size = pixel_size_at(near_t); + vec3 near_center = vs_near_plane + vs_view_direction * near_t; + + float far_pixel_size = pixel_size_at(far_t); + vec3 far_center = vs_near_plane + vs_view_direction * far_t; + + sphere_center = mix(near_center, far_center, 0.5); + sphere_radius = 0; + + for (int x = -1; x <= 1; x += 2) { + for (int y = -1; y <= 1; y += 2) { + vec3 near_corner = near_center + (near_pixel_size * 0.5 * vec3(x, y, 0)); + sphere_radius = max(sphere_radius, len_squared(near_corner - sphere_center)); + + vec3 far_corner = far_center + (far_pixel_size * 0.5 * vec3(x, y, 0)); + sphere_radius = max(sphere_radius, len_squared(far_corner - sphere_center)); + } + } + + sphere_center = point_view_to_world(sphere_center); + sphere_radius = sqrt(sphere_radius); +} void main() { - shadow_tag_usage(interp.vP, interp.P, gl_FragCoord.xy); + vec2 screen_uv = gl_FragCoord.xy / vec2(fb_resolution); + + float opaque_depth = texelFetch(hiz_tx, int2(gl_FragCoord.xy), fb_lod).r; + vec3 ws_opaque = get_world_space_from_depth(screen_uv, opaque_depth); + + vec3 ws_near_plane = get_world_space_from_depth(screen_uv, 0); + vec3 ws_view_direction = normalize(interp.P - ws_near_plane); + vec3 vs_near_plane = get_view_space_from_depth(screen_uv, 0); + vec3 vs_view_direction = normalize(interp.vP - vs_near_plane); + vec3 ls_near_plane = point_world_to_object(ws_near_plane); + vec3 ls_view_direction = normalize(point_world_to_object(interp.P) - ls_near_plane); + + /* TODO (Miguel Pozo): We could try to ray-cast against the non-inflated bounds first, + * and fallback to the inflated ones if theres no hit. + * The inflated bounds can cause unnecesary extra steps. */ + float ls_near_box_t = ray_aabb( + ls_near_plane, ls_view_direction, interp.ls_aabb_min, interp.ls_aabb_max); + vec3 ls_near_box = ls_near_plane + ls_view_direction * ls_near_box_t; + vec3 ws_near_box = point_object_to_world(ls_near_box); + + float near_box_t = distance(ws_near_plane, ws_near_box); + float far_box_t = distance(ws_near_plane, interp.P); + /* Depth test. */ + far_box_t = min(far_box_t, distance(ws_near_plane, ws_opaque)); + + /* Ray march from the front to the back of the bbox, and tag shadow usage along the way. */ + float step_size; + for (float t = near_box_t; t <= far_box_t; t += step_size) { + /* Ensure we don't get past far_box_t. */ + t = min(t, far_box_t); + step_size = pixel_size_at(t); + + vec3 P = ws_near_plane + (ws_view_direction * t); + float step_radius; + step_bounding_sphere(vs_near_plane, vs_view_direction, t, t + step_size, P, step_radius); + vec3 vP = point_world_to_view(P); + + shadow_tag_usage(vP, P, ws_view_direction, step_radius, t, gl_FragCoord.xy * exp2(fb_lod)); + } } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl index 1372153f177..bb18f56ec74 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_lib.glsl @@ -3,8 +3,7 @@ * Virtual shadowmapping: Usage tagging * * Shadow pages are only allocated if they are visible. - * This pass scan the depth buffer and tag all tiles that are needed for light shadowing as - * needed. + * This contains the common logic used for tagging shadows for opaque and transparent receivers. */ #pragma BLENDER_REQUIRE(common_intersect_lib.glsl) @@ -14,7 +13,18 @@ #pragma BLENDER_REQUIRE(eevee_light_lib.glsl) #pragma BLENDER_REQUIRE(eevee_shadow_lib.glsl) -void shadow_tag_usage_tilemap(uint l_idx, vec3 P, float dist_to_cam, const bool is_directional) +void shadow_tag_usage_tile(LightData light, ivec2 tile_co, int lod, int tilemap_index) +{ + if (tilemap_index > light_tilemap_max_get(light)) { + return; + } + + tile_co >>= lod; + int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod); + atomicOr(tiles_buf[tile_index], SHADOW_IS_USED); +} + +void shadow_tag_usage_tilemap_directional(uint l_idx, vec3 P, vec3 V, float radius) { LightData light = light_buf[l_idx]; @@ -22,83 +32,141 @@ void shadow_tag_usage_tilemap(uint l_idx, vec3 P, float dist_to_cam, const bool return; } - int lod = 0; - ivec2 tile_co; - int tilemap_index = light.tilemap_index; - if (is_directional) { - vec3 lP = shadow_world_to_local(light, P); + vec3 lP = shadow_world_to_local(light, P); + if (radius == 0) { ShadowCoordinates coord = shadow_directional_coordinates(light, lP); - - tile_co = coord.tile_coord; - tilemap_index = coord.tilemap_index; + shadow_tag_usage_tile(light, coord.tile_coord, 0, coord.tilemap_index); } else { - vec3 lP = light_world_to_local(light, P - light._position); - float dist_to_light = length(lP); - if (dist_to_light > light.influence_radius_max) { - return; - } - if (light.type == LIGHT_SPOT) { - /* Early out if out of cone. */ - float angle_tan = length(lP.xy / dist_to_light); - if (angle_tan > light.spot_tan) { - return; + vec3 start_lP = shadow_world_to_local(light, P - V * radius); + vec3 end_lP = shadow_world_to_local(light, P + V * radius); + int min_level = shadow_directional_level(light, start_lP - light._position); + int max_level = shadow_directional_level(light, end_lP - light._position); + + for (int level = min_level; level <= max_level; level++) { + ShadowCoordinates coord_min = shadow_directional_coordinates_at_level( + light, lP - vec3(radius, radius, 0), level); + ShadowCoordinates coord_max = shadow_directional_coordinates_at_level( + light, lP + vec3(radius, radius, 0), level); + + for (int x = coord_min.tile_coord.x; x <= coord_max.tile_coord.x; x++) { + for (int y = coord_min.tile_coord.y; y <= coord_max.tile_coord.y; y++) { + shadow_tag_usage_tile(light, ivec2(x, y), 0, coord_min.tilemap_index); + } } } - else if (is_area_light(light.type)) { - /* Early out if on the wrong side. */ - if (lP.z > 0.0) { - return; - } - } - - /* How much a shadow map pixel covers a final image pixel. - * We project a shadow map pixel (as a sphere for simplicity) to the receiver plane. - * We then reproject this sphere onto the camera screen and compare it to the film pixel size. - * This gives a good approximation of what LOD to select to get a somewhat uniform shadow map - * resolution in screen space. */ - float footprint_ratio = dist_to_light; - /* Project the radius to the screen. 1 unit away from the camera the same way - * pixel_world_radius_inv was computed. Not needed in orthographic mode. */ - bool is_persp = (ProjectionMatrix[3][3] == 0.0); - if (is_persp) { - footprint_ratio /= dist_to_cam; - } - /* Apply resolution ratio. */ - footprint_ratio *= tilemap_projection_ratio; - - int face_id = shadow_punctual_face_index_get(lP); - lP = shadow_punctual_local_position_to_face_local(face_id, lP); - - ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id); - tile_co = coord.tile_coord; - tilemap_index = coord.tilemap_index; - - lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[tilemap_index].lod_bias)); - lod = clamp(lod, 0, SHADOW_TILEMAP_LOD); } - tile_co >>= lod; +} - if (tilemap_index > light_tilemap_max_get(light)) { +void shadow_tag_usage_tilemap_punctual(uint l_idx, vec3 P, vec3 V, float dist_to_cam, float radius) +{ + LightData light = light_buf[l_idx]; + + if (light.tilemap_index == LIGHT_NO_SHADOW) { return; } - int tile_index = shadow_tile_offset(tile_co, tilemaps_buf[tilemap_index].tiles_index, lod); - atomicOr(tiles_buf[tile_index], SHADOW_IS_USED); + vec3 lP = light_world_to_local(light, P - light._position); + float dist_to_light = length(lP) - radius; + if (dist_to_light > light.influence_radius_max) { + return; + } + if (light.type == LIGHT_SPOT) { + /* Early out if out of cone. */ + float angle_tan = length(lP.xy / dist_to_light); + if (angle_tan > light.spot_tan) { + return; + } + } + else if (is_area_light(light.type)) { + /* Early out if on the wrong side. */ + if (lP.z - radius > 0.0) { + return; + } + } + + /* How much a shadow map pixel covers a final image pixel. + * We project a shadow map pixel (as a sphere for simplicity) to the receiver plane. + * We then reproject this sphere onto the camera screen and compare it to the film pixel size. + * This gives a good approximation of what LOD to select to get a somewhat uniform shadow map + * resolution in screen space. */ + float footprint_ratio = dist_to_light; + /* Project the radius to the screen. 1 unit away from the camera the same way + * pixel_world_radius_inv was computed. Not needed in orthographic mode. */ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + if (is_persp) { + footprint_ratio /= dist_to_cam; + } + /* Apply resolution ratio. */ + footprint_ratio *= tilemap_projection_ratio; + + if (radius == 0) { + int face_id = shadow_punctual_face_index_get(lP); + lP = shadow_punctual_local_position_to_face_local(face_id, lP); + ShadowCoordinates coord = shadow_punctual_coordinates(light, lP, face_id); + + int lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[coord.tilemap_index].lod_bias)); + lod = clamp(lod, 0, SHADOW_TILEMAP_LOD); + + shadow_tag_usage_tile(light, coord.tile_coord, lod, coord.tilemap_index); + } + else { + uint faces = 0u; + for (int x = -1; x <= 1; x += 2) { + for (int y = -1; y <= 1; y += 2) { + for (int z = -1; z <= 1; z += 2) { + vec3 _lP = lP + vec3(x, y, z) * radius; + faces |= 1u << shadow_punctual_face_index_get(_lP); + } + } + } + + for (int face_id = 0; face_id < 6; face_id++) { + if ((faces & (1u << uint(face_id))) == 0u) { + continue; + } + + int tilemap_index = light.tilemap_index + face_id; + int lod = int(ceil(-log2(footprint_ratio) + tilemaps_buf[tilemap_index].lod_bias)); + lod = clamp(lod, 0, SHADOW_TILEMAP_LOD); + + vec3 _lP = shadow_punctual_local_position_to_face_local(face_id, lP); + + vec3 offset = vec3(radius, radius, 0); + ShadowCoordinates coord_min = shadow_punctual_coordinates(light, _lP - offset, face_id); + ShadowCoordinates coord_max = shadow_punctual_coordinates(light, _lP + offset, face_id); + + for (int x = coord_min.tile_coord.x; x <= coord_max.tile_coord.x; x++) { + for (int y = coord_min.tile_coord.y; y <= coord_max.tile_coord.y; y++) { + shadow_tag_usage_tile(light, ivec2(x, y), lod, tilemap_index); + } + } + } + } +} + +/** + * \a radius Radius of the tagging area in world space. + * Used for downsampled/ray-marched tagging, so all the shadowmap texels covered get correctly + * tagged. + */ +void shadow_tag_usage(vec3 vP, vec3 P, vec3 V, float radius, float dist_to_cam, vec2 pixel) +{ + LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) { + shadow_tag_usage_tilemap_directional(l_idx, P, V, radius); + } + LIGHT_FOREACH_END + + LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) { + shadow_tag_usage_tilemap_punctual(l_idx, P, V, dist_to_cam, radius); + } + LIGHT_FOREACH_END } void shadow_tag_usage(vec3 vP, vec3 P, vec2 pixel) { float dist_to_cam = length(vP); - LIGHT_FOREACH_BEGIN_DIRECTIONAL (light_cull_buf, l_idx) { - shadow_tag_usage_tilemap(l_idx, P, dist_to_cam, true); - } - LIGHT_FOREACH_END - - LIGHT_FOREACH_BEGIN_LOCAL (light_cull_buf, light_zbin_buf, light_tile_buf, pixel, vP.z, l_idx) { - shadow_tag_usage_tilemap(l_idx, P, dist_to_cam, false); - } - LIGHT_FOREACH_END + shadow_tag_usage(vP, P, vec3(0), 0, dist_to_cam, pixel); } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl index fcca152ef82..f03f3ac1332 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tag_usage_vert.glsl @@ -3,20 +3,89 @@ * Virtual shadowmapping: Usage tagging * * Shadow pages are only allocated if they are visible. - * This renders bounding boxes for transparent objects in order to tag the correct shadows. + * This renders the bounding boxes for transparent objects in order to tag the correct shadows. */ #pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(common_shape_lib.glsl) + +#pragma BLENDER_REQUIRE(common_debug_shape_lib.glsl) + +/* Inflate bounds by half a pixel as a conservative rasterization alternative, + * to ensure the tiles needed by all LOD0 pixels get tagged */ +void inflate_bounds(vec3 ls_center, inout vec3 P, inout vec3 lP) +{ + vec3 vP = point_world_to_view(P); + + float inflate_scale = pixel_world_radius * exp2(fb_lod); + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + if (is_persp) { + inflate_scale *= -vP.z; + } + /* Half-pixel. */ + inflate_scale *= 0.5; + + vec3 vs_inflate_vector = normal_object_to_view(sign(lP - ls_center)); + vs_inflate_vector.z = 0; + /* Scale the vector so the largest axis length is 1 */ + vs_inflate_vector /= max_v2(abs(vs_inflate_vector.xy)); + vs_inflate_vector *= inflate_scale; + + vP += vs_inflate_vector; + P = point_view_to_world(vP); + lP = point_world_to_object(P); +} void main() { - ObjectBounds bounds = bounds_buf[drw_ResourceID]; + PASS_RESOURCE_ID - interp.P = bounds.bounding_corners[0].xyz; - interp.P += bounds.bounding_corners[1].xyz * pos.x; - interp.P += bounds.bounding_corners[2].xyz * pos.y; - interp.P += bounds.bounding_corners[3].xyz * pos.z; + const ObjectBounds bounds = bounds_buf[resource_id]; + + Box box = shape_box(bounds.bounding_corners[0].xyz, + bounds.bounding_corners[0].xyz + bounds.bounding_corners[1].xyz, + bounds.bounding_corners[0].xyz + bounds.bounding_corners[2].xyz, + bounds.bounding_corners[0].xyz + bounds.bounding_corners[3].xyz); + + vec3 ws_aabb_min = bounds.bounding_corners[0].xyz; + vec3 ws_aabb_max = bounds.bounding_corners[0].xyz + bounds.bounding_corners[1].xyz + + bounds.bounding_corners[2].xyz + bounds.bounding_corners[3].xyz; + + vec3 ls_center = point_world_to_object((ws_aabb_min + ws_aabb_max) / 2.0); + + vec3 ls_conservative_min = vec3(FLT_MAX); + vec3 ls_conservative_max = vec3(-FLT_MAX); + + for (int i = 0; i < 8; i++) { + vec3 P = box.corners[i]; + vec3 lP = point_world_to_object(P); + inflate_bounds(ls_center, P, lP); + + ls_conservative_min = min(ls_conservative_min, lP); + ls_conservative_max = max(ls_conservative_max, lP); + } + + interp.ls_aabb_min = ls_conservative_min; + interp.ls_aabb_max = ls_conservative_max; + + vec3 lP = mix(ls_conservative_min, ls_conservative_max, max(vec3(0), pos)); + + interp.P = point_object_to_world(lP); interp.vP = point_world_to_view(interp.P); gl_Position = point_world_to_ndc(interp.P); + +#if 0 + if (gl_VertexID == 0) { + Box debug_box = shape_box( + ls_conservative_min, + ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(1, 0, 0), + ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(0, 1, 0), + ls_conservative_min + (ls_conservative_max - ls_conservative_min) * vec3(0, 0, 1)); + for (int i = 0; i < 8; i++) { + debug_box.corners[i] = point_object_to_world(debug_box.corners[i]); + } + drw_debug(debug_box); + } +#endif } diff --git a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl index 17efe37fe35..c3017381f9e 100644 --- a/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl +++ b/source/blender/draw/engines/eevee_next/shaders/eevee_shadow_tilemap_lib.glsl @@ -98,7 +98,12 @@ ShadowTileData shadow_tile_load(usampler2D tilemaps_tx, ivec2 tile_co, int tilem return shadow_tile_unpack(tile_data); } -/* This function should be the inverse of ShadowDirectional::coverage_get(). */ +/** + * This function should be the inverse of ShadowDirectional::coverage_get(). + * + * \a lP shading point position in light space, relative to the to camera position snapped to + * the smallest clipmap level (`shadow_world_to_local(light, P) - light._position`). + */ int shadow_directional_level(LightData light, vec3 lP) { float lod; @@ -144,14 +149,11 @@ ivec2 shadow_decompress_grid_offset(eLightType light_type, ivec2 offset, int lev } /** - * \a lP shading point position in light space (world unit) and translated to camera position - * snapped to smallest clipmap level. + * \a lP shading point position in light space (`shadow_world_to_local(light, P)`). */ -ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP) +ShadowCoordinates shadow_directional_coordinates_at_level(LightData light, vec3 lP, int level) { ShadowCoordinates ret; - - int level = shadow_directional_level(light, lP - light._position); /* This difference needs to be less than 32 for the later shift to be valid. * This is ensured by ShadowDirectional::clipmap_level_range(). */ int level_relative = level - light.clipmap_lod_min; @@ -173,6 +175,15 @@ ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP) return ret; } +/** + * \a lP shading point position in light space (`shadow_world_to_local(light, P)`). + */ +ShadowCoordinates shadow_directional_coordinates(LightData light, vec3 lP) +{ + int level = shadow_directional_level(light, lP - light._position); + return shadow_directional_coordinates_at_level(light, lP, level); +} + /* Transform vector to face local coordinate. */ vec3 shadow_punctual_local_position_to_face_local(int face_id, vec3 lL) { diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_irradiance_cache_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_irradiance_cache_info.hh new file mode 100644 index 00000000000..0bc27f5ae2e --- /dev/null +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_irradiance_cache_info.hh @@ -0,0 +1,16 @@ +#include "eevee_defines.hh" +#include "gpu_shader_create_info.hh" + +GPU_SHADER_INTERFACE_INFO(eeve_debug_surfel_iface, "") + .smooth(Type::VEC3, "P") + .flat(Type::INT, "surfel_index"); + +GPU_SHADER_CREATE_INFO(eevee_debug_surfels) + .additional_info("eevee_shared", "draw_view") + .vertex_source("eevee_debug_surfels_vert.glsl") + .vertex_out(eeve_debug_surfel_iface) + .fragment_source("eevee_debug_surfels_frag.glsl") + .fragment_out(0, Type::VEC4, "out_color") + .storage_buf(0, Qualifier::READ, "DebugSurfel", "surfels_buf[]") + .push_constant(Type::FLOAT, "surfel_radius") + .do_static_compilation(true); diff --git a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh index 378ec8d10a5..347928e5061 100644 --- a/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh +++ b/source/blender/draw/engines/eevee_next/shaders/infos/eevee_shadow_info.hh @@ -8,6 +8,14 @@ /** \name Shadow pipeline * \{ */ +GPU_SHADER_CREATE_INFO(eevee_shadow_clipmap_clear) + .do_static_compilation(true) + .local_group_size(SHADOW_CLIPMAP_GROUP_SIZE) + .storage_buf(0, Qualifier::WRITE, "ShadowTileMapClip", "tilemaps_clip_buf[]") + .push_constant(Type::INT, "tilemaps_clip_buf_len") + .additional_info("eevee_shared") + .compute_source("eevee_shadow_clipmap_clear_comp.glsl"); + GPU_SHADER_CREATE_INFO(eevee_shadow_tilemap_bounds) .do_static_compilation(true) .local_group_size(SHADOW_BOUNDS_GROUP_SIZE) @@ -54,7 +62,9 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_opaque) GPU_SHADER_INTERFACE_INFO(eevee_shadow_tag_transparent_iface, "interp") .smooth(Type::VEC3, "P") - .smooth(Type::VEC3, "vP"); + .smooth(Type::VEC3, "vP") + .flat(Type::VEC3, "ls_aabb_min") + .flat(Type::VEC3, "ls_aabb_max"); GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent) .do_static_compilation(true) @@ -63,9 +73,17 @@ GPU_SHADER_CREATE_INFO(eevee_shadow_tag_usage_transparent) .storage_buf(5, Qualifier::READ_WRITE, "ShadowTileMapData", "tilemaps_buf[]") .storage_buf(6, Qualifier::READ_WRITE, "ShadowTileDataPacked", "tiles_buf[]") .push_constant(Type::FLOAT, "tilemap_projection_ratio") + .push_constant(Type::FLOAT, "pixel_world_radius") + .push_constant(Type::IVEC2, "fb_resolution") + .push_constant(Type::INT, "fb_lod") .vertex_out(eevee_shadow_tag_transparent_iface) - .additional_info( - "eevee_shared", "draw_view", "draw_view_culling", "draw_modelmat_new", "eevee_light_data") + .additional_info("eevee_shared", + "draw_resource_id_varying", + "draw_view", + "draw_view_culling", + "draw_modelmat_new", + "eevee_hiz_data", + "eevee_light_data") .vertex_source("eevee_shadow_tag_usage_vert.glsl") .fragment_source("eevee_shadow_tag_usage_frag.glsl"); diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 20b515414b8..518b4654f9b 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -195,7 +195,7 @@ static void external_cache_populate(void *vedata, Object *ob) return; } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { /* Grease Pencil objects need correct depth to do the blending. */ stl->g_data->need_depth = true; return; @@ -221,7 +221,7 @@ static void external_cache_populate(void *vedata, Object *ob) } struct GPUBatch *geom = DRW_cache_object_surface_get(ob); if (geom) { - /* Depth Prepass */ + /* Depth Pre-pass. */ DRW_shgroup_call(stl->g_data->depth_shgrp, geom, ob); } } diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 06bf531cded..49ddb335af8 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -11,10 +11,10 @@ #include "ED_gpencil.h" #include "ED_view3d.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_view3d_types.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_lib_id.h" #include "BKE_object.h" diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index 16437300dba..09667ff95ad 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -7,8 +7,8 @@ #include "DRW_engine.h" #include "DRW_render.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_object.h" @@ -23,7 +23,7 @@ #include "BLI_memblock.h" #include "DNA_camera_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" @@ -111,7 +111,7 @@ void GPENCIL_engine_init(void *ved) stl->pd->v3d_color_type = (v3d->shading.type == OB_SOLID) ? v3d->shading.color_type : -1; /* Special case: If Vertex Paint mode, use always Vertex mode. */ - if (v3d->shading.type == OB_SOLID && ctx->obact && ctx->obact->type == OB_GPENCIL && + if (v3d->shading.type == OB_SOLID && ctx->obact && ctx->obact->type == OB_GPENCIL_LEGACY && ctx->obact->mode == OB_MODE_VERTEX_GPENCIL) { stl->pd->v3d_color_type = V3D_SHADING_VERTEX_COLOR; } @@ -235,7 +235,7 @@ void GPENCIL_cache_init(void *ved) pd->do_fast_drawing = false; pd->obact = draw_ctx->obact; - if (pd->obact && pd->obact->type == OB_GPENCIL && !(pd->draw_depth_only)) { + if (pd->obact && pd->obact->type == OB_GPENCIL_LEGACY && !(pd->draw_depth_only)) { /* Check if active object has a temp stroke data. */ bGPdata *gpd = (bGPdata *)pd->obact->data; if (gpd->runtime.sbuffer_used > 0) { @@ -536,7 +536,7 @@ static void gpencil_stroke_cache_populate(bGPDlayer *gpl, gpencil_drawcall_add(iter, geom, vfirst, vcount); } - iter->stroke_index_last = gps->runtime.stroke_start + gps->totpoints + 1; + iter->stroke_index_last = gps->runtime.vertex_start + gps->totpoints + 1; } static void gpencil_sbuffer_cache_populate_fast(GPENCIL_Data *vedata, gpIterPopulateData *iter) @@ -592,7 +592,7 @@ void GPENCIL_cache_populate(void *ved, Object *ob) return; } - if (ob->data && (ob->type == OB_GPENCIL) && (ob->dt >= OB_SOLID)) { + if (ob->data && (ob->type == OB_GPENCIL_LEGACY) && (ob->dt >= OB_SOLID)) { gpIterPopulateData iter = {0}; iter.ob = ob; iter.pd = pd; @@ -917,7 +917,7 @@ void GPENCIL_draw_scene(void *ved) /* Fade 3D objects. */ if ((!pd->is_render) && (pd->fade_3d_object_opacity > -1.0f) && (pd->obact != NULL) && - (pd->obact->type == OB_GPENCIL)) { + (pd->obact->type == OB_GPENCIL_LEGACY)) { float background_color[3]; ED_view3d_background_color_get(pd->scene, pd->v3d, background_color); /* Blend color. */ diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 2f9d20b3902..712f5d7d51a 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -7,7 +7,7 @@ #pragma once -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DRW_render.h" @@ -309,7 +309,7 @@ typedef struct GPENCIL_PrivateData { float fade_3d_object_opacity; /* Mask opacity uniform. */ float mask_opacity; - /* Xray transparency in solid mode. */ + /* X-ray transparency in solid mode. */ float xray_alpha; /* Mask invert uniform. */ int mask_invert; diff --git a/source/blender/draw/engines/gpencil/gpencil_render.c b/source/blender/draw/engines/gpencil/gpencil_render.c index c7ef8677336..869462adc6f 100644 --- a/source/blender/draw/engines/gpencil/gpencil_render.c +++ b/source/blender/draw/engines/gpencil/gpencil_render.c @@ -10,7 +10,7 @@ #include "BKE_object.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DEG_depsgraph_query.h" @@ -143,7 +143,7 @@ static void GPENCIL_render_cache(void *vedata, struct RenderEngine *UNUSED(engine), Depsgraph *UNUSED(depsgraph)) { - if (ob && ELEM(ob->type, OB_GPENCIL, OB_LAMP)) { + if (ob && ELEM(ob->type, OB_GPENCIL_LEGACY, OB_LAMP)) { if (DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF) { GPENCIL_cache_populate(vedata, ob); } diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index 9b1129e77be..2f2620e2a63 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -5,11 +5,11 @@ * \ingroup draw */ #include "DNA_camera_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_shader_fx_types.h" #include "DNA_view3d_types.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BLI_link_utils.h" #include "BLI_memblock.h" diff --git a/source/blender/draw/engines/overlay/overlay_edit_uv.cc b/source/blender/draw/engines/overlay/overlay_edit_uv.cc index 76fbbac774b..d712b163c9b 100644 --- a/source/blender/draw/engines/overlay/overlay_edit_uv.cc +++ b/source/blender/draw/engines/overlay/overlay_edit_uv.cc @@ -158,7 +158,7 @@ void OVERLAY_edit_uv_init(OVERLAY_Data *vedata) pd->edit_uv.uv_opacity = sima->uv_opacity; pd->edit_uv.do_tiled_image_overlay = show_overlays && is_image_type && is_tiled_image; pd->edit_uv.do_tiled_image_border_overlay = is_image_type && is_tiled_image; - pd->edit_uv.dash_length = 4.0f * UI_DPI_FAC; + pd->edit_uv.dash_length = 4.0f * UI_SCALE_FAC; pd->edit_uv.line_style = edit_uv_line_style_from_space_image(sima); pd->edit_uv.do_smooth_wire = ((U.gpu_flag & USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE) != 0); pd->edit_uv.do_stencil_overlay = show_overlays && do_stencil_overlay; @@ -237,7 +237,7 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) GPUShader *sh = OVERLAY_shader_edit_uv_verts_get(); pd->edit_uv_verts_grp = DRW_shgroup_create(sh, psl->edit_uv_verts_ps); - const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE) * U.dpi_fac; + const float point_size = UI_GetThemeValuef(TH_VERTEX_SIZE) * UI_SCALE_FAC; DRW_shgroup_uniform_block(pd->edit_uv_verts_grp, "globalsBlock", G_draw.block_ubo); DRW_shgroup_uniform_float_copy( @@ -261,7 +261,7 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) /* uv face dots */ if (pd->edit_uv.do_face_dots) { - const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) * U.dpi_fac; + const float point_size = UI_GetThemeValuef(TH_FACEDOT_SIZE) * UI_SCALE_FAC; GPUShader *sh = OVERLAY_shader_edit_uv_face_dots_get(); pd->edit_uv_face_dots_grp = DRW_shgroup_create(sh, psl->edit_uv_verts_ps); DRW_shgroup_uniform_block(pd->edit_uv_face_dots_grp, "globalsBlock", G_draw.block_ubo); @@ -324,7 +324,7 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) obmat[3][0] = float((active_tile->tile_number - 1001) % 10); obmat[3][1] = float((active_tile->tile_number - 1001) / 10); grp = DRW_shgroup_create(sh, psl->edit_uv_tiled_image_borders_ps); - DRW_shgroup_uniform_vec4_copy(grp, "color", selected_color); + DRW_shgroup_uniform_vec4_copy(grp, "ucolor", selected_color); DRW_shgroup_call_obmat(grp, geom, obmat); } } @@ -370,7 +370,7 @@ void OVERLAY_edit_uv_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_bool_copy(grp, "imgPremultiplied", true); DRW_shgroup_uniform_bool_copy(grp, "imgAlphaBlend", true); const float4 color = {1.0f, 1.0f, 1.0f, brush->clone.alpha}; - DRW_shgroup_uniform_vec4_copy(grp, "color", color); + DRW_shgroup_uniform_vec4_copy(grp, "ucolor", color); float size_image[2]; BKE_image_get_size_fl(image, nullptr, size_image); diff --git a/source/blender/draw/engines/overlay/overlay_engine.cc b/source/blender/draw/engines/overlay/overlay_engine.cc index 5b414c8c5f0..0fcfc76e5ca 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.cc +++ b/source/blender/draw/engines/overlay/overlay_engine.cc @@ -329,7 +329,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) OB_CURVES_LEGACY, OB_SURF, OB_FONT, - OB_GPENCIL, + OB_GPENCIL_LEGACY, OB_CURVES, OB_POINTCLOUD, OB_VOLUME); @@ -467,7 +467,7 @@ static void OVERLAY_cache_populate(void *vedata, Object *ob) OVERLAY_metaball_cache_populate(data, ob); } break; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: OVERLAY_gpencil_cache_populate(data, ob); break; } diff --git a/source/blender/draw/engines/overlay/overlay_extra.cc b/source/blender/draw/engines/overlay/overlay_extra.cc index 6f32c3ae6ac..13feaf708aa 100644 --- a/source/blender/draw/engines/overlay/overlay_extra.cc +++ b/source/blender/draw/engines/overlay/overlay_extra.cc @@ -15,7 +15,7 @@ #include "BKE_curve.h" #include "BKE_global.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_movieclip.h" #include "BKE_object.h" @@ -1577,7 +1577,7 @@ void OVERLAY_extra_cache_populate(OVERLAY_Data *vedata, Object *ob) const bool from_dupli = (ob->base_flag & (BASE_FROM_SET | BASE_FROM_DUPLI)) != 0; const bool has_bounds = !ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_EMPTY, OB_SPEAKER, OB_LIGHTPROBE); const bool has_texspace = has_bounds && - !ELEM(ob->type, OB_EMPTY, OB_LATTICE, OB_ARMATURE, OB_GPENCIL); + !ELEM(ob->type, OB_EMPTY, OB_LATTICE, OB_ARMATURE, OB_GPENCIL_LEGACY); const bool draw_relations = ((pd->v3d_flag & V3D_HIDE_HELPLINES) == 0) && !is_select_mode; const bool draw_obcenters = !is_paint_mode && diff --git a/source/blender/draw/engines/overlay/overlay_gpencil.cc b/source/blender/draw/engines/overlay/overlay_gpencil.cc index f5988d91e72..7e0ac4f3d06 100644 --- a/source/blender/draw/engines/overlay/overlay_gpencil.cc +++ b/source/blender/draw/engines/overlay/overlay_gpencil.cc @@ -7,11 +7,11 @@ #include "DRW_render.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "UI_resources.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DEG_depsgraph_query.h" @@ -45,7 +45,7 @@ void OVERLAY_edit_gpencil_cache_init(OVERLAY_Data *vedata) Scene *scene = draw_ctx->scene; ToolSettings *ts = scene->toolsettings; - if (gpd == nullptr || ob->type != OB_GPENCIL) { + if (gpd == nullptr || ob->type != OB_GPENCIL_LEGACY) { return; } @@ -223,7 +223,7 @@ void OVERLAY_gpencil_cache_init(OVERLAY_Data *vedata) pd->edit_curve.show_handles = v3d->overlay.handle_display != CURVE_HANDLE_NONE; pd->edit_curve.handle_display = v3d->overlay.handle_display; - if (gpd == nullptr || ob->type != OB_GPENCIL) { + if (gpd == nullptr || ob->type != OB_GPENCIL_LEGACY) { return; } diff --git a/source/blender/draw/engines/overlay/overlay_outline.cc b/source/blender/draw/engines/overlay/overlay_outline.cc index 14ec4481472..4fdbb33c0fa 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.cc +++ b/source/blender/draw/engines/overlay/overlay_outline.cc @@ -8,11 +8,11 @@ #include "DRW_render.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_object.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "UI_resources.h" @@ -311,7 +311,7 @@ void OVERLAY_outline_cache_populate(OVERLAY_Data *vedata, return; } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { OVERLAY_outline_gpencil(pd, ob); return; } diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.cc b/source/blender/draw/engines/overlay/overlay_wireframe.cc index 7053d0039cf..16374c9e06e 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.cc +++ b/source/blender/draw/engines/overlay/overlay_wireframe.cc @@ -297,7 +297,7 @@ void OVERLAY_wireframe_cache_populate(OVERLAY_Data *vedata, shgrp = pd->wires_grp[is_xray][use_coloring]; } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { /* TODO(fclem): Make GPencil objects have correct bound-box. */ DRW_shgroup_call_no_cull(shgrp, geom, ob); } diff --git a/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert_no_geom.glsl b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert_no_geom.glsl index 30e32f70eb3..1eec222e6a9 100644 --- a/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert_no_geom.glsl +++ b/source/blender/draw/engines/overlay/shaders/overlay_edit_mesh_vert_no_geom.glsl @@ -181,10 +181,10 @@ void main() /* Enlarge edge for flag display. */ half_size += (geometry_out.finalColorOuter.a > 0.0) ? max(sizeEdge, 1.0) : 0.0; -#ifdef USE_SMOOTH_WIRE - /* Add 1 px for AA */ - half_size += 0.5; -#endif + if (do_smooth_wire) { + /* Add 1 px for AA */ + half_size += 0.5; + } vec3 edge_ofs = vec3(half_size * sizeViewportInv, 0.0); diff --git a/source/blender/draw/engines/workbench/workbench_shadow.cc b/source/blender/draw/engines/workbench/workbench_shadow.cc index ff50fd3732c..bf3abdd5b82 100644 --- a/source/blender/draw/engines/workbench/workbench_shadow.cc +++ b/source/blender/draw/engines/workbench/workbench_shadow.cc @@ -220,14 +220,14 @@ void ShadowPass::ShadowView::compute_visibility(ObjectBoundsBuf &bounds, uint words_len = (view_len_ == 1) ? divide_ceil_u(resource_len, 32) : resource_len * word_per_draw; words_len = ceil_to_multiple_u(max_ii(1, words_len), 4); - uint32_t data = 0xFFFFFFFFu; + const uint32_t data = 0xFFFFFFFFu; if (current_pass_type_ == ShadowPass::PASS) { /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */ pass_visibility_buf_.resize(words_len); - GPU_storagebuf_clear(pass_visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear(pass_visibility_buf_, data); fail_visibility_buf_.resize(words_len); - GPU_storagebuf_clear(fail_visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear(fail_visibility_buf_, data); } else if (current_pass_type_ == ShadowPass::FAIL) { /* Already computed in the ShadowPass::PASS */ @@ -236,7 +236,7 @@ void ShadowPass::ShadowView::compute_visibility(ObjectBoundsBuf &bounds, } else { visibility_buf_.resize(words_len); - GPU_storagebuf_clear(visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear(visibility_buf_, data); } if (do_visibility_) { diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 0d346d56de6..f954f548508 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -880,7 +880,7 @@ GPUBatch *DRW_cache_object_face_wireframe_get(Object *ob) return DRW_pointcloud_batch_cache_get_dots(ob); case OB_VOLUME: return DRW_cache_volume_face_wireframe_get(ob); - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return DRW_cache_gpencil_face_wireframe_get(ob); default: return NULL; @@ -945,7 +945,7 @@ int DRW_cache_object_material_count_get(struct Object *ob) return DRW_pointcloud_material_count_get(ob->data); case OB_VOLUME: return DRW_volume_material_count_get(ob->data); - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return DRW_gpencil_material_count_get(ob->data); default: BLI_assert(0); diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index 11d36b689cd..d32523a574f 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -17,7 +17,7 @@ #include "BKE_attribute.hh" #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "GPU_batch.h" @@ -363,29 +363,25 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ mr->poly_normals = mr->me->poly_normals(); } if (((data_flag & MR_DATA_LOOP_NOR) && is_auto_smooth) || (data_flag & MR_DATA_TAN_LOOP_NOR)) { - mr->loop_normals = static_cast( - MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__)); + mr->loop_normals.reinitialize(mr->loops.size()); short(*clnors)[2] = static_cast( CustomData_get_layer_for_write(&mr->me->ldata, CD_CUSTOMLOOPNORMAL, mr->me->totloop)); const bool *sharp_edges = static_cast( CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, "sharp_edge")); - BKE_mesh_normals_loop_split(reinterpret_cast(mr->vert_positions.data()), - reinterpret_cast(mr->vert_normals.data()), - mr->vert_positions.size(), - mr->edges.data(), - mr->edges.size(), - mr->loops.data(), - mr->loop_normals, - mr->loops.size(), - mr->polys.data(), - reinterpret_cast(mr->poly_normals.data()), - mr->polys.size(), - is_auto_smooth, - split_angle, - sharp_edges, - nullptr, - nullptr, - clnors); + blender::bke::mesh::normals_calc_loop(mr->vert_positions, + mr->edges, + mr->polys, + mr->loops, + {}, + mr->vert_normals, + mr->poly_normals, + sharp_edges, + mr->sharp_faces, + is_auto_smooth, + split_angle, + clnors, + nullptr, + mr->loop_normals); } } else { @@ -405,8 +401,7 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ poly_normals = mr->bm_poly_normals; } - mr->loop_normals = static_cast( - MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__)); + mr->loop_normals.reinitialize(mr->loop_len); const int clnors_offset = CustomData_get_offset(&mr->bm->ldata, CD_CUSTOMLOOPNORMAL); BM_loops_calc_normal_vcos(mr->bm, vert_coords, @@ -414,7 +409,7 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ poly_normals, is_auto_smooth, split_angle, - mr->loop_normals, + reinterpret_cast(mr->loop_normals.data()), nullptr, nullptr, clnors_offset, @@ -442,7 +437,7 @@ MeshRenderData *mesh_render_data_create(Object *object, const bool do_uvedit, const ToolSettings *ts) { - MeshRenderData *mr = static_cast(MEM_callocN(sizeof(*mr), __func__)); + MeshRenderData *mr = MEM_new(__func__); mr->toolsettings = ts; mr->mat_len = mesh_render_mat_len_get(object, me); @@ -558,21 +553,24 @@ MeshRenderData *mesh_render_data_create(Object *object, mr->p_origindex = static_cast(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); mr->material_indices = static_cast( - CustomData_get_layer_named(&me->pdata, CD_PROP_INT32, "material_index")); + CustomData_get_layer_named(&mr->me->pdata, CD_PROP_INT32, "material_index")); mr->hide_vert = static_cast( - CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".hide_vert")); + CustomData_get_layer_named(&mr->me->vdata, CD_PROP_BOOL, ".hide_vert")); mr->hide_edge = static_cast( - CustomData_get_layer_named(&me->edata, CD_PROP_BOOL, ".hide_edge")); + CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, ".hide_edge")); mr->hide_poly = static_cast( - CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".hide_poly")); + CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, ".hide_poly")); mr->select_vert = static_cast( - CustomData_get_layer_named(&me->vdata, CD_PROP_BOOL, ".select_vert")); + CustomData_get_layer_named(&mr->me->vdata, CD_PROP_BOOL, ".select_vert")); mr->select_edge = static_cast( - CustomData_get_layer_named(&me->edata, CD_PROP_BOOL, ".select_edge")); + CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, ".select_edge")); mr->select_poly = static_cast( - CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, ".select_poly")); + CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, ".select_poly")); + + mr->sharp_faces = static_cast( + CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, "sharp_face")); } else { /* #BMesh */ @@ -585,20 +583,19 @@ MeshRenderData *mesh_render_data_create(Object *object, mr->tri_len = poly_to_tri_count(mr->poly_len, mr->loop_len); } - retrieve_active_attribute_names(*mr, *object, *me); + retrieve_active_attribute_names(*mr, *object, *mr->me); return mr; } void mesh_render_data_free(MeshRenderData *mr) { - MEM_SAFE_FREE(mr->loop_normals); /* Loose geometry are owned by #MeshBufferCache. */ mr->ledges = nullptr; mr->lverts = nullptr; - MEM_freeN(mr); + MEM_delete(mr); } /** \} */ diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.cc b/source/blender/draw/intern/draw_cache_impl_gpencil.cc index 5f61cc3f926..b74b2b11e76 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.cc +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.cc @@ -6,13 +6,13 @@ */ #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_meshdata_types.h" #include "DNA_screen_types.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "DRW_engine.h" #include "DRW_render.h" @@ -603,7 +603,7 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_fill) ARegion *region = draw_ctx->region; Object *ob = draw_ctx->obact; - BLI_assert(ob && (ob->type == OB_GPENCIL)); + BLI_assert(ob && (ob->type == OB_GPENCIL_LEGACY)); /* Get origin to reproject points. */ float origin[3]; diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.cc b/source/blender/draw/intern/draw_cache_impl_mesh.cc index f8077882c12..55ab3c32fe0 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.cc +++ b/source/blender/draw/intern/draw_cache_impl_mesh.cc @@ -36,7 +36,7 @@ #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" #include "BKE_editmesh_tangent.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_tangent.h" #include "BKE_modifier.h" @@ -358,7 +358,7 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Object *object, CustomData_get_named_layer(cd_ldata, CD_PROP_FLOAT2, name) : CustomData_get_render_layer(cd_ldata, CD_PROP_FLOAT2); } - if (layer != -1) { + if (layer != -1 && !CustomData_layer_is_anonymous(cd_ldata, CD_PROP_FLOAT2, layer)) { cd_used.uv |= (1 << layer); } break; diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index d2af318bd6b..6e30eef72d3 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -9,7 +9,7 @@ #include "BKE_attribute.hh" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -757,7 +757,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mesh(const MeshRenderData * const Span polys = mesh->polys(); for (const int i : polys.index_range()) { uint32_t flag = 0; - if ((polys[i].flag & ME_SMOOTH) != 0) { + if (!(mr->sharp_faces && mr->sharp_faces[i])) { flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH; } if (mr->select_poly && mr->select_poly[i]) { @@ -786,7 +786,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mapped(Mesh *mesh, /* Selection and hiding from bmesh. */ uint32_t flag = (f) ? compute_coarse_face_flag_bm(f, mr->efa_act) : 0; /* Smooth from mesh. */ - if ((polys[i].flag & ME_SMOOTH) != 0) { + if (!(mr->sharp_faces && mr->sharp_faces[i])) { flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH; } flags_data[i] = uint(polys[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET); @@ -838,8 +838,12 @@ static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc) static void draw_subdiv_invalidate_evaluator_for_orco(Subdiv *subdiv, Mesh *mesh) { + if (!(subdiv && subdiv->evaluator)) { + return; + } + const bool has_orco = CustomData_has_layer(&mesh->vdata, CD_ORCO); - if (has_orco && subdiv->evaluator && !subdiv->evaluator->hasVertexData(subdiv->evaluator)) { + if (has_orco && !subdiv->evaluator->hasVertexData(subdiv->evaluator)) { /* If we suddenly have/need original coordinates, recreate the evaluator if the extra * source was not created yet. The refiner also has to be recreated as refinement for source * and vertex data is done only once. */ @@ -2113,13 +2117,13 @@ static bool draw_subdiv_create_requested_buffers(Object *ob, bm = mesh->edit_mesh->bm; } + draw_subdiv_invalidate_evaluator_for_orco(runtime_data->subdiv_gpu, mesh_eval); + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(runtime_data, mesh_eval, true); if (!subdiv) { return false; } - draw_subdiv_invalidate_evaluator_for_orco(subdiv, mesh_eval); - if (!BKE_subdiv_eval_begin_from_mesh( subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GPU, evaluator_cache)) { /* This could happen in two situations: diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 0b4d3e2bf35..b84c15f0471 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -24,7 +24,7 @@ #include "BKE_duplilist.h" #include "BKE_editmesh.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_mball.h" @@ -1314,9 +1314,9 @@ static void drw_engines_data_validate(void) static bool drw_gpencil_engine_needed(Depsgraph *depsgraph, View3D *v3d) { const bool exclude_gpencil_rendering = v3d ? (v3d->object_type_exclude_viewport & - (1 << OB_GPENCIL)) != 0 : + (1 << OB_GPENCIL_LEGACY)) != 0 : false; - return (!exclude_gpencil_rendering) && DEG_id_type_any_exists(depsgraph, ID_GD); + return (!exclude_gpencil_rendering) && DEG_id_type_any_exists(depsgraph, ID_GD_LEGACY); } /* -------------------------------------------------------------------- */ @@ -1876,7 +1876,7 @@ bool DRW_render_check_grease_pencil(Depsgraph *depsgraph) deg_iter_settings.depsgraph = depsgraph; deg_iter_settings.flags = DEG_OBJECT_ITER_FOR_RENDER_ENGINE_FLAGS; DEG_OBJECT_ITER_BEGIN (°_iter_settings, ob) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { if (DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF) { return true; } diff --git a/source/blender/draw/intern/draw_manager_data.cc b/source/blender/draw/intern/draw_manager_data.cc index dd89a40fbf6..6b7f0b109d1 100644 --- a/source/blender/draw/intern/draw_manager_data.cc +++ b/source/blender/draw/intern/draw_manager_data.cc @@ -15,7 +15,7 @@ #include "BKE_duplilist.h" #include "BKE_global.h" #include "BKE_image.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_pbvh.h" @@ -1243,7 +1243,7 @@ static void sculpt_draw_cb(DRWSculptCallbackData *scd, DRWShadingGroup *shgrp = scd->shading_groups[index]; if (geom != nullptr && shgrp != nullptr) { if (SCULPT_DEBUG_BUFFERS) { - /* Color each buffers in different colors. Only work in solid/Xray mode. */ + /* Color each buffers in different colors. Only work in solid/X-ray mode. */ shgrp = DRW_shgroup_create_sub(shgrp); DRW_shgroup_uniform_vec3( shgrp, "materialDiffuseColor", SCULPT_DEBUG_COLOR(scd->debug_node_nr++), 1); diff --git a/source/blender/draw/intern/draw_manager_text.cc b/source/blender/draw/intern/draw_manager_text.cc index c61ff7d4beb..31215ec0090 100644 --- a/source/blender/draw/intern/draw_manager_text.cc +++ b/source/blender/draw/intern/draw_manager_text.cc @@ -15,7 +15,7 @@ #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_unit.h" #include "DNA_mesh_types.h" @@ -127,7 +127,7 @@ static void drw_text_cache_draw_ex(DRWTextStore *dt, ARegion *region) const uiStyle *style = UI_style_get(); - BLF_size(font_id, style->widget.points * U.dpi_fac); + BLF_size(font_id, style->widget.points * UI_SCALE_FAC); BLI_memiter_iter_init(dt->cache_strings, &it); while ((vos = static_cast(BLI_memiter_iter_step(&it)))) { @@ -249,7 +249,7 @@ void DRW_text_edit_mesh_measure_stats(ARegion *region, if ((v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_INDICES) && (em->selectmode & SCE_SELECT_EDGE)) { edge_tex_count += 1; } - const short edge_tex_sep = short((edge_tex_count - 1) * 5.0f * U.dpi_fac); + const short edge_tex_sep = short((edge_tex_count - 1) * 5.0f * UI_SCALE_FAC); /* Make the precision of the display value proportionate to the grid-size. */ diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc index dea095c1b71..a5f2461f06c 100644 --- a/source/blender/draw/intern/draw_pbvh.cc +++ b/source/blender/draw/intern/draw_pbvh.cc @@ -36,7 +36,7 @@ #include "BKE_attribute.h" #include "BKE_ccg.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_paint.h" #include "BKE_pbvh.h" #include "BKE_subdiv_ccg.h" @@ -333,28 +333,26 @@ struct PBVHBatches { foreach_faces, GPUVertBufRaw *access) { - float fno[3]; + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(args->pdata, CD_PROP_BOOL, "sharp_face")); short no[3]; int last_poly = -1; - bool smooth = false; + bool flat = false; foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri *tri) { if (tri->poly != last_poly) { last_poly = tri->poly; - - const MPoly &poly = args->polys[tri->poly]; - if (!(poly.flag & ME_SMOOTH)) { - smooth = true; - BKE_mesh_calc_poly_normal( - &poly, args->mloop + poly.loopstart, args->vert_positions, fno); + flat = sharp_faces && sharp_faces[tri->poly]; + if (flat) { + const MPoly &poly = args->polys[tri->poly]; + const float3 fno = blender::bke::mesh::poly_normal_calc( + {reinterpret_cast(args->vert_positions), args->mesh_verts_num}, + {&args->mloop[poly.loopstart], poly.totloop}); normal_float_to_short_v3(no, fno); } - else { - smooth = false; - } } - if (!smooth) { + if (!flat) { normal_float_to_short_v3(no, args->vert_normals[vertex_i]); } @@ -409,7 +407,7 @@ struct PBVHBatches { foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) { float3 no(0.0f, 0.0f, 0.0f); - const bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH; + const bool smooth = !args->grid_flag_mats[grid_index].sharp; if (smooth) { no = CCG_elem_no(&args->ccg_key, elems[0]); @@ -1085,7 +1083,7 @@ struct PBVHBatches { for (int i : IndexRange(args->totprim)) { int grid_index = args->grid_indices[i]; - bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH; + bool smooth = !args->grid_flag_mats[grid_index].sharp; BLI_bitmap *gh = args->grid_hidden[grid_index]; for (int y = 0; y < gridsize - 1; y += skip) { diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h index 2f2e6bb559c..6021d9d4c7c 100644 --- a/source/blender/draw/intern/draw_subdivision.h +++ b/source/blender/draw/intern/draw_subdivision.h @@ -209,10 +209,6 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, struct MeshBufferCac void DRW_subdiv_cache_free(struct Subdiv *subdiv); -void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache, - struct MeshRenderData *mr, - const struct ToolSettings *toolsettings); - void draw_subdiv_init_origindex_buffer(struct GPUVertBuf *buffer, int32_t *vert_origindex, uint num_loops, diff --git a/source/blender/draw/intern/draw_view.cc b/source/blender/draw/intern/draw_view.cc index 46fd82a239e..30417ff6420 100644 --- a/source/blender/draw/intern/draw_view.cc +++ b/source/blender/draw/intern/draw_view.cc @@ -280,8 +280,8 @@ void View::compute_visibility(ObjectBoundsBuf &bounds, uint resource_len, bool d /* TODO(fclem): Resize to nearest pow2 to reduce fragmentation. */ visibility_buf_.resize(words_len); - uint32_t data = 0xFFFFFFFFu; - GPU_storagebuf_clear(visibility_buf_, GPU_R32UI, GPU_DATA_UINT, &data); + const uint32_t data = 0xFFFFFFFFu; + GPU_storagebuf_clear(visibility_buf_, data); if (do_visibility_) { GPUShader *shader = DRW_shader_draw_visibility_compute_get(); diff --git a/source/blender/draw/intern/draw_volume.cc b/source/blender/draw/intern/draw_volume.cc index c26b6949f3c..7d9825ef825 100644 --- a/source/blender/draw/intern/draw_volume.cc +++ b/source/blender/draw/intern/draw_volume.cc @@ -15,7 +15,7 @@ #include "BKE_fluid.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_volume.h" #include "BKE_volume_render.h" diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh index 81ab8b6bd1a..7991e7b256c 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -94,7 +94,8 @@ struct MeshRenderData { const bool *select_vert; const bool *select_edge; const bool *select_poly; - float (*loop_normals)[3]; + const bool *sharp_faces; + blender::Array loop_normals; int *lverts, *ledges; const char *active_color_name; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index 5e7b292a0d3..20e90dc249f 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -15,7 +15,7 @@ #include "BKE_attribute.h" #include "BKE_attribute.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "draw_attributes.hh" #include "draw_subdivision.h" diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc index 9e0a149d181..fc71862328a 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc @@ -7,7 +7,7 @@ #include "MEM_guardedalloc.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_math_vector_types.hh" @@ -248,7 +248,7 @@ static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdi /* HACK to fix #68857 */ if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { int layer = CustomData_get_active_layer(cd_ldata, CD_PROP_FLOAT2); - if (layer != -1) { + if (layer != -1 && !CustomData_layer_is_anonymous(cd_ldata, CD_PROP_FLOAT2, layer)) { uv_layers |= (1 << layer); } } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc index a34681486c5..8566a07d764 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -9,7 +9,7 @@ #include "MEM_guardedalloc.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "extract_mesh.hh" @@ -77,10 +77,8 @@ static void compute_area_ratio(const MeshRenderData *mr, const float2 *uv_data = (const float2 *)CustomData_get_layer(&mr->me->ldata, CD_PROP_FLOAT2); for (int poly_index = 0; poly_index < mr->poly_len; poly_index++) { const MPoly &poly = mr->polys[poly_index]; - float area = BKE_mesh_calc_poly_area( - &poly, - &mr->loops[poly.loopstart], - reinterpret_cast(mr->vert_positions.data())); + const float area = bke::mesh::poly_area_calc(mr->vert_positions, + mr->loops.slice(poly.loopstart, poly.totloop)); float uvarea = area_poly_v2(reinterpret_cast(&uv_data[poly.loopstart]), poly.totloop); tot_area += area; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc index 4c69a66d152..bd15573d859 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -41,7 +41,7 @@ static void extract_lnor_iter_poly_bm(const MeshRenderData *mr, l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { const int l_index = BM_elem_index_get(l_iter); - if (mr->loop_normals) { + if (!mr->loop_normals.is_empty()) { (*(GPUPackedNormal **)data)[l_index] = GPU_normal_convert_i10_v3(mr->loop_normals[l_index]); } else { @@ -68,14 +68,14 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, for (int ml_index = poly->loopstart; ml_index < ml_index_end; ml_index += 1) { const MLoop *ml = &mr->loops[ml_index]; GPUPackedNormal *lnor_data = &(*(GPUPackedNormal **)data)[ml_index]; - if (mr->loop_normals) { + if (!mr->loop_normals.is_empty()) { *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]); } - else if (poly->flag & ME_SMOOTH) { - *lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]); + else if (mr->sharp_faces && mr->sharp_faces[poly_index]) { + *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]); } else { - *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]); + *lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]); } /* Flag for paint mode overlay. @@ -167,7 +167,7 @@ static void extract_lnor_hq_iter_poly_bm(const MeshRenderData *mr, l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { const int l_index = BM_elem_index_get(l_iter); - if (mr->loop_normals) { + if (!mr->loop_normals.is_empty()) { normal_float_to_short_v3(&(*(gpuHQNor **)data)[l_index].x, mr->loop_normals[l_index]); } else { @@ -192,14 +192,14 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, for (int ml_index = poly->loopstart; ml_index < ml_index_end; ml_index += 1) { const MLoop *ml = &mr->loops[ml_index]; gpuHQNor *lnor_data = &(*(gpuHQNor **)data)[ml_index]; - if (mr->loop_normals) { + if (!mr->loop_normals.is_empty()) { normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]); } - else if (poly->flag & ME_SMOOTH) { - normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]); + else if (mr->sharp_faces && mr->sharp_faces[poly_index]) { + normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]); } else { - normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]); + normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]); } /* Flag for paint mode overlay. diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc index fb4319558e0..163ebf3a2f8 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc @@ -9,7 +9,7 @@ #include "BLI_string.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_paint.h" #include "draw_subdivision.h" diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc index 336a785103e..e7da5722f56 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc @@ -11,7 +11,7 @@ #include "BKE_editmesh.h" #include "BKE_editmesh_tangent.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_tangent.h" #include "extract_mesh.hh" @@ -107,7 +107,7 @@ static void extract_tan_init_common(const MeshRenderData *mr, r_tangent_names, tan_len, reinterpret_cast(mr->poly_normals.data()), - mr->loop_normals, + reinterpret_cast(mr->loop_normals.data()), orco, r_loop_data, mr->loop_len, @@ -120,13 +120,14 @@ static void extract_tan_init_common(const MeshRenderData *mr, mr->loops.data(), mr->looptris.data(), mr->tri_len, + mr->sharp_faces, cd_ldata, calc_active_tangent, r_tangent_names, tan_len, reinterpret_cast(mr->vert_normals.data()), reinterpret_cast(mr->poly_normals.data()), - mr->loop_normals, + reinterpret_cast(mr->loop_normals.data()), orco, r_loop_data, mr->loops.size(), diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc index bc73c59f556..b92d367ac0e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc @@ -31,7 +31,7 @@ static bool mesh_extract_uv_format_init(GPUVertFormat *format, /* HACK to fix #68857 */ if (extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { int layer = CustomData_get_active_layer(cd_ldata, CD_PROP_FLOAT2); - if (layer != -1) { + if (layer != -1 && !CustomData_layer_is_anonymous(cd_ldata, CD_PROP_FLOAT2, layer)) { uv_layers |= (1 << layer); } } diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc index d7d3fc6b3f5..7a88e2308d2 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc @@ -8,7 +8,7 @@ #include "MEM_guardedalloc.h" #include "BKE_deform.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "draw_subdivision.h" #include "extract_mesh.hh" diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc deleted file mode 100644 index b326f5dfa0c..00000000000 --- a/source/blender/draw/tests/shaders_test.cc +++ /dev/null @@ -1,416 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - -#include "testing/testing.h" - -#include "draw_testing.hh" - -#include "GPU_context.h" -#include "GPU_index_buffer.h" -#include "GPU_init_exit.h" -#include "GPU_shader.h" -#include "GPU_texture.h" -#include "GPU_vertex_buffer.h" - -#include "intern/draw_manager_testing.h" - -#include "engines/basic/basic_private.h" -#include "engines/eevee/eevee_private.h" -#include "engines/gpencil/gpencil_engine.h" -#include "engines/image/image_private.hh" -#include "engines/overlay/overlay_private.hh" -#include "engines/workbench/workbench_private.h" -#include "intern/draw_shader.h" - -namespace blender::draw { - -using namespace blender::draw::image_engine; - -static void test_workbench_glsl_shaders() -{ - const int MAX_WPD = 6; - WORKBENCH_PrivateData wpds[MAX_WPD]; - - wpds[0].sh_cfg = GPU_SHADER_CFG_DEFAULT; - wpds[0].shading.light = V3D_LIGHTING_FLAT; - wpds[1].sh_cfg = GPU_SHADER_CFG_DEFAULT; - wpds[1].shading.light = V3D_LIGHTING_MATCAP; - wpds[2].sh_cfg = GPU_SHADER_CFG_DEFAULT; - wpds[2].shading.light = V3D_LIGHTING_STUDIO; - wpds[3].sh_cfg = GPU_SHADER_CFG_CLIPPED; - wpds[3].shading.light = V3D_LIGHTING_FLAT; - wpds[4].sh_cfg = GPU_SHADER_CFG_CLIPPED; - wpds[4].shading.light = V3D_LIGHTING_MATCAP; - wpds[5].sh_cfg = GPU_SHADER_CFG_CLIPPED; - wpds[5].shading.light = V3D_LIGHTING_STUDIO; - - for (int wpd_index = 0; wpd_index < MAX_WPD; wpd_index++) { - WORKBENCH_PrivateData *wpd = &wpds[wpd_index]; - EXPECT_NE(workbench_shader_opaque_get(wpd, WORKBENCH_DATATYPE_MESH), nullptr); - EXPECT_NE(workbench_shader_opaque_get(wpd, WORKBENCH_DATATYPE_HAIR), nullptr); - EXPECT_NE(workbench_shader_opaque_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD), nullptr); - EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_MESH, false), nullptr); - EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_MESH, true), nullptr); - EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_HAIR, false), nullptr); - EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_HAIR, true), nullptr); - EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD, false), - nullptr); - EXPECT_NE(workbench_shader_opaque_image_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD, true), - nullptr); - EXPECT_NE(workbench_shader_composite_get(wpd), nullptr); - EXPECT_NE(workbench_shader_merge_infront_get(wpd), nullptr); - - EXPECT_NE(workbench_shader_transparent_get(wpd, WORKBENCH_DATATYPE_MESH), nullptr); - EXPECT_NE(workbench_shader_transparent_get(wpd, WORKBENCH_DATATYPE_HAIR), nullptr); - EXPECT_NE(workbench_shader_transparent_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD), nullptr); - EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_MESH, false), - nullptr); - EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_MESH, true), nullptr); - EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_HAIR, false), - nullptr); - EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_HAIR, true), nullptr); - EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD, false), - nullptr); - EXPECT_NE(workbench_shader_transparent_image_get(wpd, WORKBENCH_DATATYPE_POINTCLOUD, true), - nullptr); - EXPECT_NE(workbench_shader_transparent_resolve_get(wpd), nullptr); - } - - EXPECT_NE(workbench_shader_shadow_pass_get(false), nullptr); - EXPECT_NE(workbench_shader_shadow_pass_get(true), nullptr); - EXPECT_NE(workbench_shader_shadow_fail_get(false, false), nullptr); - EXPECT_NE(workbench_shader_shadow_fail_get(false, true), nullptr); - EXPECT_NE(workbench_shader_shadow_fail_get(true, false), nullptr); - EXPECT_NE(workbench_shader_shadow_fail_get(true, true), nullptr); - - /* NOTE: workbench_shader_cavity_get(false, false) isn't a valid option. */ - EXPECT_NE(workbench_shader_cavity_get(false, true), nullptr); - EXPECT_NE(workbench_shader_cavity_get(true, false), nullptr); - EXPECT_NE(workbench_shader_cavity_get(true, true), nullptr); - EXPECT_NE(workbench_shader_outline_get(), nullptr); - - EXPECT_NE(workbench_shader_antialiasing_accumulation_get(), nullptr); - EXPECT_NE(workbench_shader_antialiasing_get(0), nullptr); - EXPECT_NE(workbench_shader_antialiasing_get(1), nullptr); - EXPECT_NE(workbench_shader_antialiasing_get(2), nullptr); - - EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_LINEAR, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_LINEAR, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_CUBIC, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_CUBIC, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_CLOSEST, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, false, WORKBENCH_VOLUME_INTERP_CLOSEST, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_LINEAR, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_LINEAR, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_CUBIC, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_CUBIC, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_CLOSEST, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(false, true, WORKBENCH_VOLUME_INTERP_CLOSEST, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_LINEAR, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_LINEAR, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_CUBIC, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_CUBIC, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_CLOSEST, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, false, WORKBENCH_VOLUME_INTERP_CLOSEST, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_LINEAR, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_LINEAR, true), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_CUBIC, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_CUBIC, true), nullptr); - EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_CLOSEST, false), - nullptr); - EXPECT_NE(workbench_shader_volume_get(true, true, WORKBENCH_VOLUME_INTERP_CLOSEST, true), - nullptr); - - GPUShader *dof_prepare_sh; - GPUShader *dof_downsample_sh; - GPUShader *dof_blur1_sh; - GPUShader *dof_blur2_sh; - GPUShader *dof_resolve_sh; - workbench_shader_depth_of_field_get( - &dof_prepare_sh, &dof_downsample_sh, &dof_blur1_sh, &dof_blur2_sh, &dof_resolve_sh); - EXPECT_NE(dof_prepare_sh, nullptr); - EXPECT_NE(dof_downsample_sh, nullptr); - EXPECT_NE(dof_blur1_sh, nullptr); - EXPECT_NE(dof_blur2_sh, nullptr); - EXPECT_NE(dof_resolve_sh, nullptr); - - workbench_shader_free(); -} -DRAW_TEST(workbench_glsl_shaders) - -static void test_gpencil_glsl_shaders() -{ - EXPECT_NE(GPENCIL_shader_antialiasing(0), nullptr); - EXPECT_NE(GPENCIL_shader_antialiasing(1), nullptr); - EXPECT_NE(GPENCIL_shader_antialiasing(2), nullptr); - - EXPECT_NE(GPENCIL_shader_geometry_get(), nullptr); - EXPECT_NE(GPENCIL_shader_layer_blend_get(), nullptr); - EXPECT_NE(GPENCIL_shader_mask_invert_get(), nullptr); - EXPECT_NE(GPENCIL_shader_depth_merge_get(), nullptr); - EXPECT_NE(GPENCIL_shader_fx_blur_get(), nullptr); - EXPECT_NE(GPENCIL_shader_fx_colorize_get(), nullptr); - EXPECT_NE(GPENCIL_shader_fx_composite_get(), nullptr); - EXPECT_NE(GPENCIL_shader_fx_transform_get(), nullptr); - EXPECT_NE(GPENCIL_shader_fx_glow_get(), nullptr); - EXPECT_NE(GPENCIL_shader_fx_pixelize_get(), nullptr); - EXPECT_NE(GPENCIL_shader_fx_rim_get(), nullptr); - EXPECT_NE(GPENCIL_shader_fx_shadow_get(), nullptr); - - GPENCIL_shader_free(); -} -DRAW_TEST(gpencil_glsl_shaders) - -static void test_image_glsl_shaders() -{ - EXPECT_NE(IMAGE_shader_image_get(), nullptr); - EXPECT_NE(IMAGE_shader_depth_get(), nullptr); - - IMAGE_shader_free(); -} -DRAW_TEST(image_glsl_shaders) - -static void test_overlay_glsl_shaders() -{ - for (int i = 0; i < 2; i++) { - eGPUShaderConfig sh_cfg = i == 0 ? GPU_SHADER_CFG_DEFAULT : GPU_SHADER_CFG_CLIPPED; - DRW_draw_state_init_gtests(sh_cfg); - EXPECT_NE(OVERLAY_shader_antialiasing(), nullptr); - EXPECT_NE(OVERLAY_shader_armature_degrees_of_freedom_wire(), nullptr); - EXPECT_NE(OVERLAY_shader_armature_degrees_of_freedom_solid(), nullptr); - EXPECT_NE(OVERLAY_shader_armature_envelope(false), nullptr); - EXPECT_NE(OVERLAY_shader_armature_envelope(true), nullptr); - EXPECT_NE(OVERLAY_shader_armature_shape(false), nullptr); - EXPECT_NE(OVERLAY_shader_armature_shape(true), nullptr); - EXPECT_NE(OVERLAY_shader_armature_shape_wire(), nullptr); - EXPECT_NE(OVERLAY_shader_armature_sphere(false), nullptr); - EXPECT_NE(OVERLAY_shader_armature_sphere(true), nullptr); - EXPECT_NE(OVERLAY_shader_armature_stick(), nullptr); - EXPECT_NE(OVERLAY_shader_armature_wire(), nullptr); - EXPECT_NE(OVERLAY_shader_background(), nullptr); - EXPECT_NE(OVERLAY_shader_clipbound(), nullptr); - EXPECT_NE(OVERLAY_shader_depth_only(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_curve_handle(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_curve_point(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_curve_wire(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_gpencil_guide_point(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_gpencil_point(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_gpencil_wire(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_lattice_point(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_lattice_wire(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_analysis(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_depth(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_edge(false), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_edge(true), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_face(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_facedot(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_normal(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_skin_root(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_mesh_vert(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_particle_strand(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_particle_point(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_edges_get(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_face_get(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_face_dots_get(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_verts_get(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_stretching_area_get(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_stretching_angle_get(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_tiled_image_borders_get(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_stencil_image(), nullptr); - EXPECT_NE(OVERLAY_shader_edit_uv_mask_image(), nullptr); - EXPECT_NE(OVERLAY_shader_extra(false), nullptr); - EXPECT_NE(OVERLAY_shader_extra(true), nullptr); - EXPECT_NE(OVERLAY_shader_extra_groundline(), nullptr); - EXPECT_NE(OVERLAY_shader_extra_wire(false, false), nullptr); - EXPECT_NE(OVERLAY_shader_extra_wire(false, true), nullptr); - EXPECT_NE(OVERLAY_shader_extra_wire(true, false), nullptr); - EXPECT_NE(OVERLAY_shader_extra_wire(true, true), nullptr); - EXPECT_NE(OVERLAY_shader_extra_loose_point(), nullptr); - EXPECT_NE(OVERLAY_shader_extra_point(), nullptr); - EXPECT_NE(OVERLAY_shader_facing(), nullptr); - EXPECT_NE(OVERLAY_shader_gpencil_canvas(), nullptr); - EXPECT_NE(OVERLAY_shader_grid(), nullptr); - EXPECT_NE(OVERLAY_shader_grid_image(), nullptr); - EXPECT_NE(OVERLAY_shader_image(), nullptr); - EXPECT_NE(OVERLAY_shader_motion_path_line(), nullptr); - EXPECT_NE(OVERLAY_shader_motion_path_vert(), nullptr); - EXPECT_NE(OVERLAY_shader_uniform_color(), nullptr); - EXPECT_NE(OVERLAY_shader_uniform_color_pointcloud(), nullptr); - EXPECT_NE(OVERLAY_shader_outline_prepass(false), nullptr); - EXPECT_NE(OVERLAY_shader_outline_prepass(true), nullptr); - EXPECT_NE(OVERLAY_shader_outline_prepass_curves(), nullptr); - EXPECT_NE(OVERLAY_shader_outline_prepass_gpencil(), nullptr); - EXPECT_NE(OVERLAY_shader_outline_prepass_pointcloud(), nullptr); - EXPECT_NE(OVERLAY_shader_extra_grid(), nullptr); - EXPECT_NE(OVERLAY_shader_outline_detect(), nullptr); - EXPECT_NE(OVERLAY_shader_paint_face(), nullptr); - EXPECT_NE(OVERLAY_shader_paint_point(), nullptr); - EXPECT_NE(OVERLAY_shader_paint_texture(), nullptr); - EXPECT_NE(OVERLAY_shader_paint_vertcol(), nullptr); - EXPECT_NE(OVERLAY_shader_paint_weight(false), nullptr); - EXPECT_NE(OVERLAY_shader_paint_weight(true), nullptr); - EXPECT_NE(OVERLAY_shader_paint_wire(), nullptr); - EXPECT_NE(OVERLAY_shader_particle_dot(), nullptr); - EXPECT_NE(OVERLAY_shader_particle_shape(), nullptr); - EXPECT_NE(OVERLAY_shader_sculpt_mask(), nullptr); - EXPECT_NE(OVERLAY_shader_sculpt_curves_selection(), nullptr); - EXPECT_NE(OVERLAY_shader_viewer_attribute_curve(), nullptr); - EXPECT_NE(OVERLAY_shader_viewer_attribute_curves(), nullptr); - EXPECT_NE(OVERLAY_shader_viewer_attribute_mesh(), nullptr); - EXPECT_NE(OVERLAY_shader_viewer_attribute_pointcloud(), nullptr); - EXPECT_NE(OVERLAY_shader_volume_velocity(false, false), nullptr); - EXPECT_NE(OVERLAY_shader_volume_velocity(false, true), nullptr); - EXPECT_NE(OVERLAY_shader_volume_velocity(true, false), nullptr); - EXPECT_NE(OVERLAY_shader_wireframe(false), nullptr); - EXPECT_NE(OVERLAY_shader_wireframe(true), nullptr); - EXPECT_NE(OVERLAY_shader_wireframe_select(), nullptr); - EXPECT_NE(OVERLAY_shader_xray_fade(), nullptr); - } - - OVERLAY_shader_free(); -} -DRAW_TEST(overlay_glsl_shaders) - -static void test_eevee_glsl_shaders_static() -{ - EEVEE_shaders_material_shaders_init(); - - EXPECT_NE(EEVEE_shaders_bloom_blit_get(false), nullptr); - EXPECT_NE(EEVEE_shaders_bloom_blit_get(true), nullptr); - EXPECT_NE(EEVEE_shaders_bloom_downsample_get(false), nullptr); - EXPECT_NE(EEVEE_shaders_bloom_downsample_get(true), nullptr); - EXPECT_NE(EEVEE_shaders_bloom_upsample_get(false), nullptr); - EXPECT_NE(EEVEE_shaders_bloom_upsample_get(true), nullptr); - EXPECT_NE(EEVEE_shaders_bloom_resolve_get(false), nullptr); - EXPECT_NE(EEVEE_shaders_bloom_resolve_get(true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_bokeh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_setup_get(), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_flatten_tiles_get(), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_dilate_tiles_get(false), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_dilate_tiles_get(true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_downsample_get(), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_reduce_get(true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_reduce_get(false), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_FOREGROUND, false), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_FOREGROUND, true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_BACKGROUND, false), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_BACKGROUND, true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_HOLEFILL, false), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_gather_get(DOF_GATHER_HOLEFILL, true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_filter_get(), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_scatter_get(false, false), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_scatter_get(false, true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_scatter_get(true, false), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_scatter_get(true, true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_resolve_get(false, true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_resolve_get(false, false), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_resolve_get(true, true), nullptr); - EXPECT_NE(EEVEE_shaders_depth_of_field_resolve_get(true, false), nullptr); - EXPECT_NE(EEVEE_shaders_effect_downsample_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_downsample_cube_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_minz_downlevel_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_maxz_downlevel_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_minz_downdepth_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_maxz_downdepth_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_minz_downdepth_layer_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_maxz_downdepth_layer_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_maxz_copydepth_layer_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_minz_copydepth_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_maxz_copydepth_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_mist_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_motion_blur_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_motion_blur_object_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_motion_blur_hair_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_motion_blur_velocity_tiles_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_motion_blur_velocity_tiles_expand_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_ambient_occlusion_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_ambient_occlusion_debug_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_ggx_lut_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_ggx_refraction_lut_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_probe_filter_glossy_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_probe_filter_diffuse_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_probe_filter_visibility_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_probe_grid_fill_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_probe_planar_downsample_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_renderpasses_post_process_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(false), nullptr); - EXPECT_NE(EEVEE_shaders_cryptomatte_sh_get(true), nullptr); - EXPECT_NE(EEVEE_shaders_shadow_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_shadow_accum_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_subsurface_first_pass_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_subsurface_second_pass_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_volumes_clear_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_volumes_clear_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_volumes_scatter_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_volumes_scatter_with_lights_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_volumes_integration_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_volumes_resolve_sh_get(false), nullptr); - EXPECT_NE(EEVEE_shaders_volumes_resolve_sh_get(true), nullptr); - EXPECT_NE(EEVEE_shaders_volumes_accum_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_studiolight_probe_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_studiolight_background_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_probe_cube_display_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_probe_grid_display_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_probe_planar_display_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_update_noise_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_velocity_resolve_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_taa_resolve_sh_get(EFFECT_TAA), nullptr); - EXPECT_NE(EEVEE_shaders_taa_resolve_sh_get(EFFECT_TAA_REPROJECT), nullptr); - EXPECT_NE(EEVEE_shaders_effect_reflection_trace_sh_get(), nullptr); - EXPECT_NE(EEVEE_shaders_effect_reflection_resolve_sh_get(), nullptr); - EEVEE_shaders_free(); -} -DRAW_TEST(eevee_glsl_shaders_static) - -static void test_draw_shaders(eParticleRefineShaderType sh_type) -{ - DRW_shaders_free(); - EXPECT_NE(DRW_shader_hair_refine_get(PART_REFINE_CATMULL_ROM, sh_type), nullptr); - DRW_shaders_free(); -} - -static void test_draw_glsl_shaders() -{ -#ifndef __APPLE__ - test_draw_shaders(PART_REFINE_SHADER_TRANSFORM_FEEDBACK); - test_draw_shaders(PART_REFINE_SHADER_COMPUTE); -#endif - test_draw_shaders(PART_REFINE_SHADER_TRANSFORM_FEEDBACK_WORKAROUND); -} -DRAW_TEST(draw_glsl_shaders) - -static void test_basic_glsl_shaders() -{ - for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { - eGPUShaderConfig sh_cfg = static_cast(i); - BASIC_shaders_depth_sh_get(sh_cfg); - BASIC_shaders_pointcloud_depth_sh_get(sh_cfg); - BASIC_shaders_curves_depth_sh_get(sh_cfg); - BASIC_shaders_depth_conservative_sh_get(sh_cfg); - BASIC_shaders_pointcloud_depth_conservative_sh_get(sh_cfg); - } - BASIC_shaders_free(); -} -DRAW_TEST(basic_glsl_shaders) - -} // namespace blender::draw diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index c58d92d39ed..ed73e9d0eae 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -20,7 +20,7 @@ #include "DNA_cachefile_types.h" #include "DNA_camera_types.h" #include "DNA_curves_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_light_types.h" @@ -50,7 +50,7 @@ #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_key.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -695,7 +695,7 @@ static int acf_object_icon(bAnimListElem *ale) return ICON_OUTLINER_OB_VOLUME; case OB_EMPTY: return ICON_OUTLINER_OB_EMPTY; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return ICON_OUTLINER_OB_GREASEPENCIL; default: return ICON_OBJECT_DATA; @@ -5262,7 +5262,7 @@ void ANIM_channel_draw_widgets(const bContext *C, * a callback available (e.g. broken F-Curve rename) */ if (acf->name_prop(ale, &ptr, &prop)) { - const short margin_x = 3 * round_fl_to_int(UI_DPI_FAC); + const short margin_x = 3 * round_fl_to_int(UI_SCALE_FAC); const short width = ac->region->winx - offset - (margin_x * 2); uiBut *but; diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 1b55da28ef4..5609517a9f0 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -16,7 +16,7 @@ #include "BLI_utildefines.h" #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" @@ -30,7 +30,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_mask.h" @@ -3651,17 +3651,7 @@ static bool get_normalized_fcurve_bounds(FCurve *fcu, rctf *r_bounds) { const bool fcu_selection_only = false; - const bool found_bounds = BKE_fcurve_calc_bounds(fcu, - &r_bounds->xmin, - &r_bounds->xmax, - &r_bounds->ymin, - &r_bounds->ymax, - fcu_selection_only, - include_handles, - range); - if (!found_bounds) { - return false; - } + BKE_fcurve_calc_bounds(fcu, fcu_selection_only, include_handles, range, r_bounds); const short mapping_flag = ANIM_get_normalization_flags(ac); @@ -3736,8 +3726,8 @@ static void get_view_range(Scene *scene, const bool use_preview_range, float r_r r_range[1] = scene->r.pefra; } else { - r_range[0] = -FLT_MAX; - r_range[1] = FLT_MAX; + r_range[0] = scene->r.sfra; + r_range[1] = scene->r.efra; } } @@ -3754,16 +3744,6 @@ static void add_region_padding(bContext *C, bAnimContext *ac, rctf *bounds) BLI_rctf_pad_y(bounds, ac->region->winy, pad_bottom, pad_top); } -static ARegion *get_window_region(bAnimContext *ac) -{ - LISTBASE_FOREACH (ARegion *, region, &ac->area->regionbase) { - if (region->regiontype == RGN_TYPE_WINDOW) { - return region; - } - } - return NULL; -} - static int graphkeys_view_selected_channels_exec(bContext *C, wmOperator *op) { bAnimContext ac; @@ -3772,8 +3752,7 @@ static int graphkeys_view_selected_channels_exec(bContext *C, wmOperator *op) if (ANIM_animdata_get_context(C, &ac) == 0) { return OPERATOR_CANCELLED; } - - ARegion *window_region = get_window_region(&ac); + ARegion *window_region = BKE_area_find_region_type(ac.area, RGN_TYPE_WINDOW); if (!window_region) { return OPERATOR_CANCELLED; @@ -3869,7 +3848,7 @@ static int graphkeys_channel_view_pick_invoke(bContext *C, wmOperator *op, const return OPERATOR_CANCELLED; } - ARegion *window_region = get_window_region(&ac); + ARegion *window_region = BKE_area_find_region_type(ac.area, RGN_TYPE_WINDOW); if (!window_region) { return OPERATOR_CANCELLED; @@ -3890,6 +3869,7 @@ static int graphkeys_channel_view_pick_invoke(bContext *C, wmOperator *op, const float range[2]; const bool use_preview_range = RNA_boolean_get(op->ptr, "use_preview_range"); + get_view_range(ac.scene, use_preview_range, range); rctf bounds; diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c index 418331f84b1..e738e213eb4 100644 --- a/source/blender/editors/animation/anim_deps.c +++ b/source/blender/editors/animation/anim_deps.c @@ -11,7 +11,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mask_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -25,7 +25,7 @@ #include "BKE_anim_data.h" #include "BKE_context.h" #include "BKE_fcurve.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_node.h" diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c index 779b63d7e9b..e54044700e7 100644 --- a/source/blender/editors/animation/anim_draw.c +++ b/source/blender/editors/animation/anim_draw.c @@ -8,7 +8,7 @@ #include "BLI_sys_types.h" #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -177,8 +177,8 @@ void ANIM_draw_action_framerange( immUniform4f("color1", color[0], color[1], color[2], color[3]); immUniform4f("color2", 0.0f, 0.0f, 0.0f, 0.0f); - immUniform1i("size1", 2 * U.dpi_fac); - immUniform1i("size2", 4 * U.dpi_fac); + immUniform1i("size1", 2 * UI_SCALE_FAC); + immUniform1i("size2", 4 * UI_SCALE_FAC); if (sfra < efra) { immRectf(pos, v2d->cur.xmin, ymin, sfra, ymax); diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index ac73b7995f2..990d18af8c2 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -32,7 +32,7 @@ #include "DNA_cachefile_types.h" #include "DNA_camera_types.h" #include "DNA_curves_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_layer_types.h" @@ -264,7 +264,7 @@ static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo) ac->ads = sipo->ads; /* set settings for Graph Editor - "Selected = Editable" */ - if (sipo->flag & SIPO_SELCUVERTSONLY) { + if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) { sipo->ads->filterflag |= ADS_FILTER_SELEDIT; } else { @@ -1847,7 +1847,7 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, BKE_view_layer_synced_ensure(scene, view_layer); LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) { /* Only consider this object if it has got some GP data (saving on all the other tests) */ - if (base->object && (base->object->type == OB_GPENCIL)) { + if (base->object && (base->object->type == OB_GPENCIL_LEGACY)) { Object *ob = base->object; /* firstly, check if object can be included, by the following factors: @@ -2806,7 +2806,7 @@ static size_t animdata_filter_dopesheet_ob( } /* object data */ - if ((ob->data) && (ob->type != OB_GPENCIL)) { + if ((ob->data) && (ob->type != OB_GPENCIL_LEGACY)) { tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode); } @@ -2816,7 +2816,8 @@ static size_t animdata_filter_dopesheet_ob( } /* grease pencil */ - if ((ob->type == OB_GPENCIL) && (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { + if ((ob->type == OB_GPENCIL_LEGACY) && (ob->data) && + !(ads->filterflag & ADS_FILTER_NOGPENCIL)) { tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode); } } diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 694eb1f7035..74ed7e22fd4 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -251,7 +251,7 @@ static bool region_position_is_over_marker(View2D *v2d, ListBase *markers, float float pixel_distance = UI_view2d_scale_get_x(v2d) * fabsf(nearest_marker->frame - frame_at_position); - return pixel_distance <= UI_DPI_ICON_SIZE; + return pixel_distance <= UI_ICON_SIZE; } /* --------------------------------- */ @@ -419,7 +419,7 @@ static void draw_marker_name(const uchar *text_color, } #endif - const int icon_half_width = UI_DPI_ICON_SIZE * 0.6; + const int icon_half_width = UI_ICON_SIZE * 0.6; const struct uiFontStyleDraw_Params fs_params = {.align = UI_STYLE_TEXT_LEFT, .word_wrap = 0}; const struct rcti rect = { .xmin = marker_x + icon_half_width, @@ -440,7 +440,7 @@ static void draw_marker_line(const uchar *color, int xpos, int ymin, int ymax) float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniformColor4ubv(color); immUniform1i("colors_len", 0); /* "simple" mode */ @@ -482,17 +482,17 @@ static void draw_marker(const uiFontStyle *fstyle, GPU_blend(GPU_BLEND_ALPHA); - draw_marker_line(line_color, xpos, UI_DPI_FAC * 20, region_height); + draw_marker_line(line_color, xpos, UI_SCALE_FAC * 20, region_height); int icon_id = marker_get_icon_id(marker, flag); - UI_icon_draw(xpos - 0.55f * UI_DPI_ICON_SIZE, UI_DPI_FAC * 18, icon_id); + UI_icon_draw(xpos - 0.55f * UI_ICON_SIZE, UI_SCALE_FAC * 18, icon_id); GPU_blend(GPU_BLEND_NONE); - float name_y = UI_DPI_FAC * 18; + float name_y = UI_SCALE_FAC * 18; /* Give an offset to the marker that is elevated. */ if (is_elevated) { - name_y += UI_DPI_FAC * 10; + name_y += UI_SCALE_FAC * 10; } draw_marker_name(text_color, fstyle, marker, xpos, xmax, name_y); } @@ -537,7 +537,7 @@ static void get_marker_region_rect(View2D *v2d, rctf *rect) static void get_marker_clip_frame_range(View2D *v2d, float xscale, int r_range[2]) { - float font_width_max = (10 * UI_DPI_FAC) / xscale; + float font_width_max = (10 * UI_SCALE_FAC) / xscale; r_range[0] = v2d->cur.xmin - sizeof(((TimeMarker *)NULL)->name) * font_width_max; r_range[1] = v2d->cur.xmax + font_width_max; } diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index b140b2a590b..02c97613269 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -345,7 +345,7 @@ void animviz_motionpath_compute_range(Object *ob, Scene *scene) bAnimVizSettings *avs = ob->mode == OB_MODE_POSE ? &ob->pose->avs : &ob->avs; if (avs->path_range == MOTIONPATH_RANGE_MANUAL) { - /* Don't touch manually-determined ranges. */ + /* Don't touch manually-determined ranges. */ return; } diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index c7e755fb6df..701bdf3bfcd 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -41,7 +41,9 @@ #include "anim_intern.h" -/* ********************** frame change operator ***************************/ +/* -------------------------------------------------------------------- */ +/** \name Frame Change Operator + * \{ */ /* Check if the operator can be run from the current context */ static bool change_frame_poll(bContext *C) @@ -349,7 +351,11 @@ static void ANIM_OT_change_frame(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ****************** Start/End Frame Operators *******************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Start/End Frame Operators + * \{ */ static bool anim_set_end_frames_poll(bContext *C) { @@ -483,7 +489,11 @@ static void ANIM_OT_end_frame_set(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ****************** set preview range operator ****************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Set Preview Range Operator + * \{ */ static int previewrange_define_exec(bContext *C, wmOperator *op) { @@ -545,7 +555,11 @@ static void ANIM_OT_previewrange_set(wmOperatorType *ot) WM_operator_properties_border(ot); } -/* ****************** clear preview range operator ****************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Preview Range Operator + * \{ */ static int previewrange_clear_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -586,7 +600,11 @@ static void ANIM_OT_previewrange_clear(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************** registration **********************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Registration + * \{ */ void ED_operatortypes_anim(void) { @@ -632,3 +650,5 @@ void ED_keymap_anim(wmKeyConfig *keyconf) { WM_keymap_ensure(keyconf, "Animation", 0, 0); } + +/** \} */ diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 6b1fdb977ff..f7b8b47832a 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -16,7 +16,7 @@ #include "BLI_rect.h" #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc index 062c0395e37..17db24200bf 100644 --- a/source/blender/editors/animation/keyframes_keylist.cc +++ b/source/blender/editors/animation/keyframes_keylist.cc @@ -26,7 +26,7 @@ #include "DNA_anim_types.h" #include "DNA_cachefile_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c index ebeac6552cd..532002c2355 100644 --- a/source/blender/editors/animation/time_scrub_ui.c +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -42,7 +42,7 @@ void ED_time_scrub_region_rect_get(const ARegion *region, rcti *rect) static int get_centered_text_y(const rcti *rect) { - return BLI_rcti_cent_y(rect) - UI_DPI_FAC * 4; + return BLI_rcti_cent_y(rect) - UI_SCALE_FAC * 4; } static void draw_background(const rcti *rect) @@ -84,9 +84,9 @@ static void draw_current_frame(const Scene *scene, char frame_str[64]; get_current_time_str(scene, display_seconds, current_frame, sizeof(frame_str), frame_str); float text_width = UI_fontstyle_string_width(fstyle, frame_str); - float box_width = MAX2(text_width + 8 * UI_DPI_FAC, 24 * UI_DPI_FAC); - float box_padding = 3 * UI_DPI_FAC; - const int line_outline = max_ii(1, round_fl_to_int(1 * UI_DPI_FAC)); + float box_width = MAX2(text_width + 8 * UI_SCALE_FAC, 24 * UI_SCALE_FAC); + float box_padding = 3 * UI_SCALE_FAC; + const int line_outline = max_ii(1, round_fl_to_int(1 * UI_SCALE_FAC)); float bg_color[4]; UI_GetThemeColorShade4fv(TH_CFRAME, -5, bg_color); @@ -134,7 +134,7 @@ static void draw_current_frame(const Scene *scene, 1.0f, outline_color, U.pixelsize, - 4 * UI_DPI_FAC); + 4 * UI_SCALE_FAC); uchar text_color[4]; UI_GetThemeColor4ubv(TH_HEADER_TEXT_HI, text_color); @@ -176,7 +176,7 @@ void ED_time_scrub_draw(const ARegion *region, draw_background(&scrub_region_rect); rcti numbers_rect = scrub_region_rect; - numbers_rect.ymin = get_centered_text_y(&scrub_region_rect) - 4 * UI_DPI_FAC; + numbers_rect.ymin = get_centered_text_y(&scrub_region_rect) - 4 * UI_SCALE_FAC; if (discrete_frames) { UI_view2d_draw_scale_x__discrete_frames_or_seconds( region, v2d, &numbers_rect, scene, display_seconds, TH_TEXT); @@ -217,8 +217,8 @@ void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *region, bDope RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_DopeSheet, dopesheet, &ptr); const uiStyle *style = UI_style_get_dpi(); - const float padding_x = 2 * UI_DPI_FAC; - const float padding_y = UI_DPI_FAC; + const float padding_x = 2 * UI_SCALE_FAC; + const float padding_y = UI_SCALE_FAC; uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); uiLayout *layout = UI_block_layout(block, diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index 579583eb4ea..730ad990635 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -15,8 +15,8 @@ #include "DNA_armature_types.h" #include "DNA_camera_types.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "BLI_blenlib.h" @@ -32,7 +32,7 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -294,7 +294,7 @@ void ED_armature_bone_rename(Main *bmain, } /* fix grease pencil modifiers and vertex groups */ - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = (bGPdata *)ob->data; LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { diff --git a/source/blender/editors/armature/meshlaplacian.cc b/source/blender/editors/armature/meshlaplacian.cc index 01b1bdebe20..17f3d35b425 100644 --- a/source/blender/editors/armature/meshlaplacian.cc +++ b/source/blender/editors/armature/meshlaplacian.cc @@ -20,7 +20,7 @@ #include "BLT_translation.h" #include "BKE_bvhutils.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" @@ -656,7 +656,7 @@ void heat_bone_weighting(Object *ob, int a, tris_num, j, bbone, firstsegment, lastsegment; bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; - const float(*vert_positions)[3] = BKE_mesh_vert_positions(me); + const blender::Span vert_positions = me->vert_positions(); const blender::Span polys = me->polys(); const blender::Span loops = me->loops(); bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0; @@ -705,8 +705,7 @@ void heat_bone_weighting(Object *ob, mlooptri = static_cast( MEM_mallocN(sizeof(*sys->heat.mlooptri) * sys->heat.tris_num, __func__)); - BKE_mesh_recalc_looptri( - loops.data(), polys.data(), vert_positions, me->totloop, me->totpoly, mlooptri); + blender::bke::mesh::looptris_calc(vert_positions, polys, loops, {mlooptri, sys->heat.tris_num}); sys->heat.mlooptri = mlooptri; sys->heat.loops = loops; @@ -929,7 +928,7 @@ typedef struct MeshDeformBind { blender::Span polys; blender::Span loops; blender::Span looptris; - const float (*poly_nors)[3]; + blender::Span poly_normals; } cagemesh_cache; } MeshDeformBind; @@ -959,7 +958,7 @@ static void harmonic_ray_callback(void *userdata, MeshRayCallbackData *data = static_cast(userdata); MeshDeformBind *mdb = data->mdb; const blender::Span loops = mdb->cagemesh_cache.loops; - const float(*poly_nors)[3] = mdb->cagemesh_cache.poly_nors; + const blender::Span poly_normals = mdb->cagemesh_cache.poly_normals; MeshDeformIsect *isec = data->isec; float no[3], co[3], dist; float *face[3]; @@ -977,8 +976,8 @@ static void harmonic_ray_callback(void *userdata, return; } - if (poly_nors) { - copy_v3_v3(no, poly_nors[lt->poly]); + if (!poly_normals.is_empty()) { + copy_v3_v3(no, poly_normals[lt->poly]); } else { normal_tri_v3(no, UNPACK3(face)); @@ -1632,7 +1631,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin mdb->cagemesh_cache.polys = me->polys(); mdb->cagemesh_cache.loops = me->loops(); mdb->cagemesh_cache.looptris = me->looptris(); - mdb->cagemesh_cache.poly_nors = BKE_mesh_poly_normals_ensure(me); + mdb->cagemesh_cache.poly_normals = me->poly_normals(); } /* make bounding box equal size in all directions, add padding, and compute diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 21938ad8727..47a327902fe 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -22,7 +22,7 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_layer.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -278,7 +278,7 @@ void ED_armature_pose_select_in_wpaint_mode(const Scene *scene, Object *ob_active = BKE_view_layer_active_object_get(view_layer); BLI_assert(ob_active && (ob_active->mode & OB_MODE_ALL_WEIGHT_PAINT)); - if (ob_active->type == OB_GPENCIL) { + if (ob_active->type == OB_GPENCIL_LEGACY) { GpencilVirtualModifierData virtualModifierData; GpencilModifierData *md = BKE_gpencil_modifiers_get_virtual_modifierlist(ob_active, &virtualModifierData); diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt index a4d05ebaffe..9d5f10eddd2 100644 --- a/source/blender/editors/asset/CMakeLists.txt +++ b/source/blender/editors/asset/CMakeLists.txt @@ -24,6 +24,7 @@ set(SRC intern/asset_catalog.cc intern/asset_filter.cc intern/asset_handle.cc + intern/asset_import.cc intern/asset_indexer.cc intern/asset_library_reference.cc intern/asset_library_reference_enum.cc @@ -37,6 +38,7 @@ set(SRC ED_asset_catalog.hh ED_asset_filter.h ED_asset_handle.h + ED_asset_import.h ED_asset_indexer.h ED_asset_library.h ED_asset_list.h diff --git a/source/blender/editors/asset/ED_asset_handle.h b/source/blender/editors/asset/ED_asset_handle.h index 436194fd885..8bfd4f7150e 100644 --- a/source/blender/editors/asset/ED_asset_handle.h +++ b/source/blender/editors/asset/ED_asset_handle.h @@ -21,6 +21,7 @@ extern "C" { struct AssetHandle; +struct AssetRepresentation *ED_asset_handle_get_representation(const struct AssetHandle *asset); const char *ED_asset_handle_get_name(const struct AssetHandle *asset); struct AssetMetaData *ED_asset_handle_get_metadata(const struct AssetHandle *asset); struct ID *ED_asset_handle_get_local_id(const struct AssetHandle *asset); @@ -45,11 +46,4 @@ void ED_asset_handle_get_full_library_path( std::optional ED_asset_handle_get_import_method( const struct AssetHandle *asset); -namespace blender::ed::asset { - -/** If the ID already exists in the database, return it, otherwise add it. */ -ID *get_local_id_from_asset_or_append_and_reuse(Main &bmain, AssetHandle asset); - -} // namespace blender::ed::asset - #endif diff --git a/source/blender/editors/asset/ED_asset_import.h b/source/blender/editors/asset/ED_asset_import.h new file mode 100644 index 00000000000..16c06c6416c --- /dev/null +++ b/source/blender/editors/asset/ED_asset_import.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edasset + */ + +#pragma once + +#include "DNA_ID_enums.h" + +struct AssetRepresentation; +struct Main; + +#ifdef __cplusplus +extern "C" { +#endif + +struct ID *ED_asset_get_local_id_from_asset_or_append_and_reuse( + struct Main *bmain, const struct AssetRepresentation *asset_c_ptr, ID_Type idtype); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/asset/ED_asset_list.h b/source/blender/editors/asset/ED_asset_list.h index 30f961421a5..19528c5dde6 100644 --- a/source/blender/editors/asset/ED_asset_list.h +++ b/source/blender/editors/asset/ED_asset_list.h @@ -6,11 +6,12 @@ #pragma once +#include "DNA_asset_types.h" + #ifdef __cplusplus extern "C" { #endif -struct AssetHandle; struct AssetLibraryReference; struct ID; struct bContext; @@ -49,6 +50,9 @@ void ED_assetlist_storage_id_remap(struct ID *id_old, struct ID *id_new); */ void ED_assetlist_storage_exit(void); +AssetHandle ED_assetlist_asset_get_by_index(const AssetLibraryReference *library_reference, + int asset_index); + struct ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle); /** diff --git a/source/blender/editors/asset/ED_asset_list.hh b/source/blender/editors/asset/ED_asset_list.hh index 524fee274f8..eeca6390bca 100644 --- a/source/blender/editors/asset/ED_asset_list.hh +++ b/source/blender/editors/asset/ED_asset_list.hh @@ -30,4 +30,8 @@ blender::asset_system::AssetLibrary *ED_assetlist_library_get_once_available( /* Can return false to stop iterating. */ using AssetListIterFn = blender::FunctionRef; +/** + * \warning Never keep the asset handle passed to \a fn outside of \a fn's scope. While iterating, + * the file data wrapped by the asset handle can be freed, since the file cache has a maximum size. + */ void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn); diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc index 4a6a7fda40b..824d5d0ed08 100644 --- a/source/blender/editors/asset/intern/asset_handle.cc +++ b/source/blender/editors/asset/intern/asset_handle.cc @@ -9,13 +9,20 @@ #include "AS_asset_representation.h" #include "AS_asset_representation.hh" +#include "BKE_blendfile.h" + +#include "BLI_string.h" + #include "DNA_space_types.h" -#include "BLO_readfile.h" +#include "DNA_space_types.h" #include "ED_asset_handle.h" -#include "WM_api.h" +AssetRepresentation *ED_asset_handle_get_representation(const AssetHandle *asset) +{ + return asset->file_data->asset; +} const char *ED_asset_handle_get_name(const AssetHandle *asset) { @@ -53,36 +60,11 @@ void ED_asset_handle_get_full_library_path(const AssetHandle *asset_handle, { *r_full_lib_path = '\0'; - std::string asset_path = AS_asset_representation_full_path_get(asset_handle->file_data->asset); - if (asset_path.empty()) { + std::string library_path = AS_asset_representation_full_library_path_get( + asset_handle->file_data->asset); + if (library_path.empty()) { return; } - BLO_library_path_explode(asset_path.c_str(), r_full_lib_path, nullptr, nullptr); + BLI_strncpy(r_full_lib_path, library_path.c_str(), FILE_MAX); } - -namespace blender::ed::asset { - -ID *get_local_id_from_asset_or_append_and_reuse(Main &bmain, const AssetHandle asset) -{ - if (ID *local_id = ED_asset_handle_get_local_id(&asset)) { - return local_id; - } - - char blend_path[FILE_MAX_LIBEXTRA]; - ED_asset_handle_get_full_library_path(&asset, blend_path); - const char *id_name = ED_asset_handle_get_name(&asset); - - return WM_file_append_datablock(&bmain, - nullptr, - nullptr, - nullptr, - blend_path, - ED_asset_handle_get_id_type(&asset), - id_name, - BLO_LIBLINK_APPEND_RECURSIVE | - BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR | - BLO_LIBLINK_APPEND_LOCAL_ID_REUSE); -} - -} // namespace blender::ed::asset diff --git a/source/blender/editors/asset/intern/asset_import.cc b/source/blender/editors/asset/intern/asset_import.cc new file mode 100644 index 00000000000..f78084dd38c --- /dev/null +++ b/source/blender/editors/asset/intern/asset_import.cc @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup edasset + */ + +#include "AS_asset_representation.h" +#include "AS_asset_representation.hh" + +#include "BLO_readfile.h" + +#include "WM_api.h" + +#include "ED_asset_import.h" + +using namespace blender; + +ID *ED_asset_get_local_id_from_asset_or_append_and_reuse(Main *bmain, + const AssetRepresentation *asset_c_ptr, + ID_Type idtype) +{ + const asset_system::AssetRepresentation &asset = + *reinterpret_cast(asset_c_ptr); + + if (ID *local_id = asset.local_id()) { + return local_id; + } + + std::string blend_path = asset.get_identifier().full_library_path(); + if (blend_path.empty()) { + return nullptr; + } + + return WM_file_append_datablock(bmain, + nullptr, + nullptr, + nullptr, + blend_path.c_str(), + idtype, + asset.get_name().c_str(), + BLO_LIBLINK_APPEND_RECURSIVE | + BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR | + BLO_LIBLINK_APPEND_LOCAL_ID_REUSE); +} diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc index dd02e65791b..11495d4048e 100644 --- a/source/blender/editors/asset/intern/asset_indexer.cc +++ b/source/blender/editors/asset/intern/asset_indexer.cc @@ -56,13 +56,16 @@ using namespace blender::bke::idprop; * "catalog_name": "", * "description": "", * "author": "", + * "copyright": "", + * "license": "", * "tags": [""], * "properties": [..] * }] * } * \endcode * - * NOTE: entries, author, description, tags and properties are optional attributes. + * NOTE: entries, author, description, copyright, license, tags and properties are optional + * attributes. * * NOTE: File browser uses name and idcode separate. Inside the index they are joined together like * #ID.name. @@ -75,6 +78,8 @@ constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_ID("catalog_id"); constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name"); constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description"); constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author"); +constexpr StringRef ATTRIBUTE_ENTRIES_COPYRIGHT("copyright"); +constexpr StringRef ATTRIBUTE_ENTRIES_LICENSE("license"); constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags"); constexpr StringRef ATTRIBUTE_ENTRIES_PROPERTIES("properties"); @@ -178,6 +183,26 @@ struct AssetEntryReader { return lookup.lookup(ATTRIBUTE_ENTRIES_AUTHOR)->as_string_value()->value(); } + bool has_copyright() const + { + return lookup.contains(ATTRIBUTE_ENTRIES_COPYRIGHT); + } + + StringRefNull get_copyright() const + { + return lookup.lookup(ATTRIBUTE_ENTRIES_COPYRIGHT)->as_string_value()->value(); + } + + bool has_license() const + { + return lookup.contains(ATTRIBUTE_ENTRIES_LICENSE); + } + + StringRefNull get_license() const + { + return lookup.lookup(ATTRIBUTE_ENTRIES_LICENSE)->as_string_value()->value(); + } + StringRefNull get_catalog_name() const { return lookup.lookup(ATTRIBUTE_ENTRIES_CATALOG_NAME)->as_string_value()->value(); @@ -267,6 +292,16 @@ struct AssetEntryWriter { attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_AUTHOR, new StringValue(author))); } + void add_copyright(const StringRefNull copyright) + { + attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_COPYRIGHT, new StringValue(copyright))); + } + + void add_license(const StringRefNull license) + { + attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_LICENSE, new StringValue(license))); + } + void add_tags(const ListBase /* AssetTag */ *asset_tags) { ArrayValue *tags = new ArrayValue(); @@ -305,6 +340,12 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result, if (asset_data.author != nullptr) { result.add_author(asset_data.author); } + if (asset_data.copyright != nullptr) { + result.add_copyright(asset_data.copyright); + } + if (asset_data.license != nullptr) { + result.add_license(asset_data.license); + } if (!BLI_listbase_is_empty(&asset_data.tags)) { result.add_tags(&asset_data.tags); @@ -372,6 +413,18 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry, BLI_strncpy(author_c_str, author.c_str(), author.size() + 1); asset_data->author = author_c_str; } + if (entry.has_copyright()) { + const StringRefNull copyright = entry.get_copyright(); + char *copyright_c_str = static_cast(MEM_mallocN(copyright.size() + 1, __func__)); + BLI_strncpy(copyright_c_str, copyright.c_str(), copyright.size() + 1); + asset_data->copyright = copyright_c_str; + } + if (entry.has_license()) { + const StringRefNull license = entry.get_license(); + char *license_c_str = static_cast(MEM_mallocN(license.size() + 1, __func__)); + BLI_strncpy(license_c_str, license.c_str(), license.size() + 1); + asset_data->license = license_c_str; + } const StringRefNull catalog_name = entry.get_catalog_name(); BLI_strncpy(asset_data->catalog_simple_name, diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 78859a9206d..c7df300ed24 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -112,6 +112,8 @@ class AssetList : NonCopyable { void ensurePreviewsJob(const bContext *C); void clear(bContext *C); + AssetHandle asset_get_by_index(int index) const; + bool needsRefetch() const; bool isLoaded() const; asset_system::AssetLibrary *asset_library() const; @@ -139,7 +141,7 @@ void AssetList::setup() filelist_setlibrary(files, &library_ref_); filelist_setfilter_options( files, - false, + true, true, true, /* Just always hide parent, prefer to not add an extra user option for this. */ FILE_TYPE_BLENDERLIB, @@ -246,6 +248,11 @@ void AssetList::clear(bContext *C) WM_main_add_notifier(NC_ASSET | ND_ASSET_LIST, nullptr); } +AssetHandle AssetList::asset_get_by_index(int index) const +{ + return {filelist_file(filelist_, index)}; +} + /** * \return True if the asset-list needs a UI redraw. */ @@ -472,6 +479,13 @@ asset_system::AssetLibrary *ED_assetlist_library_get_once_available( return list->asset_library(); } +AssetHandle ED_assetlist_asset_get_by_index(const AssetLibraryReference *library_reference, + int asset_index) +{ + const AssetList *list = AssetListStorage::lookup_list(*library_reference); + return list->asset_get_by_index(asset_index); +} + ImBuf *ED_assetlist_asset_image_get(const AssetHandle *asset_handle) { ImBuf *imbuf = filelist_file_getimage(asset_handle->file_data); diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc index 076a332c472..d8525d4150f 100644 --- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc +++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc @@ -8,9 +8,15 @@ */ #include +#include + +#include "AS_asset_representation.h" +#include "AS_asset_representation.hh" #include "DNA_space_types.h" +#include "ED_asset.h" + #include "BKE_report.h" #include "BLI_utility_mixins.hh" @@ -19,17 +25,16 @@ #include "MEM_guardedalloc.h" -#include "ED_asset_handle.h" #include "ED_asset_temp_id_consumer.h" using namespace blender; class AssetTemporaryIDConsumer : NonCopyable, NonMovable { - const AssetHandle &handle_; + const AssetRepresentation *asset_; TempLibraryContext *temp_lib_context_ = nullptr; public: - AssetTemporaryIDConsumer(const AssetHandle &handle) : handle_(handle) + AssetTemporaryIDConsumer(const AssetRepresentation *asset) : asset_(asset) { } ~AssetTemporaryIDConsumer() @@ -41,20 +46,20 @@ class AssetTemporaryIDConsumer : NonCopyable, NonMovable { ID *get_local_id() { - return ED_asset_handle_get_local_id(&handle_); + return AS_asset_representation_local_id_get(asset_); } ID *import_id(ID_Type id_type, Main &bmain, ReportList &reports) { - const char *asset_name = ED_asset_handle_get_name(&handle_); - char blend_file_path[FILE_MAX_LIBEXTRA]; - ED_asset_handle_get_full_library_path(&handle_, blend_file_path); + const char *asset_name = AS_asset_representation_name_get(asset_); + std::string blend_file_path = AS_asset_representation_full_library_path_get(asset_); temp_lib_context_ = BLO_library_temp_load_id( - &bmain, blend_file_path, id_type, asset_name, &reports); + &bmain, blend_file_path.c_str(), id_type, asset_name, &reports); if (temp_lib_context_ == nullptr || temp_lib_context_->temp_id == nullptr) { - BKE_reportf(&reports, RPT_ERROR, "Unable to load %s from %s", asset_name, blend_file_path); + BKE_reportf( + &reports, RPT_ERROR, "Unable to load %s from %s", asset_name, blend_file_path.c_str()); return nullptr; } @@ -70,7 +75,7 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle) } BLI_assert(handle->file_data->asset != nullptr); return reinterpret_cast( - MEM_new(__func__, *handle)); + MEM_new(__func__, ED_asset_handle_get_representation(handle))); } void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer) diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 66fb3cb06a3..b4fa97a0e0a 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -665,7 +665,7 @@ static void curve_draw_exec_precalc(wmOperator *op) selem_prev = selem; } scale_px = ((len_3d > 0.0f) && (len_2d > 0.0f)) ? (len_3d / len_2d) : 0.0f; - float error_threshold = (cps->error_threshold * U.dpi_fac) * scale_px; + float error_threshold = (cps->error_threshold * UI_SCALE_FAC) * scale_px; RNA_property_float_set(op->ptr, prop, error_threshold); } @@ -684,7 +684,7 @@ static void curve_draw_exec_precalc(wmOperator *op) } if (len_squared_v2v2(selem_first->mval, selem_last->mval) <= - square_f(STROKE_CYCLIC_DIST_PX * U.dpi_fac)) { + square_f(STROKE_CYCLIC_DIST_PX * UI_SCALE_FAC)) { use_cyclic = true; } } diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc index a05ecfcaed3..7e267b93101 100644 --- a/source/blender/editors/curves/intern/curves_ops.cc +++ b/source/blender/editors/curves/intern/curves_ops.cc @@ -30,7 +30,7 @@ #include "BKE_geometry_set.hh" #include "BKE_layer.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_object.h" diff --git a/source/blender/editors/curves/intern/curves_selection.cc b/source/blender/editors/curves/intern/curves_selection.cc index 273e34909dd..1800d3ba17b 100644 --- a/source/blender/editors/curves/intern/curves_selection.cc +++ b/source/blender/editors/curves/intern/curves_selection.cc @@ -167,7 +167,7 @@ bool has_anything_selected(const VArray &varray, const IndexRange range_to bool has_anything_selected(const bke::CurvesGeometry &curves) { const VArray selection = curves.attributes().lookup(".selection"); - return !selection || contains(selection, curves.curves_range(), true); + return !selection || contains(selection, selection.index_range(), true); } bool has_anything_selected(const GSpan selection) @@ -400,9 +400,9 @@ void select_random(bke::CurvesGeometry &curves, selection.finish(); } -static void apply_selection_operation_at_index(GMutableSpan selection, - const int index, - const eSelectOp sel_op) +void apply_selection_operation_at_index(GMutableSpan selection, + const int index, + const eSelectOp sel_op) { if (selection.type().is()) { MutableSpan selection_typed = selection.typed(); @@ -440,14 +440,15 @@ static void apply_selection_operation_at_index(GMutableSpan selection, } } -static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph, - const ARegion *region, - const RegionView3D *rv3d, - const Object &object, - const bke::CurvesGeometry &curves, - float2 mouse_pos, - float radius, - FindClosestData &closest_data) +static std::optional find_closest_point_to_screen_co( + const Depsgraph &depsgraph, + const ARegion *region, + const RegionView3D *rv3d, + const Object &object, + const bke::CurvesGeometry &curves, + float2 mouse_pos, + float radius, + const FindClosestData &initial_closest) { float4x4 projection; ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr()); @@ -456,10 +457,10 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph, bke::crazyspace::get_evaluated_curves_deformation(depsgraph, object); const float radius_sq = pow2f(radius); - closest_data = threading::parallel_reduce( + const FindClosestData new_closest_data = threading::parallel_reduce( curves.points_range(), 1024, - closest_data, + initial_closest, [&](const IndexRange point_range, const FindClosestData &init) { FindClosestData best_match = init; for (const int point_i : point_range) { @@ -490,21 +491,23 @@ static bool find_closest_point_to_screen_co(const Depsgraph &depsgraph, } return b; }); - if (closest_data.index >= 0) { - return true; + + if (new_closest_data.distance < initial_closest.distance) { + return new_closest_data; } - return false; + return {}; } -static bool find_closest_curve_to_screen_co(const Depsgraph &depsgraph, - const ARegion *region, - const RegionView3D *rv3d, - const Object &object, - const bke::CurvesGeometry &curves, - float2 mouse_pos, - float radius, - FindClosestData &closest_data) +static std::optional find_closest_curve_to_screen_co( + const Depsgraph &depsgraph, + const ARegion *region, + const RegionView3D *rv3d, + const Object &object, + const bke::CurvesGeometry &curves, + float2 mouse_pos, + float radius, + const FindClosestData &initial_closest) { float4x4 projection; ED_view3d_ob_project_mat_get(rv3d, &object, projection.ptr()); @@ -515,10 +518,10 @@ static bool find_closest_curve_to_screen_co(const Depsgraph &depsgraph, const float radius_sq = pow2f(radius); const OffsetIndices points_by_curve = curves.points_by_curve(); - closest_data = threading::parallel_reduce( + const FindClosestData new_closest_data = threading::parallel_reduce( curves.curves_range(), 256, - closest_data, + initial_closest, [&](const IndexRange curves_range, const FindClosestData &init) { FindClosestData best_match = init; for (const int curve_i : curves_range) { @@ -578,64 +581,44 @@ static bool find_closest_curve_to_screen_co(const Depsgraph &depsgraph, return b; }); - if (closest_data.index >= 0) { - return true; + if (new_closest_data.distance < initial_closest.distance) { + return new_closest_data; } - return false; + return {}; } -bool select_pick(const ViewContext &vc, - const Object &object, - bke::CurvesGeometry &curves, - const eAttrDomain selection_domain, - const SelectPick_Params ¶ms, - const int2 coord, - FindClosestData initial) +std::optional closest_elem_find_screen_space( + const ViewContext &vc, + const Object &object, + bke::CurvesGeometry &curves, + const eAttrDomain domain, + const int2 coord, + const FindClosestData &initial_closest) { - FindClosestData closest = initial; - - bool found = false; - if (selection_domain == ATTR_DOMAIN_POINT) { - found = find_closest_point_to_screen_co(*vc.depsgraph, - vc.region, - vc.rv3d, - object, - curves, - float2(coord), - ED_view3d_select_dist_px(), - closest); + switch (domain) { + case ATTR_DOMAIN_POINT: + return find_closest_point_to_screen_co(*vc.depsgraph, + vc.region, + vc.rv3d, + object, + curves, + float2(coord), + ED_view3d_select_dist_px(), + initial_closest); + case ATTR_DOMAIN_CURVE: + return find_closest_curve_to_screen_co(*vc.depsgraph, + vc.region, + vc.rv3d, + object, + curves, + float2(coord), + ED_view3d_select_dist_px(), + initial_closest); + default: + BLI_assert_unreachable(); + return {}; } - else if (selection_domain == ATTR_DOMAIN_CURVE) { - found = find_closest_curve_to_screen_co(*vc.depsgraph, - vc.region, - vc.rv3d, - object, - curves, - float2(coord), - ED_view3d_select_dist_px(), - closest); - } - - bool deselected = false; - if (params.sel_op == SEL_OP_SET) { - bke::GSpanAttributeWriter selection = ensure_selection_attribute( - curves, selection_domain, CD_PROP_BOOL); - if (found || ((params.deselect_all && has_anything_selected(selection.span)))) { - fill_selection_false(selection.span); - deselected = true; - } - selection.finish(); - } - - if (found) { - bke::GSpanAttributeWriter selection = ensure_selection_attribute( - curves, selection_domain, CD_PROP_BOOL); - apply_selection_operation_at_index(selection.span, closest.index, params.sel_op); - selection.finish(); - } - - return deselected || found; } bool select_box(const ViewContext &vc, diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc index 516d67220cb..2120f711c6a 100644 --- a/source/blender/editors/geometry/geometry_attributes.cc +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -16,7 +16,7 @@ #include "BKE_deform.h" #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object_deform.h" #include "BKE_paint.h" #include "BKE_report.h" @@ -591,9 +591,15 @@ static bool geometry_color_attribute_convert_poll(bContext *C) if (GS(id->name) != ID_ME) { return false; } - - CustomDataLayer *layer = BKE_id_attributes_active_color_get(id); - if (layer == nullptr) { + const Mesh *mesh = static_cast(ob->data); + const char *name = mesh->active_color_attribute; + const bke::AttributeAccessor attributes = mesh->attributes(); + const std::optional meta_data = attributes.lookup_meta_data(name); + if (!meta_data) { + return false; + } + if (!(ATTR_DOMAIN_AS_MASK(meta_data->domain) & ATTR_DOMAIN_MASK_COLOR) || + !(CD_TYPE_AS_MASK(meta_data->data_type) & CD_MASK_COLOR_ALL)) { return false; } @@ -603,10 +609,10 @@ static bool geometry_color_attribute_convert_poll(bContext *C) static int geometry_color_attribute_convert_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); - ID *ob_data = static_cast(ob->data); - CustomDataLayer *layer = BKE_id_attributes_active_color_get(ob_data); - ED_geometry_attribute_convert(static_cast(ob->data), - layer->name, + Mesh *mesh = static_cast(ob->data); + const char *name = mesh->active_color_attribute; + ED_geometry_attribute_convert(mesh, + name, eCustomDataType(RNA_enum_get(op->ptr, "data_type")), eAttrDomain(RNA_enum_get(op->ptr, "domain")), op->reports); @@ -619,9 +625,8 @@ static int geometry_color_attribute_convert_invoke(bContext *C, { Object *ob = ED_object_context(C); Mesh *mesh = static_cast(ob->data); - - const bke::AttributeMetaData meta_data = *mesh->attributes().lookup_meta_data( - BKE_id_attributes_active_color_get(&mesh->id)->name); + const char *name = mesh->active_color_attribute; + const bke::AttributeMetaData meta_data = *mesh->attributes().lookup_meta_data(name); PropertyRNA *prop = RNA_struct_find_property(op->ptr, "domain"); if (!RNA_property_is_set(op->ptr, prop)) { diff --git a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c index cde702294d0..ca31d8e43ad 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/arrow3d_gizmo.c @@ -126,7 +126,7 @@ static void arrow_draw_geom(const ArrowGizmo3D *arrow, if (draw_options & ED_GIZMO_ARROW_DRAW_FLAG_STEM) { const float stem_width = arrow->gizmo.line_width * U.pixelsize + - (select ? ARROW_SELECT_THRESHOLD_PX * U.dpi_fac : 0); + (select ? ARROW_SELECT_THRESHOLD_PX * UI_SCALE_FAC : 0); immUniform1f("lineWidth", stem_width); wm_gizmo_vec_draw(color, vec, ARRAY_SIZE(vec), pos, GPU_PRIM_LINE_STRIP); } diff --git a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c index dca19dcf516..731b1b07193 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/button2d_gizmo.c @@ -251,14 +251,14 @@ static void button2d_draw_intern(const bContext *C, if (is_3d) { const float fac = 2.0f; GPU_matrix_translate_2f(-(fac / 2), -(fac / 2)); - GPU_matrix_scale_2f(fac / (ICON_DEFAULT_WIDTH * UI_DPI_FAC), - fac / (ICON_DEFAULT_HEIGHT * UI_DPI_FAC)); + GPU_matrix_scale_2f(fac / (ICON_DEFAULT_WIDTH * UI_SCALE_FAC), + fac / (ICON_DEFAULT_HEIGHT * UI_SCALE_FAC)); pos[0] = 1.0f; pos[1] = 1.0f; } else { - pos[0] = gz->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * UI_DPI_FAC; - pos[1] = gz->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * UI_DPI_FAC; + pos[0] = gz->matrix_basis[3][0] - (ICON_DEFAULT_WIDTH / 2.0) * UI_SCALE_FAC; + pos[1] = gz->matrix_basis[3][1] - (ICON_DEFAULT_HEIGHT / 2.0) * UI_SCALE_FAC; GPU_matrix_pop(); need_to_pop = false; } @@ -327,7 +327,7 @@ static int gizmo_button2d_cursor_get(wmGizmo *gz) static bool gizmo_button2d_bounds(bContext *C, wmGizmo *gz, rcti *r_bounding_box) { ScrArea *area = CTX_wm_area(C); - float rad = CIRCLE_RESOLUTION_3D * U.dpi_fac / 2.0f; + float rad = CIRCLE_RESOLUTION_3D * UI_SCALE_FAC / 2.0f; const float *co = NULL; float matrix_final[4][4]; float co_proj[3]; diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index 8021d976add..86ced9bd5cf 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -23,7 +23,7 @@ #include "BLF_api.h" #include "BLT_translation.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -33,7 +33,7 @@ #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "WM_api.h" diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 8526a98f0be..458715ede1d 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -23,15 +23,15 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_screen.h" #include "BKE_tracking.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_windowmanager_types.h" diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 7041dd25750..f3428d01985 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -24,7 +24,7 @@ #include "BLT_translation.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -36,7 +36,7 @@ #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_image.h" #include "BKE_material.h" #include "BKE_paint.h" diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index 8a98dcb57fc..ff3455f0b7d 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -16,11 +16,11 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_scene_types.h" #include "BKE_fcurve.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_report.h" #include "ED_anim_api.h" diff --git a/source/blender/editors/gpencil/gpencil_add_blank.c b/source/blender/editors/gpencil/gpencil_add_blank.c index b88b33913ac..d6863ccfc01 100644 --- a/source/blender/editors/gpencil/gpencil_add_blank.c +++ b/source/blender/editors/gpencil/gpencil_add_blank.c @@ -8,14 +8,14 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/editors/gpencil/gpencil_add_lineart.c b/source/blender/editors/gpencil/gpencil_add_lineart.c index 2ac26c927f4..c3a4a8a928e 100644 --- a/source/blender/editors/gpencil/gpencil_add_lineart.c +++ b/source/blender/editors/gpencil/gpencil_add_lineart.c @@ -8,15 +8,15 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_brush.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/editors/gpencil/gpencil_add_monkey.c b/source/blender/editors/gpencil/gpencil_add_monkey.c index 00066d5f2b8..6d5688230dc 100644 --- a/source/blender/editors/gpencil/gpencil_add_monkey.c +++ b/source/blender/editors/gpencil/gpencil_add_monkey.c @@ -8,14 +8,14 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/editors/gpencil/gpencil_add_stroke.c b/source/blender/editors/gpencil/gpencil_add_stroke.c index 8522c81cb39..652c9ff6c8b 100644 --- a/source/blender/editors/gpencil/gpencil_add_stroke.c +++ b/source/blender/editors/gpencil/gpencil_add_stroke.c @@ -8,14 +8,14 @@ #include "BLI_math.h" #include "BLI_utildefines.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index 664988d395c..c38a0ef7bef 100644 --- a/source/blender/editors/gpencil/gpencil_armature.c +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -19,7 +19,7 @@ #include "BLI_utildefines.h" #include "DNA_armature_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" @@ -27,8 +27,8 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_object_deform.h" @@ -525,7 +525,7 @@ static bool gpencil_generate_weights_poll(bContext *C) return false; } - if (ob->type != OB_GPENCIL) { + if (ob->type != OB_GPENCIL_LEGACY) { return false; } diff --git a/source/blender/editors/gpencil/gpencil_bake_animation.cc b/source/blender/editors/gpencil/gpencil_bake_animation.cc index 4ef2cf9ffd6..b2b639a9cc9 100644 --- a/source/blender/editors/gpencil/gpencil_bake_animation.cc +++ b/source/blender/editors/gpencil/gpencil_bake_animation.cc @@ -12,7 +12,7 @@ #include "BLI_math.h" #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -20,9 +20,9 @@ #include "BKE_anim_data.h" #include "BKE_context.h" #include "BKE_duplilist.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -86,7 +86,7 @@ static bool gpencil_bake_grease_pencil_animation_poll(bContext *C) } /* Check if grease pencil or empty for dupli groups. */ - if ((obact == nullptr) || !ELEM(obact->type, OB_GPENCIL, OB_EMPTY)) { + if ((obact == nullptr) || !ELEM(obact->type, OB_GPENCIL_LEGACY, OB_EMPTY)) { return false; } @@ -135,7 +135,7 @@ static void gpencil_bake_duplilist(Depsgraph *depsgraph, Scene *scene, Object *o ListBase *lb; lb = object_duplilist(depsgraph, scene, ob); LISTBASE_FOREACH (DupliObject *, dob, lb) { - if (dob->ob->type != OB_GPENCIL) { + if (dob->ob->type != OB_GPENCIL_LEGACY) { continue; } @@ -154,7 +154,7 @@ static void gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene /* Add active object. In some files this could not be in selected array. */ Object *obact = CTX_data_active_object(C); - if (obact->type == OB_GPENCIL) { + if (obact->type == OB_GPENCIL_LEGACY) { elem = MEM_cnew(__func__); elem->ob = obact; BLI_addtail(list, elem); @@ -170,7 +170,7 @@ static void gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene continue; } /* Add selected objects. */ - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { elem = MEM_cnew(__func__); elem->ob = ob; BLI_addtail(list, elem); diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 5cea5cc0780..2641d1903c5 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -24,7 +24,7 @@ #include "DNA_anim_types.h" #include "DNA_collection_types.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" #include "DNA_object_types.h" @@ -39,8 +39,8 @@ #include "BKE_curve.h" #include "BKE_fcurve.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_image.h" #include "BKE_layer.h" #include "BKE_main.h" @@ -1468,7 +1468,7 @@ static bool gpencil_convert_poll(bContext *C) Object *ob = CTX_data_active_object(C); Scene *scene = CTX_data_scene(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c876832bc0c..be89e63c9c5 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -25,7 +25,7 @@ #include "DNA_anim_types.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -41,8 +41,8 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_fcurve_driver.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" @@ -221,7 +221,7 @@ static int gpencil_layer_add_exec(bContext *C, wmOperator *op) else { /* GP Object */ Object *ob = CTX_data_active_object(C); - if ((ob != NULL) && (ob->type == OB_GPENCIL)) { + if ((ob != NULL) && (ob->type == OB_GPENCIL_LEGACY)) { gpd = (bGPdata *)ob->data; PropertyRNA *prop; char name[128]; @@ -536,7 +536,7 @@ enum { static bool gpencil_layer_duplicate_object_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } @@ -561,7 +561,7 @@ static int gpencil_layer_duplicate_object_exec(bContext *C, wmOperator *op) bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd_src); CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - if ((ob == ob_src) || (ob->type != OB_GPENCIL)) { + if ((ob == ob_src) || (ob->type != OB_GPENCIL_LEGACY)) { continue; } bGPdata *gpd_dst = (bGPdata *)ob->data; @@ -2225,7 +2225,7 @@ static bool gpencil_vertex_group_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { Main *bmain = CTX_data_main(C); const bGPdata *gpd = (const bGPdata *)ob->data; if (BKE_id_is_editable(bmain, &ob->id) && BKE_id_is_editable(bmain, ob->data) && @@ -2243,7 +2243,7 @@ static bool gpencil_vertex_group_weight_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { Main *bmain = CTX_data_main(C); const bGPdata *gpd = (const bGPdata *)ob->data; if (BKE_id_is_editable(bmain, &ob->id) && BKE_id_is_editable(bmain, ob->data) && @@ -2839,7 +2839,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) bool ok = false; /* Ensure we're in right mode and that the active object is correct */ - if (!ob_active || ob_active->type != OB_GPENCIL) { + if (!ob_active || ob_active->type != OB_GPENCIL_LEGACY) { return OPERATOR_CANCELLED; } @@ -2850,7 +2850,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) /* Ensure all rotations are applied before */ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { - if (ob_iter->type == OB_GPENCIL) { + if (ob_iter->type == OB_GPENCIL_LEGACY) { if ((ob_iter->rot[0] != 0) || (ob_iter->rot[1] != 0) || (ob_iter->rot[2] != 0)) { BKE_report(op->reports, RPT_ERROR, "Apply all rotations before join objects"); return OPERATOR_CANCELLED; @@ -2878,7 +2878,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) /* loop and join all data */ CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) { - if ((ob_iter->type == OB_GPENCIL) && (ob_iter != ob_active)) { + if ((ob_iter->type == OB_GPENCIL_LEGACY) && (ob_iter != ob_active)) { /* we assume that each datablock is not already used in active object */ if (ob_active->data != ob_iter->data) { Object *ob_src = ob_iter; @@ -3046,7 +3046,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) static bool gpencil_active_material_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if (ob && ob->data && (ob->type == OB_GPENCIL)) { + if (ob && ob->data && (ob->type == OB_GPENCIL_LEGACY)) { short *totcolp = BKE_object_material_len_p(ob); return *totcolp > 0; } @@ -3648,7 +3648,7 @@ void GPENCIL_OT_set_active_material(wmOperatorType *ot) static bool gpencil_materials_copy_to_object_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } short *totcolp = BKE_object_material_len_p(ob); @@ -3667,7 +3667,7 @@ static int gpencil_materials_copy_to_object_exec(bContext *C, wmOperator *op) Material *ma_active = BKE_gpencil_material(ob_src, ob_src->actcol); CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - if ((ob == ob_src) || (ob->type != OB_GPENCIL)) { + if ((ob == ob_src) || (ob->type != OB_GPENCIL_LEGACY)) { continue; } /* Duplicate materials. */ @@ -3763,7 +3763,7 @@ bool ED_gpencil_add_lattice_modifier(const bContext *C, static int gpencil_layer_mask_add_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return OPERATOR_CANCELLED; } @@ -3831,7 +3831,7 @@ void GPENCIL_OT_layer_mask_add(wmOperatorType *ot) static int gpencil_layer_mask_remove_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 6ede4726821..a444b8cbf2c 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -23,8 +23,8 @@ #include "BLT_translation.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -37,9 +37,9 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_library.h" @@ -91,7 +91,7 @@ static bool gpencil_stroke_edit_poll(bContext *C) { /* edit only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } @@ -104,7 +104,7 @@ static bool gpencil_strokes_edit3d_poll(bContext *C) { /* edit only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } @@ -119,12 +119,12 @@ static bool gpencil_editmode_toggle_poll(bContext *C) { /* edit only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } /* if using gpencil object, use this gpd */ - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { return ob->data != NULL; } @@ -134,7 +134,7 @@ static bool gpencil_editmode_toggle_poll(bContext *C) static bool gpencil_stroke_not_in_curve_edit_mode(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } bGPdata *gpd = (bGPdata *)ob->data; @@ -159,7 +159,7 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op) short mode; /* if using a gpencil object, use this datablock */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { gpd = ob->data; is_object = true; } @@ -261,7 +261,7 @@ static bool gpencil_selectmode_toggle_poll(bContext *C) { /* edit only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL) || (ob->mode != OB_MODE_EDIT_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY) || (ob->mode != OB_MODE_EDIT_GPENCIL)) { return false; } @@ -341,7 +341,7 @@ static bool gpencil_paintmode_toggle_poll(bContext *C) { /* if using gpencil object, use this gpd */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { return ob->data != NULL; } return ED_gpencil_data_get_active(C) != NULL; @@ -360,7 +360,7 @@ static int gpencil_paintmode_toggle_exec(bContext *C, wmOperator *op) short mode; /* if using a gpencil object, use this datablock */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { gpd = ob->data; is_object = true; } @@ -457,7 +457,7 @@ static bool gpencil_sculptmode_toggle_poll(bContext *C) { /* if using gpencil object, use this gpd */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { return ob->data != NULL; } return ED_gpencil_data_get_active(C) != NULL; @@ -476,7 +476,7 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op) short mode; /* if using a gpencil object, use this datablock */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { gpd = ob->data; is_object = true; } @@ -566,7 +566,7 @@ static bool gpencil_weightmode_toggle_poll(bContext *C) { /* if using gpencil object, use this gpd */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { return ob->data != NULL; } return ED_gpencil_data_get_active(C) != NULL; @@ -585,7 +585,7 @@ static int gpencil_weightmode_toggle_exec(bContext *C, wmOperator *op) short mode; /* if using a gpencil object, use this datablock */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { gpd = ob->data; is_object = true; } @@ -678,7 +678,7 @@ static bool gpencil_vertexmode_toggle_poll(bContext *C) { /* if using gpencil object, use this gpd */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { return ob->data != NULL; } return ED_gpencil_data_get_active(C) != NULL; @@ -696,7 +696,7 @@ static int gpencil_vertexmode_toggle_exec(bContext *C, wmOperator *op) short mode; /* if using a gpencil object, use this datablock */ Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { gpd = ob->data; is_object = true; } @@ -1715,6 +1715,10 @@ static int gpencil_strokes_paste_exec(bContext *C, wmOperator *op) */ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) { + /* Active frame is copied later, so don't need duplicate the stroke here. */ + if (gpl->actframe == gpf) { + continue; + } if (gpf->flag & GP_FRAME_SELECT) { if (gpf) { /* Create new stroke */ @@ -2818,7 +2822,7 @@ static bool gpencil_snap_poll(bContext *C) ScrArea *area = CTX_wm_area(C); Object *ob = CTX_data_active_object(C); - return (ob != NULL) && (ob->type == OB_GPENCIL) && + return (ob != NULL) && (ob->type == OB_GPENCIL_LEGACY) && ((area != NULL) && (area->spacetype == SPACE_VIEW3D)); } @@ -4072,7 +4076,7 @@ void GPENCIL_OT_reproject(wmOperatorType *ot) static int gpencil_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return OPERATOR_CANCELLED; } @@ -5775,7 +5779,7 @@ bool ED_object_gpencil_exit(struct Main *bmain, Object *ob) static bool gpencil_merge_by_distance_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } bGPdata *gpd = (bGPdata *)ob->data; @@ -5862,7 +5866,7 @@ typedef enum eGP_NormalizeMode { static bool gpencil_stroke_normalize_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } bGPdata *gpd = (bGPdata *)ob->data; diff --git a/source/blender/editors/gpencil/gpencil_edit_curve.c b/source/blender/editors/gpencil/gpencil_edit_curve.c index cf29ce0755b..338072d15c8 100644 --- a/source/blender/editors/gpencil/gpencil_edit_curve.c +++ b/source/blender/editors/gpencil/gpencil_edit_curve.c @@ -12,13 +12,13 @@ #include #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_view3d_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -43,7 +43,7 @@ static bool gpencil_curve_edit_mode_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } bGPdata *gpd = (bGPdata *)ob->data; diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 20e9cc32c69..397f4d7c924 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -18,7 +18,7 @@ #include "BLT_translation.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_image_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" @@ -28,8 +28,8 @@ #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_image.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -798,7 +798,7 @@ static void gpencil_create_extensions_radius(tGPDfill *tgpf) } /* Don't check endpoint distances unless the bounding boxes of the strokes - are close enough together that they can plausibly be connected. */ + * are close enough together that they can plausibly be connected. */ if (!extended_bbox_overlap(gps->boundbox_min, gps->boundbox_max, gps2->boundbox_min, @@ -2325,7 +2325,7 @@ static bool gpencil_fill_poll(bContext *C) if (ED_operator_regionactive(C)) { ScrArea *area = CTX_wm_area(C); if (area->spacetype == SPACE_VIEW3D) { - if ((obact == NULL) || (obact->type != OB_GPENCIL) || + if ((obact == NULL) || (obact->type != OB_GPENCIL_LEGACY) || (obact->mode != OB_MODE_PAINT_GPENCIL)) { return false; } @@ -2480,7 +2480,7 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op) op->customdata = NULL; /* drawing batch cache is dirty now */ - if ((ob) && (ob->type == OB_GPENCIL) && (ob->data)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY) && (ob->data)) { bGPdata *gpd2 = ob->data; DEG_id_tag_update(&gpd2->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); gpd2->flag |= GP_DATA_CACHE_IS_DIRTY; diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index ad0f1f0dc34..c8714ce8e8e 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -23,7 +23,7 @@ #include "BLT_translation.h" #include "DNA_color_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -33,8 +33,8 @@ #include "BKE_colortools.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_report.h" #include "UI_interface.h" diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 8ff3f20cef3..24966ea5d7f 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -14,13 +14,13 @@ #include "BLI_ghash.h" #include "BLI_math.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "BKE_brush.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_report.h" @@ -424,7 +424,7 @@ static bool gpencil_strokes_merge_poll(bContext *C) { /* only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } @@ -459,7 +459,7 @@ static int gpencil_stroke_merge_exec(bContext *C, wmOperator *op) Object *ob = CTX_data_active_object(C); /* sanity checks */ - if (!ob || ob->type != OB_GPENCIL) { + if (!ob || ob->type != OB_GPENCIL_LEGACY) { return OPERATOR_CANCELLED; } @@ -556,7 +556,7 @@ static bool gpencil_stroke_merge_material_poll(bContext *C) { /* only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } diff --git a/source/blender/editors/gpencil/gpencil_mesh.cc b/source/blender/editors/gpencil/gpencil_mesh.cc index 2b01fce5bf8..9ad00ef174e 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.cc +++ b/source/blender/editors/gpencil/gpencil_mesh.cc @@ -13,14 +13,14 @@ #include "BLI_math.h" #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "BKE_anim_data.h" #include "BKE_context.h" #include "BKE_duplilist.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -215,7 +215,7 @@ static int gpencil_bake_mesh_animation_exec(bContext *C, wmOperator *op) if (target == GP_TARGET_OB_SELECTED) { ob_gpencil = BKE_view_layer_non_active_selected_object(scene, CTX_data_view_layer(C), v3d); if (ob_gpencil != nullptr) { - if (ob_gpencil->type != OB_GPENCIL) { + if (ob_gpencil->type != OB_GPENCIL_LEGACY) { BKE_report(op->reports, RPT_WARNING, "Target object not a grease pencil, ignoring!"); ob_gpencil = nullptr; } diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 85cc281ca90..43d82de79dc 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -15,7 +15,7 @@ #include "BKE_paint.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -171,7 +171,7 @@ static bool gpencil_stroke_sculptmode_poll(bContext *C) return ((gpd) && (gpd->flag & GP_DATA_STROKE_EDITMODE)); } - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { return GPENCIL_SCULPT_MODE(gpd); } @@ -184,7 +184,7 @@ static bool gpencil_stroke_weightmode_poll(bContext *C) bGPdata *gpd = CTX_data_gpencil_data(C); Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { return GPENCIL_WEIGHT_MODE(gpd); } @@ -197,7 +197,7 @@ static bool gpencil_stroke_vertexmode_poll(bContext *C) bGPdata *gpd = CTX_data_gpencil_data(C); Object *ob = CTX_data_active_object(C); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { return (gpd && (gpd->flag & GP_DATA_STROKE_VERTEXMODE)); } diff --git a/source/blender/editors/gpencil/gpencil_ops_versioning.c b/source/blender/editors/gpencil/gpencil_ops_versioning.c index 60b58b6f513..9c85754f3bd 100644 --- a/source/blender/editors/gpencil/gpencil_ops_versioning.c +++ b/source/blender/editors/gpencil/gpencil_ops_versioning.c @@ -16,13 +16,13 @@ #include "BLI_listbase.h" #include "BLI_math.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_object.h" @@ -92,7 +92,7 @@ static int gpencil_convert_old_files_exec(bContext *C, wmOperator *op) if ((!is_annotation) && (view_layer != NULL)) { Object *ob; ob = BKE_object_add_for_data( - bmain, scene, view_layer, OB_GPENCIL, "GP_Scene", &scene->gpd->id, false); + bmain, scene, view_layer, OB_GPENCIL_LEGACY, "GP_Scene", &scene->gpd->id, false); zero_v3(ob->loc); DEG_relations_tag_update(bmain); /* added object */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 669b09ed279..d4ec1ba76ae 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -25,7 +25,7 @@ #include "PIL_time.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -37,10 +37,10 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_update_cache.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_update_cache_legacy.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -296,7 +296,7 @@ static bool gpencil_draw_poll(bContext *C) /* only grease pencil object type */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } @@ -2051,7 +2051,7 @@ static bool gpencil_session_initdata(bContext *C, wmOperator *op, tGPsdata *p) return 0; } - if ((!obact) || (obact->type != OB_GPENCIL)) { + if ((!obact) || (obact->type != OB_GPENCIL_LEGACY)) { View3D *v3d = p->area->spacedata.first; /* if active object doesn't exist or isn't a GP Object, create one */ const float *cur = p->scene->cursor.location; @@ -3308,7 +3308,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event gpencil_guide_event_handling(C, op, event, p); } - if ((ob->type == OB_GPENCIL) && ((p->gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)) { + if ((ob->type == OB_GPENCIL_LEGACY) && ((p->gpd->flag & GP_DATA_STROKE_PAINTMODE) == 0)) { /* FIXME: use the mode switching operator, this misses notifiers, messages. */ /* Just set paintmode flag... */ p->gpd->flag |= GP_DATA_STROKE_PAINTMODE; diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index b693d4ae185..c33f2675a91 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -24,7 +24,7 @@ #include "PIL_time.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -37,8 +37,8 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_paint.h" diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index ab3edfdd4fa..7ced965fa04 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -24,7 +24,7 @@ #include "BLT_translation.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -37,10 +37,10 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" -#include "BKE_gpencil_update_cache.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" +#include "BKE_gpencil_update_cache_legacy.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_object_deform.h" @@ -1411,7 +1411,8 @@ static float gpencil_sculpt_rotation_eval_get(tGP_BrushEditData *gso, const GP_SpaceConversion *gsc = &gso->gsc; bGPDstroke *gps_orig = (gps_eval->runtime.gps_orig) ? gps_eval->runtime.gps_orig : gps_eval; - bGPDspoint *pt_orig = &gps_orig->points[pt_eval->runtime.idx_orig]; + bGPDspoint *pt_orig = (pt_eval->runtime.pt_orig) ? &gps_orig->points[pt_eval->runtime.idx_orig] : + pt_eval; bGPDspoint *pt_prev_eval = NULL; bGPDspoint *pt_orig_prev = NULL; if (idx_eval != 0) { diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 05718eb95e0..fd3effc144a 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -20,7 +20,7 @@ #include "BLI_rand.h" #include "BLI_utildefines.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -28,9 +28,9 @@ #include "DNA_space_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_material.h" #include "BKE_report.h" @@ -2039,24 +2039,16 @@ static bool gpencil_generic_stroke_select(bContext *C, /* init space conversion stuff */ gpencil_point_conversion_init(C, &gsc); + /* Use only object transform matrix because all layer transformations are already included + * in the evaluated stroke. */ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Object *ob_eval = depsgraph != NULL ? DEG_get_evaluated_object(depsgraph, ob) : ob; + float select_mat[4][4]; + copy_m4_m4(select_mat, ob_eval->object_to_world); + /* deselect all strokes first? */ - if (SEL_OP_USE_PRE_DESELECT(sel_op) || GPENCIL_PAINT_MODE(gpd)) { - /* Set selection index to 0. */ - gpd->select_last_index = 0; - - CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { - bGPDspoint *pt; - int i; - - for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { - pt->flag &= ~GP_SPOINT_SELECT; - } - - gps->flag &= ~GP_STROKE_SELECT; - BKE_gpencil_stroke_select_index_reset(gps); - } - CTX_DATA_END; - + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { + deselect_all_selected(C); changed = true; } @@ -2071,9 +2063,9 @@ static bool gpencil_generic_stroke_select(bContext *C, for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { bGPDspoint *pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; - /* Convert point coords to screen-space. */ - const bool is_inside = is_inside_fn( - gsc.region, gpstroke_iter.diff_mat, &pt_active->x, user_data); + /* Convert point coords to screen-space. Needs to use the evaluated point + * to consider modifiers. */ + const bool is_inside = is_inside_fn(gsc.region, select_mat, &pt->x, user_data); if (strokemode == false) { const bool is_select = (pt_active->flag & GP_SPOINT_SELECT) != 0; const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); @@ -2761,7 +2753,7 @@ static bool gpencil_select_vertex_color_poll(bContext *C) { ToolSettings *ts = CTX_data_tool_settings(C); Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } bGPdata *gpd = (bGPdata *)ob->data; diff --git a/source/blender/editors/gpencil/gpencil_trace_ops.c b/source/blender/editors/gpencil/gpencil_trace_ops.c index 1a18e10412e..773c23f4d8e 100644 --- a/source/blender/editors/gpencil/gpencil_trace_ops.c +++ b/source/blender/editors/gpencil/gpencil_trace_ops.c @@ -11,13 +11,13 @@ #include "BLT_translation.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_image.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -312,7 +312,7 @@ static int gpencil_trace_image_exec(bContext *C, wmOperator *op) NULL; if (job->ob_gpencil != NULL) { - if (job->ob_gpencil->type != OB_GPENCIL) { + if (job->ob_gpencil->type != OB_GPENCIL_LEGACY) { BKE_report(op->reports, RPT_WARNING, "Target object not a grease pencil, ignoring!"); job->ob_gpencil = NULL; } diff --git a/source/blender/editors/gpencil/gpencil_trace_utils.c b/source/blender/editors/gpencil/gpencil_trace_utils.c index 75e4ef3d9b4..e148ad39f4d 100644 --- a/source/blender/editors/gpencil/gpencil_trace_utils.c +++ b/source/blender/editors/gpencil/gpencil_trace_utils.c @@ -14,13 +14,13 @@ #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_image.h" #include "BKE_main.h" #include "BKE_material.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_image_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" diff --git a/source/blender/editors/gpencil/gpencil_undo.cc b/source/blender/editors/gpencil/gpencil_undo.cc index 1062c2edc6b..885ca9b89f3 100644 --- a/source/blender/editors/gpencil/gpencil_undo.cc +++ b/source/blender/editors/gpencil/gpencil_undo.cc @@ -10,7 +10,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_listBase.h" #include "DNA_object_types.h" #include "DNA_windowmanager_types.h" @@ -19,7 +19,7 @@ #include "BKE_blender_undo.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_undo_system.h" #include "ED_gpencil.h" diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 0d61cbbdc6f..fef369427ad 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -26,7 +26,7 @@ #include "DNA_brush_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" @@ -41,9 +41,9 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_object.h" @@ -94,7 +94,7 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ScrArea *area, Object *ob, Pointer case SPACE_TOPBAR: /* Top-bar */ case SPACE_VIEW3D: /* 3D-View */ { - if (ob && (ob->type == OB_GPENCIL)) { + if (ob && (ob->type == OB_GPENCIL_LEGACY)) { /* GP Object. */ if (r_ptr) { RNA_id_pointer_create(&ob->id, r_ptr); @@ -244,7 +244,7 @@ bGPdata *ED_annotation_data_get_active_direct(ID *screen_id, ScrArea *area, Scen bGPdata *ED_gpencil_data_get_active(const bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return NULL; } return ob->data; @@ -281,7 +281,7 @@ bool ED_gpencil_data_owner_is_annotation(PointerRNA *owner_ptr) bool ED_gpencil_has_keyframe_v3d(Scene *UNUSED(scene), Object *ob, int cfra) { - if (ob && ob->data && (ob->type == OB_GPENCIL)) { + if (ob && ob->data && (ob->type == OB_GPENCIL_LEGACY)) { bGPDlayer *gpl = BKE_gpencil_layer_active_get(ob->data); if (gpl) { if (gpl->actframe) { @@ -313,7 +313,7 @@ bool gpencil_add_poll(bContext *C) bool gpencil_active_layer_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } bGPdata *gpd = (bGPdata *)ob->data; @@ -894,7 +894,7 @@ void ED_gpencil_drawing_reference_get(const Scene *scene, /* if using a gpencil object at cursor mode, can use the location of the object */ if (align_flag & GP_PROJECT_VIEWSPACE) { - if (ob && (ob->type == OB_GPENCIL)) { + if (ob && (ob->type == OB_GPENCIL_LEGACY)) { /* fallback (no strokes) - use cursor or object location */ if (align_flag & GP_PROJECT_CURSOR) { /* use 3D-cursor */ @@ -984,7 +984,7 @@ void ED_gpencil_project_stroke_to_plane(const Scene *scene, else if (axis < 3) { plane_normal[axis] = 1.0f; /* if object, apply object rotation */ - if (ob && (ob->type == OB_GPENCIL)) { + if (ob && (ob->type == OB_GPENCIL_LEGACY)) { float mat[4][4]; copy_m4_m4(mat, ob->object_to_world); @@ -1206,7 +1206,7 @@ void ED_gpencil_project_point_to_plane(const Scene *scene, else if (axis < 3) { plane_normal[axis] = 1.0f; /* if object, apply object rotation */ - if (ob && (ob->type == OB_GPENCIL)) { + if (ob && (ob->type == OB_GPENCIL_LEGACY)) { float mat[4][4]; copy_m4_m4(mat, ob->object_to_world); if ((ts->gpencil_v3d_align & GP_PROJECT_CURSOR) == 0) { @@ -1407,7 +1407,7 @@ Object *ED_gpencil_add_object(bContext *C, const float loc[3], ushort local_view { const float rot[3] = {0.0f}; - Object *ob = ED_object_add_type(C, OB_GPENCIL, NULL, loc, rot, false, local_view_bits); + Object *ob = ED_object_add_type(C, OB_GPENCIL_LEGACY, NULL, loc, rot, false, local_view_bits); /* create default brushes and colors */ ED_gpencil_add_defaults(C, ob); @@ -2124,7 +2124,7 @@ void ED_gpencil_update_color_uv(Main *bmain, Material *mat) Material *gps_ma = NULL; /* Read all strokes. */ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = ob->data; if (gpd == NULL) { continue; @@ -2761,7 +2761,7 @@ void ED_gpencil_tag_scene_gpencil(Scene *scene) /* Mark all grease pencil data-blocks of the scene. */ FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) { FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (collection, ob) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = (bGPdata *)ob->data; gpd->flag |= GP_DATA_CACHE_IS_DIRTY; DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); diff --git a/source/blender/editors/gpencil/gpencil_uv.c b/source/blender/editors/gpencil/gpencil_uv.c index 0144ffa07c7..2b9390a1beb 100644 --- a/source/blender/editors/gpencil/gpencil_uv.c +++ b/source/blender/editors/gpencil/gpencil_uv.c @@ -6,7 +6,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "BLI_blenlib.h" #include "BLI_math.h" @@ -15,8 +15,8 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "RNA_access.h" #include "RNA_define.h" @@ -326,7 +326,7 @@ static bool gpencil_transform_fill_poll(bContext *C) return false; } Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } bGPdata *gpd = (bGPdata *)ob->data; diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index 41f939813e4..f8ee23d7f9b 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -13,7 +13,7 @@ #include "BLI_math.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "BKE_context.h" @@ -99,7 +99,7 @@ static bool is_any_stroke_selected(bContext *C, const bool is_multiedit, const b static bool gpencil_vertexpaint_mode_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } @@ -799,7 +799,7 @@ static bool gpencil_material_to_vertex_poll(bContext *C) { /* only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } @@ -995,7 +995,7 @@ static bool gpencil_extract_palette_vertex_poll(bContext *C) { /* only supported with grease pencil objects */ Object *ob = CTX_data_active_object(C); - if ((ob == NULL) || (ob->type != OB_GPENCIL)) { + if ((ob == NULL) || (ob->type != OB_GPENCIL_LEGACY)) { return false; } diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index ca0729ecb94..3e96f406fd5 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -14,13 +14,13 @@ #include "BLT_translation.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_material.h" #include "BKE_report.h" diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index f73c6f8c658..85aa9e3a3d7 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -15,14 +15,14 @@ #include "DNA_armature_types.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "BKE_action.h" #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object_deform.h" diff --git a/source/blender/editors/include/ED_asset.h b/source/blender/editors/include/ED_asset.h index d7e7880e114..c5c835c6171 100644 --- a/source/blender/editors/include/ED_asset.h +++ b/source/blender/editors/include/ED_asset.h @@ -25,6 +25,7 @@ void ED_operatortypes_asset(void); #include "../asset/ED_asset_catalog.h" #include "../asset/ED_asset_filter.h" #include "../asset/ED_asset_handle.h" +#include "../asset/ED_asset_import.h" #include "../asset/ED_asset_library.h" #include "../asset/ED_asset_list.h" #include "../asset/ED_asset_mark_clear.h" diff --git a/source/blender/editors/include/ED_curves.h b/source/blender/editors/include/ED_curves.h index 311cc24d929..d6c058a3dd9 100644 --- a/source/blender/editors/include/ED_curves.h +++ b/source/blender/editors/include/ED_curves.h @@ -128,6 +128,9 @@ bke::GSpanAttributeWriter ensure_selection_attribute(bke::CurvesGeometry &curves eAttrDomain selection_domain, eCustomDataType create_type); +/** Apply a change to a single curve or point. Avoid using this when affecting many elements. */ +void apply_selection_operation_at_index(GMutableSpan selection, int index, eSelectOp sel_op); + /** * (De)select all the curves. * @@ -167,7 +170,7 @@ void select_random(bke::CurvesGeometry &curves, float probability); /** - * Helper struct for `select_pick`. + * Helper struct for `closest_elem_find_screen_space`. */ struct FindClosestData { int index = -1; @@ -175,15 +178,16 @@ struct FindClosestData { }; /** - * Select point or curve at a (screen-space) point. + * Find the closest screen-space point or curve in projected region-space. + * + * \return A new point or curve closer than the \a initial input, if one exists. */ -bool select_pick(const ViewContext &vc, - const Object &object, - bke::CurvesGeometry &curves, - eAttrDomain selection_domain, - const SelectPick_Params ¶ms, - int2 coord, - FindClosestData initial = {}); +std::optional closest_elem_find_screen_space(const ViewContext &vc, + const Object &object, + bke::CurvesGeometry &curves, + eAttrDomain domain, + int2 coord, + const FindClosestData &initial); /** * Select points or curves in a (screen-space) rectangle. diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index a4650126d85..9430aa348ab 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -109,7 +109,7 @@ enum { /* Display the hover region (edge or corner) of the underlying bounding box. */ ED_GIZMO_CAGE2D_STYLE_BOX = 0, /* Display the bounding box plus dots on four corners while hovering, usually used for - transforming a 2D shape. */ + * transforming a 2D shape. */ ED_GIZMO_CAGE2D_STYLE_BOX_TRANSFORM, /* Display the bounding circle while hovering. */ ED_GIZMO_CAGE2D_STYLE_CIRCLE, diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index c95e58f9559..bedbad8232f 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -417,7 +417,7 @@ void ED_gpencil_create_lineart(struct bContext *C, struct Object *ob); /* ------------ Object Utilities ------------ */ /** - * Helper function to create new #OB_GPENCIL Object. + * Helper function to create new #OB_GPENCIL_LEGACY Object. */ struct Object *ED_gpencil_add_object(struct bContext *C, const float loc[3], diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 10f20054840..7242b4cfd39 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -18,6 +18,7 @@ struct ViewContext; struct bContext; struct rcti; struct wmOperator; +struct wmKeyConfig; /* sculpt.cc */ @@ -28,6 +29,7 @@ bool ED_sculpt_mask_box_select(struct bContext *C, const struct rcti *rect, bool select); +void ED_keymap_sculpt(wmKeyConfig *keyconf); /* sculpt_transform.cc */ void ED_sculpt_update_modal_transform(struct bContext *C, struct Object *ob); diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index ccc53a43177..c154fa5af01 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -26,7 +26,6 @@ struct Object; struct Scene; struct SpaceImage; struct ToolSettings; -struct UVPackIsland_Params; struct View2D; struct ViewLayer; struct bContext; @@ -356,26 +355,6 @@ bool uv_coords_isect_udim(const struct Image *image, const int udim_grid[2], const float coords[2]); -/** - * Pack UV islands from multiple objects. - * - * \param scene: Scene containing the objects to be packed. - * \param objects: Array of Objects to pack. - * \param objects_len: Length of `objects` array. - * \param bmesh_override: BMesh array aligned with `objects`. - * Optional, when non-null this overrides object's BMesh. - * This is needed to perform UV packing on objects that aren't in edit-mode. - * \param udim_params: Parameters to specify UDIM target and UDIM source image. - * \param params: Parameters and options to pass to the packing engine. - * - */ -void ED_uvedit_pack_islands_multi(const struct Scene *scene, - Object **objects, - uint objects_len, - struct BMesh **bmesh_override, - const struct UVMapUDIM_Params *closest_udim, - const struct UVPackIsland_Params *params); - #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index dc3951ab770..9507ab4d476 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -48,6 +48,7 @@ struct bPoseChannel; struct bScreen; struct rctf; struct rcti; +struct wmEvent; struct wmGizmo; struct wmWindow; struct wmWindowManager; @@ -863,6 +864,20 @@ int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, float dist); void ED_view3d_select_id_validate(struct ViewContext *vc); +/** Check if the last auto-dist can be used. */ +bool ED_view3d_autodist_last_check(struct wmWindow *win, const struct wmEvent *event); +/** + * \return true when `r_ofs` is set. + * \warning #ED_view3d_autodist_last_check should be called first to ensure the data is available. + */ +bool ED_view3d_autodist_last_get(struct wmWindow *win, float r_ofs[3]); +void ED_view3d_autodist_last_set(struct wmWindow *win, + const struct wmEvent *event, + const float ofs[3], + const bool has_depth); +/** Clear and free auto-dist data. */ +void ED_view3d_autodist_last_clear(struct wmWindow *win); + /** * Get the world-space 3d location from a screen-space 2d point. * TODO: Implement #alphaoverride. We don't want to zoom into billboards. diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index de3169d045b..0ad39f8c05f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -319,12 +319,6 @@ enum { UI_BUT_CHECKBOX_INVERT = 1 << 25, }; -/* scale fixed button widths by this to account for DPI */ - -#define UI_DPI_FAC (U.dpi_fac) -/* 16 to copy ICON_DEFAULT_HEIGHT */ -#define UI_DPI_ICON_SIZE ((float)16 * UI_DPI_FAC) - /** * Button types, bits stored in 1 value... and a short even! * - bits 0-4: #uiBut.bitnr (0-31) @@ -2990,6 +2984,17 @@ uiBut *UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index); + +/** + * As above, but for a specified region. + * + * \return active button, NULL if none found or if it doesn't contain valid RNA data. + */ +uiBut *UI_region_active_but_prop_get(const struct ARegion *region, + struct PointerRNA *r_ptr, + struct PropertyRNA **r_prop, + int *r_index); + void UI_context_active_but_prop_handle(struct bContext *C, bool handle_undo); void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region); diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index fc03b0218c0..147b48b454e 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -8,6 +8,7 @@ #include +#include "BLI_function_ref.hh" #include "BLI_string_ref.hh" #include "BLI_vector.hh" @@ -17,8 +18,10 @@ namespace blender::nodes::geo_eval_log { struct GeometryAttributeInfo; } +struct PointerRNA; struct StructRNA; struct uiBlock; +struct uiList; struct uiSearchItems; namespace blender::ui { @@ -53,6 +56,60 @@ void attribute_search_add_items(StringRefNull str, } // namespace blender::ui +enum eUIListFilterResult { + /** Never show this item, even when filter results are inverted (#UILST_FLT_EXCLUDE). */ + UI_LIST_ITEM_NEVER_SHOW, + /** Show this item, unless filter results are inverted (#UILST_FLT_EXCLUDE). */ + UI_LIST_ITEM_FILTER_MATCHES, + /** Don't show this item, unless filter results are inverted (#UILST_FLT_EXCLUDE). */ + UI_LIST_ITEM_FILTER_MISMATCHES, +}; + +/** + * Function object for UI list item filtering that does the default name comparison with '*' + * wildcards. Create an instance of this once and pass it to #UI_list_filter_and_sort_items(), do + * NOT create an instance for every item, this would be costly. + */ +class uiListNameFilter { + /* Storage with an inline buffer for smaller strings (small buffer optimization). */ + struct { + char filter_buff[32]; + char *filter_dyn = nullptr; + } storage_; + char *filter_ = nullptr; + + public: + uiListNameFilter(uiList &list); + ~uiListNameFilter(); + + eUIListFilterResult operator()(const PointerRNA &itemptr, + blender::StringRefNull name, + int index); +}; + +using uiListItemFilterFn = blender::FunctionRef; +using uiListItemGetNameFn = + blender::FunctionRef; + +/** + * Filter list items using \a item_filter_fn and sort the result. This respects the normal UI list + * filter settings like alphabetical sorting (#UILST_FLT_SORT_ALPHA), and result inverting + * (#UILST_FLT_EXCLUDE). + * + * Call this from a #uiListType::filter_items callback with any #item_filter_fn. #uiListNameFilter + * can be used to apply the default name based filtering. + * + * \param get_name_fn: In some cases the name cannot be retrieved via RNA. This function can be set + * to provide the name still. + */ +void UI_list_filter_and_sort_items(uiList *ui_list, + const struct bContext *C, + uiListItemFilterFn item_filter_fn, + PointerRNA *dataptr, + const char *propname, + uiListItemGetNameFn get_name_fn = nullptr); + /** * Override this for all available view types. */ diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index f0bf04ed408..673ed93e1cd 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -60,11 +60,11 @@ enum eView2D_CommonViewTypes { #define V2D_SCROLL_MIN_ALPHA (0.4f) /* Minimum size needs to include outline which varies with line width. */ -#define V2D_SCROLL_MIN_WIDTH ((5.0f * U.dpi_fac) + (2.0f * U.pixelsize)) +#define V2D_SCROLL_MIN_WIDTH ((5.0f * UI_SCALE_FAC) + (2.0f * U.pixelsize)) /* When to start showing the full-width scroller. */ -#define V2D_SCROLL_HIDE_WIDTH (AREAMINX * U.dpi_fac) -#define V2D_SCROLL_HIDE_HEIGHT (HEADERY * U.dpi_fac) +#define V2D_SCROLL_HIDE_WIDTH (AREAMINX * UI_SCALE_FAC) +#define V2D_SCROLL_HIDE_HEIGHT (HEADERY * UI_SCALE_FAC) /** Scroll bars with 'handles' used for scale (zoom). */ #define V2D_SCROLL_HANDLE_HEIGHT (0.6f * U.widget_unit) @@ -74,7 +74,7 @@ enum eView2D_CommonViewTypes { #define V2D_SCROLL_HANDLE_SIZE_HOTSPOT (0.6f * U.widget_unit) /** Don't allow scroll thumb to show below this size (so it's never too small to click on). */ -#define V2D_SCROLL_THUMB_SIZE_MIN (30.0 * UI_DPI_FAC) +#define V2D_SCROLL_THUMB_SIZE_MIN (30.0 * UI_SCALE_FAC) /** \} */ @@ -490,8 +490,8 @@ void UI_view2d_smooth_view(const struct bContext *C, const struct rctf *cur, int smooth_viewtx); -#define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC) -#define UI_TIME_SCRUB_MARGIN_Y (23 * UI_DPI_FAC) +#define UI_MARKER_MARGIN_Y (42 * UI_SCALE_FAC) +#define UI_TIME_SCRUB_MARGIN_Y (23 * UI_SCALE_FAC) /** \} */ diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 5b1a17a0ac6..5ecf4c59ed8 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -20,6 +20,7 @@ set(INC ../../python ../../render ../../windowmanager + ../../../../intern/ghost ../../../../intern/guardedalloc ../../bmesh # RNA_prototypes.h diff --git a/source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.cc b/source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.cc index 0c33b9034ad..aca64ad0e24 100644 --- a/source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.cc +++ b/source/blender/editors/interface/eyedroppers/eyedropper_gpencil_color.cc @@ -17,12 +17,12 @@ #include "BLT_translation.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_space_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" @@ -342,7 +342,7 @@ static bool eyedropper_gpencil_poll(bContext *C) { /* Only valid if the current active object is grease pencil. */ Object *obact = CTX_data_active_object(C); - if ((obact == nullptr) || (obact->type != OB_GPENCIL)) { + if ((obact == nullptr) || (obact->type != OB_GPENCIL_LEGACY)) { return false; } diff --git a/source/blender/editors/interface/interface.cc b/source/blender/editors/interface/interface.cc index 94eeab27159..6f593c74fb9 100644 --- a/source/blender/editors/interface/interface.cc +++ b/source/blender/editors/interface/interface.cc @@ -280,7 +280,7 @@ static void ui_update_flexible_spacing(const ARegion *region, uiBlock *block) rcti rect; ui_but_to_pixelrect(&rect, region, block, static_cast(block->buttons.last)); const float buttons_width = float(rect.xmax) + UI_HEADER_OFFSET; - const float region_width = float(region->sizex) * U.dpi_fac; + const float region_width = float(region->sizex) * UI_SCALE_FAC; if (region_width <= buttons_width) { return; @@ -469,7 +469,7 @@ void ui_block_bounds_calc(uiBlock *block) /* hardcoded exception... but that one is annoying with larger safety */ uiBut *bt = static_cast(block->buttons.first); - const int xof = ((bt && STRPREFIX(bt->str, "ERROR")) ? 10 : 40) * U.dpi_fac; + const int xof = ((bt && STRPREFIX(bt->str, "ERROR")) ? 10 : 40) * UI_SCALE_FAC; block->safety.xmin = block->rect.xmin - xof; block->safety.ymin = block->rect.ymin - xof; @@ -4993,7 +4993,7 @@ int UI_preview_tile_size_x(void) int UI_preview_tile_size_y(void) { const uiStyle *style = UI_style_get(); - const float font_height = style->widget.points * UI_DPI_FAC; + const float font_height = style->widget.points * UI_SCALE_FAC; const float pad = PREVIEW_TILE_PAD; return round_fl_to_int(UI_preview_tile_size_y_no_label() + font_height + diff --git a/source/blender/editors/interface/interface_context_menu.cc b/source/blender/editors/interface/interface_context_menu.cc index 0d697cb268f..eb944b7f30e 100644 --- a/source/blender/editors/interface/interface_context_menu.cc +++ b/source/blender/editors/interface/interface_context_menu.cc @@ -180,8 +180,8 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *region, void *arg) uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Change Shortcut"), ICON_HAND); uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE); - const int bounds_offset[2] = {int(-100 * U.dpi_fac), int(36 * U.dpi_fac)}; - UI_block_bounds_set_popup(block, 6 * U.dpi_fac, bounds_offset); + const int bounds_offset[2] = {int(-100 * UI_SCALE_FAC), int(36 * UI_SCALE_FAC)}; + UI_block_bounds_set_popup(block, 6 * UI_SCALE_FAC, bounds_offset); shortcut_free_operator_property(prop); @@ -241,8 +241,8 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *region, void *arg) uiItemL(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Assign Shortcut"), ICON_HAND); uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE); - const int bounds_offset[2] = {int(-100 * U.dpi_fac), int(36 * U.dpi_fac)}; - UI_block_bounds_set_popup(block, 6 * U.dpi_fac, bounds_offset); + const int bounds_offset[2] = {int(-100 * UI_SCALE_FAC), int(36 * UI_SCALE_FAC)}; + UI_block_bounds_set_popup(block, 6 * UI_SCALE_FAC, bounds_offset); #ifdef USE_KEYMAP_ADD_HACK g_kmi_id_hack = kmi_id; diff --git a/source/blender/editors/interface/interface_draw.cc b/source/blender/editors/interface/interface_draw.cc index 79cfb2c50c9..74761daa430 100644 --- a/source/blender/editors/interface/interface_draw.cc +++ b/source/blender/editors/interface/interface_draw.cc @@ -1098,7 +1098,8 @@ static void ui_draw_colorband_handle(uint shdr_pos, float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f( + "viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 2); /* "advanced" mode */ immUniform4f("color", 0.8f, 0.8f, 0.8f, 1.0f); @@ -1672,7 +1673,7 @@ void ui_draw_but_CURVE(ARegion *region, uiBut *but, const uiWidgetColors *wcol, } cmp = cuma->curve; - GPU_point_size(max_ff(1.0f, min_ff(UI_DPI_FAC / but->block->aspect * 4.0f, 4.0f))); + GPU_point_size(max_ff(1.0f, min_ff(UI_SCALE_FAC / but->block->aspect * 4.0f, 4.0f))); immBegin(GPU_PRIM_POINTS, cuma->totpoint); for (int a = 0; a < cuma->totpoint; a++) { const float fx = rect->xmin + zoomx * (cmp[a].x - offsx); @@ -1931,7 +1932,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, GPU_line_smooth(false); if (path_len > 0) { GPU_blend(GPU_BLEND_NONE); - GPU_point_size(max_ff(3.0f, min_ff(UI_DPI_FAC / but->block->aspect * 5.0f, 5.0f))); + GPU_point_size(max_ff(3.0f, min_ff(UI_SCALE_FAC / but->block->aspect * 5.0f, 5.0f))); immBegin(GPU_PRIM_POINTS, path_len); for (int i = 0; i < path_len; i++) { fx = rect->xmin + zoomx * (pts[i].x - offsx); @@ -1946,7 +1947,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, if (selected_free_points > 0) { GPU_line_smooth(false); GPU_blend(GPU_BLEND_NONE); - GPU_point_size(max_ff(2.0f, min_ff(UI_DPI_FAC / but->block->aspect * 4.0f, 4.0f))); + GPU_point_size(max_ff(2.0f, min_ff(UI_SCALE_FAC / but->block->aspect * 4.0f, 4.0f))); immBegin(GPU_PRIM_POINTS, selected_free_points * 2); for (int i = 0; i < path_len; i++) { if (point_draw_handles(&pts[i])) { @@ -1968,7 +1969,7 @@ void ui_draw_but_CURVEPROFILE(ARegion *region, pts = profile->segments; const int segments_len = uint(profile->segments_len); if (segments_len > 0 && pts) { - GPU_point_size(max_ff(2.0f, min_ff(UI_DPI_FAC / but->block->aspect * 3.0f, 3.0f))); + GPU_point_size(max_ff(2.0f, min_ff(UI_SCALE_FAC / but->block->aspect * 3.0f, 3.0f))); immBegin(GPU_PRIM_POINTS, segments_len); for (int i = 0; i < segments_len; i++) { fx = rect->xmin + zoomx * (pts[i].x - offsx); diff --git a/source/blender/editors/interface/interface_handlers.cc b/source/blender/editors/interface/interface_handlers.cc index bca5095a190..05ccda5649c 100644 --- a/source/blender/editors/interface/interface_handlers.cc +++ b/source/blender/editors/interface/interface_handlers.cc @@ -47,6 +47,8 @@ #include "BKE_tracking.h" #include "BKE_unit.h" +#include "GHOST_C-api.h" + #include "IMB_colormanagement.h" #include "ED_screen.h" @@ -3048,7 +3050,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con if (ELEM(but->type, UI_BTYPE_TEXT, UI_BTYPE_SEARCH_MENU)) { if (but->flag & UI_HAS_ICON) { - startx += UI_DPI_ICON_SIZE / aspect; + startx += UI_ICON_SIZE / aspect; } } startx += (UI_TEXT_MARGIN_X * U.widget_unit - U.pixelsize) / aspect; @@ -3459,6 +3461,9 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) WM_cursor_modal_set(win, WM_CURSOR_TEXT_EDIT); + /* Temporarily turn off window auto-focus on platforms that support it. */ + GHOST_SetAutoFocus(false); + #ifdef WITH_INPUT_IME if (!is_num_but) { ui_textedit_ime_begin(win, but); @@ -3514,6 +3519,9 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) WM_cursor_modal_restore(win); + /* Turn back on the auto-focusing of windows. */ + GHOST_SetAutoFocus(true); + /* Free text undo history text blocks. */ ui_textedit_undo_stack_destroy(data->undo_stack_text); data->undo_stack_text = nullptr; @@ -4040,7 +4048,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data) const double value_step = is_float ? double(number_but->step_size * UI_PRECISION_FLOAT_SCALE) : int(number_but->step_size); - const float drag_map_softrange_max = UI_DRAG_MAP_SOFT_RANGE_PIXEL_MAX * UI_DPI_FAC; + const float drag_map_softrange_max = UI_DRAG_MAP_SOFT_RANGE_PIXEL_MAX * UI_SCALE_FAC; const float softrange_max = min_ff( softrange, 2 * (is_float ? min_ff(value_step, value_step_float_min) * @@ -5148,7 +5156,7 @@ static bool ui_numedit_but_NUM(uiButNumber *but, if (is_float == false) { /* at minimum, moving cursor 2 pixels should change an int button. */ - CLAMP_MIN(non_linear_scale, 0.5f * UI_DPI_FAC); + CLAMP_MIN(non_linear_scale, 0.5f * UI_SCALE_FAC); } data->dragf += (float(mx - data->draglastx) / deler) * non_linear_scale; @@ -7019,7 +7027,7 @@ static int ui_do_but_COLORBAND( else { CBData *cbd; /* ignore zoom-level for mindist */ - int mindist = (50 * UI_DPI_FAC) * block->aspect; + int mindist = (50 * UI_SCALE_FAC) * block->aspect; int xco; data->dragstartx = mx; data->dragstarty = my; @@ -7207,7 +7215,7 @@ static int ui_do_but_CURVE( CurveMapping *cumap = (CurveMapping *)but->poin; CurveMap *cuma = cumap->cm + cumap->cur; const float m_xy[2] = {float(mx), float(my)}; - float dist_min_sq = square_f(U.dpi_fac * 14.0f); /* 14 pixels radius */ + float dist_min_sq = square_f(UI_SCALE_FAC * 14.0f); /* 14 pixels radius */ int sel = -1; if (event->modifier & KM_CTRL) { @@ -7241,7 +7249,7 @@ static int ui_do_but_CURVE( BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[0].x); /* with 160px height 8px should translate to the old 0.05 coefficient at no zoom */ - dist_min_sq = square_f(U.dpi_fac * 8.0f); + dist_min_sq = square_f(UI_SCALE_FAC * 8.0f); /* loop through the curve segment table and find what's near the mouse. */ for (int i = 1; i <= CM_TABLE; i++) { @@ -7375,7 +7383,7 @@ static bool ui_numedit_but_CURVEPROFILE(uiBlock *block, if (snap) { const float d[2] = {float(mx - data->dragstartx), float(data->dragstarty)}; - if (len_squared_v2(d) < (9.0f * U.dpi_fac)) { + if (len_squared_v2(d) < (9.0f * UI_SCALE_FAC)) { snap = false; } } @@ -7521,7 +7529,8 @@ static int ui_do_but_CURVEPROFILE( /* Check for selecting of a point by finding closest point in radius. */ CurveProfilePoint *pts = profile->path; - float dist_min_sq = square_f(U.dpi_fac * 14.0f); /* 14 pixels radius for selecting points. */ + float dist_min_sq = square_f(UI_SCALE_FAC * + 14.0f); /* 14 pixels radius for selecting points. */ int i_selected = -1; short selection_type = 0; /* For handle selection. */ for (int i = 0; i < profile->path_len; i++) { @@ -7563,7 +7572,7 @@ static int ui_do_but_CURVEPROFILE( CurveProfilePoint *table = profile->table; BLI_rctf_transform_pt_v(&but->rect, &profile->view_rect, f_xy, &table[0].x); - dist_min_sq = square_f(U.dpi_fac * 8.0f); /* 8 pixel radius from each table point. */ + dist_min_sq = square_f(UI_SCALE_FAC * 8.0f); /* 8 pixel radius from each table point. */ /* Loop through the path's high resolution table and find what's near the click. */ for (int i = 1; i <= BKE_curveprofile_table_size(profile); i++) { @@ -7934,6 +7943,16 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * return WM_UI_HANDLER_CONTINUE; } +#ifdef WITH_INPUT_NDOF + /* 2D view navigation conflicts with using NDOF to adjust colors, + * especially in the node-editor, see: #105224. */ + if (event->type == NDOF_MOTION) { + if (data->region->type->keymapflag & ED_KEYMAP_VIEW2D) { + return WM_UI_HANDLER_CONTINUE; + } + } +#endif /* WITH_INPUT_NDOF */ + if (do_paste) { ui_but_paste(C, but, data, event->modifier & KM_ALT); return WM_UI_HANDLER_BREAK; @@ -8733,15 +8752,6 @@ static uiBut *ui_context_button_active(const ARegion *region, bool (*but_check_c return but_found; } -static bool ui_context_rna_button_active_test(const uiBut *but) -{ - return (but->rnapoin.data != nullptr); -} -static uiBut *ui_context_rna_button_active(const bContext *C) -{ - return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test); -} - uiBut *UI_context_active_but_get(const bContext *C) { return ui_context_button_active(CTX_wm_region(C), nullptr); @@ -8768,12 +8778,12 @@ uiBlock *UI_region_block_find_mouse_over(const ARegion *region, const int xy[2], return ui_block_find_mouse_over_ex(region, xy, only_clip); } -uiBut *UI_context_active_but_prop_get(const bContext *C, - PointerRNA *r_ptr, - PropertyRNA **r_prop, - int *r_index) +uiBut *UI_region_active_but_prop_get(const ARegion *region, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index) { - uiBut *activebut = ui_context_rna_button_active(C); + uiBut *activebut = UI_region_active_but_get(region); if (activebut && activebut->rnapoin.data) { *r_ptr = activebut->rnapoin; @@ -8789,9 +8799,19 @@ uiBut *UI_context_active_but_prop_get(const bContext *C, return activebut; } +uiBut *UI_context_active_but_prop_get(const bContext *C, + PointerRNA *r_ptr, + PropertyRNA **r_prop, + int *r_index) +{ + ARegion *region_menu = CTX_wm_menu(C); + return UI_region_active_but_prop_get( + region_menu ? region_menu : CTX_wm_region(C), r_ptr, r_prop, r_index); +} + void UI_context_active_but_prop_handle(bContext *C, const bool handle_undo) { - uiBut *activebut = ui_context_rna_button_active(C); + uiBut *activebut = UI_context_active_but_get_respect_menu(C); if (activebut) { /* TODO(@ideasman42): look into a better way to handle the button change * currently this is mainly so reset defaults works for the @@ -10131,7 +10151,7 @@ float ui_block_calc_pie_segment(uiBlock *block, const float event_xy[2]) const float len = normalize_v2_v2(block->pie_data.pie_dir, seg2); - if (len < U.pie_menu_threshold * U.dpi_fac) { + if (len < U.pie_menu_threshold * UI_SCALE_FAC) { block->pie_data.flags |= UI_PIE_INVALID_DIR; } else { @@ -10941,7 +10961,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) { const double final_time = 0.01 * U.pie_animation_timeout; float fac = duration / final_time; - const float pie_radius = U.pie_menu_radius * UI_DPI_FAC; + const float pie_radius = U.pie_menu_radius * UI_SCALE_FAC; if (fac > 1.0f) { fac = 1.0f; @@ -11016,7 +11036,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle uiBut *but = ui_region_find_active_but(menu->region); if (but && (U.pie_menu_confirm > 0) && - (dist >= U.dpi_fac * (U.pie_menu_threshold + U.pie_menu_confirm))) { + (dist >= UI_SCALE_FAC * (U.pie_menu_threshold + U.pie_menu_confirm))) { return ui_but_pie_menu_apply(C, menu, but, true); } @@ -11041,7 +11061,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle /* here instead, we use the offset location to account for the initial * direction timeout */ if ((U.pie_menu_confirm > 0) && - (dist >= U.dpi_fac * (U.pie_menu_threshold + U.pie_menu_confirm))) { + (dist >= UI_SCALE_FAC * (U.pie_menu_threshold + U.pie_menu_confirm))) { block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT; copy_v2_v2(block->pie_data.last_pos, event_xy); block->pie_data.duration_gesture = duration; diff --git a/source/blender/editors/interface/interface_icons.cc b/source/blender/editors/interface/interface_icons.cc index ed46d980fd0..dd0e505576a 100644 --- a/source/blender/editors/interface/interface_icons.cc +++ b/source/blender/editors/interface/interface_icons.cc @@ -29,7 +29,7 @@ #include "DNA_collection_types.h" #include "DNA_curve_types.h" #include "DNA_dynamicpaint_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" @@ -1741,7 +1741,7 @@ static void icon_draw_texture(float x, bool with_border, const IconTextOverlay *text_overlay) { - const float zoom_factor = w / UI_DPI_ICON_SIZE; + const float zoom_factor = w / UI_ICON_SIZE; float text_width = 0.0f; /* No need to show if too zoomed out, otherwise it just adds noise. */ @@ -2377,7 +2377,7 @@ int UI_icon_from_idcode(const int idcode) return ICON_FILE; case ID_CU_LEGACY: return ICON_CURVE_DATA; - case ID_GD: + case ID_GD_LEGACY: return ICON_OUTLINER_DATA_GREASEPENCIL; case ID_GR: return ICON_OUTLINER_COLLECTION; @@ -2492,13 +2492,13 @@ int UI_icon_color_from_collection(const Collection *collection) void UI_icon_draw(float x, float y, int icon_id) { UI_icon_draw_ex( - x, y, icon_id, U.inv_dpi_fac, 1.0f, 0.0f, nullptr, false, UI_NO_ICON_OVERLAY_TEXT); + x, y, icon_id, UI_INV_SCALE_FAC, 1.0f, 0.0f, nullptr, false, UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_alpha(float x, float y, int icon_id, float alpha) { UI_icon_draw_ex( - x, y, icon_id, U.inv_dpi_fac, alpha, 0.0f, nullptr, false, UI_NO_ICON_OVERLAY_TEXT); + x, y, icon_id, UI_INV_SCALE_FAC, alpha, 0.0f, nullptr, false, UI_NO_ICON_OVERLAY_TEXT); } void UI_icon_draw_preview(float x, float y, int icon_id, float aspect, float alpha, int size) diff --git a/source/blender/editors/interface/interface_icons_event.cc b/source/blender/editors/interface/interface_icons_event.cc index 5d8af37c55f..68a47a8aef6 100644 --- a/source/blender/editors/interface/interface_icons_event.cc +++ b/source/blender/editors/interface/interface_icons_event.cc @@ -26,12 +26,12 @@ static void icon_draw_rect_input_text( BLF_batch_draw_flush(); const int font_id = BLF_default(); BLF_color4fv(font_id, color); - BLF_size(font_id, font_size * U.dpi_fac); + BLF_size(font_id, font_size * UI_SCALE_FAC); float width, height; BLF_width_and_height(font_id, str, BLF_DRAW_STR_DUMMY_MAX, &width, &height); const float x = trunc(rect->xmin + (((rect->xmax - rect->xmin) - width) / 2.0f)); const float y = rect->ymin + (((rect->ymax - rect->ymin) - height) / 2.0f) + - (v_offset * U.dpi_fac); + (v_offset * UI_SCALE_FAC); BLF_position(font_id, x, y, 0.0f); BLF_draw(font_id, str, BLF_DRAW_STR_DUMMY_MAX); BLF_batch_draw_flush(); diff --git a/source/blender/editors/interface/interface_intern.hh b/source/blender/editors/interface/interface_intern.hh index 331e489ce05..830cc977d49 100644 --- a/source/blender/editors/interface/interface_intern.hh +++ b/source/blender/editors/interface/interface_intern.hh @@ -50,12 +50,12 @@ struct wmTimer; #define UI_MENU_WIDTH_MIN (UI_UNIT_Y * 9) /** Some extra padding added to menus containing sub-menu icons. */ -#define UI_MENU_SUBMENU_PADDING (6 * UI_DPI_FAC) +#define UI_MENU_SUBMENU_PADDING (6 * UI_SCALE_FAC) /* menu scrolling */ -#define UI_MENU_SCROLL_ARROW (12 * UI_DPI_FAC) -#define UI_MENU_SCROLL_MOUSE (UI_MENU_SCROLL_ARROW + 2 * UI_DPI_FAC) -#define UI_MENU_SCROLL_PAD (4 * UI_DPI_FAC) +#define UI_MENU_SCROLL_ARROW (12 * UI_SCALE_FAC) +#define UI_MENU_SCROLL_MOUSE (UI_MENU_SCROLL_ARROW + 2 * UI_SCALE_FAC) +#define UI_MENU_SCROLL_PAD (4 * UI_SCALE_FAC) /** Popover width (multiplied by #U.widget_unit) */ #define UI_POPOVER_WIDTH_UNITS 10 @@ -1181,12 +1181,12 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle, eFontStyle_Align text_align); #define UI_TEXT_MARGIN_X 0.4f -#define UI_POPUP_MARGIN (UI_DPI_FAC * 12) +#define UI_POPUP_MARGIN (UI_SCALE_FAC * 12) /** * Margin at top of screen for popups. * Note this value must be sufficient to draw a popover arrow to avoid cropping it. */ -#define UI_POPUP_MENU_TOP (int)(10 * UI_DPI_FAC) +#define UI_POPUP_MENU_TOP (int)(10 * UI_SCALE_FAC) #define UI_PIXEL_AA_JITTER 8 extern const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2]; diff --git a/source/blender/editors/interface/interface_layout.cc b/source/blender/editors/interface/interface_layout.cc index c2a78686608..1cab840f100 100644 --- a/source/blender/editors/interface/interface_layout.cc +++ b/source/blender/editors/interface/interface_layout.cc @@ -3962,7 +3962,7 @@ static void ui_litem_layout_radial(uiLayout *litem) * for radiation, see http://mattebb.com/weblog/radiation/ * also the old code at #5103. */ - const int pie_radius = U.pie_menu_radius * UI_DPI_FAC; + const int pie_radius = U.pie_menu_radius * UI_SCALE_FAC; const int x = litem->x; const int y = litem->y; @@ -4046,7 +4046,7 @@ static void ui_litem_layout_root_radial(uiLayout *litem) ui_item_size(item, &itemw, &itemh); ui_item_position( - item, x - itemw / 2, y + U.dpi_fac * (U.pie_menu_threshold + 9.0f), itemw, itemh); + item, x - itemw / 2, y + UI_SCALE_FAC * (U.pie_menu_threshold + 9.0f), itemw, itemh); } } @@ -5809,7 +5809,6 @@ void uiLayoutSetTooltipFunc(uiLayout *layout, if (copy_arg != nullptr && arg_used) { arg = copy_arg(arg); } - arg_used = true; if (item->type == ITEM_BUTTON) { uiButtonItem *bitem = (uiButtonItem *)item; @@ -5817,9 +5816,11 @@ void uiLayoutSetTooltipFunc(uiLayout *layout, continue; } UI_but_func_tooltip_set(bitem->but, func, arg, free_arg); + arg_used = true; } else { uiLayoutSetTooltipFunc((uiLayout *)item, func, arg, copy_arg, free_arg); + arg_used = true; } } @@ -5912,7 +5913,8 @@ static bool ui_layout_has_panel_label(const uiLayout *layout, const PanelType *p LISTBASE_FOREACH (uiItem *, subitem, &layout->items) { if (subitem->type == ITEM_BUTTON) { uiButtonItem *bitem = (uiButtonItem *)subitem; - if (!(bitem->but->flag & UI_HIDDEN) && STREQ(bitem->but->str, pt->label)) { + if (!(bitem->but->flag & UI_HIDDEN) && + STREQ(bitem->but->str, CTX_IFACE_(pt->translation_context, pt->label))) { return true; } } @@ -6123,13 +6125,13 @@ const char *UI_layout_introspect(uiLayout *layout) uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon) { const uiStyle *style = UI_style_get_dpi(); - const short icon_size = 64 * U.dpi_fac; + const short icon_size = 64 * UI_SCALE_FAC; const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); - const int dialog_width = icon_size + (text_points_max * size * U.dpi_fac); + const int dialog_width = icon_size + (text_points_max * size * UI_SCALE_FAC); /* By default, the space between icon and text/buttons will be equal to the 'columnspace', * this extra padding will add some space by increasing the left column width, * making the icon placement more symmetrical, between the block edge and the text. */ - const float icon_padding = 5.0f * U.dpi_fac; + const float icon_padding = 5.0f * UI_SCALE_FAC; /* Calculate the factor of the fixed icon column depending on the block width. */ const float split_factor = (float(icon_size) + icon_padding) / float(dialog_width - style->columnspace); diff --git a/source/blender/editors/interface/interface_ops.cc b/source/blender/editors/interface/interface_ops.cc index 6e9d73f9847..604c493c989 100644 --- a/source/blender/editors/interface/interface_ops.cc +++ b/source/blender/editors/interface/interface_ops.cc @@ -2482,7 +2482,7 @@ static int ui_drop_material_exec(bContext *C, wmOperator *op) const int target_slot = RNA_int_get(&mat_slot, "slot_index") + 1; /* only drop grease pencil material on grease pencil objects */ - if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) { + if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL_LEGACY)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/interface/interface_panel.cc b/source/blender/editors/interface/interface_panel.cc index d1702f1a9d1..9c15ad6d98e 100644 --- a/source/blender/editors/interface/interface_panel.cc +++ b/source/blender/editors/interface/interface_panel.cc @@ -1099,7 +1099,7 @@ static void panel_draw_aligned_widgets(const uiStyle *style, UI_icon_draw_ex(widget_rect.xmin + size_y * 0.2f, widget_rect.ymin + size_y * 0.2f, UI_panel_is_closed(panel) ? ICON_RIGHTARROW : ICON_DOWNARROW_HLT, - aspect * U.inv_dpi_fac, + aspect * UI_INV_SCALE_FAC, 0.7f, 0.0f, title_color, @@ -1128,7 +1128,7 @@ static void panel_draw_aligned_widgets(const uiStyle *style, UI_icon_draw_ex(widget_rect.xmax - scaled_unit * 2.2f, widget_rect.ymin + 5.0f / aspect, ICON_PINNED, - aspect * U.inv_dpi_fac, + aspect * UI_INV_SCALE_FAC, 1.0f, 0.0f, title_color, @@ -1288,7 +1288,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) const float zoom = 1.0f / aspect; const int px = U.pixelsize; const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom); - const float dpi_fac = UI_DPI_FAC; + const float dpi_fac = UI_SCALE_FAC; /* Padding of tabs around text. */ const int tab_v_pad_text = round_fl_to_int(TABS_PADDING_TEXT_FACTOR * dpi_fac * zoom) + 2 * px; /* Padding between tabs. */ @@ -1298,11 +1298,9 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) const int roundboxtype = is_left ? (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT) : (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT); bool is_alpha; - bool do_scaletabs = false; #ifdef USE_FLAT_INACTIVE bool is_active_prev = false; #endif - float scaletabs = 1.0f; /* Same for all tabs. */ /* Intentionally don't scale by 'px'. */ const int rct_xmin = is_left ? v2d->mask.xmin + 3 : (v2d->mask.xmax - category_tabs_width); @@ -1336,7 +1334,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) BLF_enable(fontid, BLF_ROTATION); BLF_rotation(fontid, M_PI_2); ui_fontscale(&fstyle_points, aspect); - BLF_size(fontid, fstyle_points * U.dpi_fac); + BLF_size(fontid, fstyle_points * UI_SCALE_FAC); /* Check the region type supports categories to avoid an assert * for showing 3D view panels in the properties space. */ @@ -1344,7 +1342,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) BLI_assert(UI_panel_category_is_visible(region)); } - /* Calculate tab rectangle and check if we need to scale down. */ + /* Calculate tab rectangle for each panel. */ LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { rcti *rct = &pc_dyn->rect; const char *category_id = pc_dyn->idname; @@ -1360,16 +1358,13 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) y_ofs += category_width + tab_v_pad + (tab_v_pad_text * 2); } - if (y_ofs > BLI_rcti_size_y(&v2d->mask)) { - scaletabs = float(BLI_rcti_size_y(&v2d->mask)) / float(y_ofs); - - LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { - rcti *rct = &pc_dyn->rect; - rct->ymin = ((rct->ymin - v2d->mask.ymax) * scaletabs) + v2d->mask.ymax; - rct->ymax = ((rct->ymax - v2d->mask.ymax) * scaletabs) + v2d->mask.ymax; - } - - do_scaletabs = true; + const int max_scroll = max_ii(y_ofs - BLI_rcti_size_y(&v2d->mask), 0); + const int scroll = clamp_i(region->category_scroll, 0, max_scroll); + region->category_scroll = scroll; + LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { + rcti *rct = &pc_dyn->rect; + rct->ymin += scroll; + rct->ymax += scroll; } /* Begin drawing. */ @@ -1405,14 +1400,17 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { const rcti *rct = &pc_dyn->rect; + if (rct->ymin > v2d->mask.ymax) { + /* Scrolled outside the top of the view, check the next tab. */ + continue; + } + if (rct->ymax < v2d->mask.ymin) { + /* Scrolled past visible bounds, no need to draw other tabs. */ + break; + } const char *category_id = pc_dyn->idname; const char *category_id_draw = IFACE_(category_id); - const int category_width = BLI_rcti_size_y(rct) - (tab_v_pad_text * 2); size_t category_draw_len = BLF_DRAW_STR_DUMMY_MAX; -#if 0 - int category_width = BLF_width(fontid, category_id_draw, BLF_DRAW_STR_DUMMY_MAX); -#endif - const bool is_active = STREQ(category_id, category_id_active); GPU_blend(GPU_BLEND_ALPHA); @@ -1469,11 +1467,6 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) /* Tab titles. */ - if (do_scaletabs) { - category_draw_len = BLF_width_to_strlen( - fontid, category_id_draw, category_draw_len, category_width, nullptr); - } - BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f); BLF_color3ubv(fontid, is_active ? theme_col_text_hi : theme_col_text); BLF_draw(fontid, category_id_draw, category_draw_len); @@ -2255,7 +2248,9 @@ static int ui_handle_panel_category_cycling(const wmEvent *event, const char *category = UI_panel_category_active_get(region, false); if (LIKELY(category)) { PanelCategoryDyn *pc_dyn = UI_panel_category_find(region, category); - if (LIKELY(pc_dyn)) { + /* Cyclic behavior between categories + * using Ctrl+Tab (+Shift for backwards) or Ctrl+Wheel Up/Down. */ + if (LIKELY(pc_dyn) && (event->modifier & KM_CTRL)) { if (is_mousewheel) { /* We can probably get rid of this and only allow Ctrl-Tabbing. */ pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev; @@ -2276,9 +2271,9 @@ static int ui_handle_panel_category_cycling(const wmEvent *event, UI_panel_category_active_set(region, pc_dyn->idname); ED_region_tag_redraw(region); } + return WM_UI_HANDLER_BREAK; } } - return WM_UI_HANDLER_BREAK; } return WM_UI_HANDLER_CONTINUE; diff --git a/source/blender/editors/interface/interface_region_color_picker.cc b/source/blender/editors/interface/interface_region_color_picker.cc index 29b32841c31..c98831e98f8 100644 --- a/source/blender/editors/interface/interface_region_color_picker.cc +++ b/source/blender/editors/interface/interface_region_color_picker.cc @@ -868,7 +868,6 @@ uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_ { uiBut *but = static_cast(arg_but); uiBlock *block; - bool show_picker = true; block = UI_block_begin(C, handle->region, __func__, UI_EMBOSS); @@ -876,17 +875,9 @@ uiBlock *ui_block_func_COLOR(bContext *C, uiPopupBlockHandle *handle, void *arg_ block->is_color_gamma_picker = true; } - if (but->block) { - /* if color block is invoked from a popup we wouldn't be able to set color properly - * this is because color picker will close popups first and then will try to figure - * out active button RNA, and of course it'll fail - */ - show_picker = (but->block->flag & UI_BLOCK_POPUP) == 0; - } - copy_v3_v3(handle->retvec, but->editvec); - ui_block_colorpicker(block, but, handle->retvec, show_picker); + ui_block_colorpicker(block, but, handle->retvec, true); block->flag = UI_BLOCK_LOOP | UI_BLOCK_KEEP_OPEN | UI_BLOCK_OUT_1 | UI_BLOCK_MOVEMOUSE_QUIT; UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); diff --git a/source/blender/editors/interface/interface_region_hud.cc b/source/blender/editors/interface/interface_region_hud.cc index 0aa3bcbdd8c..f0a31c9e739 100644 --- a/source/blender/editors/interface/interface_region_hud.cc +++ b/source/blender/editors/interface/interface_region_hud.cc @@ -173,8 +173,8 @@ static void hud_region_layout(const bContext *C, ARegion *region) if (region->panels.first && ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y))) { - int winx_new = UI_DPI_FAC * (region->sizex + 0.5f); - int winy_new = UI_DPI_FAC * (region->sizey + 0.5f); + int winx_new = UI_SCALE_FAC * (region->sizex + 0.5f); + int winy_new = UI_SCALE_FAC * (region->sizey + 0.5f); View2D *v2d = ®ion->v2d; if (region->flag & RGN_FLAG_SIZE_CLAMP_X) { diff --git a/source/blender/editors/interface/interface_region_popup.cc b/source/blender/editors/interface/interface_region_popup.cc index 7943e7dc6fa..edc6d94c250 100644 --- a/source/blender/editors/interface/interface_region_popup.cc +++ b/source/blender/editors/interface/interface_region_popup.cc @@ -288,8 +288,8 @@ static void ui_popup_block_position(wmWindow *window, /* when you are outside parent button, safety there should be smaller */ - const int s1 = 40 * U.dpi_fac; - const int s2 = 3 * U.dpi_fac; + const int s1 = 40 * UI_SCALE_FAC; + const int s2 = 3 * UI_SCALE_FAC; /* parent button to left */ if (midx < block->rect.xmin) { diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc index 1b63cbe4c97..ccc8586d9fe 100644 --- a/source/blender/editors/interface/interface_region_search.cc +++ b/source/blender/editors/interface/interface_region_search.cc @@ -651,7 +651,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) if (icon == ICON_BLANK1) { icon = ICON_NONE; - rect.xmin -= UI_DPI_ICON_SIZE / 4; + rect.xmin -= UI_ICON_SIZE / 4; } /* The previous menu item draws the active selection. */ @@ -762,7 +762,7 @@ static void ui_searchbox_region_layout_fn(const struct bContext *C, struct ARegi /* We should make this wider if there is a path or hint on the right. */ if (ui_searchbox_item_separator(data) != UI_MENU_ITEM_SEPARATOR_NONE) { - searchbox_width += 12 * data->fstyle.points * U.dpi_fac; + searchbox_width += 12 * data->fstyle.points * UI_SCALE_FAC; } rctf rect_fl; diff --git a/source/blender/editors/interface/interface_region_tooltip.cc b/source/blender/editors/interface/interface_region_tooltip.cc index fb87d940506..1216359a345 100644 --- a/source/blender/editors/interface/interface_region_tooltip.cc +++ b/source/blender/editors/interface/interface_region_tooltip.cc @@ -253,7 +253,7 @@ static void ui_tooltip_region_draw_cb(const bContext * /*C*/, ARegion *region) UI_fontstyle_set(&fstyle_mono); /* XXX: needed because we don't have mono in 'U.uifonts'. */ - BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.dpi_fac); + BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * UI_SCALE_FAC); rgb_float_to_uchar(drawcol, tip_colors[int(field->format.color_id)]); UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); } @@ -1132,7 +1132,7 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, int font_id; if (field->format.style == uiTooltipFormat::Style::Mono) { - BLF_size(blf_mono_font, data->fstyle.points * U.dpi_fac); + BLF_size(blf_mono_font, data->fstyle.points * UI_SCALE_FAC); font_id = blf_mono_font; } else { diff --git a/source/blender/editors/interface/interface_style.cc b/source/blender/editors/interface/interface_style.cc index 96eef4fdb60..38301599930 100644 --- a/source/blender/editors/interface/interface_style.cc +++ b/source/blender/editors/interface/interface_style.cc @@ -321,20 +321,20 @@ const uiStyle *UI_style_get_dpi(void) _style = *style; - _style.paneltitle.shadx = short(UI_DPI_FAC * _style.paneltitle.shadx); - _style.paneltitle.shady = short(UI_DPI_FAC * _style.paneltitle.shady); - _style.grouplabel.shadx = short(UI_DPI_FAC * _style.grouplabel.shadx); - _style.grouplabel.shady = short(UI_DPI_FAC * _style.grouplabel.shady); - _style.widgetlabel.shadx = short(UI_DPI_FAC * _style.widgetlabel.shadx); - _style.widgetlabel.shady = short(UI_DPI_FAC * _style.widgetlabel.shady); + _style.paneltitle.shadx = short(UI_SCALE_FAC * _style.paneltitle.shadx); + _style.paneltitle.shady = short(UI_SCALE_FAC * _style.paneltitle.shady); + _style.grouplabel.shadx = short(UI_SCALE_FAC * _style.grouplabel.shadx); + _style.grouplabel.shady = short(UI_SCALE_FAC * _style.grouplabel.shady); + _style.widgetlabel.shadx = short(UI_SCALE_FAC * _style.widgetlabel.shadx); + _style.widgetlabel.shady = short(UI_SCALE_FAC * _style.widgetlabel.shady); - _style.columnspace = short(UI_DPI_FAC * _style.columnspace); - _style.templatespace = short(UI_DPI_FAC * _style.templatespace); - _style.boxspace = short(UI_DPI_FAC * _style.boxspace); - _style.buttonspacex = short(UI_DPI_FAC * _style.buttonspacex); - _style.buttonspacey = short(UI_DPI_FAC * _style.buttonspacey); - _style.panelspace = short(UI_DPI_FAC * _style.panelspace); - _style.panelouter = short(UI_DPI_FAC * _style.panelouter); + _style.columnspace = short(UI_SCALE_FAC * _style.columnspace); + _style.templatespace = short(UI_SCALE_FAC * _style.templatespace); + _style.boxspace = short(UI_SCALE_FAC * _style.boxspace); + _style.buttonspacex = short(UI_SCALE_FAC * _style.buttonspacex); + _style.buttonspacey = short(UI_SCALE_FAC * _style.buttonspacey); + _style.panelspace = short(UI_SCALE_FAC * _style.panelspace); + _style.panelouter = short(UI_SCALE_FAC * _style.panelouter); return &_style; } @@ -351,7 +351,7 @@ int UI_fontstyle_string_width_with_block_aspect(const uiFontStyle *fs, { /* FIXME(@ideasman42): the final scale of the font is rounded which should be accounted for. * Failing to do so causes bad alignment when zoomed out very far in the node-editor. */ - fontstyle_set_ex(fs, U.dpi_fac / aspect); + fontstyle_set_ex(fs, UI_SCALE_FAC / aspect); return int(BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX) * aspect); } @@ -492,5 +492,5 @@ static void fontstyle_set_ex(const uiFontStyle *fs, const float dpi_fac) void UI_fontstyle_set(const uiFontStyle *fs) { - fontstyle_set_ex(fs, U.dpi_fac); + fontstyle_set_ex(fs, UI_SCALE_FAC); } diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index 55b2e780a9e..71bd66ff651 100644 --- a/source/blender/editors/interface/interface_template_asset_view.cc +++ b/source/blender/editors/interface/interface_template_asset_view.cc @@ -24,6 +24,7 @@ #include "RNA_prototypes.h" #include "UI_interface.h" +#include "UI_interface.hh" #include "WM_api.h" #include "WM_types.h" @@ -32,6 +33,7 @@ struct AssetViewListData { AssetLibraryReference asset_library_ref; + AssetFilterSettings filter_settings; bScreen *screen; bool show_names; }; @@ -45,8 +47,6 @@ static void asset_view_item_but_drag_set(uiBut *but, AssetHandle *asset_handle) } char blend_path[FILE_MAX_LIBEXTRA]; - /* Context can be null here, it's only needed for a File Browser specific hack that should go - * away before too long. */ ED_asset_handle_get_full_library_path(asset_handle, blend_path); const eAssetImportMethod import_method = @@ -68,19 +68,23 @@ static void asset_view_draw_item(uiList *ui_list, const bContext * /*C*/, uiLayout *layout, PointerRNA * /*dataptr*/, - PointerRNA *itemptr, + PointerRNA * /*itemptr*/, int /*icon*/, PointerRNA * /*active_dataptr*/, const char * /*active_propname*/, - int /*index*/, + int index, int /*flt_flag*/) { AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata; - BLI_assert(RNA_struct_is_a(itemptr->type, &RNA_AssetHandle)); - AssetHandle *asset_handle = (AssetHandle *)itemptr->data; + AssetHandle asset_handle = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index); - uiLayoutSetContextPointer(layout, "asset_handle", itemptr); + PointerRNA file_ptr; + RNA_pointer_create(&list_data->screen->id, + &RNA_FileSelectEntry, + const_cast(asset_handle.file_data), + &file_ptr); + uiLayoutSetContextPointer(layout, "active_file", &file_ptr); uiBlock *block = uiLayoutGetBlock(layout); const bool show_names = list_data->show_names; @@ -90,8 +94,8 @@ static void asset_view_draw_item(uiList *ui_list, uiBut *but = uiDefIconTextBut(block, UI_BTYPE_PREVIEW_TILE, 0, - ED_asset_handle_get_preview_icon_id(asset_handle), - show_names ? ED_asset_handle_get_name(asset_handle) : "", + ED_asset_handle_get_preview_icon_id(&asset_handle), + show_names ? ED_asset_handle_get_name(&asset_handle) : "", 0, 0, size_x, @@ -103,14 +107,43 @@ static void asset_view_draw_item(uiList *ui_list, 0, ""); ui_def_but_icon(but, - ED_asset_handle_get_preview_icon_id(asset_handle), + ED_asset_handle_get_preview_icon_id(&asset_handle), /* NOLINTNEXTLINE: bugprone-suspicious-enum-usage */ UI_HAS_ICON | UI_BUT_ICON_PREVIEW); if (!ui_list->dyn_data->custom_drag_optype) { - asset_view_item_but_drag_set(but, asset_handle); + asset_view_item_but_drag_set(but, &asset_handle); } } +static void asset_view_filter_items(uiList *ui_list, + const bContext *C, + PointerRNA *dataptr, + const char *propname) +{ + AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata; + AssetFilterSettings &filter_settings = list_data->filter_settings; + + uiListNameFilter name_filter(*ui_list); + + UI_list_filter_and_sort_items( + ui_list, + C, + [&name_filter, list_data, &filter_settings]( + const PointerRNA &itemptr, blender::StringRefNull name, int index) { + AssetHandle asset = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index); + if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) { + return UI_LIST_ITEM_NEVER_SHOW; + } + return name_filter(itemptr, name, index); + }, + dataptr, + propname, + [list_data](const PointerRNA & /*itemptr*/, int index) -> std::string { + AssetHandle asset = ED_assetlist_asset_get_by_index(&list_data->asset_library_ref, index); + return ED_asset_handle_get_name(&asset); + }); +} + static void asset_view_listener(uiList *ui_list, wmRegionListenerParams *params) { AssetViewListData *list_data = (AssetViewListData *)ui_list->dyn_data->customdata; @@ -136,16 +169,15 @@ uiListType *UI_UL_asset_view() BLI_strncpy(list_type->idname, "UI_UL_asset_view", sizeof(list_type->idname)); list_type->draw_item = asset_view_draw_item; + list_type->filter_items = asset_view_filter_items; list_type->listener = asset_view_listener; return list_type; } -static void asset_view_template_refresh_asset_collection( - const AssetLibraryReference &asset_library_ref, - const AssetFilterSettings &filter_settings, - PointerRNA &assets_dataptr, - const char *assets_propname) +static void populate_asset_collection(const AssetLibraryReference &asset_library_ref, + PointerRNA &assets_dataptr, + const char *assets_propname) { PropertyRNA *assets_prop = RNA_struct_find_property(&assets_dataptr, assets_propname); if (!assets_prop) { @@ -164,17 +196,15 @@ static void asset_view_template_refresh_asset_collection( RNA_property_collection_clear(&assets_dataptr, assets_prop); - ED_assetlist_iterate(asset_library_ref, [&](AssetHandle asset) { - if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) { - /* Don't do anything else, but return true to continue iterating. */ - return true; - } + ED_assetlist_iterate(asset_library_ref, [&](AssetHandle /*asset*/) { + /* XXX creating a dummy #RNA_AssetHandle collection item. It's #file_data will be null. This is + * because the #FileDirEntry may be freed while iterating, there's a cache for them with a + * maximum size. Further code will query as needed it using the collection index. */ PointerRNA itemptr, fileptr; RNA_property_collection_add(&assets_dataptr, assets_prop, &itemptr); - RNA_pointer_create( - nullptr, &RNA_FileSelectEntry, const_cast(asset.file_data), &fileptr); + RNA_pointer_create(nullptr, &RNA_FileSelectEntry, nullptr, &fileptr); RNA_pointer_set(&itemptr, "file_data", fileptr); return true; @@ -221,12 +251,12 @@ void uiTemplateAssetView(uiLayout *layout, ED_assetlist_ensure_previews_job(&asset_library_ref, C); const int tot_items = ED_assetlist_size(&asset_library_ref); - asset_view_template_refresh_asset_collection( - asset_library_ref, *filter_settings, *assets_dataptr, assets_propname); + populate_asset_collection(asset_library_ref, *assets_dataptr, assets_propname); AssetViewListData *list_data = (AssetViewListData *)MEM_mallocN(sizeof(*list_data), "AssetViewListData"); list_data->asset_library_ref = asset_library_ref; + list_data->filter_settings = *filter_settings; list_data->screen = CTX_wm_screen(C); list_data->show_names = (display_flags & UI_TEMPLATE_ASSET_DRAW_NO_NAMES) == 0; diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc index d5803e603f1..28ffee73ca3 100644 --- a/source/blender/editors/interface/interface_template_list.cc +++ b/source/blender/editors/interface/interface_template_list.cc @@ -8,9 +8,11 @@ #include #include "BLI_fnmatch.h" +#include "BLI_function_ref.hh" #include "BLI_listbase.h" #include "BLI_math_base.h" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BLI_utildefines.h" #include "BKE_screen.h" @@ -26,12 +28,15 @@ #include "RNA_prototypes.h" #include "UI_interface.h" +#include "UI_interface.hh" #include "UI_view2d.h" #include "WM_api.h" #include "interface_intern.hh" +using namespace blender; + /** * The validated data that was passed to #uiTemplateList (typically through Python). * Populated through #ui_template_list_data_retrieve(). @@ -148,6 +153,45 @@ static void uilist_draw_filter_default(struct uiList *ui_list, } } +uiListNameFilter::uiListNameFilter(uiList &list) +{ + const char *filter_raw = list.filter_byname; + + if (filter_raw[0]) { + const size_t slen = strlen(filter_raw); + + /* Implicitly add heading/trailing wildcards if needed. */ + if (slen + 3 <= sizeof(storage_.filter_buff)) { + filter_ = storage_.filter_buff; + } + else { + filter_ = storage_.filter_dyn = static_cast( + MEM_mallocN((slen + 3) * sizeof(char), "filter_dyn")); + } + BLI_strncpy_ensure_pad(filter_, filter_raw, '*', slen + 3); + } +} + +uiListNameFilter::~uiListNameFilter() +{ + MEM_SAFE_FREE(storage_.filter_dyn); +} + +eUIListFilterResult uiListNameFilter::operator()(const PointerRNA & /* itemptr */, + StringRefNull name, + int /* index */) +{ + if (!filter_) { + return UI_LIST_ITEM_FILTER_MATCHES; + } + + /* Case-insensitive! */ + if (fnmatch(filter_, name.c_str(), FNM_CASEFOLD) == 0) { + return UI_LIST_ITEM_FILTER_MATCHES; + } + return UI_LIST_ITEM_FILTER_MISMATCHES; +} + struct StringCmp { char name[MAX_IDPROP_NAME]; int org_idx; @@ -159,16 +203,16 @@ static int cmpstringp(const void *p1, const void *p2) return BLI_strcasecmp(((StringCmp *)p1)->name, ((StringCmp *)p2)->name); } -static void uilist_filter_items_default(struct uiList *ui_list, - const struct bContext * /*C*/, - struct PointerRNA *dataptr, - const char *propname) +void UI_list_filter_and_sort_items(uiList *ui_list, + const bContext * /*C*/, + uiListItemFilterFn item_filter_fn, + PointerRNA *dataptr, + const char *propname, + uiListItemGetNameFn get_name_fn) { uiListDyn *dyn_data = ui_list->dyn_data; PropertyRNA *prop = RNA_struct_find_property(dataptr, propname); - const char *filter_raw = ui_list->filter_byname; - char *filter = (char *)filter_raw, filter_buff[32], *filter_dyn = nullptr; const bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0; const bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_MASK) == UILST_FLT_SORT_ALPHA; @@ -176,41 +220,26 @@ static void uilist_filter_items_default(struct uiList *ui_list, dyn_data->items_shown = dyn_data->items_len = len; - if (len && (order_by_name || filter_raw[0])) { + if (len && (order_by_name || item_filter_fn)) { StringCmp *names = nullptr; int order_idx = 0, i = 0; if (order_by_name) { names = static_cast(MEM_callocN(sizeof(StringCmp) * len, "StringCmp")); } - if (filter_raw[0]) { - const size_t slen = strlen(filter_raw); + if (item_filter_fn) { dyn_data->items_filter_flags = static_cast( MEM_callocN(sizeof(int) * len, "items_filter_flags")); dyn_data->items_shown = 0; - - /* Implicitly add heading/trailing wildcards if needed. */ - if (slen + 3 <= sizeof(filter_buff)) { - filter = filter_buff; - } - else { - filter = filter_dyn = static_cast( - MEM_mallocN((slen + 3) * sizeof(char), "filter_dyn")); - } - BLI_strncpy_ensure_pad(filter, filter_raw, '*', slen + 3); } RNA_PROP_BEGIN (dataptr, itemptr, prop) { bool do_order = false; char *namebuf; - if (RNA_struct_is_a(itemptr.type, &RNA_AssetHandle)) { - /* XXX The AssetHandle design is hacky and meant to be temporary. It can't have a proper - * name property, so for now this hardcoded exception is needed. */ - AssetHandle *asset_handle = (AssetHandle *)itemptr.data; - const char *asset_name = ED_asset_handle_get_name(asset_handle); - namebuf = BLI_strdup(asset_name); + if (get_name_fn) { + namebuf = BLI_strdup(get_name_fn(itemptr, i).c_str()); } else { namebuf = RNA_struct_name_get_alloc(&itemptr, nullptr, 0, nullptr); @@ -218,9 +247,13 @@ static void uilist_filter_items_default(struct uiList *ui_list, const char *name = namebuf ? namebuf : ""; - if (filter[0]) { - /* Case-insensitive! */ - if (fnmatch(filter, name, FNM_CASEFOLD) == 0) { + if (item_filter_fn) { + const eUIListFilterResult filter_result = item_filter_fn(itemptr, name, i); + + if (filter_result == UI_LIST_ITEM_NEVER_SHOW) { + /* Pass. */ + } + else if (filter_result == UI_LIST_ITEM_FILTER_MATCHES) { dyn_data->items_filter_flags[i] = UILST_FLT_ITEM; if (!filter_exclude) { dyn_data->items_shown++; @@ -266,15 +299,30 @@ static void uilist_filter_items_default(struct uiList *ui_list, } } - if (filter_dyn) { - MEM_freeN(filter_dyn); - } if (names) { MEM_freeN(names); } } } +/** + * Default UI List filtering: Filter by name. + */ +static void uilist_filter_items_default(struct uiList *ui_list, + const struct bContext *C, + struct PointerRNA *dataptr, + const char *propname) +{ + if (ui_list->filter_byname[0]) { + uiListNameFilter name_filter(*ui_list); + UI_list_filter_and_sort_items(ui_list, C, name_filter, dataptr, propname); + } + /* Optimization: Skip filtering entirely when there is no filter string set. */ + else { + UI_list_filter_and_sort_items(ui_list, C, nullptr, dataptr, propname); + } +} + static void uilist_free_dyn_data(uiList *ui_list) { uiListDyn *dyn_data = ui_list->dyn_data; diff --git a/source/blender/editors/interface/interface_templates.cc b/source/blender/editors/interface/interface_templates.cc index 5cde372222a..625fe459758 100644 --- a/source/blender/editors/interface/interface_templates.cc +++ b/source/blender/editors/interface/interface_templates.cc @@ -39,13 +39,14 @@ #include "BLT_translation.h" #include "BKE_action.h" +#include "BKE_blendfile.h" #include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_curveprofile.h" #include "BKE_global.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_layer.h" @@ -79,8 +80,6 @@ #include "WM_api.h" #include "WM_types.h" -#include "BLO_readfile.h" - #include "UI_interface.h" #include "UI_interface_icons.h" #include "UI_view2d.h" @@ -832,7 +831,7 @@ ID *ui_template_id_liboverride_hierarchy_make( case ID_CA: case ID_SPK: case ID_AR: - case ID_GD: + case ID_GD_LEGACY: case ID_CV: case ID_PT: case ID_VO: @@ -1102,7 +1101,7 @@ static const char *template_id_browse_tip(const StructRNA *type) return N_("Browse Brush to be linked"); case ID_PA: return N_("Browse Particle Settings to be linked"); - case ID_GD: + case ID_GD_LEGACY: return N_("Browse Grease Pencil Data to be linked"); case ID_MC: return N_("Browse Movie Clip to be linked"); @@ -5688,7 +5687,7 @@ void uiTemplateColorPicker(uiLayout *layout, "", WHEEL_SIZE + 6, 0, - 14 * UI_DPI_FAC, + 14 * UI_SCALE_FAC, WHEEL_SIZE, ptr, prop, @@ -5709,7 +5708,7 @@ void uiTemplateColorPicker(uiLayout *layout, 0, 4, WHEEL_SIZE, - 18 * UI_DPI_FAC, + 18 * UI_SCALE_FAC, ptr, prop, -1, @@ -5729,7 +5728,7 @@ void uiTemplateColorPicker(uiLayout *layout, 0, 4, WHEEL_SIZE, - 18 * UI_DPI_FAC, + 18 * UI_SCALE_FAC, ptr, prop, -1, @@ -5749,7 +5748,7 @@ void uiTemplateColorPicker(uiLayout *layout, 0, 4, WHEEL_SIZE, - 18 * UI_DPI_FAC, + 18 * UI_SCALE_FAC, ptr, prop, -1, @@ -5771,7 +5770,7 @@ void uiTemplateColorPicker(uiLayout *layout, "", WHEEL_SIZE + 6, 0, - 14 * UI_DPI_FAC, + 14 * UI_SCALE_FAC, WHEEL_SIZE, ptr, prop, @@ -6359,7 +6358,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C) UI_fontstyle_set(&style->widgetlabel); int width = BLF_width(style->widgetlabel.uifont_id, report->message, report->len); width = min_ii(int(rti->widthfac * width), width); - width = max_ii(width, 10 * UI_DPI_FAC); + width = max_ii(width, 10 * UI_SCALE_FAC); UI_block_align_begin(block); @@ -6370,7 +6369,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C) "", 0, 0, - UI_UNIT_X + (6 * UI_DPI_FAC), + UI_UNIT_X + (6 * UI_SCALE_FAC), UI_UNIT_Y, nullptr, 0.0f, @@ -6386,7 +6385,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C) UI_BTYPE_ROUNDBOX, 0, "", - UI_UNIT_X + (6 * UI_DPI_FAC), + UI_UNIT_X + (6 * UI_SCALE_FAC), 0, UI_UNIT_X + width, UI_UNIT_Y, @@ -6410,7 +6409,7 @@ void uiTemplateReportsBanner(uiLayout *layout, bContext *C) "SCREEN_OT_info_log_show", WM_OP_INVOKE_REGION_WIN, UI_icon_from_report_type(report->type), - (3 * UI_DPI_FAC), + (3 * UI_SCALE_FAC), 0, UI_UNIT_X, UI_UNIT_Y, @@ -6997,7 +6996,7 @@ int uiTemplateRecentFiles(uiLayout *layout, int rows) uiItemFullO(layout, "WM_OT_open_mainfile", filename, - BLO_has_bfile_extension(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP, + BKE_blendfile_extension_check(filename) ? ICON_FILE_BLEND : ICON_FILE_BACKUP, nullptr, WM_OP_INVOKE_DEFAULT, 0, diff --git a/source/blender/editors/interface/interface_widgets.cc b/source/blender/editors/interface/interface_widgets.cc index 55ede2eda80..f50f199357d 100644 --- a/source/blender/editors/interface/interface_widgets.cc +++ b/source/blender/editors/interface/interface_widgets.cc @@ -1354,7 +1354,7 @@ static void widget_draw_icon( return; } - const float aspect = but->block->aspect * U.inv_dpi_fac; + const float aspect = but->block->aspect * UI_INV_SCALE_FAC; const float height = ICON_DEFAULT_HEIGHT / aspect; /* calculate blend color */ @@ -1447,7 +1447,7 @@ static void widget_draw_submenu_tria(const uiBut *but, const rcti *rect, const uiWidgetColors *wcol) { - const float aspect = but->block->aspect * U.inv_dpi_fac; + const float aspect = but->block->aspect * UI_INV_SCALE_FAC; const int tria_height = int(ICON_DEFAULT_HEIGHT / aspect); const int tria_width = int(ICON_DEFAULT_WIDTH / aspect) - 2 * U.pixelsize; const int xs = rect->xmax - tria_width; @@ -1641,7 +1641,7 @@ static void ui_text_clip_middle(const uiFontStyle *fstyle, uiBut *but, const rct int(UI_TEXT_CLIP_MARGIN + 0.5f); const float okwidth = float(max_ii(BLI_rcti_size_x(rect) - border, 0)); const size_t max_len = sizeof(but->drawstr); - const float minwidth = float(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f; + const float minwidth = float(UI_ICON_SIZE) / but->block->aspect * 2.0f; but->ofs = 0; but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, '\0'); @@ -1664,7 +1664,7 @@ static void ui_text_clip_middle_protect_right(const uiFontStyle *fstyle, int(UI_TEXT_CLIP_MARGIN + 0.5f); const float okwidth = float(max_ii(BLI_rcti_size_x(rect) - border, 0)); const size_t max_len = sizeof(but->drawstr); - const float minwidth = float(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f; + const float minwidth = float(UI_ICON_SIZE) / but->block->aspect * 2.0f; but->ofs = 0; but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep); @@ -2297,8 +2297,8 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle, const BIFIconID icon = BIFIconID(ui_but_icon(but)); const int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT; - const float icon_size = icon_size_init / (but->block->aspect * U.inv_dpi_fac); - const float icon_padding = 2 * UI_DPI_FAC; + const float icon_size = icon_size_init / (but->block->aspect * UI_INV_SCALE_FAC); + const float icon_padding = 2 * UI_SCALE_FAC; #ifdef USE_UI_TOOLBAR_HACK if (is_tool) { @@ -4994,11 +4994,11 @@ static void ui_draw_clip_tri(uiBlock *block, rcti *rect, uiWidgetType *wt) if (block->flag & UI_BLOCK_CLIPTOP) { /* XXX no scaling for UI here yet */ - UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 6 * U.dpi_fac, 't', draw_color); + UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 6 * UI_SCALE_FAC, 't', draw_color); } if (block->flag & UI_BLOCK_CLIPBOTTOM) { /* XXX no scaling for UI here yet */ - UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10 * U.dpi_fac, 'v', draw_color); + UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10 * UI_SCALE_FAC, 'v', draw_color); } } } @@ -5172,8 +5172,8 @@ void ui_draw_pie_center(uiBlock *block) float *pie_dir = block->pie_data.pie_dir; - const float pie_radius_internal = U.dpi_fac * U.pie_menu_threshold; - const float pie_radius_external = U.dpi_fac * (U.pie_menu_threshold + 7.0f); + const float pie_radius_internal = UI_SCALE_FAC * U.pie_menu_threshold; + const float pie_radius_external = UI_SCALE_FAC * (U.pie_menu_threshold + 7.0f); const int subd = 40; @@ -5246,8 +5246,8 @@ void ui_draw_pie_center(uiBlock *block) if (U.pie_menu_confirm > 0 && !(block->pie_data.flags & (UI_PIE_INVALID_DIR | UI_PIE_CLICK_STYLE))) { - const float pie_confirm_radius = U.dpi_fac * (pie_radius_internal + U.pie_menu_confirm); - const float pie_confirm_external = U.dpi_fac * + const float pie_confirm_radius = UI_SCALE_FAC * (pie_radius_internal + U.pie_menu_confirm); + const float pie_confirm_external = UI_SCALE_FAC * (pie_radius_internal + U.pie_menu_confirm + 7.0f); const uchar col[4] = {UNPACK3(btheme->tui.wcol_pie_menu.text_sel), 64}; @@ -5361,7 +5361,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, if (separator_type == UI_MENU_ITEM_SEPARATOR_SHORTCUT) { /* Shrink rect to exclude the shortcut string. */ - rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE; + rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_ICON_SIZE; } else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) { /* Determine max-width for the hint string to leave the name string un-clipped (if there's @@ -5390,7 +5390,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, char drawstr[UI_MAX_DRAW_STR]; const float okwidth = float(BLI_rcti_size_x(rect)); const size_t max_len = sizeof(drawstr); - const float minwidth = float(UI_DPI_ICON_SIZE); + const float minwidth = float(UI_ICON_SIZE); BLI_strncpy(drawstr, name, sizeof(drawstr)); if (drawstr[0]) { @@ -5439,7 +5439,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, char hint_drawstr[UI_MAX_DRAW_STR]; { const size_t max_len = sizeof(hint_drawstr); - const float minwidth = float(UI_DPI_ICON_SIZE); + const float minwidth = float(UI_ICON_SIZE); BLI_strncpy(hint_drawstr, cpoin + 1, sizeof(hint_drawstr)); if (hint_drawstr[0] && (max_hint_width < INT_MAX)) { @@ -5494,7 +5494,7 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle, char drawstr[UI_MAX_DRAW_STR]; const float okwidth = float(BLI_rcti_size_x(&trect)); const size_t max_len = sizeof(drawstr); - const float minwidth = float(UI_DPI_ICON_SIZE); + const float minwidth = float(UI_ICON_SIZE); BLI_strncpy(drawstr, name, sizeof(drawstr)); UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0'); diff --git a/source/blender/editors/interface/resources.cc b/source/blender/editors/interface/resources.cc index b0c8d4739e0..6a2e2ff9073 100644 --- a/source/blender/editors/interface/resources.cc +++ b/source/blender/editors/interface/resources.cc @@ -1468,7 +1468,7 @@ void UI_ThemeClearColor(int colorid) int UI_ThemeMenuShadowWidth() { bTheme *btheme = UI_GetTheme(); - return int(btheme->tui.menu_shadow_width * UI_DPI_FAC); + return int(btheme->tui.menu_shadow_width * UI_SCALE_FAC); } void UI_make_axis_color(const uchar src_col[3], uchar dst_col[3], const char axis) diff --git a/source/blender/editors/interface/view2d.cc b/source/blender/editors/interface/view2d.cc index a8d5b1ad22c..ec81711caeb 100644 --- a/source/blender/editors/interface/view2d.cc +++ b/source/blender/editors/interface/view2d.cc @@ -1288,7 +1288,7 @@ void UI_view2d_dot_grid_draw(const View2D *v2d, immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); /* Scaling the dots fully with the zoom looks too busy, but a bit of size variation is nice. */ - const float min_point_size = 2.0f * UI_DPI_FAC; + const float min_point_size = 2.0f * UI_SCALE_FAC; const float point_size_factor = 1.5f; const float max_point_size = point_size_factor * min_point_size; diff --git a/source/blender/editors/interface/view2d_draw.cc b/source/blender/editors/interface/view2d_draw.cc index 837d7de1c86..30791a84876 100644 --- a/source/blender/editors/interface/view2d_draw.cc +++ b/source/blender/editors/interface/view2d_draw.cc @@ -38,7 +38,7 @@ /* Compute display grid resolution ********************************************************/ -#define MIN_MAJOR_LINE_DISTANCE (U.v2d_min_gridsize * UI_DPI_FAC) +#define MIN_MAJOR_LINE_DISTANCE (U.v2d_min_gridsize * UI_SCALE_FAC) static float select_major_distance(const float *possible_distances, uint amount, @@ -102,17 +102,16 @@ static float view2d_major_step_x__time(const View2D *v2d, const Scene *scene) for (int step = 1; step < fps; step *= 2) { possible_distances.append(step); } - possible_distances.append(fps); - possible_distances.append(2 * fps); - possible_distances.append(5 * fps); - possible_distances.append(10 * fps); - possible_distances.append(30 * fps); - possible_distances.append(60 * fps); - possible_distances.append(2 * 60 * fps); - possible_distances.append(5 * 60 * fps); - possible_distances.append(10 * 60 * fps); - possible_distances.append(30 * 60 * fps); - possible_distances.append(60 * 60 * fps); + + for (int i = 0; i <= 5; i++) { + uint fac = pow(60, i); + possible_distances.append(fac * fps); + possible_distances.append(fac * 2 * fps); + possible_distances.append(fac * 5 * fps); + possible_distances.append(fac * 10 * fps); + possible_distances.append(fac * 30 * fps); + possible_distances.append(fac * 60 * fps); + } float distance = select_major_distance(possible_distances.data(), possible_distances.size(), @@ -304,7 +303,7 @@ static void draw_horizontal_scale_indicators(const ARegion *region, BLF_batch_draw_begin(); - const float ypos = rect->ymin + 4 * UI_DPI_FAC; + const float ypos = rect->ymin + 4 * UI_SCALE_FAC; const float xmin = rect->xmin; const float xmax = rect->xmax; @@ -384,7 +383,7 @@ static void draw_vertical_scale_indicators(const ARegion *region, BLF_shadow_offset(font_id, 1, -1); const float x_offset = 8.0f; - const float xpos = (rect->xmin + x_offset) * UI_DPI_FAC; + const float xpos = (rect->xmin + x_offset) * UI_SCALE_FAC; const float ymin = rect->ymin; const float ymax = rect->ymax; const float y_offset = (BLF_height(font_id, "0", 1) / 2.0f) - U.pixelsize; diff --git a/source/blender/editors/interface/view2d_edge_pan.cc b/source/blender/editors/interface/view2d_edge_pan.cc index 897a638dfe5..5f1600647b2 100644 --- a/source/blender/editors/interface/view2d_edge_pan.cc +++ b/source/blender/editors/interface/view2d_edge_pan.cc @@ -174,7 +174,7 @@ static float edge_pan_speed(View2DEdgePanData *vpd, const float zoom_factor = 1.0f + CLAMPIS(vpd->zoom_influence, 0.0f, 1.0f) * (zoomx - 1.0f); return distance_factor * delay_factor * zoom_factor * vpd->max_speed * U.widget_unit * - float(U.dpi_fac); + float(UI_SCALE_FAC); } static void edge_pan_apply_delta(bContext *C, View2DEdgePanData *vpd, float dx, float dy) diff --git a/source/blender/editors/interface/view2d_gizmo_navigate.cc b/source/blender/editors/interface/view2d_gizmo_navigate.cc index 05cb955c660..9e7a62e140e 100644 --- a/source/blender/editors/interface/view2d_gizmo_navigate.cc +++ b/source/blender/editors/interface/view2d_gizmo_navigate.cc @@ -221,7 +221,7 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g navgroup->state.rect_visible = *rect_visible; const float icon_size = GIZMO_SIZE; - const float icon_offset_mini = icon_size * GIZMO_MINI_OFFSET_FAC * UI_DPI_FAC; + const float icon_offset_mini = icon_size * GIZMO_MINI_OFFSET_FAC * UI_SCALE_FAC; const float co[2] = { roundf(rect_visible->xmax - (icon_offset_mini * 0.75f)), roundf(rect_visible->ymax - (icon_offset_mini * 0.75f)), diff --git a/source/blender/editors/interface/view2d_ops.cc b/source/blender/editors/interface/view2d_ops.cc index 37e5626b204..7fd898bbff8 100644 --- a/source/blender/editors/interface/view2d_ops.cc +++ b/source/blender/editors/interface/view2d_ops.cc @@ -82,6 +82,9 @@ struct v2dViewPanData { /** event starting pan, for modal exit */ int invoke_event; + /** Tag if the scroll is done in the category tab. */ + bool do_category_scroll; + /** for MMB in scrollers (old feature in past, but now not that useful) */ short in_scroller; @@ -133,6 +136,8 @@ static void view_pan_init(bContext *C, wmOperator *op) vpd->facy = BLI_rctf_size_y(&vpd->v2d->cur) / winy; vpd->v2d->flag |= V2D_IS_NAVIGATING; + + vpd->do_category_scroll = false; } /* apply transform to view (i.e. adjust 'cur' rect) */ @@ -144,14 +149,19 @@ static void view_pan_apply_ex(bContext *C, v2dViewPanData *vpd, float dx, float dx *= vpd->facx; dy *= vpd->facy; - /* only move view on an axis if change is allowed */ - if ((v2d->keepofs & V2D_LOCKOFS_X) == 0) { - v2d->cur.xmin += dx; - v2d->cur.xmax += dx; + if (!vpd->do_category_scroll) { + /* only move view on an axis if change is allowed */ + if ((v2d->keepofs & V2D_LOCKOFS_X) == 0) { + v2d->cur.xmin += dx; + v2d->cur.xmax += dx; + } + if ((v2d->keepofs & V2D_LOCKOFS_Y) == 0) { + v2d->cur.ymin += dy; + v2d->cur.ymax += dy; + } } - if ((v2d->keepofs & V2D_LOCKOFS_Y) == 0) { - v2d->cur.ymin += dy; - v2d->cur.ymax += dy; + else { + vpd->region->category_scroll -= dy; } /* Inform v2d about changes after this operation. */ @@ -212,6 +222,8 @@ static int view_pan_invoke(bContext *C, wmOperator *op, const wmEvent *event) vpd->starty = vpd->lasty = event->xy[1]; vpd->invoke_event = event->type; + vpd->do_category_scroll = ED_region_panel_category_gutter_isect_xy(vpd->region, event->xy); + if (event->type == MOUSEPAN) { RNA_int_set(op->ptr, "deltax", event->prev_xy[0] - event->xy[0]); RNA_int_set(op->ptr, "deltay", event->prev_xy[1] - event->xy[1]); @@ -482,6 +494,10 @@ static int view_scrolldown_exec(bContext *C, wmOperator *op) return OPERATOR_PASS_THROUGH; } + const wmWindow *win = CTX_wm_window(C); + vpd->do_category_scroll = ED_region_panel_category_gutter_isect_xy(vpd->region, + win->eventstate->xy); + /* set RNA-Props */ RNA_int_set(op->ptr, "deltax", 0); RNA_int_set(op->ptr, "deltay", -40); @@ -529,6 +545,10 @@ static int view_scrollup_exec(bContext *C, wmOperator *op) return OPERATOR_PASS_THROUGH; } + const wmWindow *win = CTX_wm_window(C); + vpd->do_category_scroll = ED_region_panel_category_gutter_isect_xy(vpd->region, + win->eventstate->xy); + /* set RNA-Props */ RNA_int_set(op->ptr, "deltax", 0); RNA_int_set(op->ptr, "deltay", 40); @@ -956,8 +976,8 @@ static void view_zoomdrag_apply(bContext *C, wmOperator *op) const bool zoom_to_pos = use_cursor_init && vzd->zoom_to_mouse_pos; /* get amount to move view by */ - float dx = RNA_float_get(op->ptr, "deltax") / U.dpi_fac; - float dy = RNA_float_get(op->ptr, "deltay") / U.dpi_fac; + float dx = RNA_float_get(op->ptr, "deltax") / UI_SCALE_FAC; + float dy = RNA_float_get(op->ptr, "deltay") / UI_SCALE_FAC; /* Check if the 'timer' is initialized, as zooming with the trackpad * never uses the "Continuous" zoom method, and the 'timer' is not initialized. */ @@ -2181,6 +2201,8 @@ static int reset_exec(bContext *C, wmOperator * /*op*/) View2D *v2d = ®ion->v2d; const int snap_test = ED_region_snap_size_test(region); + region->category_scroll = 0; + /* zoom 1.0 */ const int winx = float(BLI_rcti_size_x(&v2d->mask) + 1); const int winy = float(BLI_rcti_size_y(&v2d->mask) + 1); diff --git a/source/blender/editors/interface/views/tree_view.cc b/source/blender/editors/interface/views/tree_view.cc index 04987fad59b..ffbd0c56439 100644 --- a/source/blender/editors/interface/views/tree_view.cc +++ b/source/blender/editors/interface/views/tree_view.cc @@ -145,7 +145,7 @@ void AbstractTreeViewItem::add_indent(uiLayout &row) const uiLayout *subrow = uiLayoutRow(&row, true); uiLayoutSetFixedSize(subrow, true); - const float indent_size = count_parents() * UI_DPI_ICON_SIZE; + const float indent_size = count_parents() * UI_ICON_SIZE; uiDefBut(block, UI_BTYPE_SEPR, 0, "", 0, 0, indent_size, 0, nullptr, 0.0, 0.0, 0, 0, ""); /* Indent items without collapsing icon some more within their parent. Makes it clear that they diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 7fa835b6490..ac28c344e3c 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -44,7 +44,6 @@ static int wm_collada_export_invoke(bContext *C, wmOperator *op, const wmEvent * return OPERATOR_RUNNING_MODAL; } -/* function used for WM_OT_save_mainfile too */ static int wm_collada_export_exec(bContext *C, wmOperator *op) { char filepath[FILE_MAX]; @@ -673,7 +672,6 @@ void WM_OT_collada_export(wmOperatorType *ot) "Store Bindpose information in custom bone properties for later use during Collada export"); } -/* function used for WM_OT_save_mainfile too */ static int wm_collada_import_exec(bContext *C, wmOperator *op) { char filename[FILE_MAX]; diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c index 662a372b608..d1fd4cefcda 100644 --- a/source/blender/editors/io/io_gpencil_export.c +++ b/source/blender/editors/io/io_gpencil_export.c @@ -10,10 +10,10 @@ # include "BLI_path_util.h" # include "BLI_string.h" -# include "DNA_gpencil_types.h" +# include "DNA_gpencil_legacy_types.h" # include "DNA_space_types.h" -# include "BKE_gpencil.h" +# include "BKE_gpencil_legacy.h" # include "BKE_main.h" # include "BKE_report.h" # include "BKE_screen.h" diff --git a/source/blender/editors/io/io_gpencil_import.c b/source/blender/editors/io/io_gpencil_import.c index 5325965e9a5..8a66abd2fec 100644 --- a/source/blender/editors/io/io_gpencil_import.c +++ b/source/blender/editors/io/io_gpencil_import.c @@ -11,11 +11,11 @@ # include "MEM_guardedalloc.h" -# include "DNA_gpencil_types.h" +# include "DNA_gpencil_legacy_types.h" # include "DNA_space_types.h" # include "BKE_context.h" -# include "BKE_gpencil.h" +# include "BKE_gpencil_legacy.h" # include "BKE_report.h" # include "BLT_translation.h" diff --git a/source/blender/editors/io/io_ply_ops.c b/source/blender/editors/io/io_ply_ops.c index 52eeef6451e..19bba353cb8 100644 --- a/source/blender/editors/io/io_ply_ops.c +++ b/source/blender/editors/io/io_ply_ops.c @@ -64,7 +64,7 @@ static int wm_ply_export_exec(bContext *C, wmOperator *op) BKE_report(op->reports, RPT_ERROR, "No filename given"); return OPERATOR_CANCELLED; } - struct PLYExportParams export_params; + struct PLYExportParams export_params = {"\0"}; export_params.file_base_for_tests[0] = '\0'; RNA_string_get(op->ptr, "filepath", export_params.filepath); export_params.blen_filepath = CTX_data_main(C)->filepath; diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index ea4050d0ba0..8019fee01fb 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -469,7 +469,8 @@ static void mask_draw_curve_type(const bContext *C, float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f( + "viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 2); /* "advanced" mode */ immUniform4fv("color", colors[0]); @@ -806,7 +807,7 @@ void ED_mask_draw_frames( int height = (frame == cfra) ? 22 : 10; int x = (frame - sfra) * framelen; immVertex2i(pos, x, region_bottom); - immVertex2i(pos, x, region_bottom + height * UI_DPI_FAC); + immVertex2i(pos, x, region_bottom + height * UI_SCALE_FAC); } immEnd(); immUnbindProgram(); diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index d34b274c111..738fb6b0ce1 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -1732,7 +1732,7 @@ void MASK_OT_hide_view_clear(wmOperatorType *ot) /* identifiers */ ot->name = "Clear Restrict View"; - ot->description = "Reveal the layer by setting the hide flag"; + ot->description = "Reveal temporarily hidden mask layers"; ot->idname = "MASK_OT_hide_view_clear"; /* api callbacks */ @@ -1792,7 +1792,7 @@ void MASK_OT_hide_view_set(wmOperatorType *ot) { /* identifiers */ ot->name = "Set Restrict View"; - ot->description = "Hide the layer by setting the hide flag"; + ot->description = "Temporarily hide mask layers"; ot->idname = "MASK_OT_hide_view_set"; /* api callbacks */ diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 27d0c6808c8..64a4f59a5e7 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -23,7 +23,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "ED_mesh.h" @@ -213,10 +213,10 @@ void paintface_reveal(bContext *C, Object *ob, const bool select) } /** - * Join all edges of each poly in the AtomicDisjointSet. This can be used to find out which polys + * Join all edges of each poly in the #AtomicDisjointSet. This can be used to find out which polys * are connected to each other. - * \param islands Is expected to be of length mesh->totedge. - * \param skip_seams Polys separated by a seam will be treated as not connected. + * \param islands: Is expected to be of length `mesh->totedge`. + * \param skip_seams: Polys separated by a seam will be treated as not connected. */ static void build_poly_connections(blender::AtomicDisjointSet &islands, Mesh &mesh, diff --git a/source/blender/editors/mesh/editmesh_attribute.cc b/source/blender/editors/mesh/editmesh_attribute.cc index 8594f3ebc1c..f9a8d551abd 100644 --- a/source/blender/editors/mesh/editmesh_attribute.cc +++ b/source/blender/editors/mesh/editmesh_attribute.cc @@ -11,7 +11,7 @@ #include "BKE_context.h" #include "BKE_editmesh.h" #include "BKE_layer.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_report.h" #include "BKE_type_conversions.hh" diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 736555d678c..a9cc62e6a51 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -66,7 +66,7 @@ /* Detect isolated holes and fill them. */ #define USE_NET_ISLAND_CONNECT -#define KMAXDIST (10 * U.dpi_fac) /* Max mouse distance from edge before not detecting it. */ +#define KMAXDIST (10 * UI_SCALE_FAC) /* Max mouse distance from edge before not detecting it. */ /* WARNING: Knife float precision is fragile: * Be careful before making changes here see: (#43229, #42864, #42459, #41164). @@ -495,7 +495,7 @@ static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd) char numstr[256]; float numstr_size[2]; float posit[2]; - const float bg_margin = 4.0f * U.dpi_fac; + const float bg_margin = 4.0f * UI_SCALE_FAC; const float font_size = 14.0f; const int distance_precision = 4; @@ -517,7 +517,7 @@ static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd) } BLF_enable(blf_mono_font, BLF_ROTATION); - BLF_size(blf_mono_font, font_size * U.dpi_fac); + BLF_size(blf_mono_font, font_size * UI_SCALE_FAC); BLF_rotation(blf_mono_font, 0.0f); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); @@ -563,9 +563,9 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd, { const RegionView3D *rv3d = kcd->region->regiondata; const int arc_steps = 24; - const float arc_size = 64.0f * U.dpi_fac; - const float bg_margin = 4.0f * U.dpi_fac; - const float cap_size = 4.0f * U.dpi_fac; + const float arc_size = 64.0f * UI_SCALE_FAC; + const float bg_margin = 4.0f * UI_SCALE_FAC; + const float cap_size = 4.0f * UI_SCALE_FAC; const float font_size = 14.0f; const int angle_precision = 3; @@ -647,7 +647,7 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd, } BLF_enable(blf_mono_font, BLF_ROTATION); - BLF_size(blf_mono_font, font_size * U.dpi_fac); + BLF_size(blf_mono_font, font_size * UI_SCALE_FAC); BLF_rotation(blf_mono_font, 0.0f); BLF_width_and_height(blf_mono_font, numstr, sizeof(numstr), &numstr_size[0], &numstr_size[1]); @@ -907,7 +907,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v if (kcd->prev.vert) { immUniformColor3ubv(kcd->colors.point); - GPU_point_size(11 * UI_DPI_FAC); + GPU_point_size(11 * UI_SCALE_FAC); immBegin(GPU_PRIM_POINTS, 1); immVertex3fv(pos, kcd->prev.cage); @@ -916,7 +916,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v if (kcd->prev.bmface || kcd->prev.edge) { immUniformColor3ubv(kcd->colors.curpoint); - GPU_point_size(9 * UI_DPI_FAC); + GPU_point_size(9 * UI_SCALE_FAC); immBegin(GPU_PRIM_POINTS, 1); immVertex3fv(pos, kcd->prev.cage); @@ -925,7 +925,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v if (kcd->curr.vert) { immUniformColor3ubv(kcd->colors.point); - GPU_point_size(11 * UI_DPI_FAC); + GPU_point_size(11 * UI_SCALE_FAC); immBegin(GPU_PRIM_POINTS, 1); immVertex3fv(pos, kcd->curr.cage); @@ -943,7 +943,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v if (kcd->curr.bmface || kcd->curr.edge) { immUniformColor3ubv(kcd->colors.curpoint); - GPU_point_size(9 * UI_DPI_FAC); + GPU_point_size(9 * UI_SCALE_FAC); immBegin(GPU_PRIM_POINTS, 1); immVertex3fv(pos, kcd->curr.cage); @@ -984,7 +984,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v KnifeVert *kfv; immUniformColor3ubv(kcd->colors.point); - GPU_point_size(5.0 * UI_DPI_FAC); + GPU_point_size(5.0 * UI_SCALE_FAC); GPUBatch *batch = immBeginBatchAtMost(GPU_PRIM_POINTS, BLI_mempool_len(kcd->kverts)); @@ -1040,7 +1040,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v /* Draw any snapped verts first. */ rgba_uchar_to_float(fcol, kcd->colors.point_a); GPU_batch_uniform_4fv(batch, "color", fcol); - GPU_point_size(11 * UI_DPI_FAC); + GPU_point_size(11 * UI_SCALE_FAC); if (snapped_verts_count > 0) { GPU_batch_draw_range(batch, 0, snapped_verts_count); } @@ -1048,7 +1048,7 @@ static void knifetool_draw(const bContext *UNUSED(C), ARegion *UNUSED(region), v /* Now draw the rest. */ rgba_uchar_to_float(fcol, kcd->colors.curpoint_a); GPU_batch_uniform_4fv(batch, "color", fcol); - GPU_point_size(7 * UI_DPI_FAC); + GPU_point_size(7 * UI_SCALE_FAC); if (other_verts_count > 0) { GPU_batch_draw_range(batch, snapped_verts_count, other_verts_count); } diff --git a/source/blender/editors/mesh/editmesh_knife_project.cc b/source/blender/editors/mesh/editmesh_knife_project.cc index 4487c7a413a..eb073eb211c 100644 --- a/source/blender/editors/mesh/editmesh_knife_project.cc +++ b/source/blender/editors/mesh/editmesh_knife_project.cc @@ -18,7 +18,7 @@ #include "BKE_editmesh.h" #include "BKE_layer.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_object.h" #include "BKE_report.h" diff --git a/source/blender/editors/mesh/editmesh_mask_extract.cc b/source/blender/editors/mesh/editmesh_mask_extract.cc index 8dc08f233e9..c1e1bbc2adf 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.cc +++ b/source/blender/editors/mesh/editmesh_mask_extract.cc @@ -17,7 +17,7 @@ #include "BKE_editmesh.h" #include "BKE_layer.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_paint.h" #include "BKE_report.h" diff --git a/source/blender/editors/mesh/editmesh_select.cc b/source/blender/editors/mesh/editmesh_select.cc index 94c2e3352b3..2c1c3f9f80c 100644 --- a/source/blender/editors/mesh/editmesh_select.cc +++ b/source/blender/editors/mesh/editmesh_select.cc @@ -24,7 +24,7 @@ #include "BKE_editmesh.h" #include "BKE_editmesh_cache.h" #include "BKE_layer.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_report.h" #include "WM_api.h" diff --git a/source/blender/editors/mesh/editmesh_tools.cc b/source/blender/editors/mesh/editmesh_tools.cc index 9de10bb7d28..561ad629bd7 100644 --- a/source/blender/editors/mesh/editmesh_tools.cc +++ b/source/blender/editors/mesh/editmesh_tools.cc @@ -38,7 +38,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_texture.h" @@ -3125,15 +3125,15 @@ static int edbm_rotate_colors_exec(bContext *C, wmOperator *op) BMOperator bmop; - const Mesh *me = BKE_object_get_original_mesh(ob); - const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); - - if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) { + Mesh *me = BKE_object_get_original_mesh(ob); + const CustomDataLayer *layer = BKE_id_attribute_search( + &me->id, me->active_color_attribute, CD_MASK_COLOR_ALL, ATTR_DOMAIN_MASK_CORNER); + if (!layer) { continue; } int color_index = BKE_id_attribute_to_index( - &me->id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); + &me->id, layer, ATTR_DOMAIN_MASK_CORNER, CD_MASK_COLOR_ALL); EDBM_op_init(em, &bmop, op, @@ -3177,17 +3177,17 @@ static int edbm_reverse_colors_exec(bContext *C, wmOperator *op) continue; } - const Mesh *me = BKE_object_get_original_mesh(obedit); - const CustomDataLayer *layer = BKE_id_attributes_active_color_get(&me->id); - - if (!layer || BKE_id_attribute_domain(&me->id, layer) != ATTR_DOMAIN_CORNER) { + Mesh *me = BKE_object_get_original_mesh(obedit); + const CustomDataLayer *layer = BKE_id_attribute_search( + &me->id, me->active_color_attribute, CD_MASK_COLOR_ALL, ATTR_DOMAIN_MASK_CORNER); + if (!layer) { continue; } BMOperator bmop; int color_index = BKE_id_attribute_to_index( - &me->id, layer, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL); + &me->id, layer, ATTR_DOMAIN_MASK_CORNER, CD_MASK_COLOR_ALL); EDBM_op_init( em, &bmop, op, "reverse_colors faces=%hf color_index=%i", BM_ELEM_SELECT, color_index); diff --git a/source/blender/editors/mesh/editmesh_undo.cc b/source/blender/editors/mesh/editmesh_undo.cc index d3a1bb4ed6c..a31f90d5c60 100644 --- a/source/blender/editors/mesh/editmesh_undo.cc +++ b/source/blender/editors/mesh/editmesh_undo.cc @@ -17,6 +17,7 @@ #include "BLI_array_utils.h" #include "BLI_listbase.h" +#include "BLI_task.hh" #include "BKE_context.h" #include "BKE_customdata.h" @@ -25,7 +26,7 @@ #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_undo_system.h" @@ -118,8 +119,22 @@ struct UndoMesh { /** \name Array Store * \{ */ +/** + * Store separate #BArrayStore_AtSize so multiple threads + * can access array stores without locking. + */ +enum { + ARRAY_STORE_INDEX_VERT = 0, + ARRAY_STORE_INDEX_EDGE, + ARRAY_STORE_INDEX_LOOP, + ARRAY_STORE_INDEX_POLY, + ARRAY_STORE_INDEX_SHAPE, + ARRAY_STORE_INDEX_MSEL, +}; +# define ARRAY_STORE_INDEX_NUM (ARRAY_STORE_INDEX_MSEL + 1) + static struct { - BArrayStore_AtSize bs_stride; + BArrayStore_AtSize bs_stride[ARRAY_STORE_INDEX_NUM]; int users; /** @@ -132,11 +147,12 @@ static struct { TaskPool *task_pool; # endif -} um_arraystore = {{nullptr}}; +} um_arraystore = {{{nullptr}}}; static void um_arraystore_cd_compact(CustomData *cdata, const size_t data_len, - bool create, + const bool create, + const int bs_index, const BArrayCustomData *bcd_reference, BArrayCustomData **r_bcd_first) { @@ -175,7 +191,7 @@ static void um_arraystore_cd_compact(CustomData *cdata, const int stride = CustomData_sizeof(type); BArrayStore *bs = create ? BLI_array_store_at_size_ensure( - &um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : + &um_arraystore.bs_stride[bs_index], stride, ARRAY_CHUNK_SIZE) : nullptr; const int layer_len = layer_end - layer_start; @@ -284,12 +300,12 @@ static void um_arraystore_cd_expand(const BArrayCustomData *bcd, } } -static void um_arraystore_cd_free(BArrayCustomData *bcd) +static void um_arraystore_cd_free(BArrayCustomData *bcd, const int bs_index) { while (bcd) { BArrayCustomData *bcd_next = bcd->next; const int stride = CustomData_sizeof(bcd->type); - BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); + BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride[bs_index], stride); for (int i = 0; i < bcd->states_len; i++) { if (bcd->states[i]) { BLI_array_store_state_remove(bs, bcd->states[i]); @@ -309,56 +325,94 @@ static void um_arraystore_compact_ex(UndoMesh *um, const UndoMesh *um_ref, bool { Mesh *me = &um->me; - um_arraystore_cd_compact( - &me->vdata, me->totvert, create, um_ref ? um_ref->store.vdata : nullptr, &um->store.vdata); - um_arraystore_cd_compact( - &me->edata, me->totedge, create, um_ref ? um_ref->store.edata : nullptr, &um->store.edata); - um_arraystore_cd_compact( - &me->ldata, me->totloop, create, um_ref ? um_ref->store.ldata : nullptr, &um->store.ldata); - um_arraystore_cd_compact( - &me->pdata, me->totpoly, create, um_ref ? um_ref->store.pdata : nullptr, &um->store.pdata); + /* Compacting can be time consuming, run in parallel. + * + * NOTE(@ideasman42): this could be further parallelized with every custom-data layer + * running in it's own thread. If this is a bottleneck it's worth considering. + * At the moment it seems fast enough to split by element type. + * Since this is it's self a background thread, using too many threads here could + * interfere with foreground tasks. */ + blender::threading::parallel_invoke( + 4096 < (me->totvert + me->totedge + me->totloop + me->totpoly), + [&]() { + um_arraystore_cd_compact(&me->vdata, + me->totvert, + create, + ARRAY_STORE_INDEX_VERT, + um_ref ? um_ref->store.vdata : nullptr, + &um->store.vdata); + }, + [&]() { + um_arraystore_cd_compact(&me->edata, + me->totedge, + create, + ARRAY_STORE_INDEX_EDGE, + um_ref ? um_ref->store.edata : nullptr, + &um->store.edata); + }, + [&]() { + um_arraystore_cd_compact(&me->ldata, + me->totloop, + create, + ARRAY_STORE_INDEX_LOOP, + um_ref ? um_ref->store.ldata : nullptr, + &um->store.ldata); + }, + [&]() { + um_arraystore_cd_compact(&me->pdata, + me->totpoly, + create, + ARRAY_STORE_INDEX_POLY, + um_ref ? um_ref->store.pdata : nullptr, + &um->store.pdata); + }, + [&]() { + if (me->key && me->key->totkey) { + const size_t stride = me->key->elemsize; + BArrayStore *bs = create ? BLI_array_store_at_size_ensure( + &um_arraystore.bs_stride[ARRAY_STORE_INDEX_SHAPE], + stride, + ARRAY_CHUNK_SIZE) : + nullptr; + if (create) { + um->store.keyblocks = static_cast( + MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__)); + } + KeyBlock *keyblock = static_cast(me->key->block.first); + for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) { + if (create) { + BArrayState *state_reference = (um_ref && um_ref->me.key && + (i < um_ref->me.key->totkey)) ? + um_ref->store.keyblocks[i] : + nullptr; + um->store.keyblocks[i] = BLI_array_store_state_add( + bs, keyblock->data, size_t(keyblock->totelem) * stride, state_reference); + } - if (me->key && me->key->totkey) { - const size_t stride = me->key->elemsize; - BArrayStore *bs = create ? BLI_array_store_at_size_ensure( - &um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE) : - nullptr; - if (create) { - um->store.keyblocks = static_cast( - MEM_mallocN(me->key->totkey * sizeof(*um->store.keyblocks), __func__)); - } - KeyBlock *keyblock = static_cast(me->key->block.first); - for (int i = 0; i < me->key->totkey; i++, keyblock = keyblock->next) { - if (create) { - BArrayState *state_reference = (um_ref && um_ref->me.key && (i < um_ref->me.key->totkey)) ? - um_ref->store.keyblocks[i] : - nullptr; - um->store.keyblocks[i] = BLI_array_store_state_add( - bs, keyblock->data, size_t(keyblock->totelem) * stride, state_reference); - } + if (keyblock->data) { + MEM_freeN(keyblock->data); + keyblock->data = nullptr; + } + } + } + }, + [&]() { + if (me->mselect && me->totselect) { + BLI_assert(create == (um->store.mselect == nullptr)); + if (create) { + BArrayState *state_reference = um_ref ? um_ref->store.mselect : nullptr; + const size_t stride = sizeof(*me->mselect); + BArrayStore *bs = BLI_array_store_at_size_ensure( + &um_arraystore.bs_stride[ARRAY_STORE_INDEX_MSEL], stride, ARRAY_CHUNK_SIZE); + um->store.mselect = BLI_array_store_state_add( + bs, me->mselect, size_t(me->totselect) * stride, state_reference); + } - if (keyblock->data) { - MEM_freeN(keyblock->data); - keyblock->data = nullptr; - } - } - } - - if (me->mselect && me->totselect) { - BLI_assert(create == (um->store.mselect == nullptr)); - if (create) { - BArrayState *state_reference = um_ref ? um_ref->store.mselect : nullptr; - const size_t stride = sizeof(*me->mselect); - BArrayStore *bs = BLI_array_store_at_size_ensure( - &um_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); - um->store.mselect = BLI_array_store_state_add( - bs, me->mselect, size_t(me->totselect) * stride, state_reference); - } - - /* keep me->totselect for validation */ - MEM_freeN(me->mselect); - me->mselect = nullptr; - } + /* keep me->totselect for validation */ + MEM_freeN(me->mselect); + me->mselect = nullptr; + } + }); if (create) { um_arraystore.users += 1; @@ -376,9 +430,15 @@ static void um_arraystore_compact(UndoMesh *um, const UndoMesh *um_ref) static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref) { # ifdef DEBUG_PRINT - size_t size_expanded_prev, size_compacted_prev; - BLI_array_store_at_size_calc_memory_usage( - &um_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev); + size_t size_expanded_prev = 0, size_compacted_prev = 0; + + for (int bs_index = 0; bs_index < ARRAY_STORE_INDEX_NUM; bs_index++) { + size_t size_expanded_prev_iter, size_compacted_prev_iter; + BLI_array_store_at_size_calc_memory_usage( + &um_arraystore.bs_stride[bs_index], &size_expanded_prev_iter, &size_compacted_prev_iter); + size_expanded_prev += size_expanded_prev_iter; + size_compacted_prev += size_compacted_prev_iter; + } # endif # ifdef DEBUG_TIME @@ -393,9 +453,15 @@ static void um_arraystore_compact_with_info(UndoMesh *um, const UndoMesh *um_ref # ifdef DEBUG_PRINT { - size_t size_expanded, size_compacted; - BLI_array_store_at_size_calc_memory_usage( - &um_arraystore.bs_stride, &size_expanded, &size_compacted); + size_t size_expanded = 0, size_compacted = 0; + + for (int bs_index = 0; bs_index < ARRAY_STORE_INDEX_NUM; bs_index++) { + size_t size_expanded_iter, size_compacted_iter; + BLI_array_store_at_size_calc_memory_usage( + &um_arraystore.bs_stride[bs_index], &size_expanded_iter, &size_compacted_iter); + size_expanded += size_expanded_iter; + size_compacted += size_compacted_iter; + } const double percent_total = size_expanded ? ((double(size_compacted) / double(size_expanded)) * 100.0) : @@ -471,14 +537,15 @@ static void um_arraystore_free(UndoMesh *um) { Mesh *me = &um->me; - um_arraystore_cd_free(um->store.vdata); - um_arraystore_cd_free(um->store.edata); - um_arraystore_cd_free(um->store.ldata); - um_arraystore_cd_free(um->store.pdata); + um_arraystore_cd_free(um->store.vdata, ARRAY_STORE_INDEX_VERT); + um_arraystore_cd_free(um->store.edata, ARRAY_STORE_INDEX_EDGE); + um_arraystore_cd_free(um->store.ldata, ARRAY_STORE_INDEX_LOOP); + um_arraystore_cd_free(um->store.pdata, ARRAY_STORE_INDEX_POLY); if (um->store.keyblocks) { const size_t stride = me->key->elemsize; - BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); + BArrayStore *bs = BLI_array_store_at_size_get( + &um_arraystore.bs_stride[ARRAY_STORE_INDEX_SHAPE], stride); for (int i = 0; i < me->key->totkey; i++) { BArrayState *state = um->store.keyblocks[i]; BLI_array_store_state_remove(bs, state); @@ -489,7 +556,8 @@ static void um_arraystore_free(UndoMesh *um) if (um->store.mselect) { const size_t stride = sizeof(*me->mselect); - BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride, stride); + BArrayStore *bs = BLI_array_store_at_size_get(&um_arraystore.bs_stride[ARRAY_STORE_INDEX_MSEL], + stride); BArrayState *state = um->store.mselect; BLI_array_store_state_remove(bs, state); um->store.mselect = nullptr; @@ -503,8 +571,9 @@ static void um_arraystore_free(UndoMesh *um) # ifdef DEBUG_PRINT printf("mesh undo store: freeing all data!\n"); # endif - BLI_array_store_at_size_clear(&um_arraystore.bs_stride); - + for (int bs_index = 0; bs_index < ARRAY_STORE_INDEX_NUM; bs_index++) { + BLI_array_store_at_size_clear(&um_arraystore.bs_stride[bs_index]); + } # ifdef USE_ARRAY_STORE_THREAD BLI_task_pool_free(um_arraystore.task_pool); um_arraystore.task_pool = nullptr; diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 52f67860c90..9627d88f258 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -23,7 +23,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_report.h" @@ -273,19 +273,18 @@ int ED_mesh_uv_add( } if (CustomData_has_layer(&me->ldata, CD_PROP_FLOAT2) && do_init) { - CustomData_add_layer_named(&me->ldata, - CD_PROP_FLOAT2, - CD_DUPLICATE, - const_cast(static_cast( - CustomData_get_layer(&me->ldata, CD_PROP_FLOAT2))), - me->totloop, - unique_name); + CustomData_add_layer_named_with_data( + &me->ldata, + CD_PROP_FLOAT2, + MEM_dupallocN(CustomData_get_layer(&me->ldata, CD_PROP_FLOAT2)), + me->totloop, + unique_name); is_init = true; } else { CustomData_add_layer_named( - &me->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, me->totloop, unique_name); + &me->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, me->totloop, unique_name); } if (active_set || layernum_dst == 0) { @@ -343,7 +342,7 @@ static bool *ensure_corner_boolean_attribute(Mesh &mesh, const blender::StringRe CustomData_get_layer_named_for_write(&mesh.ldata, CD_PROP_BOOL, name.c_str(), mesh.totloop)); if (!data) { data = static_cast(CustomData_add_layer_named( - &mesh.ldata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, mesh.totpoly, name.c_str())); + &mesh.ldata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh.totpoly, name.c_str())); } return data; } @@ -634,7 +633,7 @@ static int mesh_customdata_add_exec__internal(bContext *C, char htype, int type) BM_data_layer_add(mesh->edit_mesh->bm, data, type); } else { - CustomData_add_layer(data, type, CD_SET_DEFAULT, nullptr, tot); + CustomData_add_layer(data, eCustomDataType(type), CD_SET_DEFAULT, tot); } DEG_id_tag_update(&mesh->id, 0); @@ -795,23 +794,21 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator /* Tag edges as sharp according to smooth threshold if needed, * to preserve auto-smooth shading. */ if (me->flag & ME_AUTOSMOOTH) { - const Span polys = me->polys(); - const Span loops = me->loops(); bke::MutableAttributeAccessor attributes = me->attributes_for_write(); bke::SpanAttributeWriter sharp_edges = attributes.lookup_or_add_for_write_span( "sharp_edge", ATTR_DOMAIN_EDGE); - BKE_edges_sharp_from_angle_set(me->totedge, - loops.data(), - loops.size(), - polys.data(), - BKE_mesh_poly_normals_ensure(me), - polys.size(), - me->smoothresh, - sharp_edges.span.data()); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, "sharp_face")); + bke::mesh::edges_sharp_from_angle_set(me->polys(), + me->loops(), + me->poly_normals(), + sharp_faces, + me->smoothresh, + sharp_edges.span); sharp_edges.finish(); } - CustomData_add_layer(&me->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, me->totloop); + CustomData_add_layer(&me->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, me->totloop); } DEG_id_tag_update(&me->id, 0); @@ -1119,8 +1116,8 @@ void ED_mesh_update(Mesh *mesh, bContext *C, bool calc_edges, bool calc_edges_lo /* Default state is not to have tessface's so make sure this is the case. */ BKE_mesh_tessface_clear(mesh); - /* Tag lazily calculated data as dirty. */ - BKE_mesh_normals_tag_dirty(mesh); + mesh->runtime->vert_normals_dirty = true; + mesh->runtime->poly_normals_dirty = true; DEG_id_tag_update(&mesh->id, 0); WM_event_add_notifier(C, NC_GEOM | ND_DATA, mesh); @@ -1146,8 +1143,7 @@ static void mesh_add_verts(Mesh *mesh, int len) CustomData_copy_data(&mesh->vdata, &vdata, 0, 0, mesh->totvert); if (!CustomData_get_layer_named(&vdata, CD_PROP_FLOAT3, "position")) { - CustomData_add_layer_named( - &vdata, CD_PROP_FLOAT3, CD_SET_DEFAULT, nullptr, totvert, "position"); + CustomData_add_layer_named(&vdata, CD_PROP_FLOAT3, CD_SET_DEFAULT, totvert, "position"); } CustomData_free(&mesh->vdata, mesh->totvert); @@ -1181,7 +1177,7 @@ static void mesh_add_edges(Mesh *mesh, int len) CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { - CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); + CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, totedge); } CustomData_free(&mesh->edata, mesh->totedge); @@ -1214,7 +1210,7 @@ static void mesh_add_loops(Mesh *mesh, int len) CustomData_copy_data(&mesh->ldata, &ldata, 0, 0, mesh->totloop); if (!CustomData_has_layer(&ldata, CD_MLOOP)) { - CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop); + CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, totloop); } BKE_mesh_runtime_clear_cache(mesh); @@ -1242,7 +1238,7 @@ static void mesh_add_polys(Mesh *mesh, int len) CustomData_copy_data(&mesh->pdata, &pdata, 0, 0, mesh->totpoly); if (!CustomData_has_layer(&pdata, CD_MPOLY)) { - CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly); + CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, totpoly); } CustomData_free(&mesh->pdata, mesh->totpoly); @@ -1468,23 +1464,19 @@ void ED_mesh_split_faces(Mesh *mesh) const bke::AttributeAccessor attributes = mesh->attributes(); const VArray mesh_sharp_edges = attributes.lookup_or_default( "sharp_edge", ATTR_DOMAIN_EDGE, false); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); Array sharp_edges(mesh->totedge); mesh_sharp_edges.materialize(sharp_edges); - BKE_edges_sharp_from_angle_set(mesh->totedge, - loops.data(), - loops.size(), - polys.data(), - BKE_mesh_poly_normals_ensure(mesh), - polys.size(), - split_angle, - sharp_edges.data()); + bke::mesh::edges_sharp_from_angle_set( + polys, loops, mesh->poly_normals(), sharp_faces, split_angle, sharp_edges); threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) { for (const int poly_i : range) { const MPoly &poly = polys[poly_i]; - if (!(poly.flag & ME_SMOOTH)) { + if (sharp_faces && sharp_faces[poly_i]) { for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { sharp_edges[loop.e] = true; } diff --git a/source/blender/editors/mesh/mesh_mirror.cc b/source/blender/editors/mesh/mesh_mirror.cc index ee5b03d0c59..30cff1f95d3 100644 --- a/source/blender/editors/mesh/mesh_mirror.cc +++ b/source/blender/editors/mesh/mesh_mirror.cc @@ -15,7 +15,7 @@ #include "DNA_object_types.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_kdtree.h" #include "ED_mesh.h" diff --git a/source/blender/editors/mesh/meshtools.cc b/source/blender/editors/mesh/meshtools.cc index 71fdf1b5ad1..0949361ddea 100644 --- a/source/blender/editors/mesh/meshtools.cc +++ b/source/blender/editors/mesh/meshtools.cc @@ -33,7 +33,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_iterators.h" #include "BKE_mesh_runtime.h" #include "BKE_multires.h" @@ -257,7 +257,7 @@ static void join_mesh_single(Depsgraph *depsgraph, CustomData_get_layer_named_for_write(pdata, CD_PROP_INT32, "material_index", totpoly)); if (!material_indices && totcol > 1) { material_indices = (int *)CustomData_add_layer_named( - pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, totpoly, "material_index"); + pdata, CD_PROP_INT32, CD_SET_DEFAULT, totpoly, "material_index"); } if (material_indices) { for (a = 0; a < me->totpoly; a++) { @@ -583,10 +583,10 @@ int ED_mesh_join_objects_exec(bContext *C, wmOperator *op) CustomData_reset(&pdata); float3 *vert_positions = (float3 *)CustomData_add_layer_named( - &vdata, CD_PROP_FLOAT3, CD_SET_DEFAULT, nullptr, totvert, "position"); - edge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); - mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, totloop); - polys = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, totpoly); + &vdata, CD_PROP_FLOAT3, CD_SET_DEFAULT, totvert, "position"); + edge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, totedge); + mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_SET_DEFAULT, totloop); + polys = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_SET_DEFAULT, totpoly); vertofs = 0; edgeofs = 0; diff --git a/source/blender/editors/object/object_add.cc b/source/blender/editors/object/object_add.cc index f2badb37624..d6b90dd4337 100644 --- a/source/blender/editors/object/object_add.cc +++ b/source/blender/editors/object/object_add.cc @@ -16,8 +16,8 @@ #include "DNA_camera_types.h" #include "DNA_collection_types.h" #include "DNA_curve_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_key_types.h" #include "DNA_light_types.h" #include "DNA_lightprobe_types.h" @@ -56,9 +56,9 @@ #include "BKE_effect.h" #include "BKE_geometry_set.h" #include "BKE_geometry_set.hh" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_layer.h" @@ -71,7 +71,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_nla.h" #include "BKE_node.h" @@ -1304,7 +1304,7 @@ static bool object_gpencil_add_poll(bContext *C) return false; } - if (obact && obact->type == OB_GPENCIL) { + if (obact && obact->type == OB_GPENCIL_LEGACY) { if (obact->mode != OB_MODE_OBJECT) { return false; } @@ -1316,7 +1316,8 @@ static bool object_gpencil_add_poll(bContext *C) static int object_gpencil_add_exec(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C), *ob_orig = ob; - bGPdata *gpd = (ob && (ob->type == OB_GPENCIL)) ? static_cast(ob->data) : nullptr; + bGPdata *gpd = (ob && (ob->type == OB_GPENCIL_LEGACY)) ? static_cast(ob->data) : + nullptr; const int type = RNA_enum_get(op->ptr, "type"); const bool use_in_front = RNA_boolean_get(op->ptr, "use_in_front"); @@ -1361,7 +1362,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op) } } - ob = ED_object_add_type(C, OB_GPENCIL, ob_name, loc, rot, true, local_view_bits); + ob = ED_object_add_type(C, OB_GPENCIL_LEGACY, ob_name, loc, rot, true, local_view_bits); gpd = static_cast(ob->data); newob = true; } @@ -2266,7 +2267,7 @@ static int object_delete_exec(bContext *C, wmOperator *op) } /* if grease pencil object, set cache as dirty */ - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = (bGPdata *)ob->data; DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); } @@ -2761,7 +2762,7 @@ static const EnumPropertyItem convert_target_items[] = { #else "Mesh from Curve, Surface, Metaball, or Text objects"}, #endif - {OB_GPENCIL, + {OB_GPENCIL_LEGACY, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", @@ -2980,7 +2981,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) if (ob->type == OB_MESH) { BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { BKE_object_free_modifiers(ob, 0); /* after derivedmesh calls! */ BKE_object_free_shaderfx(ob, 0); } @@ -3013,7 +3014,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) } } } - else if (ob->type == OB_MESH && target == OB_GPENCIL) { + else if (ob->type == OB_MESH && target == OB_GPENCIL_LEGACY) { ob->flag |= OB_DONE; /* Create a new grease pencil object and copy transformations. */ @@ -3245,7 +3246,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) /* Meshes doesn't use the "curve cache". */ BKE_object_free_curve_cache(newob); } - else if (target == OB_GPENCIL) { + else if (target == OB_GPENCIL_LEGACY) { ushort local_view_bits = (v3d && v3d->localvd) ? v3d->local_view_uuid : 0; Object *ob_gpencil = ED_gpencil_add_object(C, newob->loc, local_view_bits); copy_v3_v3(ob_gpencil->rot, newob->rot); @@ -3280,7 +3281,7 @@ static int object_convert_exec(bContext *C, wmOperator *op) /* Meshes don't use the "curve cache". */ BKE_object_free_curve_cache(newob); } - else if (target == OB_GPENCIL) { + else if (target == OB_GPENCIL_LEGACY) { if (ob->type != OB_CURVES_LEGACY) { ob->flag &= ~OB_DONE; BKE_report(op->reports, RPT_ERROR, "Convert Surfaces to Grease Pencil is not supported"); @@ -3528,7 +3529,7 @@ static void object_convert_ui(bContext * /*C*/, wmOperator *op) if (target == OB_MESH) { uiItemR(layout, op->ptr, "merge_customdata", 0, nullptr, ICON_NONE); } - else if (target == OB_GPENCIL) { + else if (target == OB_GPENCIL_LEGACY) { uiItemR(layout, op->ptr, "thickness", 0, nullptr, ICON_NONE); uiItemR(layout, op->ptr, "angle", 0, nullptr, ICON_NONE); uiItemR(layout, op->ptr, "offset", 0, nullptr, ICON_NONE); @@ -4106,7 +4107,7 @@ static bool object_join_poll(bContext *C) return false; } - if (ELEM(ob->type, OB_MESH, OB_CURVES_LEGACY, OB_SURF, OB_ARMATURE, OB_GPENCIL)) { + if (ELEM(ob->type, OB_MESH, OB_CURVES_LEGACY, OB_SURF, OB_ARMATURE, OB_GPENCIL_LEGACY)) { return ED_operator_screenactive(C); } return false; @@ -4133,7 +4134,7 @@ static int object_join_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = (bGPdata *)ob->data; if ((!gpd) || GPENCIL_ANY_MODE(gpd)) { BKE_report(op->reports, RPT_ERROR, "This data does not support joining in this mode"); @@ -4151,7 +4152,7 @@ static int object_join_exec(bContext *C, wmOperator *op) else if (ob->type == OB_ARMATURE) { ret = ED_armature_join_objects_exec(C, op); } - else if (ob->type == OB_GPENCIL) { + else if (ob->type == OB_GPENCIL_LEGACY) { ret = ED_gpencil_join_objects_exec(C, op); } diff --git a/source/blender/editors/object/object_bake.cc b/source/blender/editors/object/object_bake.cc index 74c11c44619..04516352399 100644 --- a/source/blender/editors/object/object_bake.cc +++ b/source/blender/editors/object/object_bake.cc @@ -28,7 +28,7 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_report.h" diff --git a/source/blender/editors/object/object_bake_api.cc b/source/blender/editors/object/object_bake_api.cc index 9b4bfdae137..2b689adc9d0 100644 --- a/source/blender/editors/object/object_bake_api.cc +++ b/source/blender/editors/object/object_bake_api.cc @@ -32,7 +32,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" #include "BKE_node.h" @@ -1034,12 +1034,8 @@ static void bake_targets_populate_pixels_color_attributes(BakeTargets *targets, MLoopTri *looptri = static_cast(MEM_mallocN(sizeof(*looptri) * tottri, __func__)); const blender::Span loops = me_eval->loops(); - BKE_mesh_recalc_looptri(loops.data(), - me_eval->polys().data(), - BKE_mesh_vert_positions(me_eval), - me_eval->totloop, - me_eval->totpoly, - looptri); + blender::bke::mesh::looptris_calc( + me_eval->vert_positions(), me_eval->polys(), loops, {looptri, tottri}); /* For mapping back to original mesh in case there are modifiers. */ const int *vert_origindex = static_cast( diff --git a/source/blender/editors/object/object_data_transform.cc b/source/blender/editors/object/object_data_transform.cc index ff07a12ef10..ff670681c31 100644 --- a/source/blender/editors/object/object_data_transform.cc +++ b/source/blender/editors/object/object_data_transform.cc @@ -17,7 +17,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" @@ -31,11 +31,11 @@ #include "BKE_armature.h" #include "BKE_curve.h" #include "BKE_editmesh.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_scene.h" #include "bmesh.h" @@ -461,7 +461,7 @@ XFormObjectData *ED_object_data_xform_create_ex(ID *id, bool is_edit_mode) xod_base = &xod->base; break; } - case ID_GD: { + case ID_GD_LEGACY: { bGPdata *gpd = (bGPdata *)id; const int elem_array_len = BKE_gpencil_stroke_point_count(gpd); XFormObjectData_GPencil *xod = static_cast( @@ -619,7 +619,7 @@ void ED_object_data_xform_by_mat4(struct XFormObjectData *xod_base, const float metaball_coords_and_quats_apply_with_mat4(mb, xod->elem_array, mat); break; } - case ID_GD: { + case ID_GD_LEGACY: { bGPdata *gpd = (bGPdata *)xod_base->id; XFormObjectData_GPencil *xod = (XFormObjectData_GPencil *)xod_base; BKE_gpencil_point_coords_apply_with_mat4(gpd, xod->elem_array, mat); @@ -718,7 +718,7 @@ void ED_object_data_xform_restore(struct XFormObjectData *xod_base) metaball_coords_and_quats_apply(mb, xod->elem_array); break; } - case ID_GD: { + case ID_GD_LEGACY: { bGPdata *gpd = (bGPdata *)xod_base->id; XFormObjectData_GPencil *xod = (XFormObjectData_GPencil *)xod_base; BKE_gpencil_point_coords_apply(gpd, xod->elem_array); @@ -770,7 +770,7 @@ void ED_object_data_xform_tag_update(struct XFormObjectData *xod_base) DEG_id_tag_update(&mb->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); break; } - case ID_GD: { + case ID_GD_LEGACY: { /* Generic update. */ bGPdata *gpd = (bGPdata *)xod_base->id; DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); diff --git a/source/blender/editors/object/object_edit.cc b/source/blender/editors/object/object_edit.cc index be015017282..9dc70ddff17 100644 --- a/source/blender/editors/object/object_edit.cc +++ b/source/blender/editors/object/object_edit.cc @@ -25,7 +25,7 @@ #include "DNA_armature_types.h" #include "DNA_collection_types.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -56,7 +56,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -1737,7 +1737,7 @@ static int object_mode_set_exec(bContext *C, wmOperator *op) const bool toggle = RNA_boolean_get(op->ptr, "toggle"); /* by default the operator assume is a mesh, but if gp object change mode */ - if ((ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) { + if ((ob->type == OB_GPENCIL_LEGACY) && (mode == OB_MODE_EDIT)) { mode = OB_MODE_EDIT_GPENCIL; } diff --git a/source/blender/editors/object/object_facemap_ops.c b/source/blender/editors/object/object_facemap_ops.c index 23344c38a12..26e0006da33 100644 --- a/source/blender/editors/object/object_facemap_ops.c +++ b/source/blender/editors/object/object_facemap_ops.c @@ -53,7 +53,7 @@ void ED_object_facemap_face_add(Object *ob, bFaceMap *fmap, int facenum) /* if there's is no facemap layer then create one */ if ((facemap = CustomData_get_layer_for_write(&me->pdata, CD_FACEMAP, me->totpoly)) == NULL) { - facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, NULL, me->totpoly); + facemap = CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_SET_DEFAULT, me->totpoly); } facemap[facenum] = fmap_nr; diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index e85947534cd..51ec713a67f 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -13,8 +13,8 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -24,8 +24,8 @@ #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_object.h" @@ -60,7 +60,7 @@ GpencilModifierData *ED_object_gpencil_modifier_add( GpencilModifierData *new_md = NULL; const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type); - if (ob->type != OB_GPENCIL) { + if (ob->type != OB_GPENCIL_LEGACY) { BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); return NULL; } @@ -234,7 +234,7 @@ static bool gpencil_modifier_apply_obdata( return false; } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { if (ELEM(NULL, ob, ob->data)) { return false; } @@ -261,7 +261,7 @@ bool ED_object_gpencil_modifier_apply(Main *bmain, int UNUSED(mode)) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { if (ob->mode != OB_MODE_OBJECT) { BKE_report(reports, RPT_ERROR, "Modifiers cannot be applied in paint, sculpt or edit mode"); return false; @@ -849,7 +849,7 @@ static int gpencil_modifier_copy_to_selected_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (obact->type != OB_GPENCIL) { + if (obact->type != OB_GPENCIL_LEGACY) { BKE_reportf(op->reports, RPT_ERROR, "Source object '%s' is not a grease pencil object", @@ -862,7 +862,7 @@ static int gpencil_modifier_copy_to_selected_exec(bContext *C, wmOperator *op) continue; } - if (ob->type != OB_GPENCIL) { + if (ob->type != OB_GPENCIL_LEGACY) { BKE_reportf(op->reports, RPT_WARNING, "Destination object '%s' is not a grease pencil object", @@ -905,7 +905,7 @@ static bool gpencil_modifier_copy_to_selected_poll(bContext *C) continue; } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { found_supported_objects = true; break; } diff --git a/source/blender/editors/object/object_modes.cc b/source/blender/editors/object/object_modes.cc index f0874c48f6e..23d17e08455 100644 --- a/source/blender/editors/object/object_modes.cc +++ b/source/blender/editors/object/object_modes.cc @@ -7,7 +7,7 @@ * actual mode switching logic is per-object type. */ -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_workspace_types.h" @@ -21,7 +21,7 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_modifier.h" @@ -136,7 +136,7 @@ bool ED_object_mode_compat_test(const Object *ob, eObjectMode mode) return true; } break; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: if (mode & (OB_MODE_EDIT_GPENCIL | OB_MODE_ALL_PAINT_GPENCIL)) { return true; } @@ -193,7 +193,7 @@ bool ED_object_mode_set_ex(bContext *C, eObjectMode mode, bool use_undo, ReportL return (mode == OB_MODE_OBJECT); } - if ((ob->type == OB_GPENCIL) && (mode == OB_MODE_EDIT)) { + if ((ob->type == OB_GPENCIL_LEGACY) && (mode == OB_MODE_EDIT)) { mode = OB_MODE_EDIT_GPENCIL; } @@ -291,7 +291,7 @@ static bool ed_object_mode_generic_exit_ex( } ED_object_particle_edit_mode_exit_ex(scene, ob); } - else if (ob->type == OB_GPENCIL) { + else if (ob->type == OB_GPENCIL_LEGACY) { /* Accounted for above. */ BLI_assert((ob->mode & OB_MODE_OBJECT) == 0); if (only_test) { @@ -355,7 +355,7 @@ void ED_object_posemode_set_for_weight_paint(bContext *C, Object *ob, const bool is_mode_set) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { GpencilVirtualModifierData virtualModifierData; GpencilModifierData *md = BKE_gpencil_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index 0301564f06c..c8ae73c3013 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -47,7 +47,7 @@ #include "BKE_effect.h" #include "BKE_geometry_set.hh" #include "BKE_global.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_layer.h" @@ -55,7 +55,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -124,7 +124,7 @@ static void object_force_modifier_update_for_bind(Depsgraph *depsgraph, Object * else if (ELEM(ob->type, OB_CURVES_LEGACY, OB_SURF, OB_FONT)) { BKE_displist_make_curveTypes(depsgraph, scene_eval, ob_eval, false); } - else if (ob->type == OB_GPENCIL) { + else if (ob->type == OB_GPENCIL_LEGACY) { BKE_gpencil_modifiers_calc(depsgraph, scene_eval, ob_eval); } else if (ob->type == OB_CURVES) { @@ -651,10 +651,9 @@ bool ED_object_modifier_convert_psys_to_mesh(ReportList * /*reports*/, me->totvert = verts_num; me->totedge = edges_num; - CustomData_add_layer_named( - &me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, verts_num, "position"); - CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, edges_num); - CustomData_add_layer(&me->fdata, CD_MFACE, CD_SET_DEFAULT, nullptr, 0); + CustomData_add_layer_named(&me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, verts_num, "position"); + CustomData_add_layer(&me->edata, CD_MEDGE, CD_SET_DEFAULT, edges_num); + CustomData_add_layer(&me->fdata, CD_MFACE, CD_SET_DEFAULT, 0); blender::MutableSpan positions = me->vert_positions_for_write(); blender::MutableSpan edges = me->edges_for_write(); @@ -731,8 +730,8 @@ static void add_shapekey_layers(Mesh &mesh_dest, const Mesh &mesh_src) memcpy(array, kb->data, sizeof(float[3]) * size_t(mesh_src.totvert)); } - CustomData_add_layer_named( - &mesh_dest.vdata, CD_SHAPEKEY, CD_ASSIGN, array, mesh_dest.totvert, kb->name); + CustomData_add_layer_named_with_data( + &mesh_dest.vdata, CD_SHAPEKEY, array, mesh_dest.totvert, kb->name); const int ci = CustomData_get_layer_index_n(&mesh_dest.vdata, CD_SHAPEKEY, i); mesh_dest.vdata.layers[ci].uid = kb->uid; @@ -2938,7 +2937,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, const Span positions_eval = me_eval_deform->vert_positions(); /* add vertex weights to original mesh */ - CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, nullptr, me->totvert); + CustomData_add_layer(&me->vdata, CD_MDEFORMVERT, CD_SET_DEFAULT, me->totvert); Scene *scene = DEG_get_input_scene(depsgraph); ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 0ceec68e0db..6f24797c774 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -16,7 +16,7 @@ #include "DNA_camera_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_lattice_types.h" #include "DNA_light_types.h" @@ -51,7 +51,7 @@ #include "BKE_displist.h" #include "BKE_editmesh.h" #include "BKE_fcurve.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lattice.h" @@ -733,7 +733,7 @@ bool ED_object_parent_set(ReportList *reports, invert_m4_m4(ob->parentinv, workob.object_to_world); } - else if (is_armature_parent && (ob->type == OB_GPENCIL) && (par->type == OB_ARMATURE)) { + else if (is_armature_parent && (ob->type == OB_GPENCIL_LEGACY) && (par->type == OB_ARMATURE)) { if (partype == PAR_ARMATURE) { ED_gpencil_add_armature(C, reports, ob, par); } @@ -751,7 +751,7 @@ bool ED_object_parent_set(ReportList *reports, invert_m4_m4(ob->parentinv, workob.object_to_world); } - else if ((ob->type == OB_GPENCIL) && (par->type == OB_LATTICE)) { + else if ((ob->type == OB_GPENCIL_LEGACY) && (par->type == OB_LATTICE)) { /* Add Lattice modifier */ if (partype == PAR_LATTICE) { ED_gpencil_add_lattice_modifier(C, reports, ob, par); @@ -965,7 +965,7 @@ static int parent_set_invoke_menu(bContext *C, wmOperatorType *ot) if (child->type == OB_MESH) { has_children_of_type.mesh = true; } - if (child->type == OB_GPENCIL) { + if (child->type == OB_GPENCIL_LEGACY) { has_children_of_type.gpencil = true; } if (child->type == OB_CURVES) { @@ -1432,7 +1432,7 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst /* Linking non-grease-pencil materials to a grease-pencil object causes issues. * We make sure that if one of the objects is a grease-pencil object, the other must be * as well. */ - ((ob_src->type == OB_GPENCIL) == (ob_dst->type == OB_GPENCIL))) { + ((ob_src->type == OB_GPENCIL_LEGACY) == (ob_dst->type == OB_GPENCIL_LEGACY))) { return true; } break; @@ -1456,7 +1456,7 @@ static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst } break; case MAKE_LINKS_SHADERFX: - if ((ob_src->type == OB_GPENCIL) && (ob_dst->type == OB_GPENCIL)) { + if ((ob_src->type == OB_GPENCIL_LEGACY) && (ob_dst->type == OB_GPENCIL_LEGACY)) { return true; } break; @@ -1892,7 +1892,7 @@ static void single_obdata_users( ob->data, BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS)); break; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: ob->data = ID_NEW_SET( ob->data, BKE_id_copy_ex(bmain, ob->data, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS)); diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index dd1ea454a66..678b19f8ef2 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -25,12 +25,13 @@ #include "BLT_translation.h" +#include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mirror.h" #include "BKE_mesh_remesh_voxel.h" #include "BKE_mesh_runtime.h" @@ -118,6 +119,7 @@ static bool object_remesh_poll(bContext *C) static int voxel_remesh_exec(bContext *C, wmOperator *op) { + using namespace blender; Object *ob = CTX_data_active_object(C); Mesh *mesh = static_cast(ob->data); @@ -132,8 +134,10 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) } /* Output mesh will be all smooth or all flat shading. */ - const Span polys = mesh->polys(); - const bool smooth_normals = polys.first().flag & ME_SMOOTH; + const bke::AttributeAccessor attributes = mesh->attributes(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); + const bool smooth_normals = !sharp_faces[0]; float isovalue = 0.0f; if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) { @@ -176,9 +180,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob); - if (smooth_normals) { - BKE_mesh_smooth_flag_set(static_cast(ob->data), true); - } + BKE_mesh_smooth_flag_set(static_cast(ob->data), smooth_normals); if (ob->mode == OB_MODE_SCULPT) { ED_sculpt_undo_geometry_end(ob); @@ -352,7 +354,7 @@ static void voxel_size_edit_draw(const bContext *C, ARegion * /*region*/, void * GPU_matrix_push(); GPU_matrix_mul(cd->text_mat); - BLF_size(fontid, 10.0f * fstyle_points * U.dpi_fac); + BLF_size(fontid, 10.0f * fstyle_points * UI_SCALE_FAC); BLF_color3f(fontid, 1.0f, 1.0f, 1.0f); BLF_width_and_height(fontid, str, strdrawlen, &strwidth, &strheight); BLF_position(fontid, -0.5f * strwidth, -0.5f * strheight, 0.0f); @@ -898,9 +900,7 @@ static void quadriflow_start_job(void *customdata, bool *stop, bool *do_update, BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob); - if (qj->smooth_normals) { - BKE_mesh_smooth_flag_set(static_cast(ob->data), true); - } + BKE_mesh_smooth_flag_set(static_cast(ob->data), qj->smooth_normals); if (ob->mode == OB_MODE_SCULPT) { ED_sculpt_undo_geometry_end(ob); diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 8d085cfc92a..540c1890b59 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -15,7 +15,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" #include "DNA_modifier_types.h" diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c index 4b721cb65a1..b030e643acd 100644 --- a/source/blender/editors/object/object_shader_fx.c +++ b/source/blender/editors/object/object_shader_fx.c @@ -12,7 +12,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_shader_fx_types.h" @@ -60,7 +60,7 @@ ShaderFxData *ED_object_shaderfx_add( ShaderFxData *new_fx = NULL; const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type); - if (ob->type != OB_GPENCIL) { + if (ob->type != OB_GPENCIL_LEGACY) { BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2); return NULL; } diff --git a/source/blender/editors/object/object_transform.cc b/source/blender/editors/object/object_transform.cc index de4a61a829f..f693e4918e5 100644 --- a/source/blender/editors/object/object_transform.cc +++ b/source/blender/editors/object/object_transform.cc @@ -13,7 +13,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_light_types.h" #include "DNA_mesh_types.h" @@ -35,15 +35,15 @@ #include "BKE_curve.h" #include "BKE_curves.hh" #include "BKE_editmesh.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_idtype.h" #include "BKE_lattice.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_multires.h" #include "BKE_object.h" #include "BKE_pointcloud.h" @@ -710,7 +710,7 @@ static int apply_objects_internal(bContext *C, OB_CURVES_LEGACY, OB_SURF, OB_FONT, - OB_GPENCIL, + OB_GPENCIL_LEGACY, OB_CURVES, OB_POINTCLOUD)) { ID *obdata = static_cast(ob->data); @@ -770,7 +770,7 @@ static int apply_objects_internal(bContext *C, } } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = static_cast(ob->data); if (gpd) { if (gpd->layers.first) { @@ -792,7 +792,7 @@ static int apply_objects_internal(bContext *C, "Can't apply to a GP data-block where all layers are parented: Object " "\"%s\", %s \"%s\", aborting", ob->id.name + 2, - BKE_idtype_idcode_to_name(ID_GD), + BKE_idtype_idcode_to_name(ID_GD_LEGACY), gpd->id.name + 2); changed = false; } @@ -804,7 +804,7 @@ static int apply_objects_internal(bContext *C, RPT_ERROR, R"(Can't apply to GP data-block with no layers: Object "%s", %s "%s", aborting)", ob->id.name + 2, - BKE_idtype_idcode_to_name(ID_GD), + BKE_idtype_idcode_to_name(ID_GD_LEGACY), gpd->id.name + 2); } } @@ -939,7 +939,7 @@ static int apply_objects_internal(bContext *C, cu->fsize *= scale; } } - else if (ob->type == OB_GPENCIL) { + else if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = static_cast(ob->data); BKE_gpencil_transform(gpd, mat); } @@ -1595,7 +1595,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) lt->id.tag |= LIB_TAG_DOIT; do_inverse_offset = true; } - else if (ob->type == OB_GPENCIL) { + else if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = static_cast(ob->data); float gpcenter[3]; if (gpd) { diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc index d8e17ac86b7..cc684d7bad6 100644 --- a/source/blender/editors/object/object_vgroup.cc +++ b/source/blender/editors/object/object_vgroup.cc @@ -12,7 +12,7 @@ #include "MEM_guardedalloc.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -38,7 +38,7 @@ #include "BKE_editmesh.h" #include "BKE_lattice.h" #include "BKE_layer.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" @@ -3635,7 +3635,7 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op) int dvert_tot = 0; /* Grease pencil stores vertex groups separately for each stroke, * so remap each stroke's weights separately. */ - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = static_cast(ob->data); LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { diff --git a/source/blender/editors/render/render_opengl.cc b/source/blender/editors/render/render_opengl.cc index fe50513fa64..3a6df43f004 100644 --- a/source/blender/editors/render/render_opengl.cc +++ b/source/blender/editors/render/render_opengl.cc @@ -24,7 +24,7 @@ #include "DNA_action_types.h" #include "DNA_anim_types.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -647,7 +647,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data) return IDWALK_RET_STOP_RECURSION; /* Special cases: */ - case ID_GD: /* bGPdata, (Grease Pencil) */ + case ID_GD_LEGACY: /* bGPdata, (Grease Pencil) */ /* In addition to regular ID's animdata, GreasePencil uses a specific frame-based animation * system that requires specific handling here. */ gather_frames_to_render_for_grease_pencil(oglrender, (bGPdata *)id); diff --git a/source/blender/editors/render/render_shading.cc b/source/blender/editors/render/render_shading.cc index 5ea01677a8e..5f21c51e28b 100644 --- a/source/blender/editors/render/render_shading.cc +++ b/source/blender/editors/render/render_shading.cc @@ -758,7 +758,7 @@ static int new_material_exec(bContext *C, wmOperator * /*op*/) } else { const char *name = DATA_("Material"); - if (!(ob != nullptr && ob->type == OB_GPENCIL)) { + if (!(ob != nullptr && ob->type == OB_GPENCIL_LEGACY)) { ma = BKE_material_add(bmain, name); } else { diff --git a/source/blender/editors/render/render_view.cc b/source/blender/editors/render/render_view.cc index f0427bf8683..7f212f03731 100644 --- a/source/blender/editors/render/render_view.cc +++ b/source/blender/editors/render/render_view.cc @@ -134,8 +134,8 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) int sizex, sizey; BKE_render_resolution(&scene->r, false, &sizex, &sizey); - sizex += 30 * UI_DPI_FAC; - sizey += 60 * UI_DPI_FAC; + sizex += 30 * UI_SCALE_FAC; + sizey += 60 * UI_SCALE_FAC; /* arbitrary... miniature image window views don't make much sense */ if (sizex < 320) { diff --git a/source/blender/editors/screen/area.cc b/source/blender/editors/screen/area.cc index 89c7dd7cf65..bfbea031fdd 100644 --- a/source/blender/editors/screen/area.cc +++ b/source/blender/editors/screen/area.cc @@ -183,7 +183,7 @@ static void area_draw_azone_fullscreen(short /*x1*/, short /*y1*/, short x2, sho UI_icon_draw_ex(x2 - U.widget_unit, y2 - U.widget_unit, ICON_FULLSCREEN_EXIT, - U.inv_dpi_fac, + UI_INV_SCALE_FAC, min_ff(alpha, 0.75f), 0.0f, nullptr, @@ -359,7 +359,7 @@ static void region_draw_status_text(ScrArea *area, ARegion *region) const float y = 0.4f * UI_UNIT_Y; if (overlap) { - const float pad = 2.0f * UI_DPI_FAC; + const float pad = 2.0f * UI_SCALE_FAC; const float x1 = x - (UI_UNIT_X - pad); const float x2 = x + width + (UI_UNIT_X - pad); const float y1 = pad; @@ -1301,13 +1301,13 @@ static void region_rect_recursive( } /* `prefsizex/y`, taking into account DPI. */ - int prefsizex = UI_DPI_FAC * + int prefsizex = UI_SCALE_FAC * ((region->sizex > 1) ? region->sizex + 0.5f : region->type->prefsizex); int prefsizey; if (region->flag & RGN_FLAG_PREFSIZE_OR_HIDDEN) { - prefsizex = UI_DPI_FAC * region->type->prefsizex; - prefsizey = UI_DPI_FAC * region->type->prefsizey; + prefsizex = UI_SCALE_FAC * region->type->prefsizex; + prefsizey = UI_SCALE_FAC * region->type->prefsizey; } else if (region->regiontype == RGN_TYPE_HEADER) { prefsizey = ED_area_headersize(); @@ -1322,7 +1322,8 @@ static void region_rect_recursive( prefsizey = ED_region_global_size_y(); } else { - prefsizey = UI_DPI_FAC * (region->sizey > 1 ? region->sizey + 0.5f : region->type->prefsizey); + prefsizey = UI_SCALE_FAC * + (region->sizey > 1 ? region->sizey + 0.5f : region->type->prefsizey); } if (region->flag & RGN_FLAG_HIDDEN) { @@ -1510,12 +1511,12 @@ static void region_rect_recursive( region->winy = BLI_rcti_size_y(®ion->winrct) + 1; /* If region opened normally, we store this for hide/reveal usage. */ - /* Prevent rounding errors for UI_DPI_FAC multiply and divide. */ + /* Prevent rounding errors for UI_SCALE_FAC multiply and divide. */ if (region->winx > 1) { - region->sizex = (region->winx + 0.5f) / UI_DPI_FAC; + region->sizex = (region->winx + 0.5f) / UI_SCALE_FAC; } if (region->winy > 1) { - region->sizey = (region->winy + 0.5f) / UI_DPI_FAC; + region->sizey = (region->winy + 0.5f) / UI_SCALE_FAC; } /* exception for multiple overlapping regions on same spot */ @@ -3024,8 +3025,8 @@ void ED_region_panels_layout_ex(const bContext *C, Panel *panel = static_cast(region->panels.last); if (panel != nullptr) { const int size_dyn[2] = { - int(UI_UNIT_X * (UI_panel_is_closed(panel) ? 8 : 14) / UI_DPI_FAC), - int(UI_panel_size_y(panel) / UI_DPI_FAC), + int(UI_UNIT_X * (UI_panel_is_closed(panel) ? 8 : 14) / UI_SCALE_FAC), + int(UI_panel_size_y(panel) / UI_SCALE_FAC), }; /* region size is layout based and needs to be updated */ if ((region->sizex != size_dyn[0]) || (region->sizey != size_dyn[1])) { @@ -3033,7 +3034,7 @@ void ED_region_panels_layout_ex(const bContext *C, region->sizey = size_dyn[1]; area->flag |= AREA_FLAG_REGION_SIZE_UPDATE; } - y = fabsf(region->sizey * UI_DPI_FAC - 1); + y = fabsf(region->sizey * UI_SCALE_FAC - 1); } } else { @@ -3288,7 +3289,7 @@ void ED_region_header_layout(const bContext *C, ARegion *region) bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE; /* Height of buttons and scaling needed to achieve it. */ - const int buttony = min_ii(UI_UNIT_Y, region->winy - 2 * UI_DPI_FAC); + const int buttony = min_ii(UI_UNIT_Y, region->winy - 2 * UI_SCALE_FAC); const float buttony_scale = buttony / float(UI_UNIT_Y); /* Vertically center buttons. */ @@ -3342,7 +3343,7 @@ void ED_region_header_layout(const bContext *C, ARegion *region) maxco = xco; } - int new_sizex = (maxco + UI_HEADER_OFFSET) / UI_DPI_FAC; + int new_sizex = (maxco + UI_HEADER_OFFSET) / UI_SCALE_FAC; if (region_layout_based && (region->sizex != new_sizex)) { /* region size is layout based and needs to be updated */ @@ -3402,7 +3403,7 @@ void ED_region_header_init(ARegion *region) int ED_area_headersize(void) { /* Accommodate widget and padding. */ - return U.widget_unit + int(UI_DPI_FAC * HEADER_PADDING_Y); + return U.widget_unit + int(UI_SCALE_FAC * HEADER_PADDING_Y); } int ED_area_footersize(void) @@ -3413,17 +3414,17 @@ int ED_area_footersize(void) int ED_area_global_size_y(const ScrArea *area) { BLI_assert(ED_area_is_global(area)); - return round_fl_to_int(area->global->cur_fixed_height * UI_DPI_FAC); + return round_fl_to_int(area->global->cur_fixed_height * UI_SCALE_FAC); } int ED_area_global_min_size_y(const ScrArea *area) { BLI_assert(ED_area_is_global(area)); - return round_fl_to_int(area->global->size_min * UI_DPI_FAC); + return round_fl_to_int(area->global->size_min * UI_SCALE_FAC); } int ED_area_global_max_size_y(const ScrArea *area) { BLI_assert(ED_area_is_global(area)); - return round_fl_to_int(area->global->size_max * UI_DPI_FAC); + return round_fl_to_int(area->global->size_max * UI_SCALE_FAC); } bool ED_area_is_global(const ScrArea *area) @@ -3510,7 +3511,7 @@ void ED_region_info_draw_multiline(ARegion *region, rcti rect = *ED_region_visible_rect(region); /* Needed in case scripts leave the font size at an unexpected value, see: #102213. */ - BLF_size(fontid, style->widget.points * U.dpi_fac); + BLF_size(fontid, style->widget.points * UI_SCALE_FAC); /* Box fill entire width or just around text. */ if (!full_redraw) { @@ -3764,7 +3765,7 @@ void ED_region_cache_draw_background(ARegion *region) immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformColor4ub(128, 128, 255, 64); - immRecti(pos, 0, region_bottom, region->winx, region_bottom + 8 * UI_DPI_FAC); + immRecti(pos, 0, region_bottom, region->winx, region_bottom + 8 * UI_SCALE_FAC); immUnbindProgram(); } @@ -3776,7 +3777,7 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f float font_dims[2] = {0.0f, 0.0f}; /* frame number */ - BLF_size(fontid, 11.0f * U.dpi_fac); + BLF_size(fontid, 11.0f * UI_SCALE_FAC); BLI_snprintf(numstr, sizeof(numstr), "%d", framenr); BLF_width_and_height(fontid, numstr, sizeof(numstr), &font_dims[0], &font_dims[1]); @@ -3810,7 +3811,7 @@ void ED_region_cache_draw_cached_segments( float x1 = float(points[a * 2] - sfra) / (efra - sfra + 1) * region->winx; float x2 = float(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * region->winx; - immRecti(pos, x1, region_bottom, x2, region_bottom + 8 * UI_DPI_FAC); + immRecti(pos, x1, region_bottom, x2, region_bottom + 8 * UI_SCALE_FAC); /* TODO(merwin): use primitive restart to draw multiple rects more efficiently */ } diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 85c869173bc..25034dd835b 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -147,6 +147,18 @@ void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state, const float color[4]) { int subpart_x, subpart_y, tex_w = 256, tex_h = 256; +#ifdef __APPLE__ + if (GPU_backend_get_type() == GPU_BACKEND_METAL) { + /* NOTE(Metal): The Metal backend will keep all temporary texture memory within a command + * submission in-flight, so using a partial tile size does not provide any tangible memory + * reduction, but does incur additional API overhead and significant cache inefficiency on AMD + * platforms. + * The Metal API also provides smart resource paging such that the application can + * still efficiently swap memory, even if system is low in physical memory. */ + tex_w = img_w; + tex_h = img_h; + } +#endif int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y; int components; const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y)); @@ -617,8 +629,8 @@ int ED_draw_imbuf_method(ImBuf *ibuf) void immDrawBorderCorners(uint pos, const rcti *border, float zoomx, float zoomy) { - float delta_x = 4.0f * UI_DPI_FAC / zoomx; - float delta_y = 4.0f * UI_DPI_FAC / zoomy; + float delta_x = 4.0f * UI_SCALE_FAC / zoomx; + float delta_y = 4.0f * UI_SCALE_FAC / zoomy; delta_x = min_ff(delta_x, border->xmax - border->xmin); delta_y = min_ff(delta_y, border->ymax - border->ymin); diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 9adb53195ba..9818d1d281c 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -13,7 +13,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -30,7 +30,7 @@ #include "BKE_armature.h" #include "BKE_blender.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_layer.h" #include "BKE_object.h" #include "BKE_tracking.h" diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 2ec1f499a4a..e0969b444eb 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -377,7 +377,7 @@ static bool screen_areas_can_align(bScreen *screen, ScrArea *sa1, ScrArea *sa2, return false; } - /* Areas that are _smaller_ than minimum sizes, sharing an edge to be moved. See #100772. */ + /* Areas that are _smaller_ than minimum sizes, sharing an edge to be moved. See #100772. */ if (SCREEN_DIR_IS_VERTICAL(dir)) { const short xmin = MIN2(sa1->v1->vec.x, sa2->v1->vec.x); const short xmax = MAX2(sa1->v3->vec.x, sa2->v3->vec.x); @@ -1064,7 +1064,7 @@ static void screen_global_area_refresh(wmWindow *win, static int screen_global_header_size(void) { - return (int)ceilf(ED_area_headersize() / UI_DPI_FAC); + return (int)ceilf(ED_area_headersize() / UI_SCALE_FAC); } static void screen_global_topbar_area_refresh(wmWindow *win, bScreen *screen) diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c index 3ad3fa7892c..309bedda4fd 100644 --- a/source/blender/editors/screen/screen_geometry.c +++ b/source/blender/editors/screen/screen_geometry.c @@ -284,7 +284,7 @@ short screen_geom_find_area_split_point(const ScrArea *area, { const int cur_area_width = screen_geom_area_width(area); const int cur_area_height = screen_geom_area_height(area); - const short area_min_x = AREAMINX * U.dpi_fac; + const short area_min_x = AREAMINX * UI_SCALE_FAC; const short area_min_y = ED_area_headersize(); /* area big enough? */ diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index d1fe516b406..1d8bb7cb0bc 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -46,13 +46,13 @@ typedef enum eScreenAxis { #define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the #AZone */ /* Edges must be within these to allow joining. */ -#define AREAJOINTOLERANCEX (AREAMINX * U.dpi_fac) -#define AREAJOINTOLERANCEY (HEADERY * U.dpi_fac) +#define AREAJOINTOLERANCEX (AREAMINX * UI_SCALE_FAC) +#define AREAJOINTOLERANCEY (HEADERY * UI_SCALE_FAC) /** * Expanded interaction influence of area borders. */ -#define BORDERPADDING ((2.0f * U.dpi_fac) + U.pixelsize) +#define BORDERPADDING ((2.0f * UI_SCALE_FAC) + U.pixelsize) /* area.cc */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 8b0f9154ed5..ca1f190001b 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1207,7 +1207,7 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C, if (actedge == NULL) { return NULL; } - int borderwidth = (4 * UI_DPI_FAC); + int borderwidth = (4 * UI_SCALE_FAC); ScrArea *sa1, *sa2; if (screen_geom_edge_is_horizontal(actedge)) { sa1 = BKE_screen_find_area_xy( @@ -1638,7 +1638,7 @@ static void area_move_set_limits(wmWindow *win, } } else { - int areamin = AREAMINX * U.dpi_fac; + int areamin = AREAMINX * UI_SCALE_FAC; if (area->v1->vec.x > window_rect.xmin) { areamin += U.pixelsize; @@ -1847,7 +1847,7 @@ static void area_move_apply_do(const bContext *C, if (area->v1->editflag || area->v2->editflag || area->v3->editflag || area->v4->editflag) { if (ED_area_is_global(area)) { /* Snap to minimum or maximum for global areas. */ - int height = round_fl_to_int(screen_geom_area_height(area) / UI_DPI_FAC); + int height = round_fl_to_int(screen_geom_area_height(area) / UI_SCALE_FAC); if (abs(height - area->global->size_min) < abs(height - area->global->size_max)) { area->global->cur_fixed_height = area->global->size_min; } @@ -2061,7 +2061,7 @@ static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis) return false; } - if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX * U.dpi_fac) || + if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX * UI_SCALE_FAC) || (dir_axis == SCREEN_AXIS_H && area->winy <= 2 * ED_area_headersize())) { /* Must be at least double minimum sizes to split into two. */ return false; @@ -2639,7 +2639,7 @@ static int area_max_regionsize(ScrArea *area, ARegion *scale_region, AZEdge edge } } - dist /= UI_DPI_FAC; + dist /= UI_SCALE_FAC; return dist; } @@ -2731,7 +2731,7 @@ static void region_scale_validate_size(RegionMoveData *rmd) size = &rmd->region->sizey; } - maxsize = rmd->maxsize - (UI_UNIT_Y / UI_DPI_FAC); + maxsize = rmd->maxsize - (UI_UNIT_Y / UI_SCALE_FAC); if (*size > maxsize && maxsize > 0) { *size = maxsize; @@ -2781,7 +2781,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* region sizes now get multiplied */ - delta /= UI_DPI_FAC; + delta /= UI_SCALE_FAC; const int size_no_snap = rmd->origval + delta; rmd->region->sizex = size_no_snap; @@ -2814,7 +2814,7 @@ static int region_scale_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* region sizes now get multiplied */ - delta /= UI_DPI_FAC; + delta /= UI_SCALE_FAC; const int size_no_snap = rmd->origval + delta; rmd->region->sizey = size_no_snap; @@ -3084,7 +3084,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op) if (ob) { ob_to_keylist(&ads, ob, keylist, 0); - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { const bool active = !(scene->flag & SCE_KEYS_NO_SELONLY); gpencil_to_keylist(&ads, ob->data, keylist, active); } @@ -5044,8 +5044,8 @@ static int userpref_show_exec(bContext *C, wmOperator *op) wmWindow *win_cur = CTX_wm_window(C); /* Use eventstate, not event from _invoke, so this can be called through exec(). */ const wmEvent *event = win_cur->eventstate; - int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC; - int sizey = 520 * UI_DPI_FAC; + int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_SCALE_FAC; + int sizey = 520 * UI_SCALE_FAC; PropertyRNA *prop = RNA_struct_find_property(op->ptr, "section"); if (prop && RNA_property_is_set(op->ptr, prop)) { @@ -5124,8 +5124,8 @@ static int drivers_editor_show_exec(bContext *C, wmOperator *op) /* Use eventstate, not event from _invoke, so this can be called through exec(). */ const wmEvent *event = win_cur->eventstate; - int sizex = 900 * UI_DPI_FAC; - int sizey = 580 * UI_DPI_FAC; + int sizex = 900 * UI_SCALE_FAC; + int sizey = 580 * UI_SCALE_FAC; /* Get active property to show driver for * - Need to grab it first, or else this info disappears @@ -5201,8 +5201,8 @@ static int info_log_show_exec(bContext *C, wmOperator *op) wmWindow *win_cur = CTX_wm_window(C); /* Use eventstate, not event from _invoke, so this can be called through exec(). */ const wmEvent *event = win_cur->eventstate; - int sizex = 900 * UI_DPI_FAC; - int sizey = 580 * UI_DPI_FAC; + int sizex = 900 * UI_SCALE_FAC; + int sizey = 580 * UI_SCALE_FAC; int shift_y = 480; /* changes context! */ diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc index 432309a5e72..bb12782cad5 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc @@ -20,7 +20,7 @@ #include "BKE_curves.hh" #include "BKE_curves_utils.hh" #include "BKE_geometry_set.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.hh" #include "BKE_modifier.h" diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc index 79c175caf5f..79b308626e1 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_comb.cc @@ -23,7 +23,7 @@ #include "BKE_crazyspace.hh" #include "BKE_curves.hh" #include "BKE_geometry_set.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc index 3b2e9d5735c..a8c8501f07c 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_delete.cc @@ -19,7 +19,7 @@ #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_curves.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc index cbdaaab4dc5..4149934341e 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_density.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_density.cc @@ -7,7 +7,7 @@ #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_geometry_set.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.hh" #include "BKE_modifier.h" diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc b/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc index 26af897c0bf..f0745ef3d0d 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_puff.cc @@ -5,7 +5,7 @@ #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_crazyspace.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "ED_screen.h" diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc index 20036994452..b4ce8ebc295 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_slide.cc @@ -15,7 +15,7 @@ #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_curves.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_sample.hh" #include "BKE_object.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc index 6c70b491265..13fc169a0e7 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_snake_hook.cc @@ -20,7 +20,7 @@ #include "BKE_bvhutils.h" #include "BKE_context.h" #include "BKE_curves.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sculpt_paint/paint_hide.cc b/source/blender/editors/sculpt_paint/paint_hide.cc index 6a5acfccb62..67f9b71c79d 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.cc +++ b/source/blender/editors/sculpt_paint/paint_hide.cc @@ -19,7 +19,7 @@ #include "BKE_ccg.h" #include "BKE_context.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_pbvh.h" @@ -81,7 +81,7 @@ static void partialvis_update_mesh(Object *ob, CustomData_get_layer_named_for_write(&me->vdata, CD_PROP_BOOL, ".hide_vert", me->totvert)); if (hide_vert == nullptr) { hide_vert = static_cast(CustomData_add_layer_named( - &me->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me->totvert, ".hide_vert")); + &me->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, me->totvert, ".hide_vert")); } SCULPT_undo_push_node(ob, node, SCULPT_UNDO_HIDDEN); diff --git a/source/blender/editors/sculpt_paint/paint_image.cc b/source/blender/editors/sculpt_paint/paint_image.cc index bedf7b588b2..964b9de69e6 100644 --- a/source/blender/editors/sculpt_paint/paint_image.cc +++ b/source/blender/editors/sculpt_paint/paint_image.cc @@ -33,7 +33,7 @@ #include "BKE_image.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_node_runtime.hh" #include "BKE_object.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.cc b/source/blender/editors/sculpt_paint/paint_image_proj.cc index 260eda97262..f4838823b35 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.cc +++ b/source/blender/editors/sculpt_paint/paint_image_proj.cc @@ -60,7 +60,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_node.h" @@ -406,19 +406,18 @@ struct ProjPaintState { SpinLock *tile_lock; Mesh *me_eval; - int totlooptri_eval; int totloop_eval; int totpoly_eval; - int totedge_eval; int totvert_eval; const float (*vert_positions_eval)[3]; - const float (*vert_normals)[3]; + blender::Span vert_normals; blender::Span edges_eval; blender::Span polys_eval; blender::Span loops_eval; const bool *select_poly_eval; const int *material_indices; + const bool *sharp_faces_eval; blender::Span looptris_eval; const float (*mloopuv_stencil_eval)[2]; @@ -1721,10 +1720,9 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps, if (ps->do_mask_normal) { const MLoopTri *lt = &ps->looptris_eval[tri_index]; const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)}; - const MPoly &poly = ps->polys_eval[lt->poly]; float no[3], angle_cos; - if (poly.flag & ME_SMOOTH) { + if (!(ps->sharp_faces_eval && ps->sharp_faces_eval[lt->poly])) { const float *no1, *no2, *no3; no1 = ps->vert_normals[lt_vtri[0]]; no2 = ps->vert_normals[lt_vtri[1]]; @@ -3920,8 +3918,8 @@ static void proj_paint_state_seam_bleed_init(ProjPaintState *ps) { if (ps->seam_bleed_px > 0.0f) { ps->vertFaces = MEM_cnew_array(ps->totvert_eval, "paint-vertFaces"); - ps->faceSeamFlags = MEM_cnew_array(ps->totlooptri_eval, "paint-faceSeamFlags"); - ps->faceWindingFlags = MEM_cnew_array(ps->totlooptri_eval, "paint-faceWindindFlags"); + ps->faceSeamFlags = MEM_cnew_array(ps->looptris_eval.size(), __func__); + ps->faceWindingFlags = MEM_cnew_array(ps->looptris_eval.size(), __func__); ps->loopSeamData = static_cast( MEM_mallocN(sizeof(LoopSeamData) * ps->totloop_eval, "paint-loopSeamUVs")); ps->vertSeams = MEM_cnew_array(ps->totvert_eval, "paint-vertSeams"); @@ -4071,7 +4069,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p ps->mat_array[totmat - 1] = nullptr; ps->vert_positions_eval = BKE_mesh_vert_positions(ps->me_eval); - ps->vert_normals = BKE_mesh_vert_normals_ensure(ps->me_eval); + ps->vert_normals = ps->me_eval->vert_normals(); ps->edges_eval = ps->me_eval->edges(); ps->polys_eval = ps->me_eval->polys(); ps->loops_eval = ps->me_eval->loops(); @@ -4079,9 +4077,10 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p &ps->me_eval->pdata, CD_PROP_BOOL, ".select_poly"); ps->material_indices = (const int *)CustomData_get_layer_named( &ps->me_eval->pdata, CD_PROP_INT32, "material_index"); + ps->sharp_faces_eval = static_cast( + CustomData_get_layer_named(&ps->me_eval->pdata, CD_PROP_BOOL, "sharp_face")); ps->totvert_eval = ps->me_eval->totvert; - ps->totedge_eval = ps->me_eval->totedge; ps->totpoly_eval = ps->me_eval->totpoly; ps->totloop_eval = ps->me_eval->totloop; @@ -4309,7 +4308,7 @@ static void project_paint_prepare_all_faces(ProjPaintState *ps, BLI_assert(ps->image_tot == 0); - for (tri_index = 0; tri_index < ps->totlooptri_eval; tri_index++) { + for (tri_index = 0; tri_index < ps->looptris_eval.size(); tri_index++) { bool is_face_sel; bool skip_tri = false; @@ -6530,7 +6529,10 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain, bool is_data) return ima; } -static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object *ob) +/** + * \return The name of the new attribute. + */ +static const char *proj_paint_color_attribute_create(wmOperator *op, Object *ob) { char name[MAX_NAME] = ""; float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; @@ -6544,22 +6546,20 @@ static CustomDataLayer *proj_paint_color_attribute_create(wmOperator *op, Object type = (eCustomDataType)RNA_enum_get(op->ptr, "data_type"); } - ID *id = (ID *)ob->data; - CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports); - + Mesh *mesh = static_cast(ob->data); + const CustomDataLayer *layer = BKE_id_attribute_new(&mesh->id, name, type, domain, op->reports); if (!layer) { return nullptr; } - BKE_id_attributes_active_color_set(id, layer->name); - - if (!BKE_id_attributes_default_color_get(id)) { - BKE_id_attributes_default_color_set(id, layer->name); + BKE_id_attributes_active_color_set(&mesh->id, layer->name); + if (!mesh->default_color_attribute) { + BKE_id_attributes_default_color_set(&mesh->id, layer->name); } BKE_object_attributes_active_color_fill(ob, color, false); - return layer; + return layer->name; } /** @@ -6669,9 +6669,8 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) } case PAINT_CANVAS_SOURCE_COLOR_ATTRIBUTE: { new_node = nodeAddStaticNode(C, ntree, SH_NODE_ATTRIBUTE); - if ((layer = proj_paint_color_attribute_create(op, ob))) { - BLI_strncpy_utf8( - ((NodeShaderAttribute *)new_node->storage)->name, layer->name, MAX_NAME); + if (const char *name = proj_paint_color_attribute_create(op, ob)) { + BLI_strncpy_utf8(((NodeShaderAttribute *)new_node->storage)->name, name, MAX_NAME); } break; } diff --git a/source/blender/editors/sculpt_paint/paint_mask.cc b/source/blender/editors/sculpt_paint/paint_mask.cc index 1dbc14a2324..a81838af5a4 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.cc +++ b/source/blender/editors/sculpt_paint/paint_mask.cc @@ -28,7 +28,7 @@ #include "BKE_ccg.h" #include "BKE_context.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_multires.h" #include "BKE_paint.h" #include "BKE_pbvh.h" @@ -1300,6 +1300,8 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex loop_index += 3; } + BKE_mesh_smooth_flag_set(trim_operation->mesh, false); + BKE_mesh_calc_edges(trim_operation->mesh, false, false); sculpt_gesture_trim_normals_update(sgcontext); } @@ -1711,7 +1713,11 @@ static int sculpt_trim_gesture_box_invoke(bContext *C, wmOperator *op, const wmE static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op) { + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *object = CTX_data_active_object(C); + + BKE_sculpt_update_object_for_edit(depsgraph, object, false, true, false); + SculptSession *ss = object->sculpt; if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { /* Not supported in Multires and Dyntopo. */ diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index e18b9274c5e..70ebd7fc077 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -38,7 +38,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_object.h" #include "BKE_object_deform.h" diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc index 49fbff114f1..92f3f79a44e 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.cc @@ -21,7 +21,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_geometry_set.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.cc b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.cc index a40c4a38178..e0a0b8a5be8 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.cc @@ -23,7 +23,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_iterators.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index 32682cac8ef..668fc4312ff 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -42,7 +42,7 @@ #include "BKE_key.h" #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -5549,9 +5549,9 @@ void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags) /* When sculpting and changing the positions of a mesh, tag them as changed and update. */ BKE_mesh_tag_positions_changed(mesh); /* Update the mesh's bounds eagerly since the PBVH already has that information. */ - mesh->runtime->bounds_cache.ensure([&](Bounds &r_bounds) { - BKE_pbvh_bounding_box(ob->sculpt->pbvh, r_bounds.min, r_bounds.max); - }); + Bounds bounds; + BKE_pbvh_bounding_box(ob->sculpt->pbvh, bounds.min, bounds.max); + mesh->bounds_set_eager(bounds); } } } diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index d7f1e0def14..c7df5d6d92b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -24,7 +24,7 @@ #include "BKE_brush.h" #include "BKE_colortools.h" #include "BKE_context.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_object.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.cc b/source/blender/editors/sculpt_paint/sculpt_cloth.cc index 6db4fe5b718..79ba11e6db3 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.cc +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.cc @@ -1508,7 +1508,7 @@ static int sculpt_cloth_filter_modal(bContext *C, wmOperator *op, const wmEvent } const float len = event->prev_press_xy[0] - event->xy[0]; - filter_strength = filter_strength * -len * 0.001f * UI_DPI_FAC; + filter_strength = filter_strength * -len * 0.001f * UI_SCALE_FAC; SCULPT_vertex_random_access_ensure(ss); diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc index 570e2e1cab3..ca7684fce6d 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc @@ -19,7 +19,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -309,37 +309,32 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoW return OPERATOR_INTERFACE; } -static bool dyntopo_supports_customdata_layers(const blender::Span layers, - int totelem) +static bool dyntopo_supports_layer(const CustomDataLayer &layer, const int elem_num) { - for (const CustomDataLayer &layer : layers) { - if (CD_TYPE_AS_MASK(layer.type) & CD_MASK_PROP_ALL) { - if (layer.name[0] == '\0') { - return false; - } - - if (STREQ(layer.name, ".sculpt_face_sets") && totelem > 0) { - int *fsets = static_cast(layer.data); - int fset = fsets[0]; - - /* Check if only one face set exists. */ - for (int i : IndexRange(totelem)) { - if (fsets[i] != fset) { - return false; - } + if (CD_TYPE_AS_MASK(layer.type) & CD_MASK_PROP_ALL) { + if (STREQ(layer.name, ".sculpt_face_set")) { + /* Check if only one face set exists. */ + const blender::Span face_sets(static_cast(layer.data), elem_num); + for (const int i : face_sets.index_range()) { + if (face_sets[i] != face_sets.first()) { + return false; } - - return true; } - - /* Some data is stored as generic attributes on #Mesh but in flags or field on #BMesh. */ - return BM_attribute_stored_in_bmesh_builtin(layer.name); + return true; } - /* Some layers just encode #Mesh topology or are handled as special cases for dyntopo. */ - return ELEM(layer.type, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX); + /* Some data is stored as generic attributes on #Mesh but in flags or fields on #BMesh. */ + return BM_attribute_stored_in_bmesh_builtin(layer.name); } + /* Some layers just encode #Mesh topology or are handled as special cases for dyntopo. */ + return ELEM(layer.type, CD_MEDGE, CD_MPOLY, CD_MLOOP, CD_PAINT_MASK, CD_ORIGINDEX); +} - return true; +static bool dyntopo_supports_customdata_layers(const blender::Span layers, + const int elem_num) +{ + return std::all_of(layers.begin(), layers.end(), [&](const CustomDataLayer &layer) { + return dyntopo_supports_layer(layer, elem_num); + }); } enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob) diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.cc b/source/blender/editors/sculpt_paint/sculpt_expand.cc index 32c79f302a1..a8f2634151f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.cc +++ b/source/blender/editors/sculpt_paint/sculpt_expand.cc @@ -25,7 +25,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_image.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_paint.h" #include "BKE_pbvh.h" diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc index 186b3f359d3..374d8e6f7d9 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc @@ -16,9 +16,11 @@ #include "BLI_hash.h" #include "BLI_math.h" #include "BLI_math_vector.hh" +#include "BLI_math_vector_types.hh" #include "BLI_span.hh" #include "BLI_task.h" #include "BLI_task.hh" +#include "BLI_vector.hh" #include "DNA_brush_types.h" #include "DNA_customdata_types.h" @@ -32,7 +34,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_fair.h" #include "BKE_mesh_mapping.h" #include "BKE_object.h" @@ -53,6 +55,9 @@ #include "bmesh.h" +using blender::float3; +using blender::Vector; + /* Utils. */ int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh) @@ -108,6 +113,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) { + using namespace blender; SculptThreadedTaskData *data = static_cast(userdata); SculptSession *ss = data->ob->sculpt; const Brush *brush = data->brush; @@ -120,7 +126,10 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, ss, &test, data->brush->falloff_shape); const int thread_id = BLI_task_parallel_thread_id(tls); - const float(*positions)[3] = SCULPT_mesh_deformed_positions_get(ss); + const Span positions( + reinterpret_cast(SCULPT_mesh_deformed_positions_get(ss)), + SCULPT_vertex_count_get(ss)); + const Span loops(ss->mloop, data->me->totloop); AutomaskingNodeData automask_data; SCULPT_automasking_node_begin( data->ob, ss, ss->cache->automasking, &automask_data, data->nodes[n]); @@ -134,8 +143,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, for (int j = 0; j < ss->pmap[vd.index].count; j++) { const MPoly &poly = ss->polys[vert_map->indices[j]]; - float poly_center[3]; - BKE_mesh_calc_poly_center(&poly, &ss->mloop[poly.loopstart], positions, poly_center); + const float3 poly_center = bke::mesh::poly_center_calc( + positions, loops.slice(poly.loopstart, poly.totloop)); if (!sculpt_brush_test_sq_fn(&test, poly_center)) { continue; @@ -671,8 +680,7 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op) break; } case SCULPT_FACE_SETS_FROM_NORMALS: { - const Span poly_normals( - reinterpret_cast(BKE_mesh_poly_normals_ensure(mesh)), mesh->totpoly); + const Span poly_normals = mesh->poly_normals(); sculpt_face_sets_init_flood_fill( ob, [&](const int from_face, const int /*edge*/, const int to_face) -> bool { return std::abs(math::dot(poly_normals[from_face], poly_normals[to_face])) > threshold; @@ -982,7 +990,7 @@ void SCULPT_OT_face_sets_change_visibility(wmOperatorType *ot) ot->invoke = sculpt_face_sets_change_visibility_invoke; ot->poll = SCULPT_mode_poll; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR; RNA_def_enum(ot->srna, "mode", @@ -1236,34 +1244,45 @@ static void sculpt_face_set_delete_geometry(Object *ob, static void sculpt_face_set_edit_fair_face_set(Object *ob, const int active_face_set_id, - const eMeshFairingDepth fair_order) + const eMeshFairingDepth fair_order, + const float strength) { SculptSession *ss = ob->sculpt; const int totvert = SCULPT_vertex_count_get(ss); Mesh *mesh = static_cast(ob->data); - bool *fair_verts = static_cast( - MEM_malloc_arrayN(totvert, sizeof(bool), "fair vertices")); + Vector orig_positions; + Vector fair_verts; + + orig_positions.resize(totvert); + fair_verts.resize(totvert); SCULPT_boundary_info_ensure(ob); for (int i = 0; i < totvert; i++) { PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); + orig_positions[i] = SCULPT_vertex_co_get(ss, vertex); fair_verts[i] = !SCULPT_vertex_is_boundary(ss, vertex) && SCULPT_vertex_has_face_set(ss, vertex, active_face_set_id) && SCULPT_vertex_has_unique_face_set(ss, vertex); } float(*positions)[3] = SCULPT_mesh_deformed_positions_get(ss); - BKE_mesh_prefair_and_fair_verts(mesh, positions, fair_verts, fair_order); - MEM_freeN(fair_verts); + BKE_mesh_prefair_and_fair_verts(mesh, positions, fair_verts.data(), fair_order); + + for (int i = 0; i < totvert; i++) { + if (fair_verts[i]) { + interp_v3_v3v3(positions[i], orig_positions[i], positions[i], strength); + } + } } static void sculpt_face_set_apply_edit(Object *ob, const int active_face_set_id, const int mode, - const bool modify_hidden) + const bool modify_hidden, + const float strength = 0.0f) { SculptSession *ss = ob->sculpt; @@ -1284,10 +1303,12 @@ static void sculpt_face_set_apply_edit(Object *ob, sculpt_face_set_delete_geometry(ob, ss, active_face_set_id, modify_hidden); break; case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: - sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_POSITION); + sculpt_face_set_edit_fair_face_set( + ob, active_face_set_id, MESH_FAIRING_DEPTH_POSITION, strength); break; case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: - sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_TANGENCY); + sculpt_face_set_edit_fair_face_set( + ob, active_face_set_id, MESH_FAIRING_DEPTH_TANGENCY, strength); break; } } @@ -1399,13 +1420,17 @@ static void sculpt_face_set_edit_modify_coordinates(bContext *C, PBVH *pbvh = ss->pbvh; PBVHNode **nodes; int totnode; + BKE_pbvh_search_gather(pbvh, nullptr, nullptr, &nodes, &totnode); + + const float strength = RNA_float_get(op->ptr, "strength"); + SCULPT_undo_push_begin(ob, op); for (int i = 0; i < totnode; i++) { BKE_pbvh_node_mark_update(nodes[i]); SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS); } - sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, false); + sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, false, strength); if (ss->deform_modifiers_active || ss->shapekey_active) { SCULPT_flush_stroke_deform(sd, ob, true); @@ -1416,32 +1441,37 @@ static void sculpt_face_set_edit_modify_coordinates(bContext *C, MEM_freeN(nodes); } -static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static bool sculpt_face_set_edit_init(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - const eSculptFaceSetEditMode mode = static_cast( RNA_enum_get(op->ptr, "mode")); const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden"); if (!sculpt_face_set_edit_is_operation_valid(ss, mode, modify_hidden)) { - return OPERATOR_CANCELLED; + return false; } ss->face_sets = BKE_sculpt_face_sets_ensure(BKE_mesh_from_object(ob)); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); - /* Update the current active Face Set and Vertex as the operator can be used directly from the - * tool without brush cursor. */ - SculptCursorGeometryInfo sgi; - const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])}; - if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) { - /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */ + return true; +} + +static int sculpt_face_set_edit_exec(bContext *C, wmOperator *op) +{ + if (!sculpt_face_set_edit_init(C, op)) { return OPERATOR_CANCELLED; } - const int active_face_set = SCULPT_active_face_set_get(ss); + + Object *ob = CTX_data_active_object(C); + + const int active_face_set = RNA_int_get(op->ptr, "active_face_set"); + const eSculptFaceSetEditMode mode = static_cast( + RNA_enum_get(op->ptr, "mode")); + const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden"); switch (mode) { case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY: @@ -1462,6 +1492,27 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven return OPERATOR_FINISHED; } +static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, false); + + /* Update the current active Face Set and Vertex as the operator can be used directly from the + * tool without brush cursor. */ + SculptCursorGeometryInfo sgi; + const float mval_fl[2] = {float(event->mval[0]), float(event->mval[1])}; + if (!SCULPT_cursor_geometry_info_update(C, &sgi, mval_fl, false)) { + /* The cursor is not over the mesh. Cancel to avoid editing the last updated Face Set ID. */ + return OPERATOR_CANCELLED; + } + RNA_int_set(op->ptr, "active_face_set", SCULPT_active_face_set_get(ss)); + + return sculpt_face_set_edit_exec(C, op); +} + void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot) { /* Identifiers. */ @@ -1471,12 +1522,19 @@ void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot) /* Api callbacks. */ ot->invoke = sculpt_face_set_edit_invoke; + ot->exec = sculpt_face_set_edit_exec; ot->poll = SCULPT_mode_poll; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_DEPENDS_ON_CURSOR; + + PropertyRNA *prop = RNA_def_int( + ot->srna, "active_face_set", 1, 0, INT_MAX, "Active Face Set", "", 0, 64); + RNA_def_property_flag(prop, PROP_HIDDEN); RNA_def_enum( ot->srna, "mode", prop_sculpt_face_sets_edit_types, SCULPT_FACE_SET_EDIT_GROW, "Mode", ""); + RNA_def_float(ot->srna, "strength", 1.0f, 0.0f, 1.0f, "Strength", "", 0.0f, 1.0f); + ot->prop = RNA_def_boolean(ot->srna, "modify_hidden", true, diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.cc b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.cc index 8b7a8dd1e0f..f9912aa4402 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.cc +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.cc @@ -5,6 +5,8 @@ * \ingroup edsculpt */ +#include "DNA_modifier_types.h" +#include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" #include "BLI_hash.h" @@ -13,10 +15,13 @@ #include "BLI_math_vector_types.hh" #include "BLI_task.h" +#include "BLT_translation.h" + #include "DNA_meshdata_types.h" #include "BKE_brush.h" #include "BKE_context.h" +#include "BKE_modifier.h" #include "BKE_paint.h" #include "BKE_pbvh.h" @@ -26,6 +31,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_util.h" #include "ED_view3d.h" #include "paint_intern.h" @@ -705,6 +711,55 @@ static void mesh_filter_surface_smooth_displace_task_cb(void *__restrict userdat BKE_pbvh_vertex_iter_end; } +enum { + FILTER_MESH_MODAL_CANCEL = 1, + FILTER_MESH_MODAL_CONFIRM, +}; + +wmKeyMap *filter_mesh_modal_keymap(wmKeyConfig *keyconf) +{ + static const EnumPropertyItem modal_items[] = { + {FILTER_MESH_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""}, + {FILTER_MESH_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Mesh Filter Modal Map"); + + /* This function is called for each space-type, only needs to add map once. */ + if (keymap && keymap->modal_items) { + return nullptr; + } + + keymap = WM_modalkeymap_ensure(keyconf, "Mesh Filter Modal Map", modal_items); + + WM_modalkeymap_assign(keymap, "SCULPT_OT_mesh_filter"); + + return keymap; +} + +static void sculpt_mesh_update_status_bar(bContext *C, wmOperator *op) +{ + char header[UI_MAX_DRAW_STR]; + char buf[UI_MAX_DRAW_STR]; + int available_len = sizeof(buf); + + char *p = buf; +#define WM_MODALKEY(_id) \ + WM_modalkeymap_operator_items_to_string_buf( \ + op->type, (_id), true, UI_MAX_SHORTCUT_STR, &available_len, &p) + + BLI_snprintf(header, + sizeof(header), + TIP_("%s: Confirm, %s: Cancel"), + WM_MODALKEY(FILTER_MESH_MODAL_CONFIRM), + WM_MODALKEY(FILTER_MESH_MODAL_CANCEL)); + +#undef WM_MODALKEY + + ED_workspace_status_text(C, TIP_(header)); +} + static void sculpt_mesh_filter_apply(bContext *C, wmOperator *op) { Object *ob = CTX_data_active_object(C); @@ -755,7 +810,7 @@ static void sculpt_mesh_update_strength(wmOperator *op, { const float len = prev_press_mouse[0] - mouse[0]; - float filter_strength = ss->filter_cache->start_filter_strength * -len * 0.001f * UI_DPI_FAC; + float filter_strength = ss->filter_cache->start_filter_strength * -len * 0.001f * UI_SCALE_FAC; RNA_float_set(op->ptr, "strength", filter_strength); } static void sculpt_mesh_filter_apply_with_history(bContext *C, wmOperator *op) @@ -790,17 +845,30 @@ static void sculpt_mesh_filter_apply_with_history(bContext *C, wmOperator *op) RNA_float_set(op->ptr, "strength", initial_strength); } -static void sculpt_mesh_filter_end(bContext *C, wmOperator * /*op*/) +static void sculpt_mesh_filter_end(bContext *C) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; SCULPT_filter_cache_free(ss); - SCULPT_undo_push_end(ob); SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); } -static void UNUSED_FUNCTION(sculpt_mesh_filter_cancel)(bContext *C, wmOperator * /*op*/) +static int sculpt_mesh_filter_confirm(SculptSession *ss, + wmOperator *op, + const eSculptMeshFilterType filter_type) +{ + + float initial_strength = ss->filter_cache->start_filter_strength; + /* Don't update strength property if we're storing an event history. */ + if (sculpt_mesh_filter_is_continuous(filter_type)) { + RNA_float_set(op->ptr, "strength", initial_strength); + } + + return OPERATOR_FINISHED; +} + +static void sculpt_mesh_filter_cancel(bContext *C, wmOperator * /*op*/) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; @@ -831,6 +899,7 @@ static void UNUSED_FUNCTION(sculpt_mesh_filter_cancel)(bContext *C, wmOperator * BKE_pbvh_node_mark_update(node); } + MEM_SAFE_FREE(nodes); BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB); } @@ -841,16 +910,29 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * SculptSession *ss = ob->sculpt; const eSculptMeshFilterType filter_type = eSculptMeshFilterType(RNA_enum_get(op->ptr, "type")); - if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { - float initial_strength = ss->filter_cache->start_filter_strength; - sculpt_mesh_filter_end(C, op); + WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EW_SCROLL); + sculpt_mesh_update_status_bar(C, op); - /* Don't update strength property if we're storing an event history. */ - if (sculpt_mesh_filter_is_continuous(filter_type)) { - RNA_float_set(op->ptr, "strength", initial_strength); + if (event->type == EVT_MODAL_MAP) { + int ret = OPERATOR_FINISHED; + switch (event->val) { + case FILTER_MESH_MODAL_CANCEL: + sculpt_mesh_filter_cancel(C, op); + SCULPT_undo_push_end_ex(ob, true); + ret = OPERATOR_CANCELLED; + break; + + case FILTER_MESH_MODAL_CONFIRM: + ret = sculpt_mesh_filter_confirm(ss, op, filter_type); + SCULPT_undo_push_end_ex(ob, false); + break; } - return OPERATOR_FINISHED; + sculpt_mesh_filter_end(C); + ED_workspace_status_text(C, nullptr); /* Clear status bar */ + WM_cursor_modal_restore(CTX_wm_window(C)); + + return ret; } if (event->type != MOUSEMOVE) { @@ -892,6 +974,41 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * return OPERATOR_RUNNING_MODAL; } +static void sculpt_filter_specific_init(const eSculptMeshFilterType filter_type, + wmOperator *op, + SculptSession *ss) +{ + switch (filter_type) { + case MESH_FILTER_SURFACE_SMOOTH: { + const float shape_preservation = RNA_float_get(op->ptr, "surface_smooth_shape_preservation"); + const float current_vertex_displacement = RNA_float_get(op->ptr, + "surface_smooth_current_vertex"); + mesh_filter_surface_smooth_init(ss, shape_preservation, current_vertex_displacement); + break; + } + case MESH_FILTER_SHARPEN: { + const float smooth_ratio = RNA_float_get(op->ptr, "sharpen_smooth_ratio"); + const float intensify_detail_strength = RNA_float_get(op->ptr, + "sharpen_intensify_detail_strength"); + const int curvature_smooth_iterations = RNA_int_get(op->ptr, + "sharpen_curvature_smooth_iterations"); + mesh_filter_sharpen_init( + ss, smooth_ratio, intensify_detail_strength, curvature_smooth_iterations); + break; + } + case MESH_FILTER_ENHANCE_DETAILS: { + mesh_filter_enhance_details_init_directions(ss); + break; + } + case MESH_FILTER_ERASE_DISPLACEMENT: { + mesh_filter_init_limit_surface_co(ss); + break; + } + default: + break; + } +} + /* Returns OPERATOR_PASS_THROUGH on success. */ static int sculpt_mesh_filter_start(bContext *C, wmOperator *op) { @@ -946,35 +1063,7 @@ static int sculpt_mesh_filter_start(bContext *C, wmOperator *op) filter_cache->active_face_set = SCULPT_FACE_SET_NONE; filter_cache->automasking = SCULPT_automasking_cache_init(sd, nullptr, ob); - switch (filter_type) { - case MESH_FILTER_SURFACE_SMOOTH: { - const float shape_preservation = RNA_float_get(op->ptr, "surface_smooth_shape_preservation"); - const float current_vertex_displacement = RNA_float_get(op->ptr, - "surface_smooth_current_vertex"); - mesh_filter_surface_smooth_init(ss, shape_preservation, current_vertex_displacement); - break; - } - case MESH_FILTER_SHARPEN: { - const float smooth_ratio = RNA_float_get(op->ptr, "sharpen_smooth_ratio"); - const float intensify_detail_strength = RNA_float_get(op->ptr, - "sharpen_intensify_detail_strength"); - const int curvature_smooth_iterations = RNA_int_get(op->ptr, - "sharpen_curvature_smooth_iterations"); - mesh_filter_sharpen_init( - ss, smooth_ratio, intensify_detail_strength, curvature_smooth_iterations); - break; - } - case MESH_FILTER_ENHANCE_DETAILS: { - mesh_filter_enhance_details_init_directions(ss); - break; - } - case MESH_FILTER_ERASE_DISPLACEMENT: { - mesh_filter_init_limit_surface_co(ss); - break; - } - default: - break; - } + sculpt_filter_specific_init(filter_type, op, ss); ss->filter_cache->enabled_axis[0] = deform_axis & MESH_FILTER_DEFORM_X; ss->filter_cache->enabled_axis[1] = deform_axis & MESH_FILTER_DEFORM_Y; @@ -1021,7 +1110,7 @@ static int sculpt_mesh_filter_exec(bContext *C, wmOperator *op) ss->filter_cache->no_orig_co = true; } - sculpt_mesh_filter_end(C, op); + sculpt_mesh_filter_end(C); return OPERATOR_FINISHED; } @@ -1087,7 +1176,12 @@ void SCULPT_OT_mesh_filter(wmOperatorType *ot) ot->exec = sculpt_mesh_filter_exec; ot->ui = sculpt_mesh_ui_exec; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + /* Doesn't seem to actually be called? + * Check `sculpt_mesh_filter_modal` to see where it's really called. */ + ot->cancel = sculpt_mesh_filter_cancel; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR_X | OPTYPE_BLOCKING | + OPTYPE_DEPENDS_ON_CURSOR; /* RNA. */ SCULPT_mesh_filter_properties(ot); diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.cc b/source/blender/editors/sculpt_paint/sculpt_geodesic.cc index 762cb8cabbe..33fc931fca8 100644 --- a/source/blender/editors/sculpt_paint/sculpt_geodesic.cc +++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.cc @@ -21,7 +21,7 @@ #include "BKE_ccg.h" #include "BKE_context.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_object.h" #include "BKE_paint.h" diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.hh b/source/blender/editors/sculpt_paint/sculpt_intern.hh index 36d942fc439..fae073233a6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.hh +++ b/source/blender/editors/sculpt_paint/sculpt_intern.hh @@ -1683,6 +1683,7 @@ void SCULPT_OT_set_pivot_position(wmOperatorType *ot); /* Mesh Filter. */ void SCULPT_OT_mesh_filter(wmOperatorType *ot); +struct wmKeyMap *filter_mesh_modal_keymap(struct wmKeyConfig *keyconf); /* Cloth Filter. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.cc b/source/blender/editors/sculpt_paint/sculpt_ops.cc index b8601984740..255e24dd571 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/sculpt_ops.cc @@ -32,7 +32,7 @@ #include "BKE_context.h" #include "BKE_layer.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mirror.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -1427,3 +1427,8 @@ void ED_operatortypes_sculpt(void) WM_operatortype_append(SCULPT_OT_mask_from_cavity); WM_operatortype_append(SCULPT_OT_reveal_all); } + +void ED_keymap_sculpt(wmKeyConfig *keyconf) +{ + filter_mesh_modal_keymap(keyconf); +} diff --git a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc index 5d7c4687bc1..01d8100a8ab 100644 --- a/source/blender/editors/sculpt_paint/sculpt_paint_image.cc +++ b/source/blender/editors/sculpt_paint/sculpt_paint_image.cc @@ -511,6 +511,39 @@ static void do_mark_dirty_regions(void *__restrict userdata, PBVHNode *node = data->nodes[n]; BKE_pbvh_pixels_mark_image_dirty(*node, *data->image_data.image, *data->image_data.image_user); } +/* -------------------------------------------------------------------- */ + +/** \name Fix non-manifold edge bleeding. + * \{ */ + +static Vector collect_dirty_tiles(Span nodes) +{ + Vector dirty_tiles; + for (PBVHNode *node : nodes) { + BKE_pbvh_pixels_collect_dirty_tiles(*node, dirty_tiles); + } + return dirty_tiles; +} +static void fix_non_manifold_seam_bleeding(PBVH &pbvh, + TexturePaintingUserData &user_data, + Span tile_numbers_to_fix) +{ + for (image::TileNumber tile_number : tile_numbers_to_fix) { + BKE_pbvh_pixels_copy_pixels( + pbvh, *user_data.image_data.image, *user_data.image_data.image_user, tile_number); + } +} + +static void fix_non_manifold_seam_bleeding(Object &ob, + const int totnode, + TexturePaintingUserData &user_data) +{ + Vector dirty_tiles = collect_dirty_tiles( + Span(user_data.nodes, totnode)); + fix_non_manifold_seam_bleeding(*ob.sculpt->pbvh, user_data, dirty_tiles); +} + +/** \} */ } // namespace blender::ed::sculpt_paint::paint::image @@ -568,6 +601,7 @@ void SCULPT_do_paint_brush_image(PaintModeSettings *paint_mode_settings, BKE_pbvh_parallel_range_settings(&settings, true, texnodes_num); BLI_task_parallel_range(0, texnodes_num, &data, do_push_undo_tile, &settings); BLI_task_parallel_range(0, texnodes_num, &data, do_paint_pixels, &settings); + fix_non_manifold_seam_bleeding(*ob, texnodes_num, data); TaskParallelSettings settings_flush; diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.cc b/source/blender/editors/sculpt_paint/sculpt_undo.cc index cba8a1b4690..ae604443f78 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_undo.cc @@ -47,7 +47,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" -#include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_ccg.h" #include "BKE_context.h" #include "BKE_customdata.h" @@ -55,7 +55,7 @@ #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_multires.h" #include "BKE_object.h" @@ -1731,20 +1731,27 @@ static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b) static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr) { - Mesh *me = BKE_object_get_original_mesh(ob); - const CustomDataLayer *layer; - - if (ob && me && (layer = BKE_id_attributes_active_color_get((ID *)me))) { - attr->domain = BKE_id_attribute_domain((ID *)me, layer); - BLI_strncpy(attr->name, layer->name, sizeof(attr->name)); - attr->type = layer->type; - } - else { - attr->domain = NO_ACTIVE_LAYER; - attr->name[0] = 0; - } - + using namespace blender; + Mesh *mesh = BKE_object_get_original_mesh(ob); attr->was_set = true; + attr->domain = NO_ACTIVE_LAYER; + attr->name[0] = 0; + if (!mesh) { + return; + } + const char *name = mesh->active_color_attribute; + const bke::AttributeAccessor attributes = mesh->attributes(); + const std::optional meta_data = attributes.lookup_meta_data(name); + if (!meta_data) { + return; + } + if (!(ATTR_DOMAIN_AS_MASK(meta_data->domain) & ATTR_DOMAIN_MASK_COLOR) || + !(CD_TYPE_AS_MASK(meta_data->data_type) & CD_MASK_COLOR_ALL)) { + return; + } + attr->domain = meta_data->domain; + BLI_strncpy(attr->name, name, sizeof(attr->name)); + attr->type = meta_data->data_type; } void SCULPT_undo_push_begin(Object *ob, const wmOperator *op) @@ -1862,7 +1869,8 @@ static void sculpt_undo_set_active_layer(struct bContext *C, SculptAttrRef *attr CustomData *cdata = attr->domain == ATTR_DOMAIN_POINT ? &me->vdata : &me->ldata; int totelem = attr->domain == ATTR_DOMAIN_POINT ? me->totvert : me->totloop; - CustomData_add_layer_named(cdata, attr->type, CD_SET_DEFAULT, nullptr, totelem, attr->name); + CustomData_add_layer_named( + cdata, eCustomDataType(attr->type), CD_SET_DEFAULT, totelem, attr->name); layer = BKE_id_attribute_find(&me->id, attr->name, attr->type, attr->domain); } diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index 1bd28b068f9..5524e71327b 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -15,7 +15,7 @@ #include "BLT_translation.h" #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" @@ -54,8 +54,9 @@ #include "action_intern.h" -/* ************************************************************************** */ -/* ACTION CREATION */ +/* -------------------------------------------------------------------- */ +/** \name Utilities + * \{ */ AnimData *ED_actedit_animdata_from_context(const bContext *C, ID **r_adt_id_owner) { @@ -86,9 +87,12 @@ AnimData *ED_actedit_animdata_from_context(const bContext *C, ID **r_adt_id_owne return adt; } -/* -------------------------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Create New Action + * \{ */ -/* Create new action */ static bAction *action_create_new(bContext *C, bAction *oldact) { ScrArea *area = CTX_wm_area(C); @@ -150,14 +154,18 @@ static void actedit_change_action(bContext *C, bAction *act) RNA_property_update(C, &ptr, prop); } -/* ******************** New Action Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name New Action Operator + * + * Criteria: + * 1) There must be an dope-sheet/action editor, and it must be in a mode which uses actions... + * OR + * The NLA Editor is active (i.e. Animation Data panel -> new action) + * 2) The associated #AnimData block must not be in tweak-mode. + * \{ */ -/* Criteria: - * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions... - * OR - * The NLA Editor is active (i.e. Animation Data panel -> new action) - * 2) The associated AnimData block must not be in tweak-mode. - */ static bool action_new_poll(bContext *C) { Scene *scene = CTX_data_scene(C); @@ -290,13 +298,17 @@ void ACTION_OT_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Action Push-Down Operator ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Push-Down Operator + * + * Criteria: + * 1) There must be an dope-sheet/action editor, and it must be in a mode which uses actions. + * 2) There must be an action active. + * 3) The associated #AnimData block must not be in tweak-mode. + * \{ */ -/* Criteria: - * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions - * 2) There must be an action active - * 3) The associated AnimData block must not be in tweak-mode - */ static bool action_pushdown_poll(bContext *C) { if (ED_operator_action_active(C)) { @@ -370,7 +382,11 @@ void ACTION_OT_push_down(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Action Stash Operator ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Stash Operator + * \{ */ static int action_stash_exec(bContext *C, wmOperator *op) { @@ -432,12 +448,16 @@ void ACTION_OT_stash(wmOperatorType *ot) "Create a new action once the existing one has been safely stored"); } -/* ----------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Stash & Create Operator + * + * Criteria: + * 1) There must be an dope-sheet/action editor, and it must be in a mode which uses actions. + * 2) The associated #AnimData block must not be in tweak-mode. + * \{ */ -/* Criteria: - * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions - * 2) The associated AnimData block must not be in tweak-mode - */ static bool action_stash_create_poll(bContext *C) { if (ED_operator_action_active(C)) { @@ -536,17 +556,18 @@ void ACTION_OT_stash_and_create(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************************************************************** */ -/* ACTION UNLINK */ +/** \} */ -/* ******************* Action Unlink Operator ******************** */ -/* We use a custom unlink operator here, as there are some technicalities which need special care: +/* -------------------------------------------------------------------- */ +/** \name Action Unlink Operator + * + * We use a custom unlink operator here, as there are some technicalities which need special care: * 1) When in Tweak Mode, it shouldn't be possible to unlink the active action, * or else, everything turns to custard. * 2) If the Action doesn't have any other users, the user should at least get * a warning that it is going to get lost. * 3) We need a convenient way to exit Tweak Mode from the Action Editor - */ + * \{ */ void ED_animedit_unlink_action( bContext *C, ID *id, AnimData *adt, bAction *act, ReportList *reports, bool force_delete) @@ -701,8 +722,11 @@ void ACTION_OT_unlink(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************************************************************** */ -/* ACTION BROWSING */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Browsing + * \{ */ /* Try to find NLA Strip to use for action layer up/down tool */ static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime) @@ -775,7 +799,11 @@ static void action_layer_switch_strip( BLI_assert(adt->actstrip == strip); } -/* ********************** One Layer Up Operator ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name One Layer Up Operator + * \{ */ static bool action_layer_next_poll(bContext *C) { @@ -886,7 +914,11 @@ void ACTION_OT_layer_next(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************* One Layer Down Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name One Layer Down Operator + * \{ */ static bool action_layer_prev_poll(bContext *C) { @@ -985,4 +1017,4 @@ void ACTION_OT_layer_prev(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************************************************************** */ +/** \} */ diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 47f82ffe999..2831e5d8454 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -20,7 +20,7 @@ #include "DNA_anim_types.h" #include "DNA_cachefile_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -44,8 +44,9 @@ #include "action_intern.h" -/* ************************************************************************* */ -/* Channel List */ +/* -------------------------------------------------------------------- */ +/** \name Channel List + * \{ */ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region) { @@ -110,8 +111,11 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *region) ANIM_animdata_freelist(&anim_data); } -/* ************************************************************************* */ -/* Keyframes */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keyframes + * \{ */ /* extra padding for lengths (to go under scrollers) */ #define EXTRA_SCROLL_PAD 100.0f @@ -424,8 +428,11 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *region ANIM_animdata_freelist(&anim_data); } -/* ************************************************************************* */ -/* Timeline - Caches */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Timeline - Caches + * \{ */ static bool timeline_cache_is_hidden_by_setting(SpaceAction *saction, PTCacheID *pid) { @@ -638,7 +645,7 @@ void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene) /* Iterate over pointcaches on the active object, and draw each one's range. */ float y_offset = 0.0f; - const float cache_draw_height = 4.0f * UI_DPI_FAC * U.pixelsize; + const float cache_draw_height = 4.0f * UI_SCALE_FAC * U.pixelsize; LISTBASE_FOREACH (PTCacheID *, pid, &pidlist) { if (timeline_cache_is_hidden_by_setting(saction, pid)) { continue; @@ -659,4 +666,4 @@ void timeline_draw_cache(SpaceAction *saction, Object *ob, Scene *scene) BLI_freelistN(&pidlist); } -/* ************************************************************************* */ +/** \} */ diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index d9772844358..2cb13bbbb62 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -17,7 +17,7 @@ #include "BLT_translation.h" #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" @@ -32,7 +32,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_key.h" #include "BKE_nla.h" #include "BKE_report.h" @@ -54,10 +54,9 @@ #include "action_intern.h" -/* ************************************************************************** */ -/* POSE MARKERS STUFF */ - -/* *************************** Localize Markers ***************************** */ +/* -------------------------------------------------------------------- */ +/** \name Pose Markers: Localize Markers + * \{ */ /* ensure that there is: * 1) an active action editor @@ -142,10 +141,11 @@ void ACTION_OT_markers_make_local(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************************************************************** */ -/* KEYFRAME-RANGE STUFF */ +/** \} */ -/* *************************** Calculate Range ************************** */ +/* -------------------------------------------------------------------- */ +/** \name Calculate Range + * \{ */ /* Get the min/max keyframes. */ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const short onlySel) @@ -203,7 +203,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const float tmin, tmax; /* get range and apply necessary scaling before processing */ - if (BKE_fcurve_calc_range(fcu, &tmin, &tmax, onlySel, false)) { + if (BKE_fcurve_calc_range(fcu, &tmin, &tmax, onlySel)) { if (adt) { tmin = BKE_nla_tweakedit_remap(adt, tmin, NLATIME_CONVERT_MAP); @@ -242,7 +242,11 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const return found; } -/* ****************** Automatic Preview-Range Operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View: Automatic Preview-Range Operator + * \{ */ static int actkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -292,7 +296,11 @@ void ACTION_OT_previewrange_set(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ****************** View-All Operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View: All Operator + * \{ */ /** * Find the extents of the active channel @@ -459,7 +467,11 @@ void ACTION_OT_view_selected(wmOperatorType *ot) ot->flag = 0; } -/* ****************** View-All Operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View: Frame Operator + * \{ */ static int actkeys_view_frame_exec(bContext *C, wmOperator *op) { @@ -484,10 +496,12 @@ void ACTION_OT_view_frame(wmOperatorType *ot) ot->flag = 0; } -/* ************************************************************************** */ -/* GENERAL STUFF */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keyframes: Copy/Paste Operator + * \{ */ -/* ******************** Copy/Paste Keyframes Operator ************************* */ /* NOTE: the backend code for this is shared with the graph editor */ static short copy_action_keys(bAnimContext *ac) @@ -712,7 +726,11 @@ void ACTION_OT_paste(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Insert Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keyframes: Insert Operator + * \{ */ /* defines for insert keyframes tool */ static const EnumPropertyItem prop_actkeys_insertkey_types[] = { @@ -902,7 +920,11 @@ void ACTION_OT_keyframe_insert(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_insertkey_types, 0, "Type", ""); } -/* ******************** Duplicate Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keyframes: Duplicate Operator + * \{ */ static bool duplicate_action_keys(bAnimContext *ac) { @@ -978,7 +1000,11 @@ void ACTION_OT_duplicate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Delete Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keyframes: Delete Operator + * \{ */ static bool delete_action_keys(bAnimContext *ac) { @@ -1067,7 +1093,11 @@ void ACTION_OT_delete(wmOperatorType *ot) WM_operator_properties_confirm_or_exec(ot); } -/* ******************** Clean Keyframes Operator ************************* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keyframes: Clean Operator + * \{ */ static void clean_action_keys(bAnimContext *ac, float thresh, bool clean_chan) { @@ -1143,7 +1173,11 @@ void ACTION_OT_clean(wmOperatorType *ot) RNA_def_boolean(ot->srna, "channels", false, "Channels", ""); } -/* ******************** Sample Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keyframes: Sample Operator + * \{ */ /* Evaluates the curves between each selected keyframe on each frame, and keys the value. */ static void sample_action_keys(bAnimContext *ac) @@ -1208,10 +1242,11 @@ void ACTION_OT_sample(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************************************************************** */ -/* SETTINGS STUFF */ +/** \} */ -/* ******************** Set Extrapolation-Type Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Settings: Set Extrapolation-Type Operator + * \{ */ /* defines for make/clear cyclic extrapolation tools */ #define MAKE_CYCLIC_EXPO -1 @@ -1343,7 +1378,11 @@ void ACTION_OT_extrapolation_type(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_expo_types, 0, "Type", ""); } -/* ******************** Set Interpolation-Type Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Settings: Set Interpolation-Type Operator + * \{ */ static int actkeys_ipo_exec(bContext *C, wmOperator *op) { @@ -1398,7 +1437,11 @@ void ACTION_OT_interpolation_type(wmOperatorType *ot) RNA_def_property_translation_context(ot->prop, BLT_I18NCONTEXT_ID_ACTION); } -/* ******************** Set Easing Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Settings: Set Easing Operator + * \{ */ static int actkeys_easing_exec(bContext *C, wmOperator *op) { @@ -1447,7 +1490,11 @@ void ACTION_OT_easing_type(wmOperatorType *ot) ot->srna, "type", rna_enum_beztriple_interpolation_easing_items, 0, "Type", ""); } -/* ******************** Set Handle-Type Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Settings: Set Handle-Type Operator + * \{ */ /* this function is responsible for setting handle-type of selected keyframes */ static void sethandles_action_keys(bAnimContext *ac, short mode) @@ -1532,7 +1579,11 @@ void ACTION_OT_handle_type(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_keyframe_handle_type_items, 0, "Type", ""); } -/* ******************** Set Keyframe-Type Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Settings: Set Keyframe-Type Operator + * \{ */ /* this function is responsible for setting keyframe type for keyframes */ static void setkeytype_action_keys(bAnimContext *ac, short mode) @@ -1620,10 +1671,11 @@ void ACTION_OT_keyframe_type(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", rna_enum_beztriple_keyframe_type_items, 0, "Type", ""); } -/* ************************************************************************** */ -/* TRANSFORM STUFF */ +/** \} */ -/* ***************** Jump to Selected Frames Operator *********************** */ +/* -------------------------------------------------------------------- */ +/** \name Transform: Jump to Selected Frames Operator + * \{ */ static bool actkeys_framejump_poll(bContext *C) { @@ -1722,7 +1774,11 @@ void ACTION_OT_frame_jump(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Snap Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform: Snap Keyframes Operator + * \{ */ /* defines for snap keyframes tool */ static const EnumPropertyItem prop_actkeys_snap_types[] = { @@ -1852,7 +1908,11 @@ void ACTION_OT_snap(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_snap_types, 0, "Type", ""); } -/* ******************** Mirror Keyframes Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform: Mirror Keyframes Operator + * \{ */ /* defines for mirror keyframes tool */ static const EnumPropertyItem prop_actkeys_mirror_types[] = { @@ -1976,4 +2036,4 @@ void ACTION_OT_mirror(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_actkeys_mirror_types, 0, "Type", ""); } -/* ************************************************************************** */ +/** \} */ diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 0c416712a0e..eaf69f94926 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -18,7 +18,7 @@ #include "BLI_utildefines.h" #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -28,7 +28,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_nla.h" #include "UI_interface.h" @@ -48,8 +48,9 @@ #include "action_intern.h" -/* ************************************************************************** */ -/* KEYFRAMES STUFF */ +/* -------------------------------------------------------------------- */ +/** \name Keyframes Stuff + * \{ */ static bAnimListElem *actkeys_find_list_element_at_position(bAnimContext *ac, int filter, @@ -218,12 +219,16 @@ static bool actkeys_is_key_at_position(bAnimContext *ac, float region_x, float r return found; } -/* ******************** Deselect All Operator ***************************** */ -/* This operator works in one of three ways: - * 1) (de)select all (AKEY) - test if select all or deselect all - * 2) invert all (CTRL-IKEY) - invert selection of all keyframes - * 3) (de)select all - no testing is done; only for use internal tools as normal function... - */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Deselect All Operator + * + * This operator works in one of three ways: + * 1) (de)select all (AKEY) - test if select all or deselect all. + * 2) invert all (CTRL-IKEY) - invert selection of all keyframes. + * 3) (de)select all - no testing is done; only for use internal tools as normal function. + * \{ */ /* Deselects keyframes in the action editor * - This is called by the deselect all operator, as well as other ones! @@ -352,15 +357,18 @@ void ACTION_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/* ******************** Box Select Operator **************************** */ -/** +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Box Select Operator + * * This operator currently works in one of three ways: * - BKEY - 1) all keyframes within region are selected #ACTKEYS_BORDERSEL_ALLKEYS. * - ALT-BKEY - depending on which axis of the region was larger... * - 2) x-axis, so select all frames within frame range #ACTKEYS_BORDERSEL_FRAMERANGE. * - 3) y-axis, so select all frames within channels that region included * #ACTKEYS_BORDERSEL_CHANNELS. - */ + * \{ */ /* defines for box_select mode */ enum { @@ -606,11 +614,15 @@ void ACTION_OT_select_box(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Region Select Operators ***************************** */ -/* "Region Select" operators include the Lasso and Circle Select operators. +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Region Select Operators + * + * "Region Select" operators include the Lasso and Circle Select operators. * These two ended up being lumped together, as it was easier in the * original Graph Editor implementation of these to do it this way. - */ + * \{ */ typedef struct RegionSelectData { bAnimContext *ac; @@ -903,13 +915,17 @@ void ACTION_OT_select_circle(wmOperatorType *ot) WM_operator_properties_select_operation_simple(ot); } -/* ******************** Column Select Operator **************************** */ -/* This operator works in one of four ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Column Select Operator + * + * This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) * - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY) * - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY) * - 4) select all keyframes that occur between selected markers (ALT-KKEY) - */ + * \{ */ /* defines for column-select mode */ static const EnumPropertyItem prop_column_select_types[] = { @@ -1140,7 +1156,11 @@ void ACTION_OT_select_column(wmOperatorType *ot) RNA_def_property_flag(ot->prop, PROP_HIDDEN); } -/* ******************** Select Linked Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * \{ */ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1199,7 +1219,11 @@ void ACTION_OT_select_linked(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Select More/Less Operators *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More/Less Operators + * \{ */ /* Common code to perform selection */ static void select_moreless_action_keys(bAnimContext *ac, short mode) @@ -1322,8 +1346,13 @@ void ACTION_OT_select_less(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Select Left/Right Operator ************************* */ -/* Select keyframes left/right of the current frame indicator */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Left/Right Operator + * + * Select keyframes left/right of the current frame indicator. + * \{ */ /* defines for left-right select tool */ static const EnumPropertyItem prop_actkeys_leftright_select_types[] = { @@ -1520,8 +1549,12 @@ void ACTION_OT_select_leftright(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Mouse-Click Select Operator *********************** */ -/* This operator works in one of three ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse-Click Select Operator + * + * This operator works in one of three ways: * - 1) keyframe under mouse - no special modifiers * - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier * - 3) column select all keyframes in frame under mouse - CTRL modifier @@ -1529,9 +1562,7 @@ void ACTION_OT_select_leftright(wmOperatorType *ot) * * In addition to these basic options, the SHIFT modifier can be used to toggle the * selection mode between replacing the selection (without) and inverting the selection (with). - */ - -/* ------------------- */ + * \{ */ /* option 1) select keyframe directly under mouse */ static void actkeys_mselect_single(bAnimContext *ac, @@ -1905,4 +1936,4 @@ void ACTION_OT_clickselect(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************************************************************************** */ +/** \} */ diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 34c89a13288..cbc83a94469 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -46,7 +46,9 @@ #include "action_intern.h" /* own include */ -/* ******************** default callbacks for action space ***************** */ +/* -------------------------------------------------------------------- */ +/** \name Default Callbacks for Action Space + * \{ */ static SpaceLink *action_create(const ScrArea *area, const Scene *scene) { @@ -962,3 +964,5 @@ void ED_spacetype_action(void) BKE_spacetype_register(st); } + +/** \} */ diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 9690d8bd860..3dfbe08652a 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -193,6 +193,7 @@ void ED_spacetypes_keymap(wmKeyConfig *keyconf) ED_keymap_paint(keyconf); ED_keymap_mask(keyconf); ED_keymap_marker(keyconf); + ED_keymap_sculpt(keyconf); ED_keymap_view2d(keyconf); ED_keymap_ui(keyconf); diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 463e1a14954..046bfda288b 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -256,7 +256,7 @@ static bool buttons_context_path_data(ButsContextPath *path, int type) if (RNA_struct_is_a(ptr->type, &RNA_LightProbe) && ELEM(type, -1, OB_LIGHTPROBE)) { return true; } - if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && ELEM(type, -1, OB_GPENCIL)) { + if (RNA_struct_is_a(ptr->type, &RNA_GreasePencil) && ELEM(type, -1, OB_GPENCIL_LEGACY)) { return true; } if (RNA_struct_is_a(ptr->type, &RNA_Curves) && ELEM(type, -1, OB_CURVES)) { @@ -297,7 +297,7 @@ static bool buttons_context_path_modifier(ButsContextPath *path) OB_FONT, OB_SURF, OB_LATTICE, - OB_GPENCIL, + OB_GPENCIL_LEGACY, OB_CURVES, OB_POINTCLOUD, OB_VOLUME)) { @@ -319,7 +319,7 @@ static bool buttons_context_path_shaderfx(ButsContextPath *path) if (buttons_context_path_object(path)) { Object *ob = path->ptr[path->len - 1].data; - if (ob && ELEM(ob->type, OB_GPENCIL)) { + if (ob && ELEM(ob->type, OB_GPENCIL_LEGACY)) { return true; } } diff --git a/source/blender/editors/space_buttons/buttons_texture.cc b/source/blender/editors/space_buttons/buttons_texture.cc index b4424474ebc..0eaccd7d2b8 100644 --- a/source/blender/editors/space_buttons/buttons_texture.cc +++ b/source/blender/editors/space_buttons/buttons_texture.cc @@ -29,7 +29,7 @@ #include "DNA_windowmanager_types.h" #include "BKE_context.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_layer.h" #include "BKE_linestyle.h" #include "BKE_modifier.h" diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 90d8d0c3061..59bfe794e59 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -15,7 +15,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" -#include "BKE_gpencil_modifier.h" /* Types for registering panels. */ +#include "BKE_gpencil_modifier_legacy.h" /* Types for registering panels. */ #include "BKE_lib_remap.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/editors/space_clip/clip_dopesheet_draw.cc b/source/blender/editors/space_clip/clip_dopesheet_draw.cc index 87dd61ce1e1..e39316e8dc5 100644 --- a/source/blender/editors/space_clip/clip_dopesheet_draw.cc +++ b/source/blender/editors/space_clip/clip_dopesheet_draw.cc @@ -340,7 +340,7 @@ void clip_draw_dopesheet_channels(const bContext *C, ARegion *region) /* second pass: text */ y = float(CHANNEL_FIRST); - BLF_size(fontid, 11.0f * U.dpi_fac); + BLF_size(fontid, 11.0f * UI_SCALE_FAC); LISTBASE_FOREACH (MovieTrackingDopesheetChannel *, channel, &dopesheet->channels) { float yminc = float(y - CHANNEL_HEIGHT_HALF); diff --git a/source/blender/editors/space_clip/clip_draw.cc b/source/blender/editors/space_clip/clip_draw.cc index f594767bf23..c6b730bfaf1 100644 --- a/source/blender/editors/space_clip/clip_draw.cc +++ b/source/blender/editors/space_clip/clip_draw.cc @@ -5,7 +5,7 @@ * \ingroup spclip */ -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" @@ -59,11 +59,11 @@ static void draw_keyframe(int frame, int cfra, int sfra, float framelen, int wid if (width == 1) { immBegin(GPU_PRIM_LINES, 2); immVertex2i(pos, x, 0); - immVertex2i(pos, x, height * UI_DPI_FAC); + immVertex2i(pos, x, height * UI_SCALE_FAC); immEnd(); } else { - immRecti(pos, x, 0, x + width, height * UI_DPI_FAC); + immRecti(pos, x, 0, x + width, height * UI_SCALE_FAC); } } @@ -191,7 +191,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *region, MovieClip *clip (i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, - 4 * UI_DPI_FAC); + 4 * UI_SCALE_FAC); } } } @@ -223,7 +223,7 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *region, MovieClip *clip (i - sfra + clip->start_frame - 1) * framelen, 0, (i - sfra + clip->start_frame) * framelen, - 8 * UI_DPI_FAC); + 8 * UI_SCALE_FAC); } } } @@ -234,11 +234,11 @@ static void draw_movieclip_cache(SpaceClip *sc, ARegion *region, MovieClip *clip x = (sc->user.framenr - sfra) / (efra - sfra + 1) * region->winx; immUniformThemeColor(TH_CFRAME); - immRecti(pos, x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC); + immRecti(pos, x, 0, x + ceilf(framelen), 8 * UI_SCALE_FAC); immUnbindProgram(); - ED_region_cache_draw_curfra_label(sc->user.framenr, x, 8.0f * UI_DPI_FAC); + ED_region_cache_draw_curfra_label(sc->user.framenr, x, 8.0f * UI_SCALE_FAC); pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); @@ -368,7 +368,8 @@ static void draw_stabilization_border( float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f( + "viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* "simple" mode */ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.0f); @@ -743,7 +744,7 @@ static void draw_marker_areas(SpaceClip *sc, float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* "simple" mode */ @@ -954,11 +955,11 @@ static void draw_marker_slide_zones(SpaceClip *sc, dy = 6.0f / height / sc->zoom; side = get_shortest_pattern_side(marker); - patdx = min_ff(dx * 2.0f / 3.0f, side / 6.0f) * UI_DPI_FAC; - patdy = min_ff(dy * 2.0f / 3.0f, side * width / height / 6.0f) * UI_DPI_FAC; + patdx = min_ff(dx * 2.0f / 3.0f, side / 6.0f) * UI_SCALE_FAC; + patdy = min_ff(dy * 2.0f / 3.0f, side * width / height / 6.0f) * UI_SCALE_FAC; - searchdx = min_ff(dx, (marker->search_max[0] - marker->search_min[0]) / 6.0f) * UI_DPI_FAC; - searchdy = min_ff(dy, (marker->search_max[1] - marker->search_min[1]) / 6.0f) * UI_DPI_FAC; + searchdx = min_ff(dx, (marker->search_max[0] - marker->search_min[0]) / 6.0f) * UI_SCALE_FAC; + searchdy = min_ff(dy, (marker->search_max[1] - marker->search_min[1]) / 6.0f) * UI_SCALE_FAC; px[0] = 1.0f / sc->zoom / width / sc->scale; px[1] = 1.0f / sc->zoom / height / sc->scale; @@ -1035,7 +1036,7 @@ static void draw_marker_texts(SpaceClip *sc, return; } - BLF_size(fontid, 11.0f * U.dpi_fac); + BLF_size(fontid, 11.0f * UI_SCALE_FAC); fontsize = BLF_height_max(fontid); if (marker->flag & MARKER_DISABLED) { @@ -1288,7 +1289,8 @@ static void draw_plane_marker_ex(SpaceClip *sc, float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f( + "viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* "simple" mode */ diff --git a/source/blender/editors/space_clip/clip_ops.cc b/source/blender/editors/space_clip/clip_ops.cc index 3ace6605487..78466926e05 100644 --- a/source/blender/editors/space_clip/clip_ops.cc +++ b/source/blender/editors/space_clip/clip_ops.cc @@ -1104,7 +1104,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event ARegion *region = CTX_wm_region(C); if (region->regiontype == RGN_TYPE_WINDOW) { - if (event->mval[1] > 16 * UI_DPI_FAC) { + if (event->mval[1] > 16 * UI_SCALE_FAC) { return OPERATOR_PASS_THROUGH; } } diff --git a/source/blender/editors/space_clip/space_clip.cc b/source/blender/editors/space_clip/space_clip.cc index b30a1d6f305..f6680ed8069 100644 --- a/source/blender/editors/space_clip/space_clip.cc +++ b/source/blender/editors/space_clip/space_clip.cc @@ -997,7 +997,7 @@ static void graph_region_draw(const bContext *C, ARegion *region) { rcti rect; BLI_rcti_init( - &rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y); + &rect, 0, 15 * UI_SCALE_FAC, 15 * UI_SCALE_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y); UI_view2d_draw_scale_y__values(region, v2d, &rect, TH_TEXT); } } diff --git a/source/blender/editors/space_clip/tracking_ops_detect.cc b/source/blender/editors/space_clip/tracking_ops_detect.cc index fcad5fe6fa1..23161720234 100644 --- a/source/blender/editors/space_clip/tracking_ops_detect.cc +++ b/source/blender/editors/space_clip/tracking_ops_detect.cc @@ -5,7 +5,7 @@ * \ingroup spclip */ -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 6710d4ce0e7..8f037c3bcd8 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -167,7 +167,7 @@ static void console_textview_draw_rect_calc(const ARegion *region, rcti *r_draw_rect, rcti *r_draw_rect_outer) { - const int margin = 4 * UI_DPI_FAC; + const int margin = 4 * UI_SCALE_FAC; r_draw_rect->xmin = margin; r_draw_rect->xmax = region->winx - V2D_SCROLL_WIDTH; r_draw_rect->ymin = margin; @@ -209,7 +209,7 @@ static int console_textview_main__internal(SpaceConsole *sc, /* view */ tvc.sel_start = sc->sel_start; tvc.sel_end = sc->sel_end; - tvc.lheight = sc->lheight * UI_DPI_FAC; + tvc.lheight = sc->lheight * UI_SCALE_FAC; tvc.scroll_ymin = v2d->cur.ymin; tvc.scroll_ymax = v2d->cur.ymax; diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index 684577a399f..0a1e8f27af4 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -29,7 +29,7 @@ set(INC_SYS set(SRC asset_catalog_tree_view.cc - file_draw.c + file_draw.cc file_indexer.cc file_ops.c file_panels.c diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.cc similarity index 84% rename from source/blender/editors/space_file/file_draw.c rename to source/blender/editors/space_file/file_draw.cc index ab29413be22..4ecb9a52c6a 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.cc @@ -5,16 +5,14 @@ * \ingroup spfile */ -#include -#include -#include +#include +#include +#include #include "MEM_guardedalloc.h" -#include "BLI_alloca.h" #include "BLI_blenlib.h" #include "BLI_fileops_types.h" -#include "BLI_math.h" #include "BLI_utildefines.h" #ifdef WIN32 @@ -23,10 +21,8 @@ #include "BIF_glutil.h" +#include "BKE_blendfile.h" #include "BKE_context.h" -#include "BKE_main.h" - -#include "BLO_readfile.h" #include "BLT_translation.h" @@ -55,8 +51,6 @@ #include "GPU_immediate_util.h" #include "GPU_state.h" -#include "AS_asset_representation.h" - #include "filelist.h" #include "file_intern.h" /* own include */ @@ -69,13 +63,13 @@ void ED_file_path_button(bScreen *screen, PointerRNA params_rna_ptr; uiBut *but; - BLI_assert_msg(params != NULL, + BLI_assert_msg(params != nullptr, "File select parameters not set. The caller is expected to check this."); RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, ¶ms_rna_ptr); /* callbacks for operator check functions */ - UI_block_func_set(block, file_draw_check_cb, NULL, NULL); + UI_block_func_set(block, file_draw_check_cb, nullptr, nullptr); but = uiDefButR(block, UI_BTYPE_TEXT, @@ -89,7 +83,7 @@ void ED_file_path_button(bScreen *screen, "directory", 0, 0.0f, - (float)FILE_MAX, + float(FILE_MAX), 0.0f, 0.0f, TIP_("File path")); @@ -97,8 +91,8 @@ void ED_file_path_button(bScreen *screen, BLI_assert(!UI_but_flag_is_set(but, UI_BUT_UNDO)); BLI_assert(!UI_but_is_utf8(but)); - UI_but_func_complete_set(but, autocomplete_directory, NULL); - UI_but_funcN_set(but, file_directory_enter_handle, NULL, but); + UI_but_func_complete_set(but, autocomplete_directory, nullptr); + UI_but_funcN_set(but, file_directory_enter_handle, nullptr, but); /* TODO: directory editing is non-functional while a library is loaded * until this is properly supported just disable it. */ @@ -107,13 +101,13 @@ void ED_file_path_button(bScreen *screen, } /* clear func */ - UI_block_func_set(block, NULL, NULL, NULL); + UI_block_func_set(block, nullptr, nullptr, nullptr); } /* Dummy helper - we need dynamic tooltips here. */ -static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char *UNUSED(tip)) +static char *file_draw_tooltip_func(bContext * /*C*/, void *argN, const char * /*tip*/) { - char *dyn_tooltip = argN; + char *dyn_tooltip = static_cast(argN); return BLI_strdup(dyn_tooltip); } @@ -147,17 +141,15 @@ static void file_but_enable_drag(uiBut *but, else if (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS && (file->typeflag & FILE_TYPE_ASSET) != 0) { char blend_path[FILE_MAX_LIBEXTRA]; - if (BLO_library_path_explode(path, blend_path, NULL, NULL)) { + if (BKE_blendfile_library_path_explode(path, blend_path, nullptr, nullptr)) { const int import_method = ED_fileselect_asset_import_method_get(sfile, file); BLI_assert(import_method > -1); - UI_but_drag_set_asset(but, - &(AssetHandle){.file_data = file}, - BLI_strdup(blend_path), - import_method, - icon, - preview_image, - scale); + AssetHandle asset{}; + asset.file_data = file; + + UI_but_drag_set_asset( + but, &asset, BLI_strdup(blend_path), import_method, icon, preview_image, scale); } } else if (preview_image) { @@ -187,7 +179,7 @@ static uiBut *file_add_icon_but(const SpaceFile *sfile, const float a1 = dimmed ? 1.0f : 0.0f; const float a2 = dimmed ? 0.3f : 0.0f; but = uiDefIconBut( - block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, NULL, 0.0f, 0.0f, a1, a2, NULL); + block, UI_BTYPE_LABEL, 0, icon, x, y, width, height, nullptr, 0.0f, 0.0f, a1, a2, nullptr); UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path), MEM_freeN); return but; @@ -213,7 +205,7 @@ static void file_draw_string(int sx, fs = style->widget; BLI_strncpy(fname, string, FILE_MAXFILE); - UI_text_clip_middle_ex(&fs, fname, width, UI_DPI_ICON_SIZE, sizeof(fname), '\0'); + UI_text_clip_middle_ex(&fs, fname, width, UI_ICON_SIZE, sizeof(fname), '\0'); /* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict * (for buttons it works) */ @@ -222,14 +214,10 @@ static void file_draw_string(int sx, rect.ymin = sy - height; rect.ymax = sy; - UI_fontstyle_draw(&fs, - &rect, - fname, - sizeof(fname), - col, - &(struct uiFontStyleDraw_Params){ - .align = align, - }); + uiFontStyleDraw_Params font_style_params{}; + font_style_params.align = align; + + UI_fontstyle_draw(&fs, &rect, fname, sizeof(fname), col, &font_style_params); } /** @@ -271,19 +259,13 @@ static void file_draw_string_multiline(int sx, rect.ymin = sy - BLI_rcti_size_y(&textbox) - line_height; rect.ymax = sy; - struct ResultBLF result; - UI_fontstyle_draw_ex(&style->widget, - &rect, - string, - len, - text_col, - &(struct uiFontStyleDraw_Params){ - .align = UI_STYLE_TEXT_LEFT, - .word_wrap = true, - }, - NULL, - NULL, - &result); + uiFontStyleDraw_Params font_style_params{}; + font_style_params.align = UI_STYLE_TEXT_LEFT; + font_style_params.word_wrap = true; + + ResultBLF result; + UI_fontstyle_draw_ex( + &style->widget, &rect, string, len, text_col, &font_style_params, nullptr, nullptr, &result); if (r_sx) { *r_sx = result.width; } @@ -325,12 +307,12 @@ static void file_add_preview_drag_but(const SpaceFile *sfile, drag_rect.ymin, BLI_rcti_size_x(&drag_rect), BLI_rcti_size_y(&drag_rect), - NULL, + nullptr, 0.0, 0.0, 0, 0, - NULL); + nullptr); file_but_enable_drag(but, sfile, file, path, preview_image, icon, scale); } @@ -356,38 +338,38 @@ static void file_draw_preview(const FileDirEntry *file, (file->typeflag & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); const bool is_offline = (file->attributes & FILE_ATTR_OFFLINE); - BLI_assert(imb != NULL); + BLI_assert(imb != nullptr); - ui_imbx = imb->x * UI_DPI_FAC; - ui_imby = imb->y * UI_DPI_FAC; + ui_imbx = imb->x * UI_SCALE_FAC; + ui_imby = imb->y * UI_SCALE_FAC; /* Unlike thumbnails, icons are not scaled up. */ if (((ui_imbx > layout->prv_w) || (ui_imby > layout->prv_h)) || (!is_icon && ((ui_imbx < layout->prv_w) || (ui_imby < layout->prv_h)))) { if (imb->x > imb->y) { - scaledx = (float)layout->prv_w; - scaledy = ((float)imb->y / (float)imb->x) * layout->prv_w; + scaledx = float(layout->prv_w); + scaledy = (float(imb->y) / float(imb->x)) * layout->prv_w; scale = scaledx / imb->x; } else { - scaledy = (float)layout->prv_h; - scaledx = ((float)imb->x / (float)imb->y) * layout->prv_h; + scaledy = float(layout->prv_h); + scaledx = (float(imb->x) / float(imb->y)) * layout->prv_h; scale = scaledy / imb->y; } } else { scaledx = ui_imbx; scaledy = ui_imby; - scale = UI_DPI_FAC; + scale = UI_SCALE_FAC; } - ex = (int)scaledx; - ey = (int)scaledy; - fx = ((float)layout->prv_w - (float)ex) / 2.0f; - fy = ((float)layout->prv_h - (float)ey) / 2.0f; + ex = int(scaledx); + ey = int(scaledy); + fx = (float(layout->prv_w) - float(ex)) / 2.0f; + fy = (float(layout->prv_h) - float(ey)) / 2.0f; dx = (fx + 0.5f + layout->prv_border_x); dy = (fy + 0.5f - layout->prv_border_y); - xco = tile_draw_rect->xmin + (int)dx; - yco = tile_draw_rect->ymax - layout->prv_h + (int)dy; + xco = tile_draw_rect->xmin + int(dx); + yco = tile_draw_rect->ymax - layout->prv_h + int(dy); GPU_blend(GPU_BLEND_ALPHA); @@ -417,8 +399,8 @@ static void file_draw_preview(const FileDirEntry *file, IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR); immDrawPixelsTexTiled_scaling(&state, - (float)xco, - (float)yco, + float(xco), + float(yco), imb->x, imb->y, GPU_RGBA8, @@ -435,7 +417,7 @@ static void file_draw_preview(const FileDirEntry *file, if (icon && is_icon) { /* Small icon in the middle of large image, scaled to fit container and UI scale */ float icon_x, icon_y; - const float icon_size = 16.0f / icon_aspect * U.dpi_fac; + const float icon_size = 16.0f / icon_aspect * UI_SCALE_FAC; float icon_opacity = 0.3f; uchar icon_color[4] = {0, 0, 0, 255}; float bgcolor[4]; @@ -450,7 +432,7 @@ static void file_draw_preview(const FileDirEntry *file, UI_icon_draw_ex(icon_x, icon_y, icon, - icon_aspect / U.dpi_fac, + icon_aspect / UI_SCALE_FAC, icon_opacity, 0.0f, icon_color, @@ -461,8 +443,8 @@ static void file_draw_preview(const FileDirEntry *file, if (is_link || is_offline) { /* Icon at bottom to indicate it is a shortcut, link, alias, or offline. */ float icon_x, icon_y; - icon_x = xco + (2.0f * UI_DPI_FAC); - icon_y = yco + (2.0f * UI_DPI_FAC); + icon_x = xco + (2.0f * UI_SCALE_FAC); + icon_y = yco + (2.0f * UI_SCALE_FAC); const int arrow = is_link ? ICON_LOOP_FORWARDS : ICON_URL; if (!is_icon) { /* At very bottom-left if preview style. */ @@ -471,7 +453,7 @@ static void file_draw_preview(const FileDirEntry *file, UI_icon_draw_ex(icon_x + 1, icon_y - 1, arrow, - 1.0f / U.dpi_fac, + 1.0f / UI_SCALE_FAC, 0.2f, 0.0f, dark, @@ -480,7 +462,7 @@ static void file_draw_preview(const FileDirEntry *file, UI_icon_draw_ex(icon_x, icon_y, arrow, - 1.0f / U.dpi_fac, + 1.0f / UI_SCALE_FAC, 0.6f, 0.0f, light, @@ -496,7 +478,7 @@ static void file_draw_preview(const FileDirEntry *file, UI_icon_draw_ex(icon_x, icon_y, arrow, - icon_aspect / U.dpi_fac * 1.8, + icon_aspect / UI_SCALE_FAC * 1.8f, 0.3f, 0.0f, icon_color, @@ -509,22 +491,29 @@ static void file_draw_preview(const FileDirEntry *file, float icon_x, icon_y; const uchar dark[4] = {0, 0, 0, 255}; const uchar light[4] = {255, 255, 255, 255}; - icon_x = xco + (2.0f * UI_DPI_FAC); - icon_y = yco + (2.0f * UI_DPI_FAC); + icon_x = xco + (2.0f * UI_SCALE_FAC); + icon_y = yco + (2.0f * UI_SCALE_FAC); UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, - 1.0f / U.dpi_fac, + 1.0f / UI_SCALE_FAC, 0.2f, 0.0f, dark, false, UI_NO_ICON_OVERLAY_TEXT); - UI_icon_draw_ex( - icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false, UI_NO_ICON_OVERLAY_TEXT); + UI_icon_draw_ex(icon_x, + icon_y, + icon, + 1.0f / UI_SCALE_FAC, + 0.6f, + 0.0f, + light, + false, + UI_NO_ICON_OVERLAY_TEXT); } - const bool is_current_main_data = filelist_file_get_id(file) != NULL; + const bool is_current_main_data = filelist_file_get_id(file) != nullptr; if (is_current_main_data) { /* Smaller, fainter icon at the top-right indicating that the file represents data from the * current file (from current #Main in fact). */ @@ -535,7 +524,7 @@ static void file_draw_preview(const FileDirEntry *file, UI_icon_draw_ex(icon_x, icon_y, ICON_CURRENT_FILE, - 1.0f / U.dpi_fac, + 1.0f / UI_SCALE_FAC, 0.6f, 0.0f, light, @@ -557,7 +546,7 @@ static void file_draw_preview(const FileDirEntry *file, border_color[2] = 0.0f; } immUniformColor4fv(border_color); - imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + imm_draw_box_wire_2d(pos, float(xco), float(yco), float(xco + ex), float(yco + ey)); immUnbindProgram(); } @@ -568,7 +557,7 @@ static void file_draw_preview(const FileDirEntry *file, } } -static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) +static void renamebutton_cb(bContext *C, void * /*arg1*/, char *oldname) { char newname[FILE_MAX + 12]; char orgname[FILE_MAX + 12]; @@ -623,16 +612,16 @@ static void draw_background(FileLayout *layout, View2D *v2d) /* alternating flat shade background */ for (i = 2; (i <= layout->rows + 1); i += 2) { - sy = (int)v2d->cur.ymax - layout->offset_top - i * item_height - layout->tile_border_y; + sy = int(v2d->cur.ymax) - layout->offset_top - i * item_height - layout->tile_border_y; /* Offset pattern slightly to add scroll effect. */ sy += round_fl_to_int(item_height * (v2d->tot.ymax - v2d->cur.ymax) / item_height); immRectf(pos, v2d->cur.xmin, - (float)sy, + float(sy), v2d->cur.xmax, - (float)(sy + layout->tile_h + 2 * layout->tile_border_y)); + float(sy + layout->tile_h + 2 * layout->tile_border_y)); } immUnbindProgram(); @@ -645,7 +634,7 @@ static void draw_dividers(FileLayout *layout, View2D *v2d) const int step = (layout->tile_w + 2 * layout->tile_border_x); uint vertex_len = 0; - int sx = (int)v2d->tot.xmin; + int sx = int(v2d->tot.xmin); while (sx < v2d->cur.xmax) { sx += step; vertex_len += 4; /* vertex_count = 2 points per line * 2 lines per divider */ @@ -669,7 +658,7 @@ static void draw_dividers(FileLayout *layout, View2D *v2d) immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); immBegin(GPU_PRIM_LINES, vertex_len); - sx = (int)v2d->tot.xmin; + sx = int(v2d->tot.xmin); while (sx < v2d->cur.xmax) { sx += step; @@ -715,9 +704,8 @@ static void draw_columnheader_columns(const FileSelectParams *params, const float divider_pad = 0.2 * layout->attribute_column_header_h; int sx = v2d->cur.xmin, sy = v2d->cur.ymax; - for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX; - column_type++) { - if (!file_attribute_column_type_enabled(params, column_type)) { + for (int column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX; column_type++) { + if (!file_attribute_column_type_enabled(params, FileAttributeColumnType(column_type))) { continue; } const FileAttributeColumn *column = &layout->attribute_columns[column_type]; @@ -792,7 +780,7 @@ static const char *filelist_get_details_column_string( bool is_today, is_yesterday; BLI_filelist_entry_datetime_to_string( - NULL, file->time, small_size, time, date, &is_today, &is_yesterday); + nullptr, file->time, small_size, time, date, &is_today, &is_yesterday); if (is_today || is_yesterday) { BLI_strncpy(date, is_today ? N_("Today") : N_("Yesterday"), sizeof(date)); @@ -812,7 +800,7 @@ static const char *filelist_get_details_column_string( !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) { if ((file->draw_data.size_str[0] == '\0') || update_stat_strings) { BLI_filelist_entry_size_to_string( - NULL, file->size, small_size, file->draw_data.size_str); + nullptr, file->size, small_size, file->draw_data.size_str); } return file->draw_data.size_str; @@ -822,7 +810,7 @@ static const char *filelist_get_details_column_string( break; } - return NULL; + return nullptr; } static void draw_details_columns(const FileSelectParams *params, @@ -835,8 +823,7 @@ static void draw_details_columns(const FileSelectParams *params, const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size); int sx = tile_draw_rect->xmin - layout->tile_border_x - (UI_UNIT_X * 0.1f); - for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX; - column_type++) { + for (int column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX; column_type++) { const FileAttributeColumn *column = &layout->attribute_columns[column_type]; /* Name column is not a detail column (should already be drawn), always skip here. */ @@ -844,12 +831,12 @@ static void draw_details_columns(const FileSelectParams *params, sx += column->width; continue; } - if (!file_attribute_column_type_enabled(params, column_type)) { + if (!file_attribute_column_type_enabled(params, FileAttributeColumnType(column_type))) { continue; } const char *str = filelist_get_details_column_string( - column_type, file, small_size, update_stat_strings); + FileAttributeColumnType(column_type), file, small_size, update_stat_strings); if (str) { file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING, @@ -857,7 +844,7 @@ static void draw_details_columns(const FileSelectParams *params, IFACE_(str), column->width - 2 * ATTRIBUTE_COLUMN_PADDING, layout->tile_h, - column->text_align, + eFontStyle_Align(column->text_align), text_col); } @@ -867,14 +854,14 @@ static void draw_details_columns(const FileSelectParams *params, static rcti tile_draw_rect_get(const View2D *v2d, const FileLayout *layout, - const enum eFileDisplayType display, + const eFileDisplayType display, const int file_idx, const int padx) { int tile_pos_x, tile_pos_y; ED_fileselect_layout_tilepos(layout, file_idx, &tile_pos_x, &tile_pos_y); - tile_pos_x += (int)(v2d->tot.xmin); - tile_pos_y = (int)(v2d->tot.ymax - tile_pos_y); + tile_pos_x += int(v2d->tot.xmin); + tile_pos_y = int(v2d->tot.ymax - tile_pos_y); rcti rect; rect.xmin = tile_pos_x + padx; @@ -895,8 +882,8 @@ void file_draw_list(const bContext *C, ARegion *region) FileSelectParams *params = ED_fileselect_get_active_params(sfile); FileLayout *layout = ED_fileselect_get_layout(sfile, region); View2D *v2d = ®ion->v2d; - struct FileList *files = sfile->files; - struct FileDirEntry *file; + FileList *files = sfile->files; + FileDirEntry *file; ImBuf *imb; uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); int numfiles; @@ -909,7 +896,7 @@ void file_draw_list(const bContext *C, ARegion *region) bool do_drag; uchar text_col[4]; const bool draw_columnheader = (params->display == FILE_VERTICALDISPLAY); - const float thumb_icon_aspect = MIN2(64.0f / (float)(params->thumbnail_size), 1.0f); + const float thumb_icon_aspect = MIN2(64.0f / float(params->thumbnail_size), 1.0f); numfiles = filelist_files_ensure(files); @@ -919,7 +906,7 @@ void file_draw_list(const bContext *C, ARegion *region) } offset = ED_fileselect_layout_offset( - layout, (int)region->v2d.cur.xmin, (int)-region->v2d.cur.ymax); + layout, int(region->v2d.cur.xmin), int(-region->v2d.cur.ymax)); if (offset < 0) { offset = 0; } @@ -939,7 +926,7 @@ void file_draw_list(const bContext *C, ARegion *region) column_width = (FILE_IMGDISPLAY == params->display) ? layout->tile_w : round_fl_to_int(layout->attribute_columns[COLUMN_NAME].width); - textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5); + textheight = int(layout->textheight * 3.0 / 2.0 + 0.5); align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT; @@ -966,7 +953,7 @@ void file_draw_list(const bContext *C, ARegion *region) /* Preview is not running, no need to keep generating update events! */ // printf("%s: Inactive preview task, sleeping!\n", __func__); WM_event_remove_timer_notifier(wm, win, sfile->previews_timer); - sfile->previews_timer = NULL; + sfile->previews_timer = nullptr; } } } @@ -980,7 +967,8 @@ void file_draw_list(const bContext *C, ARegion *region) const int padx = 0.1f * UI_UNIT_X; int icon_ofs = 0; - const rcti tile_draw_rect = tile_draw_rect_get(v2d, layout, params->display, i, padx); + const rcti tile_draw_rect = tile_draw_rect_get( + v2d, layout, eFileDisplayType(params->display), i, padx); file = filelist_file(files, i); file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL); @@ -998,7 +986,7 @@ void file_draw_list(const bContext *C, ARegion *region) rcti tile_bg_rect = tile_draw_rect; /* One pixel downwards, places it more in the center. */ - BLI_rcti_translate(&tile_bg_rect, 0, -1); + BLI_rcti_translate(&tile_bg_rect, 0, -U.pixelsize); draw_tile_background(&tile_bg_rect, colorid, shade); } } @@ -1037,6 +1025,33 @@ void file_draw_list(const bContext *C, ARegion *region) } else { const int icon = filelist_geticon(files, i, true); + + icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; + + /* Add dummy draggable button covering the icon and the label. */ + if (do_drag) { + const uiStyle *style = UI_style_get(); + const int str_width = UI_fontstyle_string_width(&style->widget, file->name); + const int drag_width = MIN2(str_width + icon_ofs, column_width - ATTRIBUTE_COLUMN_PADDING); + uiBut *drag_but = uiDefBut(block, + UI_BTYPE_LABEL, + 0, + "", + tile_draw_rect.xmin, + tile_draw_rect.ymin - 1, + drag_width, + layout->tile_h + layout->tile_border_y * 2, + nullptr, + 0, + 0, + 0, + 0, + 0); + UI_but_dragflag_enable(drag_but, UI_BUT_DRAG_FULL_BUT); + file_but_enable_drag(drag_but, sfile, file, path, nullptr, icon, UI_SCALE_FAC); + } + + /* Add this after the fake draggable button, so the icon button tooltip is displayed. */ uiBut *icon_but = file_add_icon_but(sfile, block, path, @@ -1046,9 +1061,10 @@ void file_draw_list(const bContext *C, ARegion *region) ICON_DEFAULT_HEIGHT_SCALE, is_hidden); if (do_drag) { - file_but_enable_drag(icon_but, sfile, file, path, NULL, icon, UI_DPI_FAC); + /* For some reason the dragging is unreliable for the icon button if we don't explicitly + * enable dragging, even though the dummy drag button above covers the same area. */ + file_but_enable_drag(icon_but, sfile, file, path, nullptr, icon, UI_SCALE_FAC); } - icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; } if (file_selflag & FILE_SEL_EDITING) { @@ -1067,7 +1083,7 @@ void file_draw_list(const bContext *C, ARegion *region) textheight, params->renamefile, 1.0f, - (float)sizeof(params->renamefile), + float(sizeof(params->renamefile)), 0, 0, ""); @@ -1085,7 +1101,7 @@ void file_draw_list(const bContext *C, ARegion *region) * Tagging regions for redrawing while drawing is rightfully prevented. However, this * active button removing basically introduces handling logic to drawing code. So a * notifier should be an acceptable workaround. */ - WM_event_add_notifier_ex(wm, win, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + WM_event_add_notifier_ex(wm, win, NC_SPACE | ND_SPACE_FILE_PARAMS, nullptr); file_selflag = filelist_entry_select_get(sfile->files, file, CHECK_ALL); } @@ -1101,7 +1117,7 @@ void file_draw_list(const bContext *C, ARegion *region) const int twidth = (params->display == FILE_IMGDISPLAY) ? column_width : column_width - 1 - icon_ofs - padx - layout->tile_border_x; - file_draw_string(txpos, typos, file->name, (float)twidth, textheight, align, text_col); + file_draw_string(txpos, typos, file->name, float(twidth), textheight, align, text_col); } if (params->display != FILE_IMGDISPLAY) { @@ -1145,7 +1161,7 @@ static void file_draw_invalid_library_hint(const bContext *C, { const char *message = TIP_("Path to asset library does not exist:"); - file_draw_string_multiline(sx, sy, message, width, line_height, text_col, NULL, &sy); + file_draw_string_multiline(sx, sy, message, width, line_height, text_col, nullptr, &sy); sy -= line_height; file_draw_string(sx, sy, library_ui_path, width, line_height, UI_STYLE_TEXT_LEFT, text_col); @@ -1161,7 +1177,7 @@ static void file_draw_invalid_library_hint(const bContext *C, "Asset Libraries are local directories that can contain .blend files with assets inside.\n" "Manage Asset Libraries from the File Paths section in Preferences"); file_draw_string_multiline( - sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, NULL, &sy); + sx + UI_UNIT_X, sy, suggestion, width - UI_UNIT_X, line_height, text_col, nullptr, &sy); uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); uiBut *but = uiDefIconTextButO(block, @@ -1169,12 +1185,12 @@ static void file_draw_invalid_library_hint(const bContext *C, "SCREEN_OT_userpref_show", WM_OP_INVOKE_DEFAULT, ICON_PREFERENCES, - NULL, + nullptr, sx + UI_UNIT_X, sy - line_height - UI_UNIT_Y * 1.2f, UI_UNIT_X * 8, UI_UNIT_Y, - NULL); + nullptr); PointerRNA *but_opptr = UI_but_operator_ptr_get(but); RNA_enum_set(but_opptr, "section", USER_SECTION_FILE_PATHS); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 8616707e42e..c3fef65c5ff 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -11,9 +11,8 @@ #include "BLI_linklist.h" #include "BLI_math.h" -#include "BLO_readfile.h" - #include "BKE_appdir.h" +#include "BKE_blendfile.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_main.h" @@ -2539,7 +2538,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN BLI_split_dirfile( path, params->dir, params->file, sizeof(params->dir), sizeof(params->file)); } - else if (BLO_library_path_explode(params->dir, tdir, &group, &name)) { + else if (BKE_blendfile_library_path_explode(params->dir, tdir, &group, &name)) { if (group) { BLI_path_append(tdir, sizeof(tdir), group); } @@ -2578,7 +2577,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN char tdir[FILE_MAX_LIBEXTRA]; /* If we are 'inside' a blend library, we cannot do anything... */ - if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { + if (lastdir && BKE_blendfile_library_path_explode(lastdir, tdir, NULL, NULL)) { BLI_strncpy(params->dir, lastdir, sizeof(params->dir)); } else { diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 455cbf0da2f..97c228a7795 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -9,8 +9,8 @@ #include "BLI_rect.h" #include "BLI_string.h" +#include "BKE_blendfile.h" #include "BKE_context.h" -#include "BLO_readfile.h" #include "ED_fileselect.h" #include "ED_screen.h" @@ -37,5 +37,5 @@ void file_path_to_ui_path(const char *path, char *r_path, int max_size) char tmp_path[PATH_MAX]; BLI_strncpy(tmp_path, path, sizeof(tmp_path)); BLI_path_slash_rstrip(tmp_path); - BLI_strncpy(r_path, BLO_has_bfile_extension(tmp_path) ? tmp_path : path, max_size); + BLI_strncpy(r_path, BKE_blendfile_extension_check(tmp_path) ? tmp_path : path, max_size); } diff --git a/source/blender/editors/space_file/filelist.cc b/source/blender/editors/space_file/filelist.cc index 2e7a70a3dd6..f27238f4fe3 100644 --- a/source/blender/editors/space_file/filelist.cc +++ b/source/blender/editors/space_file/filelist.cc @@ -48,6 +48,7 @@ #endif #include "BKE_asset.h" +#include "BKE_blendfile.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_icons.h" @@ -56,7 +57,6 @@ #include "BKE_main.h" #include "BKE_main_idmap.h" #include "BKE_preferences.h" -#include "BLO_readfile.h" #include "DNA_asset_types.h" #include "DNA_space_types.h" @@ -1353,7 +1353,7 @@ static bool filelist_checkdir_lib(FileList * /*filelist*/, char *r_dir, const bo char *name; const bool is_valid = (BLI_is_dir(r_dir) || - (BLO_library_path_explode(r_dir, tdir, nullptr, &name) && + (BKE_blendfile_library_path_explode(r_dir, tdir, nullptr, &name) && BLI_is_file(tdir) && !name)); if (do_change && !is_valid) { @@ -1950,7 +1950,7 @@ static const char *fileentry_uiname(const char *root, FileListInternEntry *entry char *group; BLI_path_join(abspath, sizeof(abspath), root, relpath); - BLO_library_path_explode(abspath, buff, &group, &name); + BKE_blendfile_library_path_explode(abspath, buff, &group, &name); if (!name) { name = group; } @@ -2623,7 +2623,7 @@ int ED_path_extension_type(const char *path) /* ATTENTION: Never return OR'ed bit-flags here, always return a single enum value! Some code * using this may do `ELEM()`-like checks. */ - if (BLO_has_bfile_extension(path)) { + if (BKE_blendfile_extension_check(path)) { return FILE_TYPE_BLENDER; } if (file_is_blend_backup(path)) { @@ -2885,7 +2885,7 @@ bool filelist_islibrary(FileList *filelist, char *dir, char **r_group) if (filelist->asset_library) { return true; } - return BLO_library_path_explode(filelist->filelist.root, dir, r_group, nullptr); + return BKE_blendfile_library_path_explode(filelist->filelist.root, dir, r_group, nullptr); } static int groupname_to_code(const char *group) @@ -3041,7 +3041,7 @@ static int filelist_readjob_list_dir(FileListReadJob *job_params, } if (!(entry->typeflag & FILE_TYPE_DIR)) { - if (do_lib && BLO_has_bfile_extension(target)) { + if (do_lib && BKE_blendfile_extension_check(target)) { /* If we are considering .blend files as libraries, promote them to directory status. */ entry->typeflag = FILE_TYPE_BLENDER; /* prevent current file being used as acceptable dir */ @@ -3234,7 +3234,7 @@ static std::optional filelist_readjob_list_lib(FileListReadJob *job_params, * will do a dir listing only when this function does not return any entries. */ /* TODO(jbakker): We should consider introducing its own function to detect if it is a lib and * call it directly from `filelist_readjob_do` to increase readability. */ - const bool is_lib = BLO_library_path_explode(root, dir, &group, nullptr); + const bool is_lib = BKE_blendfile_library_path_explode(root, dir, &group, nullptr); if (!is_lib) { return std::nullopt; } @@ -3894,6 +3894,16 @@ static void filelist_readjob_all_asset_library(FileListReadJob *job_params, /* A valid, but empty file-list from now. */ filelist->filelist.entries_num = 0; + asset_system::AssetLibrary *current_file_library; + { + AssetLibraryReference library_ref{}; + library_ref.custom_library_index = -1; + library_ref.type = ASSET_LIBRARY_LOCAL; + + current_file_library = AS_asset_library_load(job_params->current_main, library_ref); + } + + job_params->load_asset_library = current_file_library; filelist_readjob_main_assets_add_items(job_params, stop, do_update, progress); /* When only doing partially reload for main data, we're done. */ @@ -3916,6 +3926,10 @@ static void filelist_readjob_all_asset_library(FileListReadJob *job_params, if (root_path.is_empty()) { return; } + if (&nested_library == current_file_library) { + /* Skip the "Current File" library, it's already loaded above. */ + return; + } /* Override library info to read this library. */ job_params->load_asset_library = &nested_library; diff --git a/source/blender/editors/space_file/filesel.cc b/source/blender/editors/space_file/filesel.cc index 45bbb25a4de..bc9fd0140cf 100644 --- a/source/blender/editors/space_file/filesel.cc +++ b/source/blender/editors/space_file/filesel.cc @@ -630,8 +630,8 @@ void ED_fileselect_window_params_get(const wmWindow *win, int win_size[2], bool /* Get DPI/pixel-size independent size to be stored in preferences. */ WM_window_set_dpi(win); /* Ensure the DPI is taken from the right window. */ - win_size[0] = WM_window_pixels_x(win) / UI_DPI_FAC; - win_size[1] = WM_window_pixels_y(win) / UI_DPI_FAC; + win_size[0] = WM_window_pixels_x(win) / UI_SCALE_FAC; + win_size[1] = WM_window_pixels_y(win) / UI_SCALE_FAC; *is_maximized = WM_window_is_maximized(win); } @@ -967,7 +967,7 @@ float file_font_pointsize(void) #else const uiStyle *style = UI_style_get(); UI_fontstyle_set(&style->widget); - return style->widget.points * UI_DPI_FAC; + return style->widget.points * UI_SCALE_FAC; #endif } diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 3023b98668e..8ff86292ca9 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -1350,7 +1350,7 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *panel) uiBut *but = NULL; /* Get active property to show driver properties for */ - but = UI_context_active_but_prop_get((bContext *)C, &ptr, &prop, &index); + but = UI_region_active_but_prop_get(CTX_wm_region(C), &ptr, &prop, &index); if (but) { FCurve *fcu; bool driven, special; diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 23f3cb068ab..4ce7d4286df 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -84,7 +84,7 @@ static void draw_fcurve_modifier_controls_envelope(FModifier *fcm, float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* Simple dashes. */ immUniformColor3f(0.0f, 0.0f, 0.0f); @@ -235,7 +235,7 @@ static void draw_fcurve_keyframe_vertices(FCurve *fcu, View2D *v2d, bool edit, u { immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA); - immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * U.dpi_fac); + immUniform1f("size", UI_GetThemeValuef(TH_VERTEX_SIZE) * UI_SCALE_FAC); draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, false, pos); draw_fcurve_selected_keyframe_vertices(fcu, v2d, edit, true, pos); @@ -332,8 +332,8 @@ static void draw_fcurve_handle_vertices(FCurve *fcu, View2D *v2d, bool sel_handl immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA); /* set handle size */ - immUniform1f("size", (1.4f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE)) * U.dpi_fac); - immUniform1f("outlineWidth", 1.5f * U.dpi_fac); + immUniform1f("size", (1.4f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE)) * UI_SCALE_FAC); + immUniform1f("outlineWidth", 1.5f * UI_SCALE_FAC); draw_fcurve_selected_handle_vertices(fcu, v2d, false, sel_handle_only, pos); draw_fcurve_selected_handle_vertices(fcu, v2d, true, sel_handle_only, pos); @@ -406,7 +406,7 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu) uint color = GPU_vertformat_attr_add( format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR); - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) { GPU_line_smooth(true); } GPU_blend(GPU_BLEND_ALPHA); @@ -482,7 +482,7 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu) immEnd(); immUnbindProgram(); GPU_blend(GPU_BLEND_NONE); - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) { GPU_line_smooth(false); } } @@ -515,7 +515,7 @@ static void draw_fcurve_sample_control( } /* helper func - draw keyframe vertices only for an F-Curve */ -static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu) +static void draw_fcurve_samples(ARegion *region, FCurve *fcu) { FPoint *first, *last; float hsize, xscale, yscale; @@ -531,7 +531,7 @@ static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu) /* draw */ if (first && last) { /* anti-aliased lines for more consistent appearance */ - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) { GPU_line_smooth(true); } GPU_blend(GPU_BLEND_ALPHA); @@ -547,7 +547,7 @@ static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu) immUnbindProgram(); GPU_blend(GPU_BLEND_NONE); - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) { GPU_line_smooth(false); } } @@ -565,7 +565,6 @@ static void draw_fcurve_curve(bAnimContext *ac, const bool use_nla_remap, const bool draw_extrapolation) { - SpaceGraph *sipo = (SpaceGraph *)ac->sl; short mapping_flag = ANIM_get_normalization_flags(ac); /* when opening a blend file on a different sized screen or while dragging the toolbar this can @@ -601,7 +600,7 @@ static void draw_fcurve_curve(bAnimContext *ac, float pixels_per_sample = 1.5f; float samplefreq = pixels_per_sample / UI_view2d_scale_get_x(v2d); - if (sipo->flag & SIPO_BEAUTYDRAW_OFF) { + if (!(U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING)) { /* Low Precision = coarse lower-bound clamping * * Although the "Beauty Draw" flag was originally for AA'd @@ -633,7 +632,7 @@ static void draw_fcurve_curve(bAnimContext *ac, if (!draw_extrapolation) { float fcu_start = 0; float fcu_end = 0; - BKE_fcurve_calc_range(fcu_, &fcu_start, &fcu_end, false, false); + BKE_fcurve_calc_range(fcu_, &fcu_start, &fcu_end, false); fcu_start = BKE_nla_tweakedit_remap(adt, fcu_start, NLATIME_CONVERT_MAP); fcu_end = BKE_nla_tweakedit_remap(adt, fcu_end, NLATIME_CONVERT_MAP); @@ -1030,7 +1029,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn } /* anti-aliased lines for less jagged appearance */ - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) { GPU_line_smooth(true); } GPU_blend(GPU_BLEND_ALPHA); @@ -1044,7 +1043,8 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn if (BKE_fcurve_is_protected(fcu)) { /* Protected curves (non editable) are drawn with dotted lines. */ immBindBuiltinProgram(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f( + "viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* Simple dashes. */ immUniform1f("dash_width", 4.0f); immUniform1f("udash_factor", 0.5f); @@ -1105,7 +1105,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn immUnbindProgram(); - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) { GPU_line_smooth(false); } GPU_blend(GPU_BLEND_NONE); @@ -1115,7 +1115,8 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn * - If the option to only show controls if the F-Curve is selected is enabled, * we must obey this. */ - if (!(sipo->flag & SIPO_SELCUVERTSONLY) || (fcu->flag & FCURVE_SELECTED)) { + if (!(U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) || + (fcu->flag & FCURVE_SELECTED)) { if (!BKE_fcurve_are_keyframes_usable(fcu) && !(fcu->fpt && fcu->totvert)) { /* only draw controls if this is the active modifier */ if ((fcu->flag & FCURVE_ACTIVE) && (fcm)) { @@ -1153,7 +1154,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn } else { /* samples: only draw two indicators at either end as indicators */ - draw_fcurve_samples(sipo, region, fcu); + draw_fcurve_samples(region, fcu); } GPU_matrix_pop(); @@ -1192,7 +1193,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu) float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* Simple dashes. */ @@ -1300,7 +1301,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region GPU_line_width(3.0f); /* anti-aliased lines for less jagged appearance */ - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) { GPU_line_smooth(true); } GPU_blend(GPU_BLEND_ALPHA); @@ -1312,7 +1313,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* Simple dashes. */ immUniform1f("dash_width", 20.0f); @@ -1333,7 +1334,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region immUnbindProgram(); - if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + if (U.animation_flag & USER_ANIM_HIGH_QUALITY_DRAWING) { GPU_line_smooth(false); } GPU_blend(GPU_BLEND_NONE); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 73e05bbe1e3..f8c90ee8178 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2853,7 +2853,7 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot) ot->prop = prop; RNA_def_boolean( - ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve"); + ot->srna, "only_active", false, "Only Active", "Only add F-Modifier to active F-Curve"); } /** \} */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index c6a0f0e945a..df3b572442d 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -172,8 +172,9 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS | ANIMFILTER_FCURVESONLY); - if (sipo->flag & - SIPO_SELCUVERTSONLY) { /* FIXME: this should really be check for by the filtering code... */ + if (U.animation_flag & + USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) { /* FIXME: this should really be check for by the + * filtering code. */ filter |= ANIMFILTER_SEL; } mapping_flag |= ANIM_get_normalization_flags(ac); @@ -336,7 +337,6 @@ void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channel bAnimListElem *ale; int filter; - SpaceGraph *sipo = (SpaceGraph *)ac->sl; KeyframeEditData ked = {{NULL}}; KeyframeEditFunc test_cb, sel_cb; @@ -374,7 +374,7 @@ void deselect_graph_keys(bAnimContext *ac, bool test, short sel, bool do_channel if (do_channels) { /* Only change selection of channel when the visibility of keyframes * doesn't depend on this. */ - if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) { + if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) { /* deactivate the F-Curve, and deselect if deselecting keyframes. * otherwise select the F-Curve too since we've selected all the keyframes */ @@ -496,11 +496,11 @@ static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rec return rectf; } -static int initialize_animdata_selection_filter(const SpaceGraph *sipo) +static int initialize_animdata_selection_filter(void) { int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS); - if (sipo->flag & SIPO_SELCUVERTSONLY) { + if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) { filter |= ANIMFILTER_FOREDIT | ANIMFILTER_SELEDIT; } return filter; @@ -513,8 +513,7 @@ static ListBase initialize_box_select_anim_data(const int filter, bAnimContext * return anim_data; } -static void initialize_box_select_key_editing_data(const SpaceGraph *sipo, - const bool incl_handles, +static void initialize_box_select_key_editing_data(const bool incl_handles, const short mode, bAnimContext *ac, void *data, @@ -540,7 +539,7 @@ static void initialize_box_select_key_editing_data(const SpaceGraph *sipo, r_ked->data = scaled_rectf; break; } - + SpaceGraph *sipo = (SpaceGraph *)ac->sl; if (sipo->flag & SIPO_SELVHANDLESONLY) { r_ked->iterflags |= KEYFRAME_ITER_HANDLES_DEFAULT_INVISIBLE; } @@ -574,14 +573,13 @@ static bool box_select_graphkeys(bAnimContext *ac, void *data) { const rctf rectf = initialize_box_select_coords(ac, rectf_view); - SpaceGraph *sipo = (SpaceGraph *)ac->sl; - const int filter = initialize_animdata_selection_filter(sipo); + const int filter = initialize_animdata_selection_filter(); ListBase anim_data = initialize_box_select_anim_data(filter, ac); rctf scaled_rectf; KeyframeEditData ked; int mapping_flag; initialize_box_select_key_editing_data( - sipo, incl_handles, mode, ac, data, &scaled_rectf, &ked, &mapping_flag); + incl_handles, mode, ac, data, &scaled_rectf, &ked, &mapping_flag); /* Get beztriple editing/validation functions. */ const KeyframeEditFunc select_cb = ANIM_editkeyframes_select(selectmode); @@ -633,7 +631,7 @@ static bool box_select_graphkeys(bAnimContext *ac, any_key_selection_changed = true; /* Only change selection of channel when the visibility of keyframes * doesn't depend on this. */ - if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) { + if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) { /* select the curve too now that curve will be touched */ if (selectmode == SELECT_ADD) { fcu->flag |= FCURVE_SELECTED; @@ -733,14 +731,13 @@ static void box_select_graphcurves(bAnimContext *ac, const bool incl_handles, void *data) { - const SpaceGraph *sipo = (SpaceGraph *)ac->sl; - const int filter = initialize_animdata_selection_filter(sipo); + const int filter = initialize_animdata_selection_filter(); ListBase anim_data = initialize_box_select_anim_data(filter, ac); rctf scaled_rectf; KeyframeEditData ked; int mapping_flag; initialize_box_select_key_editing_data( - sipo, incl_handles, mode, ac, data, &scaled_rectf, &ked, &mapping_flag); + incl_handles, mode, ac, data, &scaled_rectf, &ked, &mapping_flag); FCurve *last_selected_curve = NULL; @@ -1707,7 +1704,7 @@ static int mouse_graph_keys(bAnimContext *ac, /* Deselect other channels too, but only do this if selection of channel * when the visibility of keyframes doesn't depend on this. */ - if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) { + if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) { ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR); } } @@ -1780,7 +1777,7 @@ static int mouse_graph_keys(bAnimContext *ac, } /* only change selection of channel when the visibility of keyframes doesn't depend on this */ - if ((sipo->flag & SIPO_SELCUVERTSONLY) == 0) { + if ((U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) == 0) { /* select or deselect curve? */ if (bezt) { /* take selection status from item that got hit, to prevent flip/flop on channel diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c index e6cbdd63ae6..9e25f4282f4 100644 --- a/source/blender/editors/space_graph/graph_view.c +++ b/source/blender/editors/space_graph/graph_view.c @@ -49,7 +49,6 @@ void get_graph_keyframe_extents(bAnimContext *ac, const bool include_handles) { Scene *scene = ac->scene; - SpaceGraph *sipo = (SpaceGraph *)ac->sl; ListBase anim_data = {NULL, NULL}; bAnimListElem *ale; @@ -58,7 +57,7 @@ void get_graph_keyframe_extents(bAnimContext *ac, /* Get data to filter, from Dopesheet. */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FCURVESONLY | ANIMFILTER_NODUPLIS); - if (sipo->flag & SIPO_SELCUVERTSONLY) { + if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) { filter |= ANIMFILTER_SEL; } @@ -86,40 +85,39 @@ void get_graph_keyframe_extents(bAnimContext *ac, for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); FCurve *fcu = (FCurve *)ale->key_data; - float txmin, txmax, tymin, tymax; + rctf bounds; float unitFac, offset; /* Get range. */ - if (BKE_fcurve_calc_bounds( - fcu, &txmin, &txmax, &tymin, &tymax, do_sel_only, include_handles, NULL)) { + if (BKE_fcurve_calc_bounds(fcu, do_sel_only, include_handles, NULL, &bounds)) { short mapping_flag = ANIM_get_normalization_flags(ac); /* Apply NLA scaling. */ if (adt) { - txmin = BKE_nla_tweakedit_remap(adt, txmin, NLATIME_CONVERT_MAP); - txmax = BKE_nla_tweakedit_remap(adt, txmax, NLATIME_CONVERT_MAP); + bounds.xmin = BKE_nla_tweakedit_remap(adt, bounds.xmin, NLATIME_CONVERT_MAP); + bounds.xmax = BKE_nla_tweakedit_remap(adt, bounds.xmax, NLATIME_CONVERT_MAP); } /* Apply unit corrections. */ unitFac = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); - tymin += offset; - tymax += offset; - tymin *= unitFac; - tymax *= unitFac; + bounds.ymin += offset; + bounds.ymax += offset; + bounds.ymin *= unitFac; + bounds.ymax *= unitFac; /* Try to set cur using these values, if they're more extreme than previously set values. */ - if ((xmin) && (txmin < *xmin)) { - *xmin = txmin; + if ((xmin) && (bounds.xmin < *xmin)) { + *xmin = bounds.xmin; } - if ((xmax) && (txmax > *xmax)) { - *xmax = txmax; + if ((xmax) && (bounds.xmax > *xmax)) { + *xmax = bounds.xmax; } - if ((ymin) && (tymin < *ymin)) { - *ymin = tymin; + if ((ymin) && (bounds.ymin < *ymin)) { + *ymin = bounds.ymin; } - if ((ymax) && (tymax > *ymax)) { - *ymax = tymax; + if ((ymax) && (bounds.ymax > *ymax)) { + *ymax = bounds.ymax; } foundBounds = true; diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index fd7a6ab6c8e..812143d3a40 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -68,7 +68,7 @@ static SpaceLink *graph_create(const ScrArea *UNUSED(area), const Scene *scene) /* settings for making it easier by default to just see what you're interested in tweaking */ sipo->ads->filterflag |= ADS_FILTER_ONLYSEL; - sipo->flag |= SIPO_SELVHANDLESONLY | SIPO_SHOW_MARKERS; + sipo->flag |= SIPO_SHOW_MARKERS; /* header */ region = MEM_callocN(sizeof(ARegion), "header for graphedit"); @@ -314,7 +314,7 @@ static void graph_main_region_draw_overlay(const bContext *C, ARegion *region) { rcti rect; BLI_rcti_init( - &rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y); + &rect, 0, 15 * UI_SCALE_FAC, 15 * UI_SCALE_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y); UI_view2d_draw_scale_y__values(region, v2d, &rect, TH_SCROLL_TEXT); } } diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index d323a7162d7..786fcd4075a 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -789,7 +789,7 @@ void uiTemplateImage(uiLayout *layout, else if (ima->type == IMA_TYPE_R_RESULT) { /* browse layer/passes */ RenderResult *rr; - const float dpi_fac = UI_DPI_FAC; + const float dpi_fac = UI_SCALE_FAC; const int menus_width = 230 * dpi_fac; /* use BKE_image_acquire_renderresult so we get the correct slot in the menu */ @@ -880,7 +880,7 @@ void uiTemplateImage(uiLayout *layout, if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) { uiItemS(layout); - const float dpi_fac = UI_DPI_FAC; + const float dpi_fac = UI_SCALE_FAC; uiblock_layer_pass_buttons(layout, ima, ima->rr, iuser, 230 * dpi_fac, NULL); } @@ -1162,7 +1162,7 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser /* render layers and passes */ if (ima && iuser) { RenderResult *rr; - const float dpi_fac = UI_DPI_FAC; + const float dpi_fac = UI_SCALE_FAC; const int menus_width = 160 * dpi_fac; const bool is_render_result = (ima->type == IMA_TYPE_R_RESULT); diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 9bf23ff4538..6460e6ebd7b 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -168,7 +168,7 @@ void ED_image_draw_info(Scene *scene, GPU_blend(GPU_BLEND_NONE); - BLF_size(blf_mono_font, 11.0f * U.dpi_fac); + BLF_size(blf_mono_font, 11.0f * UI_SCALE_FAC); BLF_color3ub(blf_mono_font, 255, 255, 255); SNPRINTF(str, "X:%-4d Y:%-4d |", x, y); @@ -452,7 +452,8 @@ void draw_image_sample_line(SpaceImage *sima) float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f( + "viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 2); /* Advanced dashes. */ immUniform4f("color", 1.0f, 1.0f, 1.0f, 1.0f); @@ -504,7 +505,7 @@ bool ED_space_image_show_cache_and_mval_over(const SpaceImage *sima, const int mval[2]) { const rcti *rect_visible = ED_region_visible_rect(region); - if (mval[1] > rect_visible->ymin + (16 * UI_DPI_FAC)) { + if (mval[1] > rect_visible->ymin + (16 * UI_SCALE_FAC)) { return false; } return ED_space_image_show_cache(sima); @@ -559,10 +560,10 @@ void draw_image_cache(const bContext *C, ARegion *region) immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); immUniformThemeColor(TH_CFRAME); - immRecti(pos, x, region_bottom, x + ceilf(framelen), region_bottom + 8 * UI_DPI_FAC); + immRecti(pos, x, region_bottom, x + ceilf(framelen), region_bottom + 8 * UI_SCALE_FAC); immUnbindProgram(); - ED_region_cache_draw_curfra_label(cfra, x, region_bottom + 8.0f * UI_DPI_FAC); + ED_region_cache_draw_curfra_label(cfra, x, region_bottom + 8.0f * UI_SCALE_FAC); if (mask != NULL) { ED_mask_draw_frames(mask, region, cfra, sfra, efra); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 13d3681b10e..31eea8c7558 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -3008,6 +3008,7 @@ static int image_scale_exec(bContext *C, wmOperator *op) ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; IMB_scaleImBuf(ibuf, size[0], size[1]); + BKE_image_mark_dirty(ima, ibuf); BKE_image_release_ibuf(ima, ibuf, NULL); ED_image_undo_push_end(); diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index a460f624d84..bd8ae8babb5 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -6,7 +6,7 @@ */ #include "DNA_defaults.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_image_types.h" #include "DNA_mask_types.h" #include "DNA_object_types.h" @@ -994,7 +994,8 @@ static void image_id_remap(ScrArea *UNUSED(area), { SpaceImage *simg = (SpaceImage *)slink; - if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_IM | FILTER_ID_GD | FILTER_ID_MSK)) { + if (!BKE_id_remapper_has_mapping_for(mappings, + FILTER_ID_IM | FILTER_ID_GD_LEGACY | FILTER_ID_MSK)) { return; } diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c index 812df2fc6cc..695d13f9425 100644 --- a/source/blender/editors/space_info/info_draw.c +++ b/source/blender/editors/space_info/info_draw.c @@ -190,7 +190,7 @@ static int info_textview_main__internal(const SpaceInfo *sinfo, /* view */ tvc.sel_start = 0; tvc.sel_end = 0; - tvc.lheight = 17 * UI_DPI_FAC; + tvc.lheight = 17 * UI_SCALE_FAC; tvc.row_vpadding = 0.4 * tvc.lheight; tvc.scroll_ymin = v2d->cur.ymin; tvc.scroll_ymax = v2d->cur.ymax; diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index f7163c03a57..baf12a0f81b 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -12,7 +12,7 @@ #include "DNA_armature_types.h" #include "DNA_collection_types.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_mesh_types.h" #include "DNA_meta_types.h" @@ -36,11 +36,11 @@ #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_editmesh.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_particle.h" @@ -164,7 +164,7 @@ static void stats_object(Object *ob, stats->totlampsel++; } break; - case OB_GPENCIL: { + case OB_GPENCIL_LEGACY: { if (is_selected) { bGPdata *gpd = (bGPdata *)ob->data; if (!BLI_gset_add(objects_gset, gpd)) { @@ -556,7 +556,7 @@ static void get_stats_string(char *info, *ofs += BLI_snprintf_rlen( info + *ofs, len - *ofs, TIP_("Bones:%s/%s"), stats_fmt->totbonesel, stats_fmt->totbone); } - else if ((ob) && (ob->type == OB_GPENCIL)) { + else if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { *ofs += BLI_snprintf_rlen(info + *ofs, len - *ofs, TIP_("Layers:%s | Frames:%s | Strokes:%s | Points:%s"), @@ -776,7 +776,7 @@ void ED_info_draw_stats( stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height); stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height); } - else if ((ob) && (ob->type == OB_GPENCIL)) { + else if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height); stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height); stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height); diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c index 12ee6f45991..c1c21bebf2b 100644 --- a/source/blender/editors/space_info/textview.c +++ b/source/blender/editors/space_info/textview.c @@ -15,7 +15,7 @@ #include "GPU_immediate.h" #include "GPU_state.h" -#include "DNA_userdef_types.h" /* For 'U.dpi_fac' */ +#include "DNA_userdef_types.h" /* For 'UI_SCALE_FAC' */ #include "UI_interface.h" #include "UI_interface_icons.h" @@ -205,7 +205,7 @@ static bool textview_draw_string(TextViewDrawState *tds, if (icon_bg) { float col[4]; - int bg_size = UI_DPI_ICON_SIZE * 1.2; + int bg_size = UI_ICON_SIZE * 1.2; float vpadding = (tds->lheight + (tds->row_vpadding * 2) - bg_size) / 2; float hpadding = tds->draw_rect->xmin - (bg_size * 1.2f); @@ -219,19 +219,19 @@ static bool textview_draw_string(TextViewDrawState *tds, .ymax = line_top - vpadding, }, true, - 4 * UI_DPI_FAC, + 4 * UI_SCALE_FAC, col); } if (icon) { - int vpadding = (tds->lheight + (tds->row_vpadding * 2) - UI_DPI_ICON_SIZE) / 2; - int hpadding = tds->draw_rect->xmin - (UI_DPI_ICON_SIZE * 1.3f); + int vpadding = (tds->lheight + (tds->row_vpadding * 2) - UI_ICON_SIZE) / 2; + int hpadding = tds->draw_rect->xmin - (UI_ICON_SIZE * 1.3f); GPU_blend(GPU_BLEND_ALPHA); UI_icon_draw_ex(hpadding, - line_top - UI_DPI_ICON_SIZE - vpadding, + line_top - UI_ICON_SIZE - vpadding, icon, - (16 / UI_DPI_ICON_SIZE), + (16 / UI_ICON_SIZE), 1.0f, 0.0f, icon_fg, diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 058cf3c49b4..83d0d1c205b 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -183,7 +183,8 @@ static void nla_actionclip_draw_markers( float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f( + "viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* "simple" mode */ immUniform1f("dash_width", 6.0f); @@ -382,7 +383,7 @@ static uint nla_draw_use_dashed_outlines(const float color[4], bool muted) float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* Simple dashes. */ immUniformColor3fv(color); @@ -789,7 +790,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region) { View2D *v2d = ®ion->v2d; const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); - const float text_margin_x = (8 * UI_DPI_FAC) * pixelx; + const float text_margin_x = (8 * UI_SCALE_FAC) * pixelx; /* build list of channels to draw */ ListBase anim_data = {NULL, NULL}; diff --git a/source/blender/editors/space_node/add_menu_assets.cc b/source/blender/editors/space_node/add_menu_assets.cc index 060e8914194..710eac2be0f 100644 --- a/source/blender/editors/space_node/add_menu_assets.cc +++ b/source/blender/editors/space_node/add_menu_assets.cc @@ -3,6 +3,7 @@ #include "AS_asset_catalog.hh" #include "AS_asset_catalog_tree.hh" #include "AS_asset_library.hh" +#include "AS_asset_representation.h" #include "BLI_multi_value_map.hh" @@ -46,7 +47,7 @@ static void node_add_menu_assets_listen_fn(const wmRegionListenerParams *params) struct LibraryAsset { AssetLibraryReference library_ref; - AssetHandle handle; + AssetRepresentation &asset; }; struct AssetItemTree { @@ -93,11 +94,11 @@ static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node return {}; } - ED_assetlist_iterate(all_library_ref, [&](AssetHandle asset) { - if (!ED_asset_filter_matches_asset(&type_filter, &asset)) { + ED_assetlist_iterate(all_library_ref, [&](AssetHandle asset_handle) { + if (!ED_asset_filter_matches_asset(&type_filter, &asset_handle)) { return true; } - const AssetMetaData &meta_data = *ED_asset_handle_get_metadata(&asset); + const AssetMetaData &meta_data = *ED_asset_handle_get_metadata(&asset_handle); const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&meta_data, "type"); if (tree_type == nullptr || IDP_Int(tree_type) != node_tree->type) { return true; @@ -111,7 +112,8 @@ static AssetItemTree build_catalog_tree(const bContext &C, const bNodeTree *node if (catalog == nullptr) { return true; } - assets_per_path.add(catalog->path, LibraryAsset{all_library_ref, asset}); + AssetRepresentation *asset = ED_asset_handle_get_representation(&asset_handle); + assets_per_path.add(catalog->path, LibraryAsset{all_library_ref, *asset}); return true; }); @@ -178,16 +180,17 @@ static void node_add_catalog_assets_draw(const bContext *C, Menu *menu) for (const LibraryAsset &item : asset_items) { uiLayout *col = uiLayoutColumn(layout, false); - PointerRNA file{ - &screen.id, &RNA_FileSelectEntry, const_cast(item.handle.file_data)}; - uiLayoutSetContextPointer(col, "active_file", &file); + + PointerRNA asset_ptr{NULL, &RNA_AssetRepresentation, &item.asset}; + uiLayoutSetContextPointer(col, "asset", &asset_ptr); PointerRNA library_ptr{&screen.id, &RNA_AssetLibraryReference, const_cast(&item.library_ref)}; uiLayoutSetContextPointer(col, "asset_library_ref", &library_ptr); - uiItemO(col, ED_asset_handle_get_name(&item.handle), ICON_NONE, "NODE_OT_add_group_asset"); + uiItemO( + col, AS_asset_representation_name_get(&item.asset), ICON_NONE, "NODE_OT_add_group_asset"); } catalog_item->foreach_child([&](asset_system::AssetCatalogTreeItem &child_item) { diff --git a/source/blender/editors/space_node/add_node_search.cc b/source/blender/editors/space_node/add_node_search.cc index 281995f59bc..c0ba8cd998e 100644 --- a/source/blender/editors/space_node/add_node_search.cc +++ b/source/blender/editors/space_node/add_node_search.cc @@ -40,7 +40,7 @@ namespace blender::ed::space_node { struct AddNodeItem { nodes::AddNodeInfo info; std::string identifier; - std::optional asset; + const AssetRepresentation *asset; }; struct AddNodeSearchStorage { @@ -66,24 +66,25 @@ static void add_node_search_listen_fn(const wmRegionListenerParams *params, void } static void search_items_for_asset_metadata(const bNodeTree &node_tree, - const AssetHandle asset, + const AssetHandle asset_handle, Vector &search_items) { - const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset); + const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset_handle); const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&asset_data, "type"); if (tree_type == nullptr || IDP_Int(tree_type) != node_tree.type) { return; } + const AssetRepresentation *asset = ED_asset_handle_get_representation(&asset_handle); AddNodeItem item{}; - item.info.ui_name = ED_asset_handle_get_name(&asset); + item.info.ui_name = ED_asset_handle_get_name(&asset_handle); item.identifier = node_tree.typeinfo->group_idname; item.info.description = asset_data.description == nullptr ? "" : asset_data.description; item.asset = asset; item.info.after_add_fn = [asset](const bContext &C, bNodeTree &node_tree, bNode &node) { Main &bmain = *CTX_data_main(&C); node.flag &= ~NODE_OPTIONS; - node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset); + node.id = ED_asset_get_local_id_from_asset_or_append_and_reuse(&bmain, asset, ID_NT); id_us_plus(node.id); BKE_ntree_update_tag_node_property(&node_tree, &node); DEG_relations_tag_update(&bmain); @@ -236,8 +237,8 @@ static void add_node_search_exec_fn(bContext *C, void *arg1, void *arg2) item->info.after_add_fn(*C, node_tree, *new_node); } - new_node->locx = storage.cursor.x / UI_DPI_FAC; - new_node->locy = storage.cursor.y / UI_DPI_FAC + 20; + new_node->locx = storage.cursor.x / UI_SCALE_FAC; + new_node->locy = storage.cursor.y / UI_SCALE_FAC + 20; nodeSetSelected(new_node, true); nodeSetActive(&node_tree, new_node); diff --git a/source/blender/editors/space_node/clipboard.cc b/source/blender/editors/space_node/clipboard.cc index 95c1c25e343..f51040d8dcc 100644 --- a/source/blender/editors/space_node/clipboard.cc +++ b/source/blender/editors/space_node/clipboard.cc @@ -260,7 +260,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) float2 mouse_location; RNA_property_float_get_array(op->ptr, offset_prop, mouse_location); - const float2 offset = (mouse_location - center) / UI_DPI_FAC; + const float2 offset = (mouse_location - center) / UI_SCALE_FAC; for (bNode *new_node : node_map.values()) { new_node->locx += offset.x; diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index ceb1d78a941..0b68e6b9dd4 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -1675,8 +1675,8 @@ void node_link_bezier_points_evaluated(const Span socket_locations, #define NODELINK_GROUP_SIZE 256 #define LINK_RESOL 24 -#define LINK_WIDTH (2.5f * UI_DPI_FAC) -#define ARROW_SIZE (7 * UI_DPI_FAC) +#define LINK_WIDTH (2.5f * UI_SCALE_FAC) +#define ARROW_SIZE (7 * UI_SCALE_FAC) /* Reroute arrow shape and mute bar. These are expanded here and shrunk in the glsl code. * See: gpu_shader_2D_nodelink_vert.glsl */ @@ -2228,7 +2228,7 @@ static std::array node_link_bezier_points_dragged(const SpaceNode &sn const bNodeLink &link) { const bNodeTree &node_tree = *snode.edittree; - const float2 cursor = snode.runtime->cursor * UI_DPI_FAC; + const float2 cursor = snode.runtime->cursor * UI_SCALE_FAC; std::array points; points[0] = link.fromsock ? socket_link_connection_location(node_tree.runtime->all_socket_locations, diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index 2b715ee1907..58f6dc18447 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -143,10 +143,10 @@ static void add_existing_group_input_fn(nodes::LinkSearchOpParams ¶ms, */ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree, const bNodeSocket &socket, - const AssetHandle asset, + const AssetHandle asset_handle, Vector &search_link_ops) { - const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset); + const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&asset_handle); const IDProperty *tree_type = BKE_asset_metadata_idprop_find(&asset_data, "type"); if (tree_type == nullptr || IDP_Int(tree_type) != node_tree.type) { return; @@ -182,7 +182,8 @@ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree, continue; } - const StringRef asset_name = ED_asset_handle_get_name(&asset); + AssetRepresentation *asset = ED_asset_handle_get_representation(&asset_handle); + const StringRef asset_name = ED_asset_handle_get_name(&asset_handle); const StringRef socket_name = socket_property->name; search_link_ops.append( @@ -193,7 +194,7 @@ static void search_link_ops_for_asset_metadata(const bNodeTree &node_tree, bNode &node = params.add_node(params.node_tree.typeinfo->group_idname); node.flag &= ~NODE_OPTIONS; - node.id = asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset); + node.id = ED_asset_get_local_id_from_asset_or_append_and_reuse(&bmain, asset, ID_NT); id_us_plus(node.id); BKE_ntree_update_tag_node_property(¶ms.node_tree, &node); DEG_relations_tag_update(&bmain); @@ -309,7 +310,7 @@ static void gather_socket_link_operations(const bContext &C, continue; } search_link_ops.append( - {std::string(IFACE_("Group Input ")) + UI_MENU_ARROW_SEP + interface_socket->name, + {std::string(IFACE_("Group Input")) + " " + UI_MENU_ARROW_SEP + interface_socket->name, [interface_socket](nodes::LinkSearchOpParams ¶ms) { add_existing_group_input_fn(params, *interface_socket); }, @@ -380,8 +381,8 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2) BLI_assert(new_nodes.size() == 1); bNode *new_node = new_nodes.first(); - new_node->locx = storage.cursor.x / UI_DPI_FAC; - new_node->locy = storage.cursor.y / UI_DPI_FAC + 20; + new_node->locx = storage.cursor.x / UI_SCALE_FAC; + new_node->locy = storage.cursor.y / UI_SCALE_FAC + 20; if (storage.in_out() == SOCK_IN) { new_node->locx -= new_node->width; } diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index 473ae4a6f83..c21c27832cf 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -7,6 +7,8 @@ #include +#include "AS_asset_representation.h" + #include "MEM_guardedalloc.h" #include "DNA_collection_types.h" @@ -55,8 +57,8 @@ namespace blender::ed::space_node { static void position_node_based_on_mouse(bNode &node, const float2 &location) { - node.locx = location.x - NODE_DY * 1.5f / UI_DPI_FAC; - node.locy = location.y + NODE_DY * 0.5f / UI_DPI_FAC; + node.locx = location.x - NODE_DY * 1.5f / UI_SCALE_FAC; + node.locy = location.y + NODE_DY * 0.5f / UI_SCALE_FAC; } bNode *add_node(const bContext &C, const StringRef idname, const float2 &location) @@ -204,8 +206,8 @@ static int add_reroute_exec(bContext *C, wmOperator *op) const float2 insert_point = std::accumulate( cuts.values().begin(), cuts.values().end(), float2(0)) / cuts.size(); - reroute->locx = insert_point.x / UI_DPI_FAC; - reroute->locy = insert_point.y / UI_DPI_FAC; + reroute->locx = insert_point.x / UI_SCALE_FAC; + reroute->locy = insert_point.y / UI_SCALE_FAC; /* Attach the reroute node to frame nodes behind it. */ for (const int i : frame_nodes.index_range()) { @@ -348,8 +350,8 @@ static int node_add_group_invoke(bContext *C, wmOperator *op, const wmEvent *eve &snode->runtime->cursor[0], &snode->runtime->cursor[1]); - snode->runtime->cursor[0] /= UI_DPI_FAC; - snode->runtime->cursor[1] /= UI_DPI_FAC; + snode->runtime->cursor[0] /= UI_SCALE_FAC; + snode->runtime->cursor[1] /= UI_SCALE_FAC; return node_add_group_exec(C, op); } @@ -378,14 +380,16 @@ void NODE_OT_add_group(wmOperatorType *ot) /** \name Add Node Group Asset Operator * \{ */ -static bool add_node_group_asset(const bContext &C, const AssetHandle asset, ReportList &reports) +static bool add_node_group_asset(const bContext &C, + const AssetRepresentation *asset, + ReportList &reports) { Main &bmain = *CTX_data_main(&C); SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree &edit_tree = *snode.edittree; bNodeTree *node_group = reinterpret_cast( - asset::get_local_id_from_asset_or_append_and_reuse(bmain, asset)); + ED_asset_get_local_id_from_asset_or_append_and_reuse(&bmain, asset, ID_NT)); if (!node_group) { return false; } @@ -427,9 +431,8 @@ static int node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEven if (!library_ref) { return OPERATOR_CANCELLED; } - bool is_valid; - const AssetHandle handle = CTX_wm_asset_handle(C, &is_valid); - if (!is_valid) { + const AssetRepresentation *asset = CTX_wm_asset(C); + if (!asset) { return OPERATOR_CANCELLED; } @@ -440,9 +443,9 @@ static int node_add_group_asset_invoke(bContext *C, wmOperator *op, const wmEven &snode.runtime->cursor[0], &snode.runtime->cursor[1]); - snode.runtime->cursor /= UI_DPI_FAC; + snode.runtime->cursor /= UI_SCALE_FAC; - if (!add_node_group_asset(*C, handle, *op->reports)) { + if (!add_node_group_asset(*C, asset, *op->reports)) { return OPERATOR_CANCELLED; } @@ -460,12 +463,11 @@ static char *node_add_group_asset_get_description(struct bContext *C, struct wmOperatorType * /*op*/, struct PointerRNA * /*values*/) { - bool is_valid; - const AssetHandle handle = CTX_wm_asset_handle(C, &is_valid); - if (!is_valid) { + const AssetRepresentation *asset = CTX_wm_asset(C); + if (!asset) { return nullptr; } - const AssetMetaData &asset_data = *ED_asset_handle_get_metadata(&handle); + const AssetMetaData &asset_data = *AS_asset_representation_metadata_get(asset); if (!asset_data.description) { return nullptr; } @@ -541,8 +543,8 @@ static int node_add_object_invoke(bContext *C, wmOperator *op, const wmEvent *ev &snode->runtime->cursor[0], &snode->runtime->cursor[1]); - snode->runtime->cursor[0] /= UI_DPI_FAC; - snode->runtime->cursor[1] /= UI_DPI_FAC; + snode->runtime->cursor[0] /= UI_SCALE_FAC; + snode->runtime->cursor[1] /= UI_SCALE_FAC; return node_add_object_exec(C, op); } @@ -628,8 +630,8 @@ static int node_add_collection_invoke(bContext *C, wmOperator *op, const wmEvent &snode->runtime->cursor[0], &snode->runtime->cursor[1]); - snode->runtime->cursor[0] /= UI_DPI_FAC; - snode->runtime->cursor[1] /= UI_DPI_FAC; + snode->runtime->cursor[0] /= UI_SCALE_FAC; + snode->runtime->cursor[1] /= UI_SCALE_FAC; return node_add_collection_exec(C, op); } @@ -743,8 +745,8 @@ static int node_add_file_invoke(bContext *C, wmOperator *op, const wmEvent *even &snode->runtime->cursor[0], &snode->runtime->cursor[1]); - snode->runtime->cursor[0] /= UI_DPI_FAC; - snode->runtime->cursor[1] /= UI_DPI_FAC; + snode->runtime->cursor[0] /= UI_SCALE_FAC; + snode->runtime->cursor[1] /= UI_SCALE_FAC; if (WM_operator_properties_id_lookup_is_set(op->ptr) || RNA_struct_property_is_set(op->ptr, "filepath")) { diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index a9db1fa50bd..737b50aa288 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -308,7 +308,7 @@ float2 node_to_view(const bNode &node, const float2 &co) { float2 result; nodeToView(&node, co.x, co.y, &result.x, &result.y); - return result * UI_DPI_FAC; + return result * UI_SCALE_FAC; } void node_to_updated_rect(const bNode &node, rctf &r_rect) @@ -324,8 +324,8 @@ void node_to_updated_rect(const bNode &node, rctf &r_rect) float2 node_from_view(const bNode &node, const float2 &co) { - const float x = co.x / UI_DPI_FAC; - const float y = co.y / UI_DPI_FAC; + const float x = co.x / UI_SCALE_FAC; + const float y = co.y / UI_SCALE_FAC; float2 result; nodeFromView(&node, x, y, &result.x, &result.y); return result; @@ -768,10 +768,10 @@ static void node_socket_draw_multi_input(const float color[4], const float2 location) { /* The other sockets are drawn with the keyframe shader. There, the outline has a base thickness - * that can be varied but always scales with the size the socket is drawn at. Using `U.dpi_fac` - * has the same effect here. It scales the outline correctly across different screen DPI's - * and UI scales without being affected by the 'line-width'. */ - const float outline_width = NODE_SOCK_OUTLINE_SCALE * U.dpi_fac; + * that can be varied but always scales with the size the socket is drawn at. Using + * `UI_SCALE_FAC` has the same effect here. It scales the outline correctly across different + * screen DPI's and UI scales without being affected by the 'line-width'. */ + const float outline_width = NODE_SOCK_OUTLINE_SCALE * UI_SCALE_FAC; /* UI_draw_roundbox draws the outline on the outer side, so compensate for the outline width. */ const rctf rect = { @@ -2021,7 +2021,7 @@ static void node_draw_extra_info_row(const bNode &node, const int row, const NodeExtraInfoRow &extra_info_row) { - const float but_icon_left = rect.xmin + 6.0f * U.dpi_fac; + const float but_icon_left = rect.xmin + 6.0f * UI_SCALE_FAC; const float but_icon_width = NODE_HEADER_ICON_SIZE * 0.8f; const float but_icon_right = but_icon_left + but_icon_width; @@ -2031,7 +2031,7 @@ static void node_draw_extra_info_row(const bNode &node, 0, extra_info_row.icon, int(but_icon_left), - int(rect.ymin + row * (20.0f * U.dpi_fac)), + int(rect.ymin + row * (20.0f * UI_SCALE_FAC)), but_icon_width, UI_UNIT_Y, nullptr, @@ -2048,7 +2048,7 @@ static void node_draw_extra_info_row(const bNode &node, } UI_block_emboss_set(&block, UI_EMBOSS); - const float but_text_left = but_icon_right + 6.0f * U.dpi_fac; + const float but_text_left = but_icon_right + 6.0f * UI_SCALE_FAC; const float but_text_right = rect.xmax; const float but_text_width = but_text_right - but_text_left; @@ -2057,7 +2057,7 @@ static void node_draw_extra_info_row(const bNode &node, 0, extra_info_row.text.c_str(), int(but_text_left), - int(rect.ymin + row * (20.0f * U.dpi_fac)), + int(rect.ymin + row * (20.0f * UI_SCALE_FAC)), short(but_text_width), short(NODE_DY), nullptr, @@ -2087,19 +2087,19 @@ static void node_draw_extra_info_panel(TreeDrawContext &tree_draw_ctx, float color[4]; rctf extra_info_rect; - const float width = (node.width - 6.0f) * U.dpi_fac; + const float width = (node.width - 6.0f) * UI_SCALE_FAC; if (node.is_frame()) { extra_info_rect.xmin = rct.xmin; - extra_info_rect.xmax = rct.xmin + 95.0f * U.dpi_fac; - extra_info_rect.ymin = rct.ymin + 2.0f * U.dpi_fac; - extra_info_rect.ymax = rct.ymin + 2.0f * U.dpi_fac; + extra_info_rect.xmax = rct.xmin + 95.0f * UI_SCALE_FAC; + extra_info_rect.ymin = rct.ymin + 2.0f * UI_SCALE_FAC; + extra_info_rect.ymax = rct.ymin + 2.0f * UI_SCALE_FAC; } else { - extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac; + extra_info_rect.xmin = rct.xmin + 3.0f * UI_SCALE_FAC; extra_info_rect.xmax = rct.xmin + width; extra_info_rect.ymin = rct.ymax; - extra_info_rect.ymax = rct.ymax + extra_info_rows.size() * (20.0f * U.dpi_fac); + extra_info_rect.ymax = rct.ymax + extra_info_rows.size() * (20.0f * UI_SCALE_FAC); if (node.flag & NODE_MUTED) { UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color); @@ -2115,10 +2115,11 @@ static void node_draw_extra_info_panel(TreeDrawContext &tree_draw_ctx, /* Draw outline. */ const float outline_width = 1.0f; - extra_info_rect.xmin = rct.xmin + 3.0f * U.dpi_fac - outline_width; + extra_info_rect.xmin = rct.xmin + 3.0f * UI_SCALE_FAC - outline_width; extra_info_rect.xmax = rct.xmin + width + outline_width; extra_info_rect.ymin = rct.ymax - outline_width; - extra_info_rect.ymax = rct.ymax + outline_width + extra_info_rows.size() * (20.0f * U.dpi_fac); + extra_info_rect.ymax = rct.ymax + outline_width + + extra_info_rows.size() * (20.0f * UI_SCALE_FAC); UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color); UI_draw_roundbox_corner_set( @@ -2328,7 +2329,7 @@ static void node_draw_basis(const bContext &C, showname, int(rct.xmin + NODE_MARGIN_X + 0.4f), int(rct.ymax - NODE_DY), - short(iconofs - rct.xmin - (18.0f * U.dpi_fac)), + short(iconofs - rct.xmin - (18.0f * UI_SCALE_FAC)), short(NODE_DY), nullptr, 0, @@ -2560,7 +2561,7 @@ static void node_draw_hidden(const bContext &C, showname, round_fl_to_int(rct.xmin + NODE_MARGIN_X), round_fl_to_int(centy - NODE_DY * 0.5f), - short(BLI_rctf_size_x(&rct) - ((18.0f + 12.0f) * U.dpi_fac)), + short(BLI_rctf_size_x(&rct) - ((18.0f + 12.0f) * UI_SCALE_FAC)), short(NODE_DY), nullptr, 0, @@ -2716,14 +2717,27 @@ static void count_multi_input_socket_links(bNodeTree &ntree, SpaceNode &snode) } } +static float frame_node_label_height(const NodeFrame &frame_data) +{ + return frame_data.label_size * UI_SCALE_FAC; +} + +#define NODE_FRAME_MARGIN (1.5f * U.widget_unit) + /* XXX Does a bounding box update by iterating over all children. * Not ideal to do this in every draw call, but doing as transform callback doesn't work, * since the child node totr rects are not updated properly at that point. */ static void frame_node_prepare_for_draw(bNode &node, Span nodes) { - const float margin = 1.5f * U.widget_unit; NodeFrame *data = (NodeFrame *)node.storage; + const float margin = NODE_FRAME_MARGIN; + const float has_label = node.label[0] != '\0'; + + const float label_height = frame_node_label_height(*data); + /* Add an additional 25 % to account for the descenders. This works well in most cases. */ + const float margin_top = 0.5f * margin + (has_label ? 1.25f * label_height : 0.5f * margin); + /* Initialize rect from current frame size. */ rctf rect; node_to_updated_rect(node, rect); @@ -2743,7 +2757,7 @@ static void frame_node_prepare_for_draw(bNode &node, Span nodes) noderect.xmin -= margin; noderect.xmax += margin; noderect.ymin -= margin; - noderect.ymax += margin; + noderect.ymax += margin_top; /* First child initializes frame. */ if (bbinit) { @@ -2841,8 +2855,7 @@ static void frame_node_draw_label(TreeDrawContext &tree_draw_ctx, BLF_enable(fontid, BLF_ASPECT); BLF_aspect(fontid, aspect, aspect, 1.0f); - /* Clamp. Otherwise it can suck up a LOT of memory. */ - BLF_size(fontid, MIN2(24.0f, font_size) * U.dpi_fac); + BLF_size(fontid, font_size * UI_SCALE_FAC); /* Title color. */ int color_id = node_get_colorid(tree_draw_ctx, node); @@ -2850,21 +2863,18 @@ static void frame_node_draw_label(TreeDrawContext &tree_draw_ctx, UI_GetThemeColorBlendShade3ubv(TH_TEXT, color_id, 0.4f, 10, color); BLF_color3ubv(fontid, color); - const float margin = float(NODE_DY / 4); + const float margin = NODE_FRAME_MARGIN; const float width = BLF_width(fontid, label, sizeof(label)); - const float ascender = BLF_ascender(fontid); - const int label_height = ((margin / aspect) + (ascender * aspect)); + const int label_height = frame_node_label_height(*data); - /* 'x' doesn't need aspect correction */ const rctf &rct = node.runtime->totr; - /* XXX a bit hacky, should use separate align values for x and y. */ - float x = BLI_rctf_cent_x(&rct) - (0.5f * width); - float y = rct.ymax - label_height; + const float label_x = BLI_rctf_cent_x(&rct) - (0.5f * width); + const float label_y = rct.ymax - label_height - (0.5f * margin); - /* label */ + /* Label. */ const bool has_label = node.label[0] != '\0'; if (has_label) { - BLF_position(fontid, x, y, 0); + BLF_position(fontid, label_x, label_y, 0); BLF_draw(fontid, label, sizeof(label)); } @@ -2875,11 +2885,10 @@ static void frame_node_draw_label(TreeDrawContext &tree_draw_ctx, const float line_spacing = (line_height_max * aspect); const float line_width = (BLI_rctf_size_x(&rct) - 2 * margin) / aspect; - /* 'x' doesn't need aspect correction. */ - x = rct.xmin + margin; - y = rct.ymax - label_height - (has_label ? line_spacing : 0); + const float x = rct.xmin + margin; + float y = rct.ymax - label_height - (has_label ? line_spacing + margin : 0); - int y_min = y + ((margin * 2) - (y - rct.ymin)); + const int y_min = rct.ymin + margin; BLF_enable(fontid, BLF_CLIPPING | BLF_WORD_WRAP); BLF_clipping(fontid, rct.xmin, rct.ymin + margin, rct.xmax, rct.ymax); @@ -3110,7 +3119,7 @@ static void draw_tree_path(const bContext &C, ARegion ®ion) const rcti *rect = ED_region_visible_rect(®ion); const uiStyle *style = UI_style_get_dpi(); - const float padding_x = 16 * UI_DPI_FAC; + const float padding_x = 16 * UI_SCALE_FAC; const int x = rect->xmin + padding_x; const int y = region.winy - UI_UNIT_Y * 0.6f; const int width = BLI_rcti_size_x(rect) - 2 * padding_x; @@ -3264,8 +3273,8 @@ void node_draw_space(const bContext &C, ARegion ®ion) win->eventstate->xy[1] - region.winrct.ymin, &snode.runtime->cursor[0], &snode.runtime->cursor[1]); - snode.runtime->cursor[0] /= UI_DPI_FAC; - snode.runtime->cursor[1] /= UI_DPI_FAC; + snode.runtime->cursor[0] /= UI_SCALE_FAC; + snode.runtime->cursor[1] /= UI_SCALE_FAC; ED_region_draw_cb_draw(&C, ®ion, REGION_DRAW_PRE_VIEW); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 79473957f33..a9a1f30f5cd 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -916,8 +916,8 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) WM_event_drag_start_mval(event, region, mval); float mx, my; UI_view2d_region_to_view(®ion->v2d, mval.x, mval.y, &mx, &my); - const float dx = (mx - nsw->mxstart) / UI_DPI_FAC; - const float dy = (my - nsw->mystart) / UI_DPI_FAC; + const float dx = (mx - nsw->mxstart) / UI_SCALE_FAC; + const float dy = (my - nsw->mystart) / UI_SCALE_FAC; if (node) { float *pwidth = &node->width; @@ -941,8 +941,8 @@ static int node_resize_modal(bContext *C, wmOperator *op, const wmEvent *event) /* Height works the other way round. */ { - float heightmin = UI_DPI_FAC * node->typeinfo->minheight; - float heightmax = UI_DPI_FAC * node->typeinfo->maxheight; + float heightmin = UI_SCALE_FAC * node->typeinfo->minheight; + float heightmax = UI_SCALE_FAC * node->typeinfo->maxheight; if (nsw->directions & NODE_RESIZE_TOP) { float locmin = nsw->oldlocy - nsw->oldheight; diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 11e64bb2f4c..2a0a49d640d 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -129,8 +129,8 @@ ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT); #define NODE_DYS (U.widget_unit / 2) #define NODE_DY U.widget_unit #define NODE_SOCKDY (0.1f * U.widget_unit) -#define NODE_WIDTH(node) (node.width * UI_DPI_FAC) -#define NODE_HEIGHT(node) (node.height * UI_DPI_FAC) +#define NODE_WIDTH(node) (node.width * UI_SCALE_FAC) +#define NODE_HEIGHT(node) (node.height * UI_SCALE_FAC) #define NODE_MARGIN_X (1.2f * U.widget_unit) #define NODE_SOCKSIZE (0.25f * U.widget_unit) #define NODE_SOCKSIZE_DRAW_MULIPLIER 2.25f diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 0d13338ff3b..6e2adbf5a85 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -133,7 +133,7 @@ static void pick_input_link_by_link_intersect(const bContext &C, bNode &node = socket->owner_node(); /* Distance to test overlapping of cursor on link. */ - const float cursor_link_touch_distance = 12.5f * UI_DPI_FAC; + const float cursor_link_touch_distance = 12.5f * UI_SCALE_FAC; bNodeLink *link_to_pick = nullptr; clear_picking_highlight(&node_tree.links); @@ -649,7 +649,8 @@ static int view_socket(const bContext &C, const float2 socket_location = btree.runtime->all_socket_locations[bsocket_to_view.index_in_tree()]; const int viewer_type = get_default_viewer_type(&C); - const float2 location{socket_location.x / UI_DPI_FAC + 100, socket_location.y / UI_DPI_FAC}; + const float2 location{socket_location.x / UI_SCALE_FAC + 100, + socket_location.y / UI_SCALE_FAC}; viewer_node = add_static_node(C, viewer_type, location); } @@ -823,17 +824,18 @@ static void draw_draglink_tooltip(const bContext * /*C*/, ARegion * /*region*/, uchar text_col[4]; UI_GetThemeColor4ubv(TH_TEXT, text_col); - const int padding = 4 * UI_DPI_FAC; + const int padding = 4 * UI_SCALE_FAC; const float x = nldrag->in_out == SOCK_IN ? nldrag->cursor[0] - 3.3f * padding : nldrag->cursor[0]; - const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC; + const float y = nldrag->cursor[1] - 2.0f * UI_SCALE_FAC; const bool new_link = nldrag->in_out == nldrag->start_socket->in_out; const bool swap_links = nldrag->swap_links; const int icon = !swap_links ? ICON_ADD : (new_link ? ICON_ANIM : ICON_UV_SYNC_SELECT); - UI_icon_draw_ex(x, y, icon, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); + UI_icon_draw_ex( + x, y, icon, UI_INV_SCALE_FAC, 1.0f, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); } static void draw_draglink_tooltip_activate(const ARegion ®ion, bNodeLinkDrag &nldrag) @@ -898,27 +900,35 @@ static void displace_links(bNodeTree *ntree, const bNode *node, bNodeLink *inser bNodeSocket *replacement_socket = node_find_linkable_socket(*ntree, node, linked_socket); if (linked_socket->is_input()) { - if (linked_socket->limit + 1 < nodeSocketLinkLimit(linked_socket)) { + BLI_assert(!linked_socket->is_multi_input()); + ntree->ensure_topology_cache(); + + if (linked_socket->directly_linked_links().is_empty()) { + return; + } + bNodeLink *displaced_link = linked_socket->directly_linked_links().first(); + + if (!replacement_socket) { + nodeRemLink(ntree, displaced_link); return; } - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { - if (link->tosock == linked_socket) { - if (!replacement_socket) { - nodeRemLink(ntree, link); - BKE_ntree_update_tag_link_removed(ntree); + displaced_link->tosock = replacement_socket; + + if (replacement_socket->is_multi_input()) { + /* Check for duplicate links when linking to multi input sockets. */ + for (bNodeLink *existing_link : replacement_socket->runtime->directly_linked_links) { + if (existing_link->fromsock == displaced_link->fromsock) { + nodeRemLink(ntree, displaced_link); return; } - - link->tosock = replacement_socket; - if (replacement_socket->is_multi_input()) { - link->multi_input_socket_index = node_socket_count_links(*ntree, *replacement_socket) - - 1; - } - BKE_ntree_update_tag_link_changed(ntree); - return; } + const int multi_input_index = node_socket_count_links(*ntree, *replacement_socket) - 1; + displaced_link->multi_input_socket_index = multi_input_index; } + + BKE_ntree_update_tag_link_changed(ntree); + return; } LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) { @@ -954,18 +964,31 @@ static void node_swap_links(bNodeLinkDrag &nldrag, bNodeTree &ntree) if (linked_socket.is_input()) { LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { - if (link->tosock == &linked_socket) { - link->tosock = start_socket; - link->tonode = start_node; + if (link->tosock != &linked_socket) { + continue; } + if (link->fromnode == start_node) { + /* Don't link a node to itself. */ + nodeRemLink(&ntree, link); + continue; + } + + link->tosock = start_socket; + link->tonode = start_node; } } else { LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { - if (link->fromsock == &linked_socket) { - link->fromsock = start_socket; - link->fromnode = start_node; + if (link->fromsock != &linked_socket) { + continue; } + if (link->tonode == start_node) { + /* Don't link a node to itself. */ + nodeRemLink(&ntree, link); + continue; + } + link->fromsock = start_socket; + link->fromnode = start_node; } } @@ -976,29 +999,46 @@ static void node_remove_existing_links_if_needed(bNodeLinkDrag &nldrag, bNodeTre { bNodeSocket &linked_socket = *nldrag.hovered_socket; - const int link_count = node_socket_count_links(ntree, linked_socket); + int link_count = node_socket_count_links(ntree, linked_socket); const int link_limit = nodeSocketLinkLimit(&linked_socket); + Set links_to_remove; - if (link_count < link_limit) { - return; - } + ntree.ensure_topology_cache(); - if (linked_socket.is_input()) { - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) { - if (link->tosock == &linked_socket) { - nodeRemLink(&ntree, link); - return; + /* Remove duplicate links first. */ + for (const bNodeLink dragged_link : nldrag.links) { + if (linked_socket.is_input()) { + for (bNodeLink *link : linked_socket.runtime->directly_linked_links) { + const bool duplicate_link = link->fromsock == dragged_link.fromsock; + if (duplicate_link) { + links_to_remove.add(link); + link_count--; + } + } + } + else { + for (bNodeLink *link : linked_socket.runtime->directly_linked_links) { + const bool duplicate_link = link->tosock == dragged_link.tosock; + if (duplicate_link) { + links_to_remove.add(link); + link_count--; + } } } } - else { - LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree.links) { - if (link->fromsock == &linked_socket) { - nodeRemLink(&ntree, link); - return; + + for (bNodeLink *link : linked_socket.runtime->directly_linked_links) { + const bool link_limit_exceeded = !(link_count < link_limit); + if (link_limit_exceeded) { + if (links_to_remove.add(link)) { + link_count--; } } } + + for (bNodeLink *link : links_to_remove) { + nodeRemLink(&ntree, link); + } } static void add_dragged_links_to_tree(bContext &C, bNodeLinkDrag &nldrag) @@ -2287,7 +2327,7 @@ static void node_offset_apply(bNode &node, const float offset_x) /* NODE_TEST is used to flag nodes that shouldn't be offset (again) */ if ((node.flag & NODE_TEST) == 0) { node.runtime->anim_init_locx = node.locx; - node.runtime->anim_ofsx = (offset_x / UI_DPI_FAC); + node.runtime->anim_ofsx = (offset_x / UI_SCALE_FAC); node.flag |= NODE_TEST; } } @@ -2391,7 +2431,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd, bNode *prev = iofsd->prev, *next = iofsd->next; bNode *init_parent = insert.parent; /* store old insert.parent for restoring later */ - const float min_margin = U.node_margin * UI_DPI_FAC; + const float min_margin = U.node_margin * UI_SCALE_FAC; const float width = NODE_WIDTH(insert); const bool needs_alignment = (next->runtime->totr.xmin - prev->runtime->totr.xmax) < (width + (min_margin * 2.0f)); diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index b11997ba1b6..eafc963e433 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -370,7 +370,7 @@ static int backimage_fit_exec(bContext *C, wmOperator * /*op*/) BKE_image_release_ibuf(ima, ibuf, lock); - snode->zoom *= min_ff(facx, facy) * U.dpi_fac; + snode->zoom *= min_ff(facx, facy) * UI_SCALE_FAC; snode->xof = 0; snode->yof = 0; diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index 0e82227b855..cc71df93963 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -6,7 +6,7 @@ */ #include "DNA_ID.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -15,7 +15,7 @@ #include "MEM_guardedalloc.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_lib_id.h" #include "BKE_lib_remap.h" #include "BKE_node.h" @@ -616,8 +616,8 @@ static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region) node_set_cursor(*win, *snode, snode->runtime->cursor); /* XXX snode->runtime->cursor is in placing new nodes space */ - snode->runtime->cursor[0] /= UI_DPI_FAC; - snode->runtime->cursor[1] /= UI_DPI_FAC; + snode->runtime->cursor[0] /= UI_SCALE_FAC; + snode->runtime->cursor[1] /= UI_SCALE_FAC; } /* Initialize main region, setting handlers. */ @@ -950,7 +950,7 @@ static void node_id_remap_cb(ID *old_id, ID *new_id, void *user_data) snode->from = new_id; } } - else if (GS(old_id->name) == ID_GD) { + else if (GS(old_id->name) == ID_GD_LEGACY) { if ((ID *)snode->gpd == old_id) { snode->gpd = (bGPdata *)new_id; id_us_min(old_id); diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.cc b/source/blender/editors/space_outliner/outliner_dragdrop.cc index 3ef63405fe4..90da334e930 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.cc +++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc @@ -636,7 +636,7 @@ static int material_drop_invoke(bContext *C, wmOperator * /*op*/, const wmEvent } /* only drop grease pencil material on grease pencil objects */ - if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) { + if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL_LEGACY)) { return OPERATOR_CANCELLED; } @@ -828,7 +828,7 @@ static bool datastack_drop_are_types_valid(StackDropData *drop_data) switch (drop_data->drag_tselem->type) { case TSE_MODIFIER_BASE: case TSE_MODIFIER: - return (ob_parent->type == OB_GPENCIL) == (ob_dst->type == OB_GPENCIL); + return (ob_parent->type == OB_GPENCIL_LEGACY) == (ob_dst->type == OB_GPENCIL_LEGACY); break; case TSE_CONSTRAINT_BASE: case TSE_CONSTRAINT: @@ -836,7 +836,7 @@ static bool datastack_drop_are_types_valid(StackDropData *drop_data) break; case TSE_GPENCIL_EFFECT_BASE: case TSE_GPENCIL_EFFECT: - return ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL; + return ob_parent->type == OB_GPENCIL_LEGACY && ob_dst->type == OB_GPENCIL_LEGACY; break; } @@ -949,7 +949,7 @@ static void datastack_drop_link(bContext *C, StackDropData *drop_data) break; } case TSE_GPENCIL_EFFECT_BASE: - if (ob_dst->type != OB_GPENCIL) { + if (ob_dst->type != OB_GPENCIL_LEGACY) { return; } @@ -967,11 +967,12 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) switch (drop_data->drag_tselem->type) { case TSE_MODIFIER: - if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) { + if (drop_data->ob_parent->type == OB_GPENCIL_LEGACY && ob_dst->type == OB_GPENCIL_LEGACY) { ED_object_gpencil_modifier_copy_to_object( ob_dst, static_cast(drop_data->drag_directdata)); } - else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) { + else if (drop_data->ob_parent->type != OB_GPENCIL_LEGACY && + ob_dst->type != OB_GPENCIL_LEGACY) { ED_object_modifier_copy_to_object(C, ob_dst, drop_data->ob_parent, @@ -992,7 +993,7 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) } break; case TSE_GPENCIL_EFFECT: { - if (ob_dst->type != OB_GPENCIL) { + if (ob_dst->type != OB_GPENCIL_LEGACY) { return; } @@ -1019,7 +1020,7 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa int index = 0; switch (drop_data->drag_tselem->type) { case TSE_MODIFIER: - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { index = outliner_get_insert_index( drag_te, drop_te, insert_type, &ob->greasepencil_modifiers); ED_object_gpencil_modifier_move_to_index( diff --git a/source/blender/editors/space_outliner/outliner_draw.cc b/source/blender/editors/space_outliner/outliner_draw.cc index 4682ea661dc..b91e5adbb30 100644 --- a/source/blender/editors/space_outliner/outliner_draw.cc +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -8,8 +8,8 @@ #include "DNA_armature_types.h" #include "DNA_collection_types.h" #include "DNA_constraint_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_lightprobe_types.h" #include "DNA_object_force_types.h" @@ -30,7 +30,7 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_idtype.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -119,7 +119,7 @@ static bool is_object_data_in_editmode(const ID *id, const Object *obact) const short id_type = GS(id->name); - if (id_type == ID_GD && obact && obact->data == id) { + if (id_type == ID_GD_LEGACY && obact && obact->data == id) { bGPdata *gpd = (bGPdata *)id; return GPENCIL_EDIT_MODE(gpd); } @@ -1803,7 +1803,7 @@ static void outliner_draw_overrides_rna_buts(uiBlock *block, const ListBase *lb, const int x) { - const float pad_x = 2.0f * UI_DPI_FAC; + const float pad_x = 2.0f * UI_SCALE_FAC; const float pad_y = 0.5f * U.pixelsize; const float item_max_width = round_fl_to_int(OL_RNA_COL_SIZEX - 2 * pad_x); const float item_height = round_fl_to_int(UI_UNIT_Y - 2.0f * pad_y); @@ -2357,7 +2357,7 @@ static BIFIconID tree_element_get_icon_from_id(const ID *id) else { return ICON_OUTLINER_OB_EMPTY; } - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return ICON_OUTLINER_OB_GREASEPENCIL; } @@ -2454,7 +2454,7 @@ static BIFIconID tree_element_get_icon_from_id(const ID *id) } case ID_LS: return ICON_LINE_DATA; - case ID_GD: + case ID_GD_LEGACY: return ICON_OUTLINER_DATA_GREASEPENCIL; case ID_LP: { const LightProbe *lp = (LightProbe *)id; @@ -2645,7 +2645,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) Object *ob = (Object *)tselem->id; data.drag_id = tselem->id; - if (ob->type != OB_GPENCIL) { + if (ob->type != OB_GPENCIL_LEGACY) { ModifierData *md = static_cast(BLI_findlink(&ob->modifiers, tselem->nr)); const ModifierTypeInfo *modifier_type = static_cast( BKE_modifier_get_info((ModifierType)md->type)); @@ -2903,7 +2903,7 @@ static bool tselem_draw_icon(uiBlock *block, UI_icon_draw_ex(x, y, data.icon, - U.inv_dpi_fac, + UI_INV_SCALE_FAC, alpha, 0.0f, btheme->collection_color[collection->color_tag].color, @@ -2919,10 +2919,11 @@ static bool tselem_draw_icon(uiBlock *block, /* Restrict column clip. it has been coded by simply overdrawing, doesn't work for buttons. */ uchar color[4]; if (UI_icon_get_theme_color(data.icon, color)) { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true, &text_overlay); + UI_icon_draw_ex(x, y, data.icon, UI_INV_SCALE_FAC, alpha, 0.0f, color, true, &text_overlay); } else { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false, &text_overlay); + UI_icon_draw_ex( + x, y, data.icon, UI_INV_SCALE_FAC, alpha, 0.0f, nullptr, false, &text_overlay); } } else { @@ -3529,7 +3530,7 @@ static void outliner_draw_hierarchy_lines(SpaceOutliner *space_outliner, float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* "simple" mode */ immUniform1f("dash_width", 8.0f); UI_GetThemeColorBlend3ubv(TH_BACK, TH_TEXT, 0.4f, col); @@ -3813,7 +3814,8 @@ static int outliner_width(SpaceOutliner *space_outliner, float right_column_width) { if (space_outliner->outlinevis == SO_DATA_API) { - return outliner_data_api_buttons_start_x(max_tree_width) + OL_RNA_COL_SIZEX + 10 * UI_DPI_FAC; + return outliner_data_api_buttons_start_x(max_tree_width) + OL_RNA_COL_SIZEX + + 10 * UI_SCALE_FAC; } return max_tree_width + right_column_width; } diff --git a/source/blender/editors/space_outliner/outliner_intern.hh b/source/blender/editors/space_outliner/outliner_intern.hh index ad5d653949c..72b48c48b67 100644 --- a/source/blender/editors/space_outliner/outliner_intern.hh +++ b/source/blender/editors/space_outliner/outliner_intern.hh @@ -127,7 +127,7 @@ struct TreeElementIcon { ID_AC, \ ID_BR, \ ID_PA, \ - ID_GD, \ + ID_GD_LEGACY, \ ID_LS, \ ID_LP, \ ID_CV, \ diff --git a/source/blender/editors/space_outliner/outliner_select.cc b/source/blender/editors/space_outliner/outliner_select.cc index c2975833dcc..f273dc5d580 100644 --- a/source/blender/editors/space_outliner/outliner_select.cc +++ b/source/blender/editors/space_outliner/outliner_select.cc @@ -11,8 +11,8 @@ #include "DNA_armature_types.h" #include "DNA_collection_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -28,8 +28,8 @@ #include "BKE_constraint.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -219,7 +219,7 @@ void outliner_item_mode_toggle(bContext *C, static void tree_element_viewlayer_activate(bContext *C, TreeElement *te) { /* paranoia check */ - if (te->idcode != ID_SCE) { + if (te->store_elem->type != TSE_R_LAYER) { return; } @@ -1220,7 +1220,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE case ID_KE: case ID_SPK: case ID_AR: - case ID_GD: + case ID_GD_LEGACY: case ID_LP: case ID_CV: case ID_PT: @@ -1270,7 +1270,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE if (tselem->type != TSE_MODIFIER_BASE) { Object *ob = (Object *)tselem->id; - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { BKE_gpencil_modifier_panel_expand(static_cast(te->directdata)); } else { diff --git a/source/blender/editors/space_outliner/outliner_tools.cc b/source/blender/editors/space_outliner/outliner_tools.cc index a639ccd74ae..b821d56fe1c 100644 --- a/source/blender/editors/space_outliner/outliner_tools.cc +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -14,7 +14,7 @@ #include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_curves_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_linestyle_types.h" #include "DNA_material_types.h" @@ -153,7 +153,7 @@ static void get_element_operation_type( case ID_NT: case ID_BR: case ID_PA: - case ID_GD: + case ID_GD_LEGACY: case ID_MC: case ID_MSK: case ID_PAL: diff --git a/source/blender/editors/space_outliner/outliner_tree.cc b/source/blender/editors/space_outliner/outliner_tree.cc index 0adbc073938..ccefc4a2342 100644 --- a/source/blender/editors/space_outliner/outliner_tree.cc +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -17,8 +17,8 @@ #include "DNA_collection_types.h" #include "DNA_constraint_types.h" #include "DNA_curves_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_key_types.h" #include "DNA_light_types.h" #include "DNA_lightprobe_types.h" @@ -511,7 +511,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } /* vertex groups */ - if (ELEM(ob->type, OB_MESH, OB_GPENCIL, OB_LATTICE)) { + if (ELEM(ob->type, OB_MESH, OB_GPENCIL_LEGACY, OB_LATTICE)) { const ListBase *defbase = BKE_object_defgroup_list(ob); if (!BLI_listbase_is_empty(defbase)) { TreeElement *tenla = outliner_add_element( @@ -727,7 +727,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } break; } - case ID_GD: { + case ID_GD_LEGACY: { bGPdata *gpd = (bGPdata *)id; if (outliner_animdata_test(gpd->adt)) { @@ -1438,8 +1438,8 @@ static bool outliner_element_visible_get(const Scene *scene, return false; } break; - case OB_GPENCIL: - if (exclude_filter & SO_FILTER_NO_OB_GPENCIL) { + case OB_GPENCIL_LEGACY: + if (exclude_filter & SO_FILTER_NO_OB_GPENCIL_LEGACY) { return false; } break; diff --git a/source/blender/editors/space_outliner/space_outliner.cc b/source/blender/editors/space_outliner/space_outliner.cc index d6b72c4eb7f..2308db83177 100644 --- a/source/blender/editors/space_outliner/space_outliner.cc +++ b/source/blender/editors/space_outliner/space_outliner.cc @@ -195,6 +195,11 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params) ED_region_tag_redraw(region); } break; + case NC_ASSET: + if (ELEM(wmn->action, NA_ADDED, NA_REMOVED)) { + ED_region_tag_redraw_no_rebuild(region); + } + break; case NC_MATERIAL: switch (wmn->data) { case ND_SHADING_LINKS: @@ -521,7 +526,7 @@ static void write_space_outliner(BlendWriter *writer, const SpaceOutliner *space /* TODO the mempool could be moved to #SpaceOutliner_Runtime so that #SpaceOutliner could * hold the #TreeStore directly. */ - /* Address relative to the tree-store, as noted above. */ + /* Address relative to the tree-store, as noted above. */ void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *)); /* There should be plenty of memory addresses within the mempool data that we can point into, * just double-check we don't potentially end up with a memory address that another DNA diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index 66c1fa34914..a1eeb35bb8e 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -79,8 +79,14 @@ ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data) } else { TreeElement &te_view_layer = *outliner_add_element( - &space_outliner_, &tree, scene, nullptr, TSE_R_LAYER, 0); - TREESTORE(&te_view_layer)->flag &= ~TSE_CLOSED; + &space_outliner_, &tree, view_layer, nullptr, TSE_R_LAYER, 0); + + TreeStoreElem *tselem = TREESTORE(&te_view_layer); + + if (!tselem->used) { + tselem->flag &= ~TSE_CLOSED; + } + te_view_layer.name = view_layer->name; te_view_layer.directdata = view_layer; diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc index 3de45fdf2e8..c9f7cb90eb8 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc @@ -6,7 +6,7 @@ #include "BLI_utildefines.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_space_types.h" #include "../outliner_intern.hh" diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc index 86f5fd4eff5..d4f6865fb75 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -58,7 +58,7 @@ std::unique_ptr TreeElementID::createFromID(TreeElement &legacy_t case ID_MSK: case ID_LS: case ID_LP: - case ID_GD: + case ID_GD_LEGACY: case ID_WS: case ID_CV: case ID_PT: diff --git a/source/blender/editors/space_sequencer/sequencer_channels_draw.c b/source/blender/editors/space_sequencer/sequencer_channels_draw.c index 901417c152f..57ba48318c0 100644 --- a/source/blender/editors/space_sequencer/sequencer_channels_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_channels_draw.c @@ -11,6 +11,7 @@ #include "DNA_screen_types.h" #include "BKE_context.h" +#include "BKE_screen.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" @@ -41,18 +42,6 @@ /* Own include. */ #include "sequencer_intern.h" -static ARegion *timeline_region_get(const ScrArea *area) -{ - LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - if (region->regiontype == RGN_TYPE_WINDOW) { - return region; - } - } - - BLI_assert_unreachable(); - return NULL; -} - static float draw_offset_get(const View2D *timeline_region_v2d) { return timeline_region_v2d->cur.ymin; @@ -335,7 +324,8 @@ void channel_draw_context_init(const bContext *C, r_context->ed = SEQ_editing_get(r_context->scene); r_context->seqbase = SEQ_active_seqbase_get(r_context->ed); r_context->channels = SEQ_channels_displayed_get(r_context->ed); - r_context->timeline_region = timeline_region_get(CTX_wm_area(C)); + r_context->timeline_region = BKE_area_find_region_type(r_context->area, RGN_TYPE_WINDOW); + BLI_assert(r_context->timeline_region != NULL); r_context->timeline_region_v2d = &r_context->timeline_region->v2d; r_context->channel_height = channel_height_pixelspace_get(r_context->timeline_region_v2d); diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c index 49c2f48666b..797145fb57d 100644 --- a/source/blender/editors/space_sequencer/sequencer_drag_drop.c +++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c @@ -429,7 +429,7 @@ static void draw_seq_in_view(bContext *C, wmWindow *UNUSED(win), wmDrag *drag, c float handle_size = 8.0f; /* SEQ_HANDLE_SIZE */ /* Calculate height needed for drawing text on strip. */ - float text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + float text_margin_y = y2 - min_ff(0.40f, 20 * UI_SCALE_FAC * pixely); float text_margin_x = 2.0f * (pixelx * handle_size) * U.pixelsize; rctf rect; diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 5276914346d..debdb677d63 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -1330,10 +1330,10 @@ static void draw_seq_strip(const bContext *C, (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION)) { /* Calculate height needed for drawing text on strip. */ - text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + text_margin_y = y2 - min_ff(0.40f, 20 * UI_SCALE_FAC * pixely); /* Is there enough space for drawing something else than text? */ - y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac; + y_threshold = ((y2 - y1) / pixely) > 20 * UI_SCALE_FAC; } else { text_margin_y = y2; @@ -1423,7 +1423,7 @@ static void draw_seq_strip(const bContext *C, if (sseq->flag & SEQ_SHOW_OVERLAY) { /* Don't draw strip if there is not enough vertical or horizontal space. */ - if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) { + if (((x2 - x1) > 32 * pixelx * UI_SCALE_FAC) && ((y2 - y1) > 8 * pixely * UI_SCALE_FAC)) { /* Depending on the vertical space, draw text on top or in the center of strip. */ draw_seq_text_overlay( scene, v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active); @@ -1650,7 +1650,7 @@ static void sequencer_draw_borders_overlay(const SpaceSeq *sseq, float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniformThemeColor(TH_BACK); immUniform1i("colors_len", 0); /* Simple dashes. */ @@ -2470,7 +2470,7 @@ static bool draw_cache_view_iter_fn(void *userdata, if ((cache_type & SEQ_CACHE_STORE_FINAL_OUT) && (drawdata->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT)) { - stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) - v2d->cur.ymin; + stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_SCALE_FAC * U.pixelsize) - v2d->cur.ymin; stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HANDLE_HEIGHT); stripe_top = stripe_bot + stripe_ht; vbo = drawdata->final_out_vbo; @@ -2551,7 +2551,7 @@ static void draw_cache_view(const bContext *C) float stripe_bot, stripe_top; float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; - float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) - + float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_SCALE_FAC * U.pixelsize) - v2d->cur.ymin; CLAMP_MAX(stripe_ht, 0.2f); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 1c5063b8aac..b61612bf7fc 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1851,6 +1851,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) seq_new->start = start_ofs; seq_new->type = SEQ_TYPE_IMAGE; seq_new->len = 1; + seq->flag |= SEQ_SINGLE_FRAME_CONTENT; seq_new->endofs = 1 - step; /* New strip. */ @@ -2918,6 +2919,13 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op) RNA_END; } + if (len == 1) { + seq->flag |= SEQ_SINGLE_FRAME_CONTENT; + } + else { + seq->flag &= ~SEQ_SINGLE_FRAME_CONTENT; + } + /* Reset these else we won't see all the images. */ seq->anim_startofs = seq->anim_endofs = 0; diff --git a/source/blender/editors/space_sequencer/sequencer_gizmo_retime_type.cc b/source/blender/editors/space_sequencer/sequencer_gizmo_retime_type.cc index a984ec10002..829c40af23e 100644 --- a/source/blender/editors/space_sequencer/sequencer_gizmo_retime_type.cc +++ b/source/blender/editors/space_sequencer/sequencer_gizmo_retime_type.cc @@ -54,10 +54,14 @@ using blender::MutableSpan; -#define REMOVE_GIZMO_HEIGHT 14.0f * U.dpi_fac /* Pixels from bottom of strip. */ -#define RETIME_HANDLE_TRIANGLE_SIZE 14.0f * U.dpi_fac /* Size in pixels. */ -#define RETIME_HANDLE_MOUSEOVER_THRESHOLD 16.0f * U.dpi_fac /* Size in pixels. */ -#define RETIME_BUTTON_SIZE 0.6f /* Factor based on icon size. */ +/** Pixels from bottom of strip. */ +#define REMOVE_GIZMO_HEIGHT (14.0f * UI_SCALE_FAC) +/** Size in pixels. */ +#define RETIME_HANDLE_TRIANGLE_SIZE (14.0f * UI_SCALE_FAC) +/** Size in pixels. */ +#define RETIME_HANDLE_MOUSEOVER_THRESHOLD (16.0f * UI_SCALE_FAC) +/** Factor based on icon size. */ +#define RETIME_BUTTON_SIZE 0.6f static float strip_y_rescale(const Sequence *seq, const float y_value) { @@ -178,8 +182,8 @@ static ButtonDimensions button_dimensions_get(const bContext *C, const RetimeBut const View2D *v2d = UI_view2d_fromcontext(C); const Sequence *seq = active_seq_from_context(C); - const float icon_height = UI_icon_get_height(gizmo->icon_id) * U.dpi_fac; - const float icon_width = UI_icon_get_width(gizmo->icon_id) * U.dpi_fac; + const float icon_height = UI_icon_get_height(gizmo->icon_id) * UI_SCALE_FAC; + const float icon_width = UI_icon_get_width(gizmo->icon_id) * UI_SCALE_FAC; const float icon_x = UI_view2d_view_to_region_x(v2d, BKE_scene_frame_get(scene)) + icon_width / 2; const float icon_y = UI_view2d_view_to_region_y(v2d, strip_y_rescale(seq, 0.5)) - diff --git a/source/blender/editors/space_sequencer/sequencer_retiming.cc b/source/blender/editors/space_sequencer/sequencer_retiming.cc index cc43eae4217..89fbba42ea1 100644 --- a/source/blender/editors/space_sequencer/sequencer_retiming.cc +++ b/source/blender/editors/space_sequencer/sequencer_retiming.cc @@ -229,15 +229,16 @@ void SEQUENCER_OT_retiming_handle_move(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_int(ot->srna, - "handle_index", - 0, - 0, - INT_MAX, - "Handle Index", - "Index of handle to be moved", - 0, - INT_MAX); + PropertyRNA *prop = RNA_def_int(ot->srna, + "handle_index", + 0, + 0, + INT_MAX, + "Handle Index", + "Index of handle to be moved", + 0, + INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } /** \} */ @@ -252,6 +253,8 @@ static int sequesequencer_retiming_handle_add_exec(bContext *C, wmOperator *op) const Editing *ed = SEQ_editing_get(scene); Sequence *seq = ed->act_seq; + SEQ_retiming_data_ensure(seq); + float timeline_frame; if (RNA_struct_property_is_set(op->ptr, "timeline_frame")) { timeline_frame = RNA_int_get(op->ptr, "timeline_frame"); @@ -365,15 +368,16 @@ void SEQUENCER_OT_retiming_handle_remove(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ - RNA_def_int(ot->srna, - "handle_index", - 0, - 0, - INT_MAX, - "Handle Index", - "Index of handle to be removed", - 0, - INT_MAX); + PropertyRNA *prop = RNA_def_int(ot->srna, + "handle_index", + 0, + 0, + INT_MAX, + "Handle Index", + "Index of handle to be removed", + 0, + INT_MAX); + RNA_def_property_flag(prop, PROP_HIDDEN); } /** \} */ diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c index d1606b14152..13e8f109598 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c @@ -439,7 +439,7 @@ void draw_seq_strip_thumbnail(View2D *v2d, } /* If width of the strip too small ignore drawing thumbnails. */ - if ((y2 - y1) / pixely <= 20 * U.dpi_fac) { + if ((y2 - y1) / pixely <= 20 * UI_SCALE_FAC) { return; } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 5661208dc15..b345cac7836 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -292,7 +292,7 @@ static void sequencer_refresh(const bContext *C, ScrArea *area) case SEQ_VIEW_SEQUENCE_PREVIEW: if (region_main && region_preview) { /* Get available height (without DPI correction). */ - const float height = (area->winy - ED_area_headersize()) / UI_DPI_FAC; + const float height = (area->winy - ED_area_headersize()) / UI_SCALE_FAC; /* We reuse hidden region's size, allows to find same layout as before if we just switch * between one 'full window' view and the combined one. This gets lost if we switch to both diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index b35facd020b..30d15d46106 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -356,7 +356,7 @@ static float get_column_width(const ColumnValues &values) { float data_width = get_default_column_width(values); const int fontid = UI_style_get()->widget.uifont_id; - BLF_size(fontid, UI_DEFAULT_TEXT_POINTS * U.dpi_fac); + BLF_size(fontid, UI_DEFAULT_TEXT_POINTS * UI_SCALE_FAC); const StringRefNull name = values.name(); const float name_width = BLF_width(fontid, name.data(), name.size()); return std::max(name_width / UI_UNIT_X + 1.0f, data_width); @@ -370,7 +370,7 @@ static float get_column_width_in_pixels(const ColumnValues &values) static int get_index_column_width(const int tot_rows) { const int fontid = UI_style_get()->widget.uifont_id; - BLF_size(fontid, UI_style_get_dpi()->widget.points * U.dpi_fac); + BLF_size(fontid, UI_style_get_dpi()->widget.points * UI_SCALE_FAC); return std::to_string(std::max(0, tot_rows - 1)).size() * BLF_width(fontid, "0", 1) + UI_UNIT_X * 0.75; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 2b7d981319c..e0c2a6852af 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -13,7 +13,7 @@ #include "BKE_global.h" #include "BKE_instances.hh" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_volume.h" @@ -268,7 +268,7 @@ std::unique_ptr GeometryDataSource::get_column_values( if (STREQ(column_id.name, "Rotation")) { return std::make_unique( column_id.name, VArray::ForFunc(domain_num, [transforms](int64_t index) { - return float3(math::to_euler(transforms[index])); + return float3(math::to_euler(math::normalize(transforms[index]))); })); } if (STREQ(column_id.name, "Scale")) { diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc index e50e655853f..c199e20f9ca 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_draw.cc @@ -13,7 +13,7 @@ #include "spreadsheet_draw.hh" -#define CELL_RIGHT_PADDING (2.0f * UI_DPI_FAC) +#define CELL_RIGHT_PADDING (2.0f * UI_SCALE_FAC) namespace blender::ed::spreadsheet { diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index aa5689bd047..d527688c3b1 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -13,9 +13,9 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" -#include "BLO_readfile.h" #include "BLT_translation.h" +#include "BKE_blendfile.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_screen.h" @@ -202,7 +202,7 @@ static void recent_files_menu_draw(const bContext *UNUSED(C), Menu *menu) if (!BLI_listbase_is_empty(&G.recent_files)) { for (recent = G.recent_files.first; (recent); recent = recent->next) { const char *file = BLI_path_basename(recent->filepath); - const int icon = BLO_has_bfile_extension(file) ? ICON_FILE_BLEND : ICON_FILE_BACKUP; + const int icon = BKE_blendfile_extension_check(file) ? ICON_FILE_BLEND : ICON_FILE_BACKUP; PointerRNA ptr; uiItemFullO(layout, "WM_OT_open_mainfile", file, icon, NULL, WM_OP_INVOKE_DEFAULT, 0, &ptr); RNA_string_set(&ptr, "filepath", recent->filepath); diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 1516435c6fc..45107547b8f 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -55,7 +55,7 @@ static SpaceLink *userpref_create(const ScrArea *area, const Scene *UNUSED(scene region->alignment = RGN_ALIGN_LEFT; /* Use smaller size when opened in area like properties editor. */ - if (area->winx && area->winx < 3.0f * UI_NAVIGATION_REGION_WIDTH * UI_DPI_FAC) { + if (area->winx && area->winx < 3.0f * UI_NAVIGATION_REGION_WIDTH * UI_SCALE_FAC) { region->sizex = UI_NARROW_NAVIGATION_REGION_WIDTH; } diff --git a/source/blender/editors/space_view3d/drawobject.cc b/source/blender/editors/space_view3d/drawobject.cc index b7d016e3040..835b2d6d0d0 100644 --- a/source/blender/editors/space_view3d/drawobject.cc +++ b/source/blender/editors/space_view3d/drawobject.cc @@ -16,7 +16,7 @@ #include "BKE_customdata.h" #include "BKE_editmesh.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_object.h" diff --git a/source/blender/editors/space_view3d/space_view3d.cc b/source/blender/editors/space_view3d/space_view3d.cc index 475d8ee124f..5f5ba3aab2d 100644 --- a/source/blender/editors/space_view3d/space_view3d.cc +++ b/source/blender/editors/space_view3d/space_view3d.cc @@ -13,7 +13,7 @@ #include "DNA_collection_types.h" #include "DNA_defaults.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lightprobe_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" @@ -32,7 +32,7 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_lattice.h" @@ -41,7 +41,7 @@ #include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_screen.h" diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index 380a0c47b3e..492282f1433 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -511,7 +511,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float int yi = 200; const float tilt_limit = DEG2RADF(21600.0f); const int butw = 200; - const int buth = 20 * UI_DPI_FAC; + const int buth = 20 * UI_SCALE_FAC; const int but_margin = 2; const char *c; @@ -1210,7 +1210,7 @@ static void v3d_object_dimension_buts(bContext *C, uiLayout *layout, View3D *v3d BLI_assert(C == NULL); int yi = 200; const int butw = 200; - const int buth = 20 * UI_DPI_FAC; + const int buth = 20 * UI_SCALE_FAC; BKE_object_dimensions_get(ob, tfp->ob_dims); copy_v3_v3(tfp->ob_dims_orig, tfp->ob_dims); diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c index 875097b4827..bf32a509dd9 100644 --- a/source/blender/editors/space_view3d/view3d_cursor_snap.c +++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c @@ -320,7 +320,7 @@ static void v3d_cursor_plane_draw(const RegionView3D *rv3d, color_alpha *= max_ff(0.3f, 1.0f - square_f(square_f(1.0f - view_dot))); } - const float scale_mod = U.gizmo_size * 2 * U.dpi_fac / U.pixelsize; + const float scale_mod = U.gizmo_size * 2 * UI_SCALE_FAC / U.pixelsize; float final_scale = (scale_mod * pixel_size); diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c index 35ae745bab3..f58f39d87a2 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate.c @@ -250,8 +250,8 @@ static void WIDGETGROUP_navigate_draw_prepare(const bContext *C, wmGizmoGroup *g const bool show_navigate = (U.uiflag & USER_SHOW_GIZMO_NAVIGATE) != 0; const bool show_rotate_gizmo = (U.mini_axis_type == USER_MINI_AXIS_TYPE_GIZMO); - const float icon_offset = ((GIZMO_SIZE / 2.0f) + GIZMO_OFFSET) * UI_DPI_FAC; - const float icon_offset_mini = (GIZMO_MINI_SIZE + GIZMO_MINI_OFFSET) * UI_DPI_FAC; + const float icon_offset = ((GIZMO_SIZE / 2.0f) + GIZMO_OFFSET) * UI_SCALE_FAC; + const float icon_offset_mini = (GIZMO_MINI_SIZE + GIZMO_MINI_OFFSET) * UI_SCALE_FAC; const float co_rotate[2] = { rect_visible->xmax - icon_offset, rect_visible->ymax - icon_offset, diff --git a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c index 70afb0eaff1..7b811594cb5 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_navigate_type.c @@ -42,7 +42,7 @@ #include "view3d_intern.h" /* Radius of the entire background. */ -#define WIDGET_RADIUS ((U.gizmo_size_navigate_v3d / 2.0f) * UI_DPI_FAC) +#define WIDGET_RADIUS ((U.gizmo_size_navigate_v3d / 2.0f) * UI_SCALE_FAC) /* Sizes of axis spheres containing XYZ characters in relation to above. */ #define AXIS_HANDLE_SIZE 0.20f diff --git a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc index b3310f6084b..83ea8310e45 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc +++ b/source/blender/editors/space_view3d/view3d_gizmo_preselect_type.cc @@ -22,7 +22,7 @@ #include "BKE_editmesh_cache.h" #include "BKE_global.h" #include "BKE_layer.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 4ab1e1d4ae4..fd940470cc1 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -13,7 +13,7 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_report.h" @@ -23,7 +23,7 @@ #include "BKE_scene.h" #include "BKE_unit.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_view3d_types.h" @@ -329,12 +329,8 @@ static bool view3d_ruler_item_mousemove(const bContext *C, RulerInfo *ruler_info, RulerItem *ruler_item, const int mval[2], - const bool do_thickness -#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK - , - const bool do_snap -#endif -) + const bool do_thickness, + const bool do_snap) { wmGizmo *snap_gizmo = ruler_info->snap_data.gizmo; const float eps_bias = 0.0002f; @@ -389,31 +385,28 @@ static bool view3d_ruler_item_mousemove(const bContext *C, NULL); } } - else -#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK - if (do_snap) -#endif - { + else { View3D *v3d = ruler_info->area->spacedata.first; - float *prev_point = NULL; + if (do_snap) { + float *prev_point = NULL; + BLI_assert(ED_gizmotypes_snap_3d_is_enabled(snap_gizmo)); - if (inter->co_index != 1) { - if (ruler_item->flag & RULERITEM_USE_ANGLE) { - prev_point = ruler_item->co[1]; + if (inter->co_index != 1) { + if (ruler_item->flag & RULERITEM_USE_ANGLE) { + prev_point = ruler_item->co[1]; + } + else if (inter->co_index == 0) { + prev_point = ruler_item->co[2]; + } + else { + prev_point = ruler_item->co[0]; + } } - else if (inter->co_index == 0) { - prev_point = ruler_item->co[2]; + if (prev_point != NULL) { + RNA_property_float_set_array( + snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); } - else { - prev_point = ruler_item->co[0]; - } - } - if (prev_point != NULL) { - RNA_property_float_set_array( - snap_gizmo->ptr, ruler_info->snap_data.prop_prevpoint, prev_point); - } - if (ED_gizmotypes_snap_3d_is_enabled(snap_gizmo)) { ED_gizmotypes_snap_3d_data_get(C, snap_gizmo, co, NULL, NULL, NULL); } @@ -628,9 +621,9 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) RulerItem *ruler_item = (RulerItem *)gz; ARegion *region = ruler_info->region; RegionView3D *rv3d = region->regiondata; - const float cap_size = 4.0f * U.dpi_fac; - const float bg_margin = 4.0f * U.dpi_fac; - const float arc_size = 64.0f * U.dpi_fac; + const float cap_size = 4.0f * UI_SCALE_FAC; + const float bg_margin = 4.0f * UI_SCALE_FAC; + const float arc_size = 64.0f * UI_SCALE_FAC; #define ARC_STEPS 24 const int arc_steps = ARC_STEPS; const float color_act[4] = {1.0f, 1.0f, 1.0f, 1.0f}; @@ -650,7 +643,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) GPU_line_width(1.0f); BLF_enable(blf_mono_font, BLF_ROTATION); - BLF_size(blf_mono_font, 14.0f * U.dpi_fac); + BLF_size(blf_mono_font, 14.0f * UI_SCALE_FAC); BLF_rotation(blf_mono_font, 0.0f); UI_GetThemeColor3ubv(TH_TEXT, color_text); @@ -1041,7 +1034,12 @@ static int gizmo_ruler_modal(bContext *C, #ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK const bool do_snap = !(tweak_flag & WM_GIZMO_TWEAK_SNAP); +#else + /* Ensure snap is up to date. */ + ED_gizmotypes_snap_3d_data_get(C, ruler_info->snap_data.gizmo, NULL, NULL, NULL, NULL); + const bool do_snap = ED_gizmotypes_snap_3d_is_enabled(ruler_info->snap_data.gizmo); #endif + const bool do_thickness = tweak_flag & WM_GIZMO_TWEAK_PRECISE; if (ruler_info->drag_state_prev.do_thickness != do_thickness) { do_cursor_update = true; @@ -1050,17 +1048,8 @@ static int gizmo_ruler_modal(bContext *C, if (do_cursor_update) { if (ruler_info->state == RULER_STATE_DRAG) { struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - if (view3d_ruler_item_mousemove(C, - depsgraph, - ruler_info, - ruler_item, - event->mval, - do_thickness -#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK - , - do_snap -#endif - )) { + if (view3d_ruler_item_mousemove( + C, depsgraph, ruler_info, ruler_item, event->mval, do_thickness, do_snap)) { do_draw = true; } } @@ -1119,17 +1108,8 @@ static int gizmo_ruler_invoke(bContext *C, wmGizmo *gz, const wmEvent *event) /* update the new location */ struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - view3d_ruler_item_mousemove(C, - depsgraph, - ruler_info, - ruler_item_pick, - event->mval, - false -#ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK - , - false -#endif - ); + view3d_ruler_item_mousemove( + C, depsgraph, ruler_info, ruler_item_pick, event->mval, false, false); } } else { @@ -1295,7 +1275,6 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e { ARegion *region = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); - RegionView3D *rv3d = region->regiondata; if (v3d->gizmo_flag & (V3D_GIZMO_HIDE | V3D_GIZMO_HIDE_TOOL)) { BKE_report(op->reports, RPT_WARNING, "Gizmos hidden in this view"); @@ -1304,7 +1283,6 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e wmGizmoMap *gzmap = region->gizmo_map; wmGizmoGroup *gzgroup = WM_gizmomap_group_find(gzmap, view3d_gzgt_ruler_id); - const bool use_depth = (v3d->shading.type >= OB_SOLID); if (!gizmo_ruler_check_for_operator(gzgroup)) { return OPERATOR_CANCELLED; @@ -1324,31 +1302,21 @@ static int view3d_ruler_add_invoke(bContext *C, wmOperator *op, const wmEvent *e OPERATOR_RUNNING_MODAL) { RulerInfo *ruler_info = gzgroup->customdata; RulerInteraction *inter = ruler_item->gz.interaction_data; - if (use_depth) { - struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - /* snap the first point added, not essential but handy */ - inter->co_index = 0; - view3d_ruler_item_mousemove(C, - depsgraph, - ruler_info, - ruler_item, - mval, - false + struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + inter->co_index = 0; + #ifndef USE_SNAP_DETECT_FROM_KEYMAP_HACK - , - true + /* Snap the first point added, not essential but handy. */ + const bool do_snap = true; +#else + const bool do_snap = ED_gizmotypes_snap_3d_is_enabled(ruler_info->snap_data.gizmo); #endif - ); - copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]); - RNA_property_float_set_array(ruler_info->snap_data.gizmo->ptr, - ruler_info->snap_data.prop_prevpoint, - inter->drag_start_co); - } - else { - negate_v3_v3(inter->drag_start_co, rv3d->ofs); - copy_v3_v3(ruler_item->co[0], inter->drag_start_co); - view3d_ruler_item_project(ruler_info, ruler_item->co[0], mval); - } + + view3d_ruler_item_mousemove(C, depsgraph, ruler_info, ruler_item, mval, false, do_snap); + copy_v3_v3(inter->drag_start_co, ruler_item->co[inter->co_index]); + RNA_property_float_set_array(ruler_info->snap_data.gizmo->ptr, + ruler_info->snap_data.prop_prevpoint, + inter->drag_start_co); copy_v3_v3(ruler_item->co[2], ruler_item->co[0]); ruler_item->gz.highlight_part = inter->co_index = 2; diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c index a4891c67810..d3134633fea 100644 --- a/source/blender/editors/space_view3d/view3d_header.c +++ b/source/blender/editors/space_view3d/view3d_header.c @@ -9,7 +9,7 @@ #include #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" diff --git a/source/blender/editors/space_view3d/view3d_iterators.cc b/source/blender/editors/space_view3d/view3d_iterators.cc index e7e8eb5b275..3cd9d3c9d52 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.cc +++ b/source/blender/editors/space_view3d/view3d_iterators.cc @@ -23,7 +23,7 @@ #include "BKE_curve.h" #include "BKE_displist.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_iterators.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" diff --git a/source/blender/editors/space_view3d/view3d_navigate.c b/source/blender/editors/space_view3d/view3d_navigate.c index 9f4710b28a0..e46778adb05 100644 --- a/source/blender/editors/space_view3d/view3d_navigate.c +++ b/source/blender/editors/space_view3d/view3d_navigate.c @@ -5,7 +5,7 @@ */ #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "MEM_guardedalloc.h" @@ -16,7 +16,7 @@ #include "BKE_armature.h" #include "BKE_context.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" #include "BKE_layer.h" #include "BKE_object.h" #include "BKE_paint.h" @@ -274,16 +274,29 @@ ViewOpsData *viewops_data_create(bContext *C, const wmEvent *event, enum eViewOp /* we need the depth info before changing any viewport options */ if (viewops_flag & VIEWOPS_FLAG_DEPTH_NAVIGATE) { - float fallback_depth_pt[3]; + wmWindow *win = CTX_wm_window(C); + const bool use_depth_last = ED_view3d_autodist_last_check(win, event); - view3d_operator_needs_opengl(C); /* Needed for Z-buffer drawing. */ + if (use_depth_last) { + vod->use_dyn_ofs = ED_view3d_autodist_last_get(win, vod->dyn_ofs); + } + else { + float fallback_depth_pt[3]; - negate_v3_v3(fallback_depth_pt, rv3d->ofs); + view3d_operator_needs_opengl(C); /* Needed for Z-buffer drawing. */ - vod->use_dyn_ofs = ED_view3d_autodist( - depsgraph, vod->region, vod->v3d, event->mval, vod->dyn_ofs, true, fallback_depth_pt); + negate_v3_v3(fallback_depth_pt, rv3d->ofs); + + vod->use_dyn_ofs = ED_view3d_autodist( + depsgraph, vod->region, vod->v3d, event->mval, vod->dyn_ofs, true, fallback_depth_pt); + + ED_view3d_autodist_last_set(win, event, vod->dyn_ofs, vod->use_dyn_ofs); + } } else { + wmWindow *win = CTX_wm_window(C); + ED_view3d_autodist_last_clear(win); + vod->use_dyn_ofs = false; } vod->init.persp = rv3d->persp; @@ -882,7 +895,7 @@ static int viewselected_exec(bContext *C, wmOperator *op) BKE_view_layer_synced_ensure(scene_eval, view_layer_eval); Object *ob_eval = BKE_view_layer_active_object_get(view_layer_eval); Object *obedit = CTX_data_edit_object(C); - const bGPdata *gpd_eval = ob_eval && (ob_eval->type == OB_GPENCIL) ? ob_eval->data : NULL; + const bGPdata *gpd_eval = ob_eval && (ob_eval->type == OB_GPENCIL_LEGACY) ? ob_eval->data : NULL; const bool is_gp_edit = gpd_eval ? GPENCIL_ANY_MODE(gpd_eval) : false; const bool is_face_map = ((is_gp_edit == false) && region->gizmo_map && WM_gizmomap_is_any_selected(region->gizmo_map)); diff --git a/source/blender/editors/space_view3d/view3d_navigate_rotate.c b/source/blender/editors/space_view3d/view3d_navigate_rotate.c index 446a1e929c1..b1971dda4e8 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_rotate.c +++ b/source/blender/editors/space_view3d/view3d_navigate_rotate.c @@ -234,7 +234,7 @@ static void viewrotate_apply(ViewOpsData *vod, const int event_xy[2]) float xaxis[3]; /* Radians per-pixel. */ - const float sensitivity = U.view_rotate_sensitivity_turntable / U.dpi_fac; + const float sensitivity = U.view_rotate_sensitivity_turntable / UI_SCALE_FAC; /* Get the 3x3 matrix and its inverse from the quaternion */ quat_to_mat3(m, vod->curr.viewquat); diff --git a/source/blender/editors/space_view3d/view3d_navigate_zoom.c b/source/blender/editors/space_view3d/view3d_navigate_zoom.c index 51aab367959..f766e4a454f 100644 --- a/source/blender/editors/space_view3d/view3d_navigate_zoom.c +++ b/source/blender/editors/space_view3d/view3d_navigate_zoom.c @@ -199,7 +199,7 @@ static float viewzoom_scale_value(const rcti *winrct, fac = (float)(xy_init[1] - xy_curr[1]); } - fac /= U.dpi_fac; + fac /= UI_SCALE_FAC; if (zoom_invert != zoom_invert_force) { fac = -fac; @@ -215,8 +215,8 @@ static float viewzoom_scale_value(const rcti *winrct, BLI_rcti_cent_x(winrct), BLI_rcti_cent_y(winrct), }; - float len_new = (5 * U.dpi_fac) + ((float)len_v2v2_int(ctr, xy_curr) / U.dpi_fac); - float len_old = (5 * U.dpi_fac) + ((float)len_v2v2_int(ctr, xy_init) / U.dpi_fac); + float len_new = (5 * UI_SCALE_FAC) + ((float)len_v2v2_int(ctr, xy_curr) / UI_SCALE_FAC); + float len_old = (5 * UI_SCALE_FAC) + ((float)len_v2v2_int(ctr, xy_init) / UI_SCALE_FAC); /* intentionally ignore 'zoom_invert' for scale */ if (zoom_invert_force) { @@ -226,16 +226,16 @@ static float viewzoom_scale_value(const rcti *winrct, zfac = val_orig * (len_old / max_ff(len_new, 1.0f)) / val; } else { /* USER_ZOOM_DOLLY */ - float len_new = 5 * U.dpi_fac; - float len_old = 5 * U.dpi_fac; + float len_new = 5 * UI_SCALE_FAC; + float len_old = 5 * UI_SCALE_FAC; if (U.uiflag & USER_ZOOM_HORIZ) { - len_new += (winrct->xmax - (xy_curr[0])) / U.dpi_fac; - len_old += (winrct->xmax - (xy_init[0])) / U.dpi_fac; + len_new += (winrct->xmax - (xy_curr[0])) / UI_SCALE_FAC; + len_old += (winrct->xmax - (xy_init[0])) / UI_SCALE_FAC; } else { - len_new += (winrct->ymax - (xy_curr[1])) / U.dpi_fac; - len_old += (winrct->ymax - (xy_init[1])) / U.dpi_fac; + len_new += (winrct->ymax - (xy_curr[1])) / UI_SCALE_FAC; + len_old += (winrct->ymax - (xy_init[1])) / UI_SCALE_FAC; } if (zoom_invert != zoom_invert_force) { diff --git a/source/blender/editors/space_view3d/view3d_select.cc b/source/blender/editors/space_view3d/view3d_select.cc index e2cfc6fad0b..1a17d44255a 100644 --- a/source/blender/editors/space_view3d/view3d_select.cc +++ b/source/blender/editors/space_view3d/view3d_select.cc @@ -13,7 +13,7 @@ #include "DNA_action_types.h" #include "DNA_armature_types.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" #include "DNA_meta_types.h" @@ -31,6 +31,7 @@ #include "BLI_math_bits.h" #include "BLI_rect.h" #include "BLI_string.h" +#include "BLI_task.hh" #include "BLI_utildefines.h" #include "BLI_vector.hh" @@ -52,7 +53,7 @@ #include "BKE_editmesh.h" #include "BKE_layer.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_paint.h" #include "BKE_scene.h" @@ -2315,7 +2316,7 @@ static Base *mouse_select_object_center(ViewContext *vc, Base *startbase, const Base *basact = nullptr; /* Put the active object at a disadvantage to cycle through other objects. */ - const float penalty_dist = 10.0f * UI_DPI_FAC; + const float penalty_dist = 10.0f * UI_SCALE_FAC; Base *base = startbase; while (base) { if (BASE_SELECTABLE(v3d, base)) { @@ -2985,8 +2986,13 @@ static bool ed_wpaint_vertex_select_pick(bContext *C, return changed || found; } +struct ClosestCurveDataBlock { + Curves *curves_id = nullptr; + blender::ed::curves::FindClosestData elem = {}; +}; + /** - * Cursor selection for the Curves object. + * Cursor selection for all Curves objects in edit mode. * * \returns true if the selection changed. */ @@ -2999,35 +3005,81 @@ static bool ed_curves_select_pick(bContext &C, const int mval[2], const SelectPi ED_view3d_viewcontext_init(&C, &vc, depsgraph); uint bases_len; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( + Base **bases_ptr = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( vc.scene, vc.view_layer, vc.v3d, &bases_len); + Span bases(bases_ptr, bases_len); - bool changed = false; - ed::curves::FindClosestData closest_data; - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base = bases[base_index]; - Object *curves_ob = base->object; - Curves &curves_id = *static_cast(curves_ob->data); - bke::CurvesGeometry &curves = curves_id.geometry.wrap(); + Curves &active_curves_id = *static_cast(vc.obedit->data); + const eAttrDomain selection_domain = eAttrDomain(active_curves_id.selection_domain); - if (ed::curves::select_pick(vc, - *curves_ob, - curves, - eAttrDomain(curves_id.selection_domain), - params, - mval, - closest_data)) { - changed = true; - /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a - * generic attribute for now. */ - DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &curves_id); - } + const ClosestCurveDataBlock closest = threading::parallel_reduce( + bases.index_range(), + 1L, + ClosestCurveDataBlock(), + [&](const IndexRange range, const ClosestCurveDataBlock &init) { + ClosestCurveDataBlock new_closest = init; + for (Base *base : bases.slice(range)) { + Object &curves_ob = *base->object; + Curves &curves_id = *static_cast(curves_ob.data); + std::optional new_closest_elem = + ed::curves::closest_elem_find_screen_space(vc, + curves_ob, + curves_id.geometry.wrap(), + selection_domain, + mval, + new_closest.elem); + if (new_closest_elem) { + new_closest.elem = *new_closest_elem; + new_closest.curves_id = &curves_id; + } + } + return new_closest; + }, + [](const ClosestCurveDataBlock &a, const ClosestCurveDataBlock &b) { + return (a.elem.distance < b.elem.distance) ? a : b; + }); + + std::atomic deselected = false; + if (params.deselect_all || params.sel_op == SEL_OP_SET) { + threading::parallel_for(bases.index_range(), 1L, [&](const IndexRange range) { + for (Base *base : bases.slice(range)) { + Curves &curves_id = *static_cast(base->object->data); + bke::CurvesGeometry &curves = curves_id.geometry.wrap(); + if (ed::curves::has_anything_selected(curves)) { + bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute( + curves, selection_domain, CD_PROP_BOOL); + ed::curves::fill_selection_false(selection.span); + selection.finish(); + + deselected = true; + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a + * generic attribute for now. */ + DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &curves_id); + } + } + }); } - MEM_freeN(bases); + if (!closest.curves_id) { + MEM_freeN(bases_ptr); + return deselected; + } - return changed; + bke::GSpanAttributeWriter selection = ed::curves::ensure_selection_attribute( + closest.curves_id->geometry.wrap(), selection_domain, CD_PROP_BOOL); + ed::curves::apply_selection_operation_at_index( + selection.span, closest.elem.index, params.sel_op); + selection.finish(); + + /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a + * generic attribute for now. */ + DEG_id_tag_update(&closest.curves_id->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(&C, NC_GEOM | ND_DATA, closest.curves_id); + + MEM_freeN(bases_ptr); + + return true; } static int view3d_select_exec(bContext *C, wmOperator *op) @@ -3036,7 +3088,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); - if (obact && obact->type == OB_GPENCIL && GPENCIL_ANY_MODE((bGPdata *)obact->data)) { + if (obact && obact->type == OB_GPENCIL_LEGACY && GPENCIL_ANY_MODE((bGPdata *)obact->data)) { /* Prevent acting on Grease Pencil (when not in object mode), it implements its own selection * operator in other modes. We might still fall trough to here (because that operator uses * OPERATOR_PASS_THROUGH to make tweak work) but if we don't stop here code below assumes we @@ -3081,7 +3133,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op) if (obedit && enumerate) { /* Enumerate makes no sense in edit-mode unless also explicitly picking objects or bones. - * Pass the event through so the event may be handled by loop-select for e.g. see: #100204. */ + * Pass the event through so the event may be handled by loop-select for e.g. see: #100204. + */ if (obedit->type != OB_ARMATURE) { return OPERATOR_PASS_THROUGH | OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index d87a2730c7b..385ab423155 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -1005,6 +1005,77 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name View Auto-Depth Last State Access + * + * Calling consecutive track-pad gestures reuses the previous offset to prevent + * each track-pad event using a different offset, see: #103263. + * \{ */ + +static const char *view3d_autodepth_last_id = "view3d_autodist_last"; + +/** + * Auto-depth values for #ED_view3d_autodist_last_check and related functions. + */ +typedef struct View3D_AutoDistLast { + float ofs[3]; + bool has_depth; +} View3D_AutoDistLast; + +bool ED_view3d_autodist_last_check(wmWindow *win, const wmEvent *event) +{ + if (event->flag & WM_EVENT_IS_CONSECUTIVE) { + const View3D_AutoDistLast *autodepth_last = WM_event_consecutive_data_get( + win, view3d_autodepth_last_id); + if (autodepth_last) { + return true; + } + } + return false; +} + +void ED_view3d_autodist_last_clear(wmWindow *win) +{ + WM_event_consecutive_data_free(win); +} + +void ED_view3d_autodist_last_set(wmWindow *win, + const wmEvent *event, + const float ofs[3], + const bool has_depth) +{ + ED_view3d_autodist_last_clear(win); + + if (WM_event_consecutive_gesture_test(event)) { + View3D_AutoDistLast *autodepth_last = MEM_callocN(sizeof(*autodepth_last), __func__); + + autodepth_last->has_depth = has_depth; + copy_v3_v3(autodepth_last->ofs, ofs); + + WM_event_consecutive_data_set(win, view3d_autodepth_last_id, autodepth_last); + } +} + +bool ED_view3d_autodist_last_get(wmWindow *win, float r_ofs[3]) +{ + const View3D_AutoDistLast *autodepth_last = WM_event_consecutive_data_get( + win, view3d_autodepth_last_id); + /* #ED_view3d_autodist_last_check should be called first. */ + BLI_assert(autodepth_last); + if (autodepth_last == NULL) { + return false; + } + + if (autodepth_last->has_depth == false) { + zero_v3(r_ofs); + return false; + } + copy_v3_v3(r_ofs, autodepth_last->ofs); + return true; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name View Auto-Depth Utilities * \{ */ diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 4cc282a1cab..61bf06bde90 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -15,7 +15,7 @@ #include "BKE_action.h" #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_idprop.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -623,7 +623,7 @@ int view3d_opengl_select_ex(ViewContext *vc, /* While this uses 'alloca' in a loop (which we typically avoid), * the number of items is nearly always 1, maybe 2..3 in rare cases. */ LinkNode *ob_pose_list = NULL; - if (obact->type == OB_GPENCIL) { + if (obact->type == OB_GPENCIL_LEGACY) { GpencilVirtualModifierData virtualModifierData; const GpencilModifierData *md = BKE_gpencil_modifiers_get_virtual_modifierlist( obact, &virtualModifierData); @@ -675,7 +675,7 @@ int view3d_opengl_select_ex(ViewContext *vc, GPU_depth_test(GPU_DEPTH_LESS_EQUAL); } - /* If in xray mode, we select the wires in priority. */ + /* If in X-ray mode, we select the wires in priority. */ if (XRAY_ACTIVE(v3d) && use_nearest) { /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop * because the OpenGL context created & destroyed inside this function. */ diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 2ded01255c5..30fe664485a 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -9,7 +9,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mask_types.h" #include "DNA_mesh_types.h" #include "DNA_screen_types.h" @@ -66,7 +66,8 @@ bool transdata_check_local_islands(TransInfo *t, short around) if (t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) { return false; } - return ((around == V3D_AROUND_LOCAL_ORIGINS) && ELEM(t->obedit_type, OB_MESH, OB_GPENCIL)); + return ((around == V3D_AROUND_LOCAL_ORIGINS) && + ELEM(t->obedit_type, OB_MESH, OB_GPENCIL_LEGACY)); } /* ************************** SPACE DEPENDENT CODE **************************** */ diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index bd8f8237bd9..6afe4c62aa7 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -6,7 +6,7 @@ */ #include "DNA_anim_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_mask_types.h" #include "MEM_guardedalloc.h" @@ -17,7 +17,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_key.h" #include "BKE_layer.h" #include "BKE_mask.h" diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index b4e48674892..20e494ecdab 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -5,7 +5,7 @@ * \ingroup edtransform */ -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "MEM_guardedalloc.h" @@ -16,9 +16,9 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_curve.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_curve.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_curve_legacy.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_layer.h" #include "ED_gpencil.h" diff --git a/source/blender/editors/transform/transform_convert_node.cc b/source/blender/editors/transform/transform_convert_node.cc index 13095ff6f5a..8e14b900394 100644 --- a/source/blender/editors/transform/transform_convert_node.cc +++ b/source/blender/editors/transform/transform_convert_node.cc @@ -48,11 +48,11 @@ static void create_transform_data_for_node(TransData &td, /* account for parents (nested nodes) */ if (node.parent) { - nodeToView(node.parent, node.locx, node.locy, &locx, &locy); + nodeToView(node.parent, node.locx + node.offsetx, node.locy + node.offsety, &locx, &locy); } else { - locx = node.locx; - locy = node.locy; + locx = node.locx + node.offsetx; + locy = node.locy + node.offsety; } /* use top-left corner as the transform origin for nodes */ @@ -142,7 +142,7 @@ static void createTransNodeData(bContext * /*C*/, TransInfo *t) tc->data_2d = MEM_cnew_array(tc->data_len, __func__); for (const int i : nodes.index_range()) { - create_transform_data_for_node(tc->data[i], tc->data_2d[i], *nodes[i], UI_DPI_FAC); + create_transform_data_for_node(tc->data[i], tc->data_2d[i], *nodes[i], UI_SCALE_FAC); } } @@ -197,7 +197,7 @@ static void node_snap_grid_apply(TransInfo *t) static void flushTransNodes(TransInfo *t) { using namespace blender::ed; - const float dpi_fac = UI_DPI_FAC; + const float dpi_fac = UI_SCALE_FAC; SpaceNode *snode = static_cast(t->area->spacedata.first); TransCustomDataNode *customdata = (TransCustomDataNode *)t->custom.type.data; @@ -244,11 +244,16 @@ static void flushTransNodes(TransInfo *t) /* account for parents (nested nodes) */ if (node->parent) { - nodeFromView(node->parent, loc[0], loc[1], &loc[0], &loc[1]); + nodeFromView(node->parent, + loc[0] - node->offsetx, + loc[1] - node->offsety, + &node->locx, + &node->locy); + } + else { + node->locx = loc[0] - node->offsetx; + node->locy = loc[1] - node->offsety; } - - node->locx = loc[0]; - node->locy = loc[1]; } /* handle intersection with noodles */ diff --git a/source/blender/editors/transform/transform_draw_cursors.c b/source/blender/editors/transform/transform_draw_cursors.c index 0cec6e7943b..b76cfce7e96 100644 --- a/source/blender/editors/transform/transform_draw_cursors.c +++ b/source/blender/editors/transform/transform_draw_cursors.c @@ -35,9 +35,9 @@ enum eArrowDirection { static void drawArrow(const uint pos_id, const enum eArrowDirection dir) { - int offset = 5.0f * UI_DPI_FAC; - int length = (6.0f * UI_DPI_FAC) + (4.0f * U.pixelsize); - int size = (3.0f * UI_DPI_FAC) + (2.0f * U.pixelsize); + int offset = 5.0f * UI_SCALE_FAC; + int length = (6.0f * UI_SCALE_FAC) + (4.0f * U.pixelsize); + int size = (3.0f * UI_SCALE_FAC) + (2.0f * U.pixelsize); /* To line up the arrow point nicely, one end has to be extended by half its width. But * being on a 45 degree angle, Pythagoras says a movement of sqrt(2)/2 * (line width /2) */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 05590494be5..1f69d95cd7c 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -9,7 +9,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "BLI_blenlib.h" #include "BLI_math.h" @@ -705,7 +705,7 @@ void postTrans(bContext *C, TransInfo *t) if (t->data_len_all != 0) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { /* free data malloced per trans-data */ - if (ELEM(t->obedit_type, OB_CURVES_LEGACY, OB_SURF, OB_GPENCIL) || + if (ELEM(t->obedit_type, OB_CURVES_LEGACY, OB_SURF, OB_GPENCIL_LEGACY) || (t->spacetype == SPACE_GRAPH)) { TransData *td = tc->data; for (int a = 0; a < tc->data_len; a++, td++) { diff --git a/source/blender/editors/transform/transform_gizmo_3d.cc b/source/blender/editors/transform/transform_gizmo_3d.cc index 1366d02ada0..a76e9d735b0 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.cc +++ b/source/blender/editors/transform/transform_gizmo_3d.cc @@ -9,7 +9,7 @@ */ #include "DNA_armature_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_lattice_types.h" #include "DNA_meta_types.h" @@ -19,7 +19,7 @@ #include "BKE_curve.h" #include "BKE_editmesh.h" #include "BKE_global.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_layer.h" #include "BKE_object.h" #include "BKE_paint.h" diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c index 6eb5a5e3449..01270df5f14 100644 --- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c +++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c @@ -142,7 +142,7 @@ static void gizmo_mesh_extrude_setup(const bContext *C, wmGizmoGroup *gzgroup) /* Grease pencil does not use `obedit`. */ /* GPXX: Remove if OB_MODE_EDIT_GPENCIL is merged with OB_MODE_EDIT */ const Object *obact = CTX_data_active_object(C); - if (obact->type == OB_GPENCIL) { + if (obact->type == OB_GPENCIL_LEGACY) { op_idname = "GPENCIL_OT_extrude_move"; } else if (obact->type == OB_MESH) { diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index ebfb746f24c..e72ae622f93 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -10,7 +10,7 @@ #include "DNA_anim_types.h" #include "DNA_armature_types.h" #include "DNA_constraint_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_windowmanager_types.h" #include "BLI_listbase.h" @@ -55,12 +55,13 @@ eTfmMode transform_mode_really_used(bContext *C, eTfmMode mode) bool transdata_check_local_center(const TransInfo *t, short around) { - return ((around == V3D_AROUND_LOCAL_ORIGINS) && - ((t->options & (CTX_OBJECT | CTX_POSE_BONE)) || - /* implicit: (t->flag & T_EDIT) */ - ELEM(t->obedit_type, OB_MESH, OB_CURVES_LEGACY, OB_MBALL, OB_ARMATURE, OB_GPENCIL) || - (t->spacetype == SPACE_GRAPH) || - (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE | CTX_SEQUENCER_IMAGE)))); + return ( + (around == V3D_AROUND_LOCAL_ORIGINS) && + ((t->options & (CTX_OBJECT | CTX_POSE_BONE)) || + /* implicit: (t->flag & T_EDIT) */ + ELEM(t->obedit_type, OB_MESH, OB_CURVES_LEGACY, OB_MBALL, OB_ARMATURE, OB_GPENCIL_LEGACY) || + (t->spacetype == SPACE_GRAPH) || + (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE | CTX_SEQUENCER_IMAGE)))); } bool transform_mode_is_changeable(const int mode) diff --git a/source/blender/editors/transform/transform_mode_bend.c b/source/blender/editors/transform/transform_mode_bend.c index 918ba6bd108..0f51d667112 100644 --- a/source/blender/editors/transform/transform_mode_bend.c +++ b/source/blender/editors/transform/transform_mode_bend.c @@ -9,7 +9,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "BLI_math.h" #include "BLI_string.h" diff --git a/source/blender/editors/transform/transform_mode_gpopacity.c b/source/blender/editors/transform/transform_mode_gpopacity.c index ddaabfe33cd..4ee3c56e2f1 100644 --- a/source/blender/editors/transform/transform_mode_gpopacity.c +++ b/source/blender/editors/transform/transform_mode_gpopacity.c @@ -13,7 +13,7 @@ #include "BKE_context.h" #include "BKE_unit.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "ED_screen.h" diff --git a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c index 0c3d25150ee..e1a8f719ef6 100644 --- a/source/blender/editors/transform/transform_mode_gpshrinkfatten.c +++ b/source/blender/editors/transform/transform_mode_gpshrinkfatten.c @@ -13,7 +13,7 @@ #include "BKE_context.h" #include "BKE_unit.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "ED_screen.h" diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index edbeafc3ac7..b9e0716fcec 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -7,7 +7,7 @@ #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "BLI_math.h" #include "BLI_string.h" diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 3ea18ef1152..18812bc9671 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -9,7 +9,7 @@ #include "MEM_guardedalloc.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "BLI_math.h" #include "BLI_string.h" diff --git a/source/blender/editors/transform/transform_snap_object.cc b/source/blender/editors/transform/transform_snap_object.cc index a2ba0a60729..394779865f3 100644 --- a/source/blender/editors/transform/transform_snap_object.cc +++ b/source/blender/editors/transform/transform_snap_object.cc @@ -34,7 +34,7 @@ #include "BKE_geometry_set.h" #include "BKE_global.h" #include "BKE_layer.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_object.h" @@ -1427,7 +1427,7 @@ struct Nearest2dUserData { }; struct { const float (*vert_positions)[3]; - const float (*vert_normals)[3]; + const blender::float3 *vert_normals; const MEdge *edges; /* only used for #BVHTreeFromMeshEdges */ const MLoop *loop; const MLoopTri *looptris; @@ -1716,7 +1716,7 @@ static void nearest2d_data_init_mesh(const Mesh *mesh, r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get; r_nearest2d->vert_positions = BKE_mesh_vert_positions(mesh); - r_nearest2d->vert_normals = BKE_mesh_vert_normals_ensure(mesh); + r_nearest2d->vert_normals = mesh->vert_normals().data(); r_nearest2d->edges = mesh->edges().data(); r_nearest2d->loop = mesh->loops().data(); r_nearest2d->looptris = mesh->looptris().data(); @@ -2968,7 +2968,7 @@ static eSnapMode snap_obj_fn(SnapObjectContext *sctx, break; } case OB_EMPTY: - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: case OB_LAMP: retval = snap_object_center( sctx, ob_eval, obmat, dt->dist_px, sctx->ret.loc, sctx->ret.no, &sctx->ret.index); @@ -3200,7 +3200,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, - const eSnapMode snap_to_flag, + eSnapMode snap_to_flag, const SnapObjectParams *params, const float init_co[3], const float mval[2], @@ -3235,7 +3235,16 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont const RegionView3D *rv3d = static_cast(region->regiondata); - bool use_occlusion_test = params->use_occlusion_test && !XRAY_ENABLED(v3d); + if (snap_to_flag & (SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST)) { + if (params->use_occlusion_test && XRAY_ENABLED(v3d)) { + /* Remove Snap to Face with Occlusion Test as they are not visible in wireframe mode. */ + snap_to_flag &= ~(SCE_SNAP_MODE_FACE_RAYCAST | SCE_SNAP_MODE_FACE_NEAREST); + } + else if (prev_co == nullptr || init_co == nullptr) { + /* No location to work with #SCE_SNAP_MODE_FACE_NEAREST. */ + snap_to_flag &= ~SCE_SNAP_MODE_FACE_NEAREST; + } + } /* NOTE: if both face ray-cast and face nearest are enabled, first find result of nearest, then * override with ray-cast. */ @@ -3261,7 +3270,7 @@ static eSnapMode transform_snap_context_project_view3d_mixed_impl(SnapObjectCont } } - if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST || use_occlusion_test) { + if (snap_to_flag & SCE_SNAP_MODE_FACE_RAYCAST) { float ray_start[3], ray_normal[3]; if (!ED_view3d_win_to_ray_clipped_ex( depsgraph, region, v3d, mval, nullptr, ray_normal, ray_start, true)) { diff --git a/source/blender/editors/undo/ed_undo.cc b/source/blender/editors/undo/ed_undo.cc index b4a42f9e1ea..9c055f3d097 100644 --- a/source/blender/editors/undo/ed_undo.cc +++ b/source/blender/editors/undo/ed_undo.cc @@ -178,7 +178,7 @@ static void ed_undo_step_pre(bContext *C, if (area && (area->spacetype == SPACE_VIEW3D)) { Object *obact = CTX_data_active_object(C); - if (obact && (obact->type == OB_GPENCIL)) { + if (obact && (obact->type == OB_GPENCIL_LEGACY)) { ED_gpencil_toggle_brush_cursor(C, false, nullptr); } } @@ -212,7 +212,7 @@ static void ed_undo_step_post(bContext *C, /* Set special modes for grease pencil */ if (area != nullptr && (area->spacetype == SPACE_VIEW3D)) { Object *obact = CTX_data_active_object(C); - if (obact && (obact->type == OB_GPENCIL)) { + if (obact && (obact->type == OB_GPENCIL_LEGACY)) { /* set cursor */ if (obact->mode & OB_MODE_ALL_PAINT_GPENCIL) { ED_gpencil_toggle_brush_cursor(C, true, nullptr); diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c index 1eacb7a2045..bc091a77aa1 100644 --- a/source/blender/editors/util/ed_draw.c +++ b/source/blender/editors/util/ed_draw.c @@ -53,7 +53,7 @@ * #ED_slider_destroy. * \{ */ -#define SLIDE_PIXEL_DISTANCE (300.0f * U.dpi_fac) +#define SLIDE_PIXEL_DISTANCE (300.0f * UI_SCALE_FAC) #define OVERSHOOT_RANGE_DELTA 0.2f typedef struct tSlider { @@ -571,7 +571,7 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *region, void *arg_ float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 0); /* "simple" mode */ immUniformThemeColor3(TH_VIEW_OVERLAY); @@ -819,7 +819,7 @@ void ED_region_image_metadata_draw( GPU_matrix_translate_2f(x, y); GPU_matrix_scale_2f(zoomx, zoomy); - BLF_size(blf_mono_font, style->widgetlabel.points * U.dpi_fac); + BLF_size(blf_mono_font, style->widgetlabel.points * UI_SCALE_FAC); /* *** upper box*** */ diff --git a/source/blender/editors/util/ed_util.cc b/source/blender/editors/util/ed_util.cc index 77e5be4e0dd..480270b25cb 100644 --- a/source/blender/editors/util/ed_util.cc +++ b/source/blender/editors/util/ed_util.cc @@ -33,7 +33,7 @@ #include "DEG_depsgraph.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "ED_armature.h" #include "ED_asset.h" @@ -101,7 +101,7 @@ void ED_editors_init(bContext *C) /* For multi-edit mode we may already have mode data. */ continue; } - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { /* Grease pencil does not need a toggle of mode. However we may have a non-active object * stuck in a grease-pencil edit mode. */ if (ob != obact) { diff --git a/source/blender/editors/util/ed_viewer_path.cc b/source/blender/editors/util/ed_viewer_path.cc index be569aa02fa..6f67d92681b 100644 --- a/source/blender/editors/util/ed_viewer_path.cc +++ b/source/blender/editors/util/ed_viewer_path.cc @@ -50,10 +50,11 @@ static void viewer_path_for_geometry_node(const SpaceNode &snode, modifier = nmd; } } - - ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier(); - modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name); - BLI_addtail(&r_dst.path, modifier_elem); + if (modifier != nullptr) { + ModifierViewerPathElem *modifier_elem = BKE_viewer_path_elem_new_modifier(); + modifier_elem->modifier_name = BLI_strdup(modifier->modifier.name); + BLI_addtail(&r_dst.path, modifier_elem); + } Vector tree_path = snode.treepath; for (const int i : tree_path.index_range().drop_back(1)) { diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 7c59c6b5a45..ea8aa543f23 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -28,7 +28,7 @@ void ED_image_draw_cursor(ARegion *region, const float cursor[2]) UI_view2d_scale_get_inverse(®ion->v2d, &zoom[0], &zoom[1]); - mul_v2_fl(zoom, 256.0f * UI_DPI_FAC); + mul_v2_fl(zoom, 256.0f * UI_SCALE_FAC); x_fac = zoom[0]; y_fac = zoom[1]; @@ -43,7 +43,7 @@ void ED_image_draw_cursor(ARegion *region, const float cursor[2]) float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); - immUniform2f("viewport_size", viewport_size[2] / UI_DPI_FAC, viewport_size[3] / UI_DPI_FAC); + immUniform2f("viewport_size", viewport_size[2] / UI_SCALE_FAC, viewport_size[3] / UI_SCALE_FAC); immUniform1i("colors_len", 2); /* "advanced" mode */ immUniform4f("color", 1.0f, 0.0f, 0.0f, 1.0f); diff --git a/source/blender/editors/uvedit/uvedit_islands.cc b/source/blender/editors/uvedit/uvedit_islands.cc index aae65284d8c..132210cddb9 100644 --- a/source/blender/editors/uvedit/uvedit_islands.cc +++ b/source/blender/editors/uvedit/uvedit_islands.cc @@ -11,223 +11,14 @@ * This API uses #BMesh data structures and doesn't have limitations for manifold meshes. */ -#include "MEM_guardedalloc.h" - -#include "DNA_meshdata_types.h" -#include "DNA_scene_types.h" -#include "DNA_space_types.h" - -#include "BLI_boxpack_2d.h" -#include "BLI_convexhull_2d.h" -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_rect.h" - -#include "BKE_customdata.h" #include "BKE_editmesh.h" -#include "BKE_image.h" -#include "DEG_depsgraph.h" +#include "BLI_math.h" + +#include "DNA_image_types.h" #include "ED_uvedit.h" /* Own include. */ -#include "GEO_uv_pack.hh" - -#include "WM_api.h" -#include "WM_types.h" - -#include "bmesh.h" - -static void mul_v2_m2_add_v2v2(float r[2], - const float mat[2][2], - const float a[2], - const float b[2]) -{ - /* Compute `r = mat * (a + b)` with high precision. */ - const double x = double(a[0]) + double(b[0]); - const double y = double(a[1]) + double(b[1]); - - r[0] = float(mat[0][0] * x + mat[1][0] * y); - r[1] = float(mat[0][1] * x + mat[1][1] * y); -} - -static void island_uv_transform(FaceIsland *island, - const float matrix[2][2], /* Scale and rotation. */ - const float pre_translate[2] /* (pre) Translation. */ -) -{ - /* Use a pre-transform to compute `A * (x+b)` - * - * \note Ordinarily, we'd use a post_transform like `A * x + b` - * In general, post-transforms are easier to work with when using homogenous co-ordinates. - * - * When UV mapping into the unit square, post-transforms can lose precision on small islands. - * Instead we're using a pre-transform to maintain precision. - * - * To convert post-transform to pre-transform, use `A * x + b == A * (x + c), c = A^-1 * b` - */ - - const int cd_loop_uv_offset = island->offsets.uv; - const int faces_len = island->faces_len; - for (int i = 0; i < faces_len; i++) { - BMFace *f = island->faces[i]; - BMLoop *l; - BMIter iter; - BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { - float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset); - mul_v2_m2_add_v2v2(luv, matrix, luv, pre_translate); - } - } -} - -/* -------------------------------------------------------------------- */ -/** \name UV Face Array Utilities - * \{ */ - -static void bm_face_array_calc_bounds(BMFace **faces, - const int faces_len, - const int cd_loop_uv_offset, - rctf *r_bounds_rect) -{ - BLI_assert(cd_loop_uv_offset >= 0); - float bounds_min[2], bounds_max[2]; - INIT_MINMAX2(bounds_min, bounds_max); - for (int i = 0; i < faces_len; i++) { - BMFace *f = faces[i]; - BM_face_uv_minmax(f, bounds_min, bounds_max, cd_loop_uv_offset); - } - r_bounds_rect->xmin = bounds_min[0]; - r_bounds_rect->ymin = bounds_min[1]; - r_bounds_rect->xmax = bounds_max[0]; - r_bounds_rect->ymax = bounds_max[1]; -} - -/** - * Return an array of un-ordered UV coordinates, - * without duplicating coordinates for loops that share a vertex. - */ -static float (*bm_face_array_calc_unique_uv_coords( - BMFace **faces, int faces_len, const int cd_loop_uv_offset, int *r_coords_len))[2] -{ - BLI_assert(cd_loop_uv_offset >= 0); - int coords_len_alloc = 0; - for (int i = 0; i < faces_len; i++) { - BMFace *f = faces[i]; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - BM_elem_flag_enable(l_iter, BM_ELEM_TAG); - } while ((l_iter = l_iter->next) != l_first); - coords_len_alloc += f->len; - } - - float(*coords)[2] = static_cast( - MEM_mallocN(sizeof(*coords) * coords_len_alloc, __func__)); - int coords_len = 0; - - for (int i = 0; i < faces_len; i++) { - BMFace *f = faces[i]; - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(f); - do { - if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { - /* Already walked over, continue. */ - continue; - } - - BM_elem_flag_disable(l_iter, BM_ELEM_TAG); - const float *luv = BM_ELEM_CD_GET_FLOAT_P(l_iter, cd_loop_uv_offset); - copy_v2_v2(coords[coords_len++], luv); - - /* Un tag all connected so we don't add them twice. - * Note that we will tag other loops not part of `faces` but this is harmless, - * since we're only turning off a tag. */ - BMVert *v_pivot = l_iter->v; - BMEdge *e_first = v_pivot->e; - const BMEdge *e = e_first; - do { - if (e->l != nullptr) { - const BMLoop *l_radial = e->l; - do { - if (l_radial->v == l_iter->v) { - if (BM_elem_flag_test(l_radial, BM_ELEM_TAG)) { - const float *luv_radial = BM_ELEM_CD_GET_FLOAT_P(l_radial, cd_loop_uv_offset); - if (equals_v2v2(luv, luv_radial)) { - /* Don't add this UV when met in another face in `faces`. */ - BM_elem_flag_disable(l_iter, BM_ELEM_TAG); - } - } - } - } while ((l_radial = l_radial->radial_next) != e->l); - } - } while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != e_first); - } while ((l_iter = l_iter->next) != l_first); - } - *r_coords_len = coords_len; - return coords; -} - -static void face_island_uv_rotate_fit_aabb(FaceIsland *island) -{ - BMFace **faces = island->faces; - const int faces_len = island->faces_len; - const float aspect_y = island->aspect_y; - const int cd_loop_uv_offset = island->offsets.uv; - - /* Calculate unique coordinates since calculating a convex hull can be an expensive operation. */ - int coords_len; - float(*coords)[2] = bm_face_array_calc_unique_uv_coords( - faces, faces_len, cd_loop_uv_offset, &coords_len); - - /* Correct aspect ratio. */ - if (aspect_y != 1.0f) { - for (int i = 0; i < coords_len; i++) { - coords[i][1] /= aspect_y; - } - } - - float angle = BLI_convexhull_aabb_fit_points_2d(coords, coords_len); - - /* Rotate coords by `angle` before computing bounding box. */ - if (angle != 0.0f) { - float matrix[2][2]; - angle_to_mat2(matrix, angle); - matrix[0][1] *= aspect_y; - matrix[1][1] *= aspect_y; - for (int i = 0; i < coords_len; i++) { - mul_m2_v2(matrix, coords[i]); - } - } - - /* Compute new AABB. */ - float bounds_min[2], bounds_max[2]; - INIT_MINMAX2(bounds_min, bounds_max); - for (int i = 0; i < coords_len; i++) { - minmax_v2v2_v2(bounds_min, bounds_max, coords[i]); - } - - float size[2]; - sub_v2_v2v2(size, bounds_max, bounds_min); - if (size[1] < size[0]) { - angle += DEG2RADF(90.0f); - } - - MEM_freeN(coords); - - /* Apply rotation back to BMesh. */ - if (angle != 0.0f) { - float matrix[2][2]; - float pre_translate[2] = {0, 0}; - angle_to_mat2(matrix, angle); - matrix[1][0] *= 1.0f / aspect_y; - /* matrix[1][1] *= aspect_y / aspect_y; */ - matrix[0][1] *= aspect_y; - island_uv_transform(island, matrix, pre_translate); - } -} - -/** \} */ - /* -------------------------------------------------------------------- */ /** \name UDIM packing helper functions * \{ */ @@ -261,58 +52,6 @@ bool uv_coords_isect_udim(const Image *image, const int udim_grid[2], const floa return false; } -/** - * Calculates distance to nearest UDIM image tile in UV space and its UDIM tile number. - */ -static float uv_nearest_image_tile_distance(const Image *image, - const float coords[2], - float nearest_tile_co[2]) -{ - BKE_image_find_nearest_tile_with_offset(image, coords, nearest_tile_co); - - /* Add 0.5 to get tile center coordinates. */ - float nearest_tile_center_co[2] = {nearest_tile_co[0], nearest_tile_co[1]}; - add_v2_fl(nearest_tile_center_co, 0.5f); - - return len_squared_v2v2(coords, nearest_tile_center_co); -} - -/** - * Calculates distance to nearest UDIM grid tile in UV space and its UDIM tile number. - */ -static float uv_nearest_grid_tile_distance(const int udim_grid[2], - const float coords[2], - float nearest_tile_co[2]) -{ - const float coords_floor[2] = {floorf(coords[0]), floorf(coords[1])}; - - if (coords[0] > udim_grid[0]) { - nearest_tile_co[0] = udim_grid[0] - 1; - } - else if (coords[0] < 0) { - nearest_tile_co[0] = 0; - } - else { - nearest_tile_co[0] = coords_floor[0]; - } - - if (coords[1] > udim_grid[1]) { - nearest_tile_co[1] = udim_grid[1] - 1; - } - else if (coords[1] < 0) { - nearest_tile_co[1] = 0; - } - else { - nearest_tile_co[1] = coords_floor[1]; - } - - /* Add 0.5 to get tile center coordinates. */ - float nearest_tile_center_co[2] = {nearest_tile_co[0], nearest_tile_co[1]}; - add_v2_fl(nearest_tile_center_co, 0.5f); - - return len_squared_v2v2(coords, nearest_tile_center_co); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -436,211 +175,3 @@ int bm_mesh_calc_uv_islands(const Scene *scene, } /** \} */ - -static bool island_has_pins(const Scene *scene, - FaceIsland *island, - const UVPackIsland_Params *params) -{ - const bool pin_unselected = params->pin_unselected; - const bool only_selected_faces = params->only_selected_faces; - BMLoop *l; - BMIter iter; - const int pin_offset = island->offsets.pin; - for (int i = 0; i < island->faces_len; i++) { - BMFace *efa = island->faces[i]; - if (pin_unselected && only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - return true; - } - BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) { - if (BM_ELEM_CD_GET_BOOL(l, pin_offset)) { - return true; - } - if (pin_unselected && !uvedit_uv_select_test(scene, l, island->offsets)) { - return true; - } - } - } - return false; -} - -/* -------------------------------------------------------------------- */ -/** \name Public UV Island Packing - * - * \note This behavior loosely follows #geometry::uv_parametrizer_pack. - * \{ */ - -void ED_uvedit_pack_islands_multi(const Scene *scene, - Object **objects, - const uint objects_len, - BMesh **bmesh_override, - const UVMapUDIM_Params *closest_udim, - const UVPackIsland_Params *params) -{ - blender::Vector island_vector; - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMesh *bm = nullptr; - if (bmesh_override) { - /* Note: obedit is still required for aspect ratio and ID_RECALC_GEOMETRY. */ - bm = bmesh_override[ob_index]; - } - else { - BMEditMesh *em = BKE_editmesh_from_object(obedit); - bm = em->bm; - } - BLI_assert(bm); - - const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); - if (offsets.uv == -1) { - continue; - } - - const float aspect_y = params->correct_aspect ? ED_uvedit_get_aspect_y(obedit) : 1.0f; - - bool only_selected_faces = params->only_selected_faces; - bool only_selected_uvs = params->only_selected_uvs; - if (params->ignore_pinned && params->pin_unselected) { - only_selected_faces = false; - only_selected_uvs = false; - } - ListBase island_list = {nullptr}; - bm_mesh_calc_uv_islands(scene, - bm, - &island_list, - only_selected_faces, - only_selected_uvs, - params->use_seams, - aspect_y, - offsets); - - /* Remove from linked list and append to blender::Vector. */ - LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) { - BLI_remlink(&island_list, island); - if (params->ignore_pinned && island_has_pins(scene, island, params)) { - MEM_freeN(island->faces); - MEM_freeN(island); - continue; - } - island_vector.append(island); - } - } - - if (island_vector.size() == 0) { - return; - } - - /* Coordinates of bounding box containing all selected UVs. */ - float selection_min_co[2], selection_max_co[2]; - INIT_MINMAX2(selection_min_co, selection_max_co); - - for (int index = 0; index < island_vector.size(); index++) { - FaceIsland *island = island_vector[index]; - if (closest_udim) { - /* Only calculate selection bounding box if using closest_udim. */ - for (int i = 0; i < island->faces_len; i++) { - BMFace *f = island->faces[i]; - BM_face_uv_minmax(f, selection_min_co, selection_max_co, island->offsets.uv); - } - } - - if (params->rotate) { - face_island_uv_rotate_fit_aabb(island); - } - - bm_face_array_calc_bounds( - island->faces, island->faces_len, island->offsets.uv, &island->bounds_rect); - } - - /* Center of bounding box containing all selected UVs. */ - float selection_center[2]; - if (closest_udim) { - selection_center[0] = (selection_min_co[0] + selection_max_co[0]) / 2.0f; - selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f; - } - - float scale[2] = {1.0f, 1.0f}; - blender::Vector pack_island_vector; - for (int i = 0; i < island_vector.size(); i++) { - FaceIsland *face_island = island_vector[i]; - blender::geometry::PackIsland *pack_island = new blender::geometry::PackIsland(); - pack_island->bounds_rect = face_island->bounds_rect; - pack_island_vector.append(pack_island); - } - BoxPack *box_array = pack_islands(pack_island_vector, *params, scale); - - float base_offset[2] = {0.0f, 0.0f}; - copy_v2_v2(base_offset, params->udim_base_offset); - - if (closest_udim) { - const Image *image = closest_udim->image; - const int *udim_grid = closest_udim->grid_shape; - /* Check if selection lies on a valid UDIM grid tile. */ - bool is_valid_udim = uv_coords_isect_udim(image, udim_grid, selection_center); - if (is_valid_udim) { - base_offset[0] = floorf(selection_center[0]); - base_offset[1] = floorf(selection_center[1]); - } - /* If selection doesn't lie on any UDIM then find the closest UDIM grid or image tile. */ - else { - float nearest_image_tile_co[2] = {FLT_MAX, FLT_MAX}; - float nearest_image_tile_dist = FLT_MAX, nearest_grid_tile_dist = FLT_MAX; - if (image) { - nearest_image_tile_dist = uv_nearest_image_tile_distance( - image, selection_center, nearest_image_tile_co); - } - - float nearest_grid_tile_co[2] = {0.0f, 0.0f}; - nearest_grid_tile_dist = uv_nearest_grid_tile_distance( - udim_grid, selection_center, nearest_grid_tile_co); - - base_offset[0] = (nearest_image_tile_dist < nearest_grid_tile_dist) ? - nearest_image_tile_co[0] : - nearest_grid_tile_co[0]; - base_offset[1] = (nearest_image_tile_dist < nearest_grid_tile_dist) ? - nearest_image_tile_co[1] : - nearest_grid_tile_co[1]; - } - } - - float matrix[2][2]; - float matrix_inverse[2][2]; - float pre_translate[2]; - for (int i = 0; i < island_vector.size(); i++) { - FaceIsland *island = island_vector[box_array[i].index]; - matrix[0][0] = scale[0]; - matrix[0][1] = 0.0f; - matrix[1][0] = 0.0f; - matrix[1][1] = scale[1]; - invert_m2_m2(matrix_inverse, matrix); - - /* Add base_offset, post transform. */ - mul_v2_m2v2(pre_translate, matrix_inverse, base_offset); - - /* Translate to box_array from bounds_rect. */ - pre_translate[0] += box_array[i].x - island->bounds_rect.xmin; - pre_translate[1] += box_array[i].y - island->bounds_rect.ymin; - island_uv_transform(island, matrix, pre_translate); - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - DEG_id_tag_update(static_cast(obedit->data), ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); - } - - for (FaceIsland *island : island_vector) { - MEM_freeN(island->faces); - MEM_freeN(island); - } - - for (int i = 0; i < pack_island_vector.size(); i++) { - blender::geometry::PackIsland *pack_island = pack_island_vector[i]; - pack_island_vector[i] = nullptr; - delete pack_island; - } - - MEM_freeN(box_array); -} - -/** \} */ diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.cc b/source/blender/editors/uvedit/uvedit_unwrap_ops.cc index 4f0357dd06d..6f9276c94ed 100644 --- a/source/blender/editors/uvedit/uvedit_unwrap_ops.cc +++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.cc @@ -19,6 +19,7 @@ #include "DNA_scene_types.h" #include "BLI_array.hh" +#include "BLI_convexhull_2d.h" #include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_math.h" @@ -38,7 +39,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_subdiv.h" @@ -140,8 +141,7 @@ static bool ED_uvedit_ensure_uvs(Object *obedit) /** \name UDIM Access * \{ */ -static void ED_uvedit_udim_params_from_image_space(const SpaceImage *sima, - UVPackIsland_Params *r_params) +void blender::geometry::UVPackIsland_Params::setUDIMOffsetFromSpaceImage(const SpaceImage *sima) { if (!sima) { return; /* Nothing to do. */ @@ -154,8 +154,8 @@ static void ED_uvedit_udim_params_from_image_space(const SpaceImage *sima, ImageTile *active_tile = static_cast( BLI_findlink(&image->tiles, image->active_tile_index)); if (active_tile) { - r_params->udim_base_offset[0] = (active_tile->tile_number - 1001) % 10; - r_params->udim_base_offset[1] = (active_tile->tile_number - 1001) / 10; + udim_base_offset[0] = (active_tile->tile_number - 1001) % 10; + udim_base_offset[1] = (active_tile->tile_number - 1001) / 10; } return; } @@ -163,8 +163,8 @@ static void ED_uvedit_udim_params_from_image_space(const SpaceImage *sima, /* TODO: Support storing an active UDIM when there are no tiles present. * Until then, use 2D cursor to find the active tile index for the UDIM grid. */ if (uv_coords_isect_udim(sima->image, sima->tile_grid_shape, sima->cursor)) { - r_params->udim_base_offset[0] = floorf(sima->cursor[0]); - r_params->udim_base_offset[1] = floorf(sima->cursor[1]); + udim_base_offset[0] = floorf(sima->cursor[0]); + udim_base_offset[1] = floorf(sima->cursor[1]); } } /** \} */ @@ -194,10 +194,14 @@ struct UnwrapOptions { bool pin_unselected; }; -struct UnwrapResultInfo { - int count_changed; - int count_failed; -}; +void blender::geometry::UVPackIsland_Params::setFromUnwrapOptions(const UnwrapOptions &options) +{ + only_selected_uvs = options.only_selected_uvs; + only_selected_faces = options.only_selected_faces; + use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams; + correct_aspect = options.correct_aspect; + pin_unselected = options.pin_unselected; +} static bool uvedit_have_selection(const Scene *scene, BMEditMesh *em, const UnwrapOptions *options) { @@ -1016,6 +1020,460 @@ void UV_OT_minimize_stretch(wmOperatorType *ot) /** \} */ +/** Compute `r = mat * (a + b)` with high precision. */ +static void mul_v2_m2_add_v2v2(float r[2], + const float mat[2][2], + const float a[2], + const float b[2]) +{ + const double x = double(a[0]) + double(b[0]); + const double y = double(a[1]) + double(b[1]); + + r[0] = float(mat[0][0] * x + mat[1][0] * y); + r[1] = float(mat[0][1] * x + mat[1][1] * y); +} + +static void island_uv_transform(FaceIsland *island, + const float matrix[2][2], /* Scale and rotation. */ + const float pre_translate[2] /* (pre) Translation. */ +) +{ + /* Use a pre-transform to compute `A * (x+b)` + * + * \note Ordinarily, we'd use a post_transform like `A * x + b` + * In general, post-transforms are easier to work with when using homogenous co-ordinates. + * + * When UV mapping into the unit square, post-transforms can lose precision on small islands. + * Instead we're using a pre-transform to maintain precision. + * + * To convert post-transform to pre-transform, use `A * x + b == A * (x + c), c = A^-1 * b` + */ + + const int cd_loop_uv_offset = island->offsets.uv; + const int faces_len = island->faces_len; + for (int i = 0; i < faces_len; i++) { + BMFace *f = island->faces[i]; + BMLoop *l; + BMIter iter; + BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) { + float *luv = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset); + mul_v2_m2_add_v2v2(luv, matrix, luv, pre_translate); + } + } +} + +static void bm_face_array_calc_bounds(BMFace **faces, + const int faces_len, + const int cd_loop_uv_offset, + rctf *r_bounds_rect) +{ + BLI_assert(cd_loop_uv_offset >= 0); + float bounds_min[2], bounds_max[2]; + INIT_MINMAX2(bounds_min, bounds_max); + for (int i = 0; i < faces_len; i++) { + BMFace *f = faces[i]; + BM_face_uv_minmax(f, bounds_min, bounds_max, cd_loop_uv_offset); + } + r_bounds_rect->xmin = bounds_min[0]; + r_bounds_rect->ymin = bounds_min[1]; + r_bounds_rect->xmax = bounds_max[0]; + r_bounds_rect->ymax = bounds_max[1]; +} + +/** + * Return an array of un-ordered UV coordinates, + * without duplicating coordinates for loops that share a vertex. + */ +static float (*bm_face_array_calc_unique_uv_coords( + BMFace **faces, int faces_len, const int cd_loop_uv_offset, int *r_coords_len))[2] +{ + BLI_assert(cd_loop_uv_offset >= 0); + int coords_len_alloc = 0; + for (int i = 0; i < faces_len; i++) { + BMFace *f = faces[i]; + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + BM_elem_flag_enable(l_iter, BM_ELEM_TAG); + } while ((l_iter = l_iter->next) != l_first); + coords_len_alloc += f->len; + } + + float(*coords)[2] = static_cast( + MEM_mallocN(sizeof(*coords) * coords_len_alloc, __func__)); + int coords_len = 0; + + for (int i = 0; i < faces_len; i++) { + BMFace *f = faces[i]; + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (!BM_elem_flag_test(l_iter, BM_ELEM_TAG)) { + /* Already walked over, continue. */ + continue; + } + + BM_elem_flag_disable(l_iter, BM_ELEM_TAG); + const float *luv = BM_ELEM_CD_GET_FLOAT_P(l_iter, cd_loop_uv_offset); + copy_v2_v2(coords[coords_len++], luv); + + /* Un tag all connected so we don't add them twice. + * Note that we will tag other loops not part of `faces` but this is harmless, + * since we're only turning off a tag. */ + BMVert *v_pivot = l_iter->v; + BMEdge *e_first = v_pivot->e; + const BMEdge *e = e_first; + do { + if (e->l != nullptr) { + const BMLoop *l_radial = e->l; + do { + if (l_radial->v == l_iter->v) { + if (BM_elem_flag_test(l_radial, BM_ELEM_TAG)) { + const float *luv_radial = BM_ELEM_CD_GET_FLOAT_P(l_radial, cd_loop_uv_offset); + if (equals_v2v2(luv, luv_radial)) { + /* Don't add this UV when met in another face in `faces`. */ + BM_elem_flag_disable(l_iter, BM_ELEM_TAG); + } + } + } + } while ((l_radial = l_radial->radial_next) != e->l); + } + } while ((e = BM_DISK_EDGE_NEXT(e, v_pivot)) != e_first); + } while ((l_iter = l_iter->next) != l_first); + } + *r_coords_len = coords_len; + return coords; +} + +static void face_island_uv_rotate_fit_aabb(FaceIsland *island) +{ + BMFace **faces = island->faces; + const int faces_len = island->faces_len; + const float aspect_y = island->aspect_y; + const int cd_loop_uv_offset = island->offsets.uv; + + /* Calculate unique coordinates since calculating a convex hull can be an expensive operation. */ + int coords_len; + float(*coords)[2] = bm_face_array_calc_unique_uv_coords( + faces, faces_len, cd_loop_uv_offset, &coords_len); + + /* Correct aspect ratio. */ + if (aspect_y != 1.0f) { + for (int i = 0; i < coords_len; i++) { + coords[i][1] /= aspect_y; + } + } + + /* As the UV Packing API doesn't yet support rotation, we need + * to pre-rotate each island into the smallest AABB. */ + float angle = BLI_convexhull_aabb_fit_points_2d(coords, coords_len); + + /* Rotate coords by `angle` before computing bounding box. */ + if (angle != 0.0f) { + float matrix[2][2]; + angle_to_mat2(matrix, angle); + matrix[0][1] *= aspect_y; + matrix[1][1] *= aspect_y; + for (int i = 0; i < coords_len; i++) { + mul_m2_v2(matrix, coords[i]); + } + } + + /* Compute new AABB. */ + float bounds_min[2], bounds_max[2]; + INIT_MINMAX2(bounds_min, bounds_max); + for (int i = 0; i < coords_len; i++) { + minmax_v2v2_v2(bounds_min, bounds_max, coords[i]); + } + + /* "Stand-up" islands. + * If we rotate the AABB by 90 degrees, the aspect ratio correction for the X axis will be + * `aspect_y` and for the Y axis will be `1.0f / aspect_y`. Applying both corrections gives + * a combined factor of `aspect_y / (1.0f / aspect_y) == aspect_y * aspect_y`. */ + float size[2]; + sub_v2_v2v2(size, bounds_max, bounds_min); + if (size[1] < size[0] * (aspect_y * aspect_y)) { + angle += DEG2RADF(90.0f); + } + + MEM_freeN(coords); + + /* Apply rotation back to BMesh. */ + if (angle != 0.0f) { + float matrix[2][2]; + float pre_translate[2] = {0, 0}; + angle_to_mat2(matrix, angle); + matrix[1][0] *= 1.0f / aspect_y; + /* matrix[1][1] *= aspect_y / aspect_y; */ + matrix[0][1] *= aspect_y; + island_uv_transform(island, matrix, pre_translate); + } +} + +/** + * Calculates distance to nearest UDIM image tile in UV space and its UDIM tile number. + */ +static float uv_nearest_image_tile_distance(const Image *image, + const float coords[2], + float nearest_tile_co[2]) +{ + BKE_image_find_nearest_tile_with_offset(image, coords, nearest_tile_co); + + /* Add 0.5 to get tile center coordinates. */ + float nearest_tile_center_co[2] = {nearest_tile_co[0], nearest_tile_co[1]}; + add_v2_fl(nearest_tile_center_co, 0.5f); + + return len_squared_v2v2(coords, nearest_tile_center_co); +} + +/** + * Calculates distance to nearest UDIM grid tile in UV space and its UDIM tile number. + */ +static float uv_nearest_grid_tile_distance(const int udim_grid[2], + const float coords[2], + float nearest_tile_co[2]) +{ + const float coords_floor[2] = {floorf(coords[0]), floorf(coords[1])}; + + if (coords[0] > udim_grid[0]) { + nearest_tile_co[0] = udim_grid[0] - 1; + } + else if (coords[0] < 0) { + nearest_tile_co[0] = 0; + } + else { + nearest_tile_co[0] = coords_floor[0]; + } + + if (coords[1] > udim_grid[1]) { + nearest_tile_co[1] = udim_grid[1] - 1; + } + else if (coords[1] < 0) { + nearest_tile_co[1] = 0; + } + else { + nearest_tile_co[1] = coords_floor[1]; + } + + /* Add 0.5 to get tile center coordinates. */ + float nearest_tile_center_co[2] = {nearest_tile_co[0], nearest_tile_co[1]}; + add_v2_fl(nearest_tile_center_co, 0.5f); + + return len_squared_v2v2(coords, nearest_tile_center_co); +} + +static bool island_has_pins(const Scene *scene, + FaceIsland *island, + const blender::geometry::UVPackIsland_Params *params) +{ + const bool pin_unselected = params->pin_unselected; + const bool only_selected_faces = params->only_selected_faces; + BMLoop *l; + BMIter iter; + const int pin_offset = island->offsets.pin; + for (int i = 0; i < island->faces_len; i++) { + BMFace *efa = island->faces[i]; + if (pin_unselected && only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + return true; + } + BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) { + if (BM_ELEM_CD_GET_BOOL(l, pin_offset)) { + return true; + } + if (pin_unselected && !uvedit_uv_select_test(scene, l, island->offsets)) { + return true; + } + } + } + return false; +} + +/** + * Pack UV islands from multiple objects. + * + * \param scene: Scene containing the objects to be packed. + * \param objects: Array of Objects to pack. + * \param objects_len: Length of `objects` array. + * \param bmesh_override: BMesh array aligned with `objects`. + * Optional, when non-null this overrides object's BMesh. + * This is needed to perform UV packing on objects that aren't in edit-mode. + * \param udim_params: Parameters to specify UDIM target and UDIM source image. + * \param params: Parameters and options to pass to the packing engine. + */ +static void uvedit_pack_islands_multi(const Scene *scene, + Object **objects, + const int objects_len, + BMesh **bmesh_override, + const UVMapUDIM_Params *closest_udim, + const blender::geometry::UVPackIsland_Params *params) +{ + blender::Vector island_vector; + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMesh *bm = nullptr; + if (bmesh_override) { + /* Note: obedit is still required for aspect ratio and ID_RECALC_GEOMETRY. */ + bm = bmesh_override[ob_index]; + } + else { + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bm = em->bm; + } + BLI_assert(bm); + + const BMUVOffsets offsets = BM_uv_map_get_offsets(bm); + if (offsets.uv == -1) { + continue; + } + + const float aspect_y = params->correct_aspect ? ED_uvedit_get_aspect_y(obedit) : 1.0f; + + bool only_selected_faces = params->only_selected_faces; + bool only_selected_uvs = params->only_selected_uvs; + if (params->ignore_pinned && params->pin_unselected) { + only_selected_faces = false; + only_selected_uvs = false; + } + ListBase island_list = {nullptr}; + bm_mesh_calc_uv_islands(scene, + bm, + &island_list, + only_selected_faces, + only_selected_uvs, + params->use_seams, + aspect_y, + offsets); + + /* Remove from linked list and append to blender::Vector. */ + LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) { + BLI_remlink(&island_list, island); + if (params->ignore_pinned && island_has_pins(scene, island, params)) { + MEM_freeN(island->faces); + MEM_freeN(island); + continue; + } + island_vector.append(island); + } + } + + if (island_vector.size() == 0) { + return; + } + + /* Coordinates of bounding box containing all selected UVs. */ + float selection_min_co[2], selection_max_co[2]; + INIT_MINMAX2(selection_min_co, selection_max_co); + + for (int index = 0; index < island_vector.size(); index++) { + FaceIsland *island = island_vector[index]; + if (closest_udim) { + /* Only calculate selection bounding box if using closest_udim. */ + for (int i = 0; i < island->faces_len; i++) { + BMFace *f = island->faces[i]; + BM_face_uv_minmax(f, selection_min_co, selection_max_co, island->offsets.uv); + } + } + + if (params->rotate) { + face_island_uv_rotate_fit_aabb(island); + } + + bm_face_array_calc_bounds( + island->faces, island->faces_len, island->offsets.uv, &island->bounds_rect); + } + + /* Center of bounding box containing all selected UVs. */ + float selection_center[2]; + if (closest_udim) { + selection_center[0] = (selection_min_co[0] + selection_max_co[0]) / 2.0f; + selection_center[1] = (selection_min_co[1] + selection_max_co[1]) / 2.0f; + } + + float scale[2] = {1.0f, 1.0f}; + blender::Vector pack_island_vector; + for (int i = 0; i < island_vector.size(); i++) { + FaceIsland *face_island = island_vector[i]; + blender::geometry::PackIsland *pack_island = new blender::geometry::PackIsland(); + pack_island->bounds_rect = face_island->bounds_rect; + pack_island->caller_index = i; + pack_island_vector.append(pack_island); + } + pack_islands(pack_island_vector, *params, scale); + + float base_offset[2] = {0.0f, 0.0f}; + copy_v2_v2(base_offset, params->udim_base_offset); + + if (closest_udim) { + const Image *image = closest_udim->image; + const int *udim_grid = closest_udim->grid_shape; + /* Check if selection lies on a valid UDIM grid tile. */ + bool is_valid_udim = uv_coords_isect_udim(image, udim_grid, selection_center); + if (is_valid_udim) { + base_offset[0] = floorf(selection_center[0]); + base_offset[1] = floorf(selection_center[1]); + } + /* If selection doesn't lie on any UDIM then find the closest UDIM grid or image tile. */ + else { + float nearest_image_tile_co[2] = {FLT_MAX, FLT_MAX}; + float nearest_image_tile_dist = FLT_MAX, nearest_grid_tile_dist = FLT_MAX; + if (image) { + nearest_image_tile_dist = uv_nearest_image_tile_distance( + image, selection_center, nearest_image_tile_co); + } + + float nearest_grid_tile_co[2] = {0.0f, 0.0f}; + nearest_grid_tile_dist = uv_nearest_grid_tile_distance( + udim_grid, selection_center, nearest_grid_tile_co); + + base_offset[0] = (nearest_image_tile_dist < nearest_grid_tile_dist) ? + nearest_image_tile_co[0] : + nearest_grid_tile_co[0]; + base_offset[1] = (nearest_image_tile_dist < nearest_grid_tile_dist) ? + nearest_image_tile_co[1] : + nearest_grid_tile_co[1]; + } + } + + float matrix[2][2]; + float matrix_inverse[2][2]; + float pre_translate[2]; + for (int64_t i : pack_island_vector.index_range()) { + blender::geometry::PackIsland *pack_island = pack_island_vector[i]; + FaceIsland *island = island_vector[pack_island->caller_index]; + matrix[0][0] = scale[0]; + matrix[0][1] = 0.0f; + matrix[1][0] = 0.0f; + matrix[1][1] = scale[1]; + invert_m2_m2(matrix_inverse, matrix); + + /* Add base_offset, post transform. */ + mul_v2_m2v2(pre_translate, matrix_inverse, base_offset); + + /* Add pre-translation from #pack_islands. */ + pre_translate[0] += pack_island->pre_translate.x; + pre_translate[1] += pack_island->pre_translate.y; + + /* Perform the transformation. */ + island_uv_transform(island, matrix, pre_translate); + + /* Cleanup memory. */ + pack_island_vector[i] = nullptr; + delete pack_island; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + DEG_id_tag_update(static_cast(obedit->data), ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); + } + + for (FaceIsland *island : island_vector) { + MEM_freeN(island->faces); + MEM_freeN(island); + } +} + /* -------------------------------------------------------------------- */ /** \name Pack UV Islands Operator * \{ */ @@ -1058,14 +1516,10 @@ static int pack_islands_exec(bContext *C, wmOperator *op) RNA_float_set(op->ptr, "margin", scene->toolsettings->uvcalc_margin); } - UVPackIsland_Params pack_island_params{}; + blender::geometry::UVPackIsland_Params pack_island_params; + pack_island_params.setFromUnwrapOptions(options); pack_island_params.rotate = RNA_boolean_get(op->ptr, "rotate"); - pack_island_params.only_selected_uvs = options.only_selected_uvs; - pack_island_params.only_selected_faces = options.only_selected_faces; - pack_island_params.use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams; - pack_island_params.correct_aspect = options.correct_aspect; pack_island_params.ignore_pinned = false; - pack_island_params.pin_unselected = options.pin_unselected; pack_island_params.margin_method = eUVPackIsland_MarginMethod( RNA_enum_get(op->ptr, "margin_method")); pack_island_params.margin = RNA_float_get(op->ptr, "margin"); @@ -1073,7 +1527,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op) UVMapUDIM_Params closest_udim_buf; UVMapUDIM_Params *closest_udim = nullptr; if (udim_source == PACK_UDIM_SRC_ACTIVE) { - ED_uvedit_udim_params_from_image_space(sima, &pack_island_params); + pack_island_params.setUDIMOffsetFromSpaceImage(sima); } else if (sima) { BLI_assert(udim_source == PACK_UDIM_SRC_CLOSEST); @@ -1083,7 +1537,7 @@ static int pack_islands_exec(bContext *C, wmOperator *op) closest_udim->grid_shape[1] = sima->tile_grid_shape[1]; } - ED_uvedit_pack_islands_multi( + uvedit_pack_islands_multi( scene, objects, objects_len, nullptr, closest_udim, &pack_island_params); MEM_freeN(objects); @@ -1789,7 +2243,8 @@ static void uv_map_clip_correct(const Scene *scene, static void uvedit_unwrap(const Scene *scene, Object *obedit, const UnwrapOptions *options, - UnwrapResultInfo *result_info) + int *r_count_changed, + int *r_count_failed) { BMEditMesh *em = BKE_editmesh_from_object(obedit); if (!CustomData_has_layer(&em->bm->ldata, CD_PROP_FLOAT2)) { @@ -1801,20 +2256,15 @@ static void uvedit_unwrap(const Scene *scene, ParamHandle *handle; if (use_subsurf) { - handle = construct_param_handle_subsurfed( - scene, obedit, em, options, result_info ? &result_info->count_failed : nullptr); + handle = construct_param_handle_subsurfed(scene, obedit, em, options, r_count_failed); } else { - handle = construct_param_handle( - scene, obedit, em->bm, options, result_info ? &result_info->count_failed : nullptr); + handle = construct_param_handle(scene, obedit, em->bm, options, r_count_failed); } blender::geometry::uv_parametrizer_lscm_begin( handle, false, scene->toolsettings->unwrapper == 0); - blender::geometry::uv_parametrizer_lscm_solve( - handle, - result_info ? &result_info->count_changed : nullptr, - result_info ? &result_info->count_failed : nullptr); + blender::geometry::uv_parametrizer_lscm_solve(handle, r_count_changed, r_count_failed); blender::geometry::uv_parametrizer_lscm_end(handle); blender::geometry::uv_parametrizer_average(handle, true, false, false); @@ -1828,11 +2278,12 @@ static void uvedit_unwrap_multi(const Scene *scene, Object **objects, const int objects_len, const UnwrapOptions *options, - UnwrapResultInfo *result_info) + int *r_count_changed = nullptr, + int *r_count_failed = nullptr) { for (uint ob_index = 0; ob_index < objects_len; ob_index++) { Object *obedit = objects[ob_index]; - uvedit_unwrap(scene, obedit, options, result_info); + uvedit_unwrap(scene, obedit, options, r_count_changed, r_count_failed); DEG_id_tag_update(static_cast(obedit->data), ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data); } @@ -1849,20 +2300,14 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len options.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0; uvedit_unwrap_multi(scene, objects, objects_len, &options, nullptr); - UVPackIsland_Params pack_island_params{}; + blender::geometry::UVPackIsland_Params pack_island_params; + pack_island_params.setFromUnwrapOptions(options); pack_island_params.rotate = true; - pack_island_params.only_selected_uvs = options.only_selected_uvs; - pack_island_params.only_selected_faces = options.only_selected_faces; - pack_island_params.use_seams = !options.topology_from_uvs || - options.topology_from_uvs_use_seams; - pack_island_params.correct_aspect = options.correct_aspect; pack_island_params.ignore_pinned = true; - pack_island_params.pin_unselected = options.pin_unselected; pack_island_params.margin_method = ED_UVPACK_MARGIN_SCALED; pack_island_params.margin = scene->toolsettings->uvcalc_margin; - ED_uvedit_pack_islands_multi( - scene, objects, objects_len, nullptr, nullptr, &pack_island_params); + uvedit_pack_islands_multi(scene, objects, objects_len, nullptr, nullptr, &pack_island_params); } } @@ -1992,38 +2437,33 @@ static int unwrap_exec(bContext *C, wmOperator *op) } /* execute unwrap */ - UnwrapResultInfo result_info{}; - result_info.count_changed = 0; - result_info.count_failed = 0; - uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info); + int count_changed = 0; + int count_failed = 0; + uvedit_unwrap_multi(scene, objects, objects_len, &options, &count_changed, &count_failed); - UVPackIsland_Params pack_island_params{}; + blender::geometry::UVPackIsland_Params pack_island_params; + pack_island_params.setFromUnwrapOptions(options); pack_island_params.rotate = true; - pack_island_params.only_selected_uvs = options.only_selected_uvs; - pack_island_params.only_selected_faces = options.only_selected_faces; - pack_island_params.use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams; - pack_island_params.correct_aspect = options.correct_aspect; pack_island_params.ignore_pinned = true; - pack_island_params.pin_unselected = options.pin_unselected; pack_island_params.margin_method = eUVPackIsland_MarginMethod( RNA_enum_get(op->ptr, "margin_method")); pack_island_params.margin = RNA_float_get(op->ptr, "margin"); - ED_uvedit_pack_islands_multi(scene, objects, objects_len, nullptr, nullptr, &pack_island_params); + uvedit_pack_islands_multi(scene, objects, objects_len, nullptr, nullptr, &pack_island_params); MEM_freeN(objects); - if (result_info.count_failed == 0 && result_info.count_changed == 0) { + if (count_failed == 0 && count_changed == 0) { BKE_report(op->reports, RPT_WARNING, "Unwrap could not solve any island(s), edge seams may need to be added"); } - else if (result_info.count_failed) { + else if (count_failed) { BKE_reportf(op->reports, RPT_WARNING, "Unwrap failed to solve %d of %d island(s), edge seams may need to be added", - result_info.count_failed, - result_info.count_changed + result_info.count_failed); + count_failed, + count_changed + count_failed); } return OPERATOR_FINISHED; @@ -2380,7 +2820,7 @@ static int smart_project_exec(bContext *C, wmOperator *op) /* Depsgraph refresh functions are called here. */ const bool correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"); - UVPackIsland_Params params{}; + blender::geometry::UVPackIsland_Params params; params.rotate = true; params.only_selected_uvs = only_selected_uvs; params.only_selected_faces = true; @@ -2389,10 +2829,10 @@ static int smart_project_exec(bContext *C, wmOperator *op) params.margin_method = eUVPackIsland_MarginMethod(RNA_enum_get(op->ptr, "margin_method")); params.margin = RNA_float_get(op->ptr, "island_margin"); - ED_uvedit_pack_islands_multi( + uvedit_pack_islands_multi( scene, objects_changed, object_changed_len, nullptr, nullptr, ¶ms); - /* #ED_uvedit_pack_islands_multi only supports `per_face_aspect = false`. */ + /* #uvedit_pack_islands_multi only supports `per_face_aspect = false`. */ const bool per_face_aspect = false; uv_map_clip_correct( scene, objects_changed, object_changed_len, op, per_face_aspect, only_selected_uvs); @@ -2719,13 +3159,12 @@ static void uv_map_mirror(BMFace *efa, * than 0.5 units in the *u* coordinate. * If we find such a face, we try and improve the unwrapping * by adding (1.0, 0.0) onto some of the face's UVs. - + * * Note that this is only a heuristic. The property we're * attempting to maintain is that the winding of the face * in UV space corresponds with the handedness of the face * in 3D space w.r.t to the unwrapping. Even for triangles, - * that property is somewhat complicated to evaluate. - */ + * that property is somewhat complicated to evaluate. */ float right_u = -1.0e30f; BMLoop *l; @@ -3370,7 +3809,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob) uvedit_unwrap_cube_project(scene, bm, 2.0, false, false, nullptr); /* Pack UVs. */ - UVPackIsland_Params params{}; + blender::geometry::UVPackIsland_Params params; params.rotate = true; params.only_selected_uvs = false; params.only_selected_faces = false; @@ -3379,7 +3818,7 @@ void ED_uvedit_add_simple_uvs(Main *bmain, const Scene *scene, Object *ob) params.margin_method = ED_UVPACK_MARGIN_SCALED; params.margin = 0.001f; - ED_uvedit_pack_islands_multi(scene, &ob, 1, &bm, nullptr, ¶ms); + uvedit_pack_islands_multi(scene, &ob, 1, &bm, nullptr, ¶ms); /* Write back from BMesh to Mesh. */ BMeshToMeshParams bm_to_me_params{}; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index 6526dd68d9c..3b9670a9d9b 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -10,6 +10,7 @@ #include "BKE_attribute.hh" #include "BKE_global.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include @@ -400,6 +401,7 @@ static bool testEdgeMark(Mesh *me, const FreestyleEdge *fed, const MLoopTri *lt, void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) { + using namespace blender; char *name = ob->id.name + 2; const Span vert_positions = me->vert_positions(); @@ -409,12 +411,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) // Compute loop triangles int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *mlooptri = (MLoopTri *)MEM_malloc_arrayN(tottri, sizeof(*mlooptri), __func__); - BKE_mesh_recalc_looptri(mesh_loops.data(), - mesh_polys.data(), - reinterpret_cast(vert_positions.data()), - me->totloop, - me->totpoly, - mlooptri); + blender::bke::mesh::looptris_calc(vert_positions, mesh_polys, mesh_loops, {mlooptri, tottri}); // Compute loop normals BKE_mesh_calc_normals_split(me); @@ -514,14 +511,16 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) FrsMaterial tmpMat; - const blender::VArray material_indices = me->attributes().lookup_or_default( + const bke::AttributeAccessor attributes = me->attributes(); + const VArray material_indices = attributes.lookup_or_default( "material_index", ATTR_DOMAIN_FACE, 0); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); // We parse the vlak nodes again and import meshes while applying the clipping // by the near and far view planes. for (int a = 0; a < tottri; a++) { const MLoopTri *lt = &mlooptri[a]; - const MPoly *poly = &mesh_polys[lt->poly]; Material *mat = BKE_object_material_get(ob, material_indices[lt->poly] + 1); copy_v3_v3(v1, vert_positions[mesh_loops[lt->tri[0]].v]); @@ -536,7 +535,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) v2[2] += _z_offset; v3[2] += _z_offset; - if (_smooth && (poly->flag & ME_SMOOTH) && lnors) { + if (_smooth && (!sharp_faces[lt->poly]) && lnors) { copy_v3_v3(n1, lnors[lt->tri[0]]); copy_v3_v3(n2, lnors[lt->tri[1]]); copy_v3_v3(n3, lnors[lt->tri[2]]); diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 40f49b458f4..9cad3c1eb72 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -35,7 +35,7 @@ #include "BKE_lib_id.h" /* free_libblock */ #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_node.h" #include "BKE_node_tree_update.h" #include "BKE_object.h" @@ -582,34 +582,34 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) mesh->totcol = group->materials.size(); float3 *vert_positions = (float3 *)CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_SET_DEFAULT, nullptr, mesh->totvert, "position"); + &mesh->vdata, CD_PROP_FLOAT3, CD_SET_DEFAULT, mesh->totvert, "position"); MEdge *edges = (MEdge *)CustomData_add_layer( - &mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); + &mesh->edata, CD_MEDGE, CD_SET_DEFAULT, mesh->totedge); MPoly *polys = (MPoly *)CustomData_add_layer( - &mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); + &mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, mesh->totpoly); MLoop *loops = (MLoop *)CustomData_add_layer( - &mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); + &mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, mesh->totloop); int *material_indices = (int *)CustomData_add_layer_named( - &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, mesh->totpoly, "material_index"); + &mesh->pdata, CD_PROP_INT32, CD_SET_DEFAULT, mesh->totpoly, "material_index"); blender::float2 *loopsuv[2] = {nullptr}; if (hasTex) { // First UV layer loopsuv[0] = static_cast(CustomData_add_layer_named( - &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, mesh->totloop, uvNames[0])); + &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, mesh->totloop, uvNames[0])); CustomData_set_layer_active(&mesh->ldata, CD_PROP_FLOAT2, 0); // Second UV layer loopsuv[1] = static_cast(CustomData_add_layer_named( - &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, mesh->totloop, uvNames[1])); + &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, mesh->totloop, uvNames[1])); CustomData_set_layer_active(&mesh->ldata, CD_PROP_FLOAT2, 1); } // colors and transparency (the latter represented by grayscale colors) MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named( - &mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, mesh->totloop, "Color"); + &mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, mesh->totloop, "Color"); MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named( - &mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, mesh->totloop, "Alpha"); + &mesh->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, mesh->totloop, "Alpha"); BKE_id_attributes_active_color_set( &mesh->id, CustomData_get_layer_name(&mesh->ldata, CD_PROP_BYTE_COLOR, 0)); diff --git a/source/blender/functions/FN_lazy_function_execute.hh b/source/blender/functions/FN_lazy_function_execute.hh index 5785fddaa51..dec04c33d37 100644 --- a/source/blender/functions/FN_lazy_function_execute.hh +++ b/source/blender/functions/FN_lazy_function_execute.hh @@ -94,7 +94,7 @@ inline void execute_lazy_function_eagerly_impl( fn.execute(params, context); fn.destruct_storage(context.storage); - /* Make sure all outputs have been computed. */ + /* Make sure all outputs have been computed. */ BLI_assert(!Span(set_outputs).contains(false)); } diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index b1996ac8f43..ec36dfd1282 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -125,7 +125,7 @@ namespace detail { */ template /* Perform additional optimizations on this loop because it is a very hot loop. For example, the - * math node in geometry nodes is processed here. */ + * math node in geometry nodes is processed here. */ #if (defined(__GNUC__) && !defined(__clang__)) [[gnu::optimize("-funroll-loops")]] [[gnu::optimize("O3")]] #endif @@ -407,6 +407,9 @@ inline void execute_element_fn_as_multi_function(const ElementFn element_fn, std::forward(args)...); }); } + else { + UNUSED_VARS(exec_preset); + } /* If devirtualized execution was disabled or not possible, use a fallback method which is * slower but always works. */ diff --git a/source/blender/geometry/GEO_uv_pack.hh b/source/blender/geometry/GEO_uv_pack.hh index a6adcb4cbaf..25d78a9bc61 100644 --- a/source/blender/geometry/GEO_uv_pack.hh +++ b/source/blender/geometry/GEO_uv_pack.hh @@ -1,8 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BLI_boxpack_2d.h" +#include "BLI_math_matrix.hh" #include "BLI_span.hh" +#include "DNA_space_types.h" #include "DNA_vec_types.h" #pragma once @@ -11,8 +12,7 @@ * \ingroup geo */ -/** Workaround to forward-declare C type in C++ header. */ -extern "C" { +struct UnwrapOptions; enum eUVPackIsland_MarginMethod { ED_UVPACK_MARGIN_SCALED = 0, /* Use scale of existing UVs to multiply margin. */ @@ -20,11 +20,20 @@ enum eUVPackIsland_MarginMethod { ED_UVPACK_MARGIN_FRACTION, /* Specify a precise fraction of final UV output. */ }; +namespace blender::geometry { + /** See also #UnwrapOptions. */ -struct UVPackIsland_Params { +class UVPackIsland_Params { + public: + /** Reasonable defaults. */ + UVPackIsland_Params(); + + void setFromUnwrapOptions(const UnwrapOptions &options); + void setUDIMOffsetFromSpaceImage(const SpaceImage *sima); + /** Islands can be rotated to improve packing. */ bool rotate; - /** (In UV Editor) only pack islands which have one or more selected UVs.*/ + /** (In UV Editor) only pack islands which have one or more selected UVs. */ bool only_selected_uvs; /** (In 3D Viewport or UV Editor) only pack islands which have selected faces. */ bool only_selected_faces; @@ -43,17 +52,16 @@ struct UVPackIsland_Params { /** Additional translation for bottom left corner. */ float udim_base_offset[2]; }; -} - -namespace blender::geometry { class PackIsland { public: rctf bounds_rect; + float2 pre_translate; /* Output. */ + int caller_index; /* Unchanged by #pack_islands, used by caller. */ }; -BoxPack *pack_islands(const Span &island_vector, - const UVPackIsland_Params ¶ms, - float r_scale[2]); +void pack_islands(const Span &islands, + const UVPackIsland_Params ¶ms, + float r_scale[2]); } // namespace blender::geometry diff --git a/source/blender/geometry/GEO_uv_parametrizer.hh b/source/blender/geometry/GEO_uv_parametrizer.hh index 58345f427cb..f0a8905e368 100644 --- a/source/blender/geometry/GEO_uv_parametrizer.hh +++ b/source/blender/geometry/GEO_uv_parametrizer.hh @@ -49,9 +49,9 @@ void uv_parametrizer_face_add(ParamHandle *handle, void uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys); void uv_parametrizer_construct_end(ParamHandle *handle, - bool fill, + bool fill_holes, bool topology_from_uvs, - int *count_fail); + int *r_count_failed = nullptr); void uv_parametrizer_delete(ParamHandle *handle); /** \} */ diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc index aee002c49cd..ec066307f76 100644 --- a/source/blender/geometry/intern/add_curves_on_mesh.cc +++ b/source/blender/geometry/intern/add_curves_on_mesh.cc @@ -5,7 +5,7 @@ #include "BLI_task.hh" #include "BKE_attribute_math.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_sample.hh" #include "GEO_add_curves_on_mesh.hh" diff --git a/source/blender/geometry/intern/curve_constraints.cc b/source/blender/geometry/intern/curve_constraints.cc index c4933d05287..dd5e53c7ccb 100644 --- a/source/blender/geometry/intern/curve_constraints.cc +++ b/source/blender/geometry/intern/curve_constraints.cc @@ -159,7 +159,8 @@ void solve_length_and_collision_constraints(const OffsetIndices points_by_c else { /* Minimum distance is larger than allowed segment length. * The unilateral collision constraint is satisfied by just clamping segment length. */ - positions_cu[point_i] = prev_pos_cu + math::normalize(old_pos_su - prev_pos_cu) * goal_segment_length_cu; + positions_cu[point_i] = prev_pos_cu + math::normalize(old_pos_su - prev_pos_cu) * + goal_segment_length_cu; } } if (used_iterations == max_collisions) { diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc index 3278742cc30..ebd2883abdc 100644 --- a/source/blender/geometry/intern/mesh_merge_by_distance.cc +++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc @@ -13,7 +13,7 @@ #include "DNA_meshdata_types.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "GEO_mesh_merge_by_distance.hh" @@ -805,8 +805,6 @@ static void weld_poly_loop_ctx_alloc(Span polys, const int loopstart = poly.loopstart; const int totloop = poly.totloop; - int vert_ctx_len = 0; - int prev_wloop_len = wloop_len; for (const int i_loop : mloop.index_range().slice(loopstart, totloop)) { int v = mloop[i_loop].v; @@ -815,9 +813,6 @@ static void weld_poly_loop_ctx_alloc(Span polys, int e_dest = edge_dest_map[e]; bool is_vert_ctx = v_dest != OUT_OF_CONTEXT; bool is_edge_ctx = e_dest != OUT_OF_CONTEXT; - if (is_vert_ctx) { - vert_ctx_len++; - } if (is_vert_ctx || is_edge_ctx) { WeldLoop wl{}; wl.vert = is_vert_ctx ? v_dest : v; @@ -845,10 +840,12 @@ static void weld_poly_loop_ctx_alloc(Span polys, wpoly.append(wp); poly_map[i] = wpoly_len++; - if (totloop > 5 && vert_ctx_len > 1) { - int max_new = (totloop / 3) - 1; - vert_ctx_len /= 2; - maybe_new_poly += MIN2(max_new, vert_ctx_len); + if (totloop > 5 && loops_len > 1) { + /* We could be smarter here and actually count how many new polygons will be created. + * But counting this can be inefficient as it depends on the number of non-consecutive + * self polygon merges. For now just estimate a maximum value. */ + int max_new = std::min((totloop / 3), loops_len) - 1; + maybe_new_poly += max_new; CLAMP_MIN(max_ctx_poly_len, totloop); } } @@ -1115,8 +1112,11 @@ static int poly_find_doubles(const OffsetIndices poly_corners_offsets, { /* Fills the `r_buffer` buffer with the intersection of the arrays in `buffer_a` and `buffer_b`. * `buffer_a` and `buffer_b` have a sequence of sorted, non-repeating indices representing - * polygons. */ - const auto intersect = [](const Span buffer_a, const Span buffer_b, int *r_buffer) { + * polygons. */ + const auto intersect = [](const Span buffer_a, + const Span buffer_b, + const BitVector<> &is_double, + int *r_buffer) { int result_num = 0; int index_a = 0, index_b = 0; while (index_a < buffer_a.size() && index_b < buffer_b.size()) { @@ -1130,7 +1130,12 @@ static int poly_find_doubles(const OffsetIndices poly_corners_offsets, } else { /* Equality. */ - r_buffer[result_num++] = value_a; + + /* Do not add duplicates. + * As they are already in the original array, this can cause buffer overflow. */ + if (!is_double[value_a]) { + r_buffer[result_num++] = value_a; + } index_a++; index_b++; } @@ -1217,6 +1222,7 @@ static int poly_find_doubles(const OffsetIndices poly_corners_offsets, int *isect_result = doubles_buffer.data() + doubles_buffer_num + 1; + /* `polys_a` are the polygons connected to the first corner. So skip the first corner. */ for (int corner_index : IndexRange(corner_first + 1, corner_num - 1)) { elem_index = corners[corner_index]; link_offs = linked_polys_offset[elem_index]; @@ -1230,8 +1236,10 @@ static int poly_find_doubles(const OffsetIndices poly_corners_offsets, polys_b_num--; } while (poly_to_test != poly_index); - doubles_num = intersect( - Span{polys_a, polys_a_num}, Span{polys_b, polys_b_num}, isect_result); + doubles_num = intersect(Span{polys_a, polys_a_num}, + Span{polys_b, polys_b_num}, + is_double, + isect_result); if (doubles_num == 0) { break; @@ -1249,6 +1257,12 @@ static int poly_find_doubles(const OffsetIndices poly_corners_offsets, } doubles_buffer_num += doubles_num; doubles_offsets.append(++doubles_buffer_num); + + if ((doubles_buffer_num + 1) == poly_num) { + /* The last slot is the remaining unduplicated polygon. + * Avoid checking intersection as there are no more slots left. */ + break; + } } } diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc index 052cd4c5171..6032b19ac25 100644 --- a/source/blender/geometry/intern/mesh_primitive_cuboid.cc +++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc @@ -8,7 +8,7 @@ #include "DNA_meshdata_types.h" #include "BKE_geometry_set.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "GEO_mesh_primitive_cuboid.hh" @@ -407,6 +407,7 @@ Mesh *create_cuboid_mesh(const float3 &size, MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); calculate_positions(config, positions); @@ -417,6 +418,9 @@ Mesh *create_cuboid_mesh(const float3 &size, calculate_uvs(config, mesh, uv_id); } + const float3 bounds = size * 0.5f; + mesh->bounds_set_eager({-bounds, bounds}); + return mesh; } diff --git a/source/blender/geometry/intern/mesh_split_edges.cc b/source/blender/geometry/intern/mesh_split_edges.cc index 91b28652bbe..506f7355111 100644 --- a/source/blender/geometry/intern/mesh_split_edges.cc +++ b/source/blender/geometry/intern/mesh_split_edges.cc @@ -6,7 +6,7 @@ #include "BKE_attribute.hh" #include "BKE_attribute_math.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "GEO_mesh_split_edges.hh" @@ -135,11 +135,11 @@ static void add_new_edges(Mesh &mesh, CustomData_free(&mesh.edata, mesh.totedge); mesh.totedge = new_edges.size(); - CustomData_add_layer(&mesh.edata, CD_MEDGE, CD_CONSTRUCT, nullptr, mesh.totedge); + CustomData_add_layer(&mesh.edata, CD_MEDGE, CD_CONSTRUCT, mesh.totedge); mesh.edges_for_write().copy_from(new_edges); if (new_orig_indices != nullptr) { - CustomData_add_layer(&mesh.edata, CD_ORIGINDEX, CD_ASSIGN, new_orig_indices, mesh.totedge); + CustomData_add_layer_with_data(&mesh.edata, CD_ORIGINDEX, new_orig_indices, mesh.totedge); } for (NewAttributeData &new_data : dst_attributes) { diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 22c925a1310..e3b630c37b0 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -12,7 +12,7 @@ #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_geometry_set.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "GEO_mesh_to_curve.hh" diff --git a/source/blender/geometry/intern/mesh_to_volume.cc b/source/blender/geometry/intern/mesh_to_volume.cc index ba3b47f47ad..d098f6ce584 100644 --- a/source/blender/geometry/intern/mesh_to_volume.cc +++ b/source/blender/geometry/intern/mesh_to_volume.cc @@ -2,7 +2,7 @@ #include "BLI_math_matrix.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_volume.h" diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 6359dc7a2aa..3a6b92c6e93 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -19,7 +19,7 @@ #include "BKE_geometry_set_instances.hh" #include "BKE_instances.hh" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "BKE_type_conversions.hh" @@ -846,7 +846,6 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate( options.propagation_info, attributes_to_propagate); attributes_to_propagate.remove("position"); - attributes_to_propagate.remove("shade_smooth"); r_create_id = attributes_to_propagate.pop_try("id").has_value(); r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value(); OrderedAttributes ordered_attributes; diff --git a/source/blender/geometry/intern/trim_curves.cc b/source/blender/geometry/intern/trim_curves.cc index 810f950158a..d4b6f8d34ad 100644 --- a/source/blender/geometry/intern/trim_curves.cc +++ b/source/blender/geometry/intern/trim_curves.cc @@ -548,7 +548,7 @@ static void sample_interval_bezier(const Span src_positions, } } else { - /* General case, compute the insertion point. */ + /* General case, compute the insertion point. */ end_point_insert = knot_insert_bezier( src_positions, src_handles_l, src_handles_r, end_point); @@ -1063,7 +1063,7 @@ bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves, dst_curves.attributes_for_write().remove("cyclic"); } else { - /* Only trimmed curves are no longer cyclic. */ + /* Only trimmed curves are no longer cyclic. */ if (bke::SpanAttributeWriter cyclic = dst_attributes.lookup_for_write_span("cyclic")) { cyclic.span.fill_indices(selection, false); cyclic.finish(); diff --git a/source/blender/geometry/intern/uv_pack.cc b/source/blender/geometry/intern/uv_pack.cc index 7768770b1c6..b6de169ff20 100644 --- a/source/blender/geometry/intern/uv_pack.cc +++ b/source/blender/geometry/intern/uv_pack.cc @@ -6,11 +6,13 @@ #include "GEO_uv_pack.hh" +#include "BLI_array.hh" #include "BLI_boxpack_2d.h" #include "BLI_convexhull_2d.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" +#include "BLI_vector.hh" #include "DNA_meshdata_types.h" #include "DNA_scene_types.h" @@ -20,21 +22,172 @@ namespace blender::geometry { -static float pack_islands_scale_margin(const Span &island_vector, +UVPackIsland_Params::UVPackIsland_Params() +{ + /* TEMPORARY, set every thing to "zero" for backwards compatibility. */ + rotate = false; + only_selected_uvs = false; + only_selected_faces = false; + use_seams = false; + correct_aspect = false; + ignore_pinned = false; + pin_unselected = false; + margin = 0.001f; + margin_method = ED_UVPACK_MARGIN_SCALED; + udim_base_offset[0] = 0.0f; + udim_base_offset[1] = 0.0f; +} + +/* Compact representation for AABB packers. */ +class UVAABBIsland { + public: + float2 uv_diagonal; + float2 uv_placement; + int64_t index; +}; + +/** + * Pack AABB islands using the "Alpaca" strategy, with no rotation. + * + * Each box is packed into an "L" shaped region, gradually filling up space. + * "Alpaca" is a pun, as it's pronounced the same as "L-Packer" in English. + * + * In theory, alpaca_turbo should be the fastest non-trivial packer, hence the "turbo" suffix. + * + * Technically, the algorithm here is only `O(n)`, In practice, to get reasonable results, + * the input must be pre-sorted, which costs an additional `O(nlogn)` time complexity. + */ +static void pack_islands_alpaca_turbo(const Span islands, + float *r_max_u, + float *r_max_v) +{ + /* Exclude an initial AABB near the origin. */ + float next_u1 = *r_max_u; + float next_v1 = *r_max_v; + bool zigzag = next_u1 < next_v1; /* Horizontal or Vertical strip? */ + + float u0 = zigzag ? next_u1 : 0.0f; + float v0 = zigzag ? 0.0f : next_v1; + + /* Visit every island in order. */ + for (UVAABBIsland *island : islands) { + float dsm_u = island->uv_diagonal.x; + float dsm_v = island->uv_diagonal.y; + + bool restart = false; + if (zigzag) { + restart = (next_v1 < v0 + dsm_v); + } + else { + restart = (next_u1 < u0 + dsm_u); + } + if (restart) { + /* We're at the end of a strip. Restart from U axis or V axis. */ + zigzag = next_u1 < next_v1; + u0 = zigzag ? next_u1 : 0.0f; + v0 = zigzag ? 0.0f : next_v1; + } + + /* Place the island. */ + island->uv_placement.x = u0; + island->uv_placement.y = v0; + if (zigzag) { + /* Move upwards. */ + v0 += dsm_v; + next_u1 = max_ff(next_u1, u0 + dsm_u); + next_v1 = max_ff(next_v1, v0); + } + else { + /* Move sideways. */ + u0 += dsm_u; + next_v1 = max_ff(next_v1, v0 + dsm_v); + next_u1 = max_ff(next_u1, u0); + } + } + + /* Write back total pack AABB. */ + *r_max_u = next_u1; + *r_max_v = next_v1; +} + +static float pack_islands_scale_margin(const Span islands, BoxPack *box_array, const float scale, const float margin) { - for (const int64_t index : island_vector.index_range()) { - PackIsland *island = island_vector[index]; - BoxPack *box = &box_array[index]; - box->index = int(index); - box->w = BLI_rctf_size_x(&island->bounds_rect) * scale + 2 * margin; - box->h = BLI_rctf_size_y(&island->bounds_rect) * scale + 2 * margin; + /* #BLI_box_pack_2d produces layouts with high packing efficiency, but has `O(n^3)` + * time complexity, causing poor performance if there are lots of islands. See: #102843. + * #pack_islands_alpaca_turbo is designed to be the fastest packing method, `O(nlogn)`, + * but has poor packing efficiency if the AABBs have a spread of sizes and aspect ratios. + * Here, we merge the best properties of both packers into one combined packer. + * + * The free tuning parameter, `alpaca_cutoff` will determine how many islands are packed + * using each method. + * + * The current strategy is: + * - Sort islands in size order. + * - Call #BLI_box_pack_2d on the first `alpaca_cutoff` islands. + * - Call #pack_islands_alpaca_turbo on the remaining islands. + * - Combine results. + */ + + /* First, copy information from our input into the AABB structure. */ + Array aabbs(islands.size()); + for (const int64_t i : islands.index_range()) { + PackIsland *pack_island = islands[i]; + UVAABBIsland *aabb = new UVAABBIsland(); + aabb->index = i; + aabb->uv_diagonal.x = BLI_rctf_size_x(&pack_island->bounds_rect) * scale + 2 * margin; + aabb->uv_diagonal.y = BLI_rctf_size_y(&pack_island->bounds_rect) * scale + 2 * margin; + aabbs[i] = aabb; } - float max_u, max_v; - BLI_box_pack_2d(box_array, int(island_vector.size()), &max_u, &max_v); - return max_ff(max_u, max_v); + + /* Sort from "biggest" to "smallest". */ + std::stable_sort(aabbs.begin(), aabbs.end(), [](const UVAABBIsland *a, const UVAABBIsland *b) { + /* Just choose the AABB with larger rectangular area. */ + return b->uv_diagonal.x * b->uv_diagonal.y < a->uv_diagonal.x * a->uv_diagonal.y; + }); + + /* Partition island_vector, largest will go to box_pack, the rest alpaca_turbo. + * See discussion above for details. */ + const int64_t alpaca_cutoff = int64_t(1024); /* TODO: Tune constant. */ + int64_t max_box_pack = std::min(alpaca_cutoff, islands.size()); + + /* Prepare for box_pack_2d. */ + for (const int64_t i : islands.index_range()) { + UVAABBIsland *aabb = aabbs[i]; + BoxPack *box = &box_array[i]; + box->index = int(aabb->index); + box->w = aabb->uv_diagonal.x; + box->h = aabb->uv_diagonal.y; + } + + /* Call box_pack_2d (slow for large N.) */ + float max_u = 0.0f; + float max_v = 0.0f; + BLI_box_pack_2d(box_array, int(max_box_pack), &max_u, &max_v); + + /* At this stage, `max_u` and `max_v` contain the box_pack UVs. */ + + /* Call Alpaca. */ + pack_islands_alpaca_turbo(aabbs.as_span().drop_front(max_box_pack), &max_u, &max_v); + + /* Write back Alpaca UVs. */ + for (int64_t index = max_box_pack; index < aabbs.size(); index++) { + UVAABBIsland *aabb = aabbs[index]; + BoxPack *box = &box_array[index]; + box->x = aabb->uv_placement.x; + box->y = aabb->uv_placement.y; + } + + /* Memory management. */ + for (int64_t i : aabbs.index_range()) { + UVAABBIsland *aabb = aabbs[i]; + aabbs[i] = nullptr; + delete aabb; + } + + return std::max(max_u, max_v); } static float pack_islands_margin_fraction(const Span &island_vector, @@ -102,7 +255,7 @@ static float pack_islands_margin_fraction(const Span &island_vecto } } - scale = max_ff(scale, min_scale_roundoff); + scale = std::max(scale, min_scale_roundoff); /* Evaluate our `f`. */ scale_last = scale; @@ -164,9 +317,9 @@ static float calc_margin_from_aabb_length_sum(const Span &island_v return params.margin * aabb_length_sum * 0.1f; } -BoxPack *pack_islands(const Span &island_vector, - const UVPackIsland_Params ¶ms, - float r_scale[2]) +static BoxPack *pack_islands_box_array(const Span &island_vector, + const UVPackIsland_Params ¶ms, + float r_scale[2]) { BoxPack *box_array = static_cast( MEM_mallocN(sizeof(*box_array) * island_vector.size(), __func__)); @@ -213,4 +366,20 @@ BoxPack *pack_islands(const Span &island_vector, return box_array; } +void pack_islands(const Span &islands, + const UVPackIsland_Params ¶ms, + float r_scale[2]) +{ + BoxPack *box_array = pack_islands_box_array(islands, params, r_scale); + + for (int64_t i : islands.index_range()) { + BoxPack *box = box_array + i; + PackIsland *island = islands[box->index]; + island->pre_translate.x = box->x - island->bounds_rect.xmin; + island->pre_translate.y = box->y - island->bounds_rect.ymin; + } + + MEM_freeN(box_array); +} + } // namespace blender::geometry diff --git a/source/blender/geometry/intern/uv_parametrizer.cc b/source/blender/geometry/intern/uv_parametrizer.cc index cf39fe1f422..4e461181051 100644 --- a/source/blender/geometry/intern/uv_parametrizer.cc +++ b/source/blender/geometry/intern/uv_parametrizer.cc @@ -3957,49 +3957,48 @@ void uv_parametrizer_edge_set_seam(ParamHandle *phandle, ParamKey *vkeys) } void uv_parametrizer_construct_end(ParamHandle *phandle, - bool fill, + bool fill_holes, bool topology_from_uvs, - int *count_fail) + int *r_count_failed) { - PChart *chart = phandle->construction_chart; int i, j; - PEdge *outer; param_assert(phandle->state == PHANDLE_STATE_ALLOCATED); phandle->ncharts = p_connect_pairs(phandle, topology_from_uvs); - phandle->charts = p_split_charts(phandle, chart, phandle->ncharts); + phandle->charts = p_split_charts(phandle, phandle->construction_chart, phandle->ncharts); MEM_freeN(phandle->construction_chart); phandle->construction_chart = nullptr; phash_delete(phandle->hash_verts); + phandle->hash_verts = nullptr; phash_delete(phandle->hash_edges); + phandle->hash_edges = nullptr; phash_delete(phandle->hash_faces); - phandle->hash_verts = phandle->hash_edges = phandle->hash_faces = nullptr; + phandle->hash_faces = nullptr; for (i = j = 0; i < phandle->ncharts; i++) { - PVert *v; - chart = phandle->charts[i]; + PChart *chart = phandle->charts[i]; + PEdge *outer; p_chart_boundaries(chart, &outer); if (!topology_from_uvs && chart->nboundaries == 0) { MEM_freeN(chart); - if (count_fail != nullptr) { - *count_fail += 1; + if (r_count_failed) { + *r_count_failed += 1; } continue; } - phandle->charts[j] = chart; - j++; + phandle->charts[j++] = chart; - if (fill && (chart->nboundaries > 1)) { + if (fill_holes && chart->nboundaries > 1) { p_chart_fill_boundaries(phandle, chart, outer); } - for (v = chart->verts; v; v = v->nextlink) { + for (PVert *v = chart->verts; v; v = v->nextlink) { p_vert_load_pin_select_uvs(phandle, v); } } @@ -4168,6 +4167,7 @@ void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, boo } geometry::PackIsland *pack_island = new geometry::PackIsland(); + pack_island->caller_index = i; pack_island_vector.append(pack_island); float minv[2]; @@ -4179,62 +4179,35 @@ void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, boo pack_island->bounds_rect.ymax = maxv[1]; } - UVPackIsland_Params params{}; + UVPackIsland_Params params; params.rotate = do_rotate; - params.only_selected_uvs = false; - params.only_selected_faces = false; - params.use_seams = false; - params.correct_aspect = false; - params.ignore_pinned = false; - params.pin_unselected = false; params.margin = margin; params.margin_method = ED_UVPACK_MARGIN_SCALED; - params.udim_base_offset[0] = 0.0f; - params.udim_base_offset[1] = 0.0f; float scale[2] = {1.0f, 1.0f}; - BoxPack *box_array = pack_islands(pack_island_vector, params, scale); + pack_islands(pack_island_vector, params, scale); for (int64_t i : pack_island_vector.index_range()) { - BoxPack *box = box_array + i; - PackIsland *pack_island = pack_island_vector[box->index]; - pack_island->bounds_rect.xmin = box->x; - pack_island->bounds_rect.ymin = box->y; - pack_island->bounds_rect.xmax = box->x + box->w; - pack_island->bounds_rect.ymax = box->y + box->h; - } - - unpacked = 0; - for (int i = 0; i < handle->ncharts; i++) { - PChart *chart = handle->charts[i]; - - if (ignore_pinned && chart->has_pins) { - unpacked++; - continue; - } - PackIsland *pack_island = pack_island_vector[i - unpacked]; - - float minv[2]; - float maxv[2]; - p_chart_uv_bbox(chart, minv, maxv); + PackIsland *pack_island = pack_island_vector[i]; + PChart *chart = handle->charts[pack_island->caller_index]; /* TODO: Replace with #mul_v2_m2_add_v2v2 here soon. */ float m[2]; float b[2]; m[0] = scale[0]; m[1] = scale[1]; - b[0] = pack_island->bounds_rect.xmin - minv[0]; - b[1] = pack_island->bounds_rect.ymin - minv[1]; + b[0] = pack_island->pre_translate.x; + b[1] = pack_island->pre_translate.y; for (PVert *v = chart->verts; v; v = v->nextlink) { /* Unusual accumulate-and-multiply here (will) reduce round-off error. */ v->uv[0] = m[0] * (v->uv[0] + b[0]); v->uv[1] = m[1] * (v->uv[1] + b[1]); } - pack_island_vector[i - unpacked] = nullptr; + pack_island_vector[i] = nullptr; delete pack_island; } - MEM_freeN(box_array); + if (handle->aspx != handle->aspy) { uv_parametrizer_scale(handle, handle->aspx, handle->aspy); } diff --git a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h index 2f3cf4d2312..58ccc2299bd 100644 --- a/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h +++ b/source/blender/gpencil_modifiers/MOD_gpencil_modifiertypes.h @@ -6,7 +6,7 @@ #pragma once -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" /* ****************** Type structures for all modifiers ****************** */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c index 7b2d44c2853..1605da90c6c 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c @@ -10,7 +10,7 @@ #include "MEM_guardedalloc.h" #include "BKE_context.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_material.h" #include "BKE_screen.h" @@ -40,7 +40,7 @@ static bool gpencil_modifier_ui_poll(const bContext *C, PanelType *UNUSED(pt)) { Object *ob = ED_object_active_context(C); - return (ob != NULL) && (ob->type == OB_GPENCIL); + return (ob != NULL) && (ob->type == OB_GPENCIL_LEGACY); } /* -------------------------------------------------------------------- */ diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index d4ada842d0b..8707eae7fa6 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -11,15 +11,15 @@ #include "BLI_math_vector.h" #include "BLI_utildefines.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "BKE_deform.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_material.h" #include "BKE_scene.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c index a3665920d15..2b8c0d99b05 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarmature.c @@ -14,8 +14,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -23,9 +23,9 @@ #include "BKE_armature.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index c8ab376bed9..8e949292b11 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -18,16 +18,16 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c index 5daa45aba99..05eb80c0bef 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilbuild.c @@ -20,8 +20,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -29,9 +29,9 @@ #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c index 9a237630bc8..da33312d0b5 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilcolor.c @@ -15,15 +15,15 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_colortools.h" #include "BKE_context.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c index dfb859542f5..ffbb8d9c1f0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencildash.c @@ -13,16 +13,16 @@ #include "BLI_string.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c index 8a88cc0a01e..5c7400292ed 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilenvelope.c @@ -15,8 +15,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -24,9 +24,9 @@ #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c index 04b4ca469af..dc41cc9401f 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilhook.c @@ -17,8 +17,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" #include "DNA_object_types.h" @@ -29,8 +29,8 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c index 051ad2cd1bb..88a3e8164d0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillattice.c @@ -14,8 +14,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -23,8 +23,8 @@ #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lattice.h" #include "BKE_lib_query.h" #include "BKE_main.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c index a6e8d417699..b0a54cb7837 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillength.c @@ -17,15 +17,15 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c index 995dc268123..5546524cccb 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencillineart.c @@ -14,8 +14,8 @@ #include "DNA_collection_types.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -24,8 +24,8 @@ #include "BKE_collection.h" #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c index 65c5c2a8b37..747dcc239ce 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmirror.c @@ -15,16 +15,16 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c index ad0fd915c81..6ae2c323c81 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilmultiply.c @@ -10,8 +10,8 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -23,9 +23,9 @@ #include "BLT_translation.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c index 100df37f402..40394dc09cc 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilnoise.c @@ -17,8 +17,8 @@ #include "MEM_guardedalloc.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" @@ -26,9 +26,9 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c index 58ca9de38c6..e787073cda5 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloffset.c @@ -19,8 +19,8 @@ #include "BLI_math.h" #include "BLI_rand.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" @@ -28,8 +28,8 @@ #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c index 34ae3b460a4..a06c7817f17 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilopacity.c @@ -13,8 +13,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" @@ -22,7 +22,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c index 32a54bbee4c..c71de59bd49 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciloutline.c @@ -15,17 +15,17 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c index ae0eb5a0a25..c4ac6f680e6 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilshrinkwrap.c @@ -15,8 +15,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -24,8 +24,8 @@ #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c index f1826c3a59d..231da156c84 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsimplify.c @@ -14,14 +14,14 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c index cba7895c85d..1a60359e7f3 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsmooth.c @@ -14,8 +14,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" @@ -23,8 +23,8 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c index 091d9b42bb1..f68ebebd7d2 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilsubdiv.c @@ -14,14 +14,14 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c index 6d1166e9f5b..1b7efc79457 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltexture.c @@ -14,16 +14,16 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c index cd683544a42..ea754ef8b20 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilthick.c @@ -14,8 +14,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" @@ -23,7 +23,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c index 490efecdeb5..4ef6dd2c30a 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltime.c @@ -19,17 +19,17 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_modifier.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c index 7ca28e69886..da9a833e390 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpenciltint.c @@ -15,8 +15,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_material_types.h" #include "DNA_meshdata_types.h" #include "DNA_modifier_types.h" @@ -28,7 +28,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c index ac56b88d221..237fc6e5afb 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_angle.c @@ -14,16 +14,16 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c index f0c7632e828..76d2d1692bc 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilweight_proximity.c @@ -14,8 +14,8 @@ #include "BLT_translation.h" #include "DNA_defaults.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" @@ -23,8 +23,8 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_query.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc index 046e480e0eb..b9b6b5c2eb5 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc @@ -27,12 +27,12 @@ #include "BKE_duplilist.h" #include "BKE_editmesh.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_object.h" @@ -41,7 +41,7 @@ #include "DEG_depsgraph_query.h" #include "DNA_camera_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -1481,6 +1481,7 @@ struct EdgeFeatData { blender::Span looptris; LineartTriangle *tri_array; blender::VArray sharp_edges; + blender::VArray sharp_faces; LineartVert *v_array; float crease_threshold; bool use_auto_smooth; @@ -1648,8 +1649,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, if (ld->conf.use_crease) { bool do_crease = true; if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth && - (e_feat_data->polys[looptris[f1].poly].flag & ME_SMOOTH) && - (e_feat_data->polys[looptris[f2].poly].flag & ME_SMOOTH)) { + (!e_feat_data->sharp_faces[looptris[f1].poly]) && + (!e_feat_data->sharp_faces[looptris[f2].poly])) { do_crease = false; } if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < e_feat_data->crease_threshold)) { @@ -2092,6 +2093,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, const bke::AttributeAccessor attributes = me->attributes(); const VArray sharp_edges = attributes.lookup_or_default( "sharp_edge", ATTR_DOMAIN_EDGE, false); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); EdgeFeatData edge_feat_data = {nullptr}; edge_feat_data.ld = la_data; @@ -2103,6 +2106,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, edge_feat_data.loops = me->loops(); edge_feat_data.looptris = looptris; edge_feat_data.sharp_edges = sharp_edges; + edge_feat_data.sharp_faces = sharp_faces; edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges); edge_feat_data.tri_array = la_tri_arr; edge_feat_data.v_array = la_v_arr; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c index 45ceb646361..e89e9b58805 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_ops.c @@ -15,8 +15,8 @@ #include "BKE_context.h" #include "BKE_global.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_legacy.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -25,8 +25,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "MOD_gpencil_lineart.h" @@ -174,7 +174,7 @@ typedef struct LineartBakeJob { static bool lineart_gpencil_bake_single_target(LineartBakeJob *bj, Object *ob, int frame) { bool touched = false; - if (ob->type != OB_GPENCIL || G.is_break) { + if (ob->type != OB_GPENCIL_LEGACY || G.is_break) { return false; } @@ -285,7 +285,7 @@ static int lineart_gpencil_bake_common(bContext *C, if (!bake_all_targets) { Object *ob = CTX_data_active_object(C); - if (!ob || ob->type != OB_GPENCIL) { + if (!ob || ob->type != OB_GPENCIL_LEGACY) { WM_report(RPT_ERROR, "No active object or active object isn't a GPencil object."); return OPERATOR_FINISHED; } @@ -294,7 +294,7 @@ static int lineart_gpencil_bake_common(bContext *C, else { /* #CTX_DATA_BEGIN is not available for iterating in objects while using the job system. */ CTX_DATA_BEGIN (C, Object *, ob, visible_objects) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { if (md->type == eGpencilModifierType_Lineart) { BLI_linklist_prepend(&bj->objects, ob); @@ -384,7 +384,7 @@ static int lineart_gpencil_bake_strokes_commom_modal(bContext *C, static void lineart_gpencil_clear_strokes_exec_common(Object *ob) { /* TODO: move these checks to an operator poll function. */ - if ((ob == NULL) || ob->type != OB_GPENCIL) { + if ((ob == NULL) || ob->type != OB_GPENCIL_LEGACY) { return; } LISTBASE_FOREACH (GpencilModifierData *, md, &ob->greasepencil_modifiers) { diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c index 19bc69b5566..5d1e43ffe21 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_shadow.c @@ -10,14 +10,14 @@ #include "lineart_intern.h" #include "BKE_global.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_lib_id.h" #include "BKE_material.h" #include "BKE_object.h" #include "BKE_scene.h" #include "DEG_depsgraph_query.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index ee14eab1920..bfc0a1b3c7a 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -410,6 +410,7 @@ set(GLSL_SRC shaders/gpu_shader_codegen_lib.glsl + shaders/common/gpu_shader_bicubic_sampler_lib.glsl shaders/common/gpu_shader_common_color_ramp.glsl shaders/common/gpu_shader_common_color_utils.glsl shaders/common/gpu_shader_common_curves.glsl @@ -605,6 +606,7 @@ set(SRC_SHADER_CREATE_INFOS ../draw/engines/eevee_next/shaders/infos/eevee_depth_of_field_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_film_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_hiz_info.hh + ../draw/engines/eevee_next/shaders/infos/eevee_irradiance_cache_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_light_culling_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_material_info.hh ../draw/engines/eevee_next/shaders/infos/eevee_motion_blur_info.hh @@ -808,11 +810,11 @@ if(WITH_GTESTS) set(TEST_SRC tests/gpu_testing.cc - tests/gpu_index_buffer_test.cc - tests/gpu_push_constants_test.cc - tests/gpu_shader_builtin_test.cc - tests/gpu_shader_test.cc - tests/gpu_storage_buffer_test.cc + tests/index_buffer_test.cc + tests/push_constants_test.cc + tests/shader_test.cc + tests/storage_buffer_test.cc + tests/texture_test.cc tests/gpu_testing.hh ) diff --git a/source/blender/gpu/GPU_debug.h b/source/blender/gpu/GPU_debug.h index 198dddc9f6c..d4b51bddcff 100644 --- a/source/blender/gpu/GPU_debug.h +++ b/source/blender/gpu/GPU_debug.h @@ -5,6 +5,40 @@ * \ingroup gpu * * Helpers for GPU / drawing debugging. + * + * + ** GPU debug capture usage example: + * + ** Instant frame capture. ** + * + * \code + * #include "GPU_debug.h" + * static void do_render_engine(Render *re) + * { + * GPU_debug_capture_begin(); + * RE_engine_render(re, false); + * GPU_debug_capture_end(); + * } + * \endcode + * + ** Capture scopes. ** + * + * \code + * #include "GPU_debug.h" + * void *capture_scope = nullptr; + * static void do_render_engine(Render *re) + * { + * if (!capture_scope) { + * // Create capture scope which will display in external tool. + * capture_scope = GPU_debug_capture_scope_create("Render Frame"); + * } + * + * // Commands within scope boundary captured when requested in tool. + * GPU_debug_capture_scope_begin(capture_scope); + * RE_engine_render(re, false); + * GPU_debug_capture_scope_end(capture_scope); + * } + * \endcode */ #pragma once @@ -29,6 +63,37 @@ void GPU_debug_get_groups_names(int name_buf_len, char *r_name_buf); */ bool GPU_debug_group_match(const char *ref); +/** + * GPU Frame capture support. + * + * Allows instantaneous frame capture of GPU calls between begin/end. + */ +void GPU_debug_capture_begin(void); +void GPU_debug_capture_end(void); + +/** + * GPU debug frame capture scopes. + * + * Allows creation of a GPU frame capture scope that define a region within which an external GPU + * Frame capture tool can perform a deferred capture of GPU API calls within the boundary upon user + * request. + * + * \param name Unique name of capture scope displayed within capture tool. + * \return pointer wrapping an API-specific capture scope object. + * \note a capture scope should be created a single time and only used within one begin/end pair. + */ +void *GPU_debug_capture_scope_create(const char *name); + +/** + * Used to declare the region within which GPU calls are captured when the scope is triggered. + * + * \param scope Pointer to capture scope object created with GPU_debug_capture_scope_create. + * \return True if the capture tool is actively capturing this scope when function is executed. + * Otherwise, False. + */ +bool GPU_debug_capture_scope_begin(void *scope); +void GPU_debug_capture_scope_end(void *scope); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index c706b10f1dd..a3ebda62126 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -167,11 +167,12 @@ GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser, eGPUSamplerState sampler_state); -GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, - struct Image *ima, - struct ImageUser *iuser, - eGPUSamplerState sampler_state); -GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); +void GPU_image_tiled(GPUMaterial *mat, + struct Image *ima, + struct ImageUser *iuser, + eGPUSamplerState sampler_state, + GPUNodeLink **r_image_tiled_link, + GPUNodeLink **r_image_tiled_mapping_link); GPUNodeLink *GPU_image_sky(GPUMaterial *mat, int width, int height, diff --git a/source/blender/gpu/GPU_storage_buffer.h b/source/blender/gpu/GPU_storage_buffer.h index 8ed60d9000a..1399353b085 100644 --- a/source/blender/gpu/GPU_storage_buffer.h +++ b/source/blender/gpu/GPU_storage_buffer.h @@ -39,12 +39,14 @@ void GPU_storagebuf_bind(GPUStorageBuf *ssbo, int slot); void GPU_storagebuf_unbind(GPUStorageBuf *ssbo); void GPU_storagebuf_unbind_all(void); -void GPU_storagebuf_clear(GPUStorageBuf *ssbo, - eGPUTextureFormat internal_format, - eGPUDataFormat data_format, - void *data); void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo); +/** + * Clear the content of the buffer using the given #clear_value. #clear_value will be used as a + * repeatable pattern of 32bits. + */ +void GPU_storagebuf_clear(GPUStorageBuf *ssbo, uint32_t clear_value); + /** * Read back content of the buffer to CPU for inspection. * Slow! Only use for inspection / debugging. diff --git a/source/blender/gpu/intern/gpu_codegen.cc b/source/blender/gpu/intern/gpu_codegen.cc index 5c2b81f4b84..eb3fec6afd3 100644 --- a/source/blender/gpu/intern/gpu_codegen.cc +++ b/source/blender/gpu/intern/gpu_codegen.cc @@ -99,6 +99,8 @@ struct GPUPass { /** Hint that an optimized variant of this pass should be created based on a complexity heuristic * during pass code generation. */ bool should_optimize; + /** Whether pass is in the GPUPass cache. */ + bool cached; }; /* -------------------------------------------------------------------- */ @@ -132,6 +134,7 @@ static GPUPass *gpu_pass_cache_lookup(uint32_t hash) static void gpu_pass_cache_insert_after(GPUPass *node, GPUPass *pass) { BLI_spin_lock(&pass_cache_spin); + pass->cached = true; if (node != nullptr) { /* Add after the first pass having the same hash. */ pass->next = node->next; @@ -775,6 +778,7 @@ GPUPass *GPU_generate_pass(GPUMaterial *material, pass->create_info = codegen.create_info; pass->hash = codegen.hash_get(); pass->compiled = false; + pass->cached = false; /* Only flag pass optimization hint if this is the first generated pass for a material. * Optimized passes cannot be optimized further, even if the heuristic is still not * favorable. */ @@ -881,14 +885,6 @@ GPUShader *GPU_pass_shader_get(GPUPass *pass) return pass->shader; } -void GPU_pass_release(GPUPass *pass) -{ - BLI_spin_lock(&pass_cache_spin); - BLI_assert(pass->refcount > 0); - pass->refcount--; - BLI_spin_unlock(&pass_cache_spin); -} - static void gpu_pass_free(GPUPass *pass) { BLI_assert(pass->refcount == 0); @@ -899,6 +895,18 @@ static void gpu_pass_free(GPUPass *pass) MEM_freeN(pass); } +void GPU_pass_release(GPUPass *pass) +{ + BLI_spin_lock(&pass_cache_spin); + BLI_assert(pass->refcount > 0); + pass->refcount--; + /* Un-cached passes will not be filtered by garbage collection, so release here. */ + if (pass->refcount == 0 && !pass->cached) { + gpu_pass_free(pass); + } + BLI_spin_unlock(&pass_cache_spin); +} + void GPU_pass_cache_garbage_collect(void) { static int lasttime = 0; diff --git a/source/blender/gpu/intern/gpu_context_private.hh b/source/blender/gpu/intern/gpu_context_private.hh index 2217e5262ed..73791a5c54b 100644 --- a/source/blender/gpu/intern/gpu_context_private.hh +++ b/source/blender/gpu/intern/gpu_context_private.hh @@ -47,6 +47,7 @@ class Context { FrameBuffer *front_right = nullptr; DebugStack debug_stack; + bool debug_is_capturing = false; /* GPUContext counter used to assign a unique ID to each GPUContext. * NOTE(Metal): This is required by the Metal Backend, as a bug exists in the global OS shader @@ -84,6 +85,13 @@ class Context { virtual void debug_group_begin(const char *, int){}; virtual void debug_group_end(){}; + /* Returns true if capture successfully started. */ + virtual bool debug_capture_begin() = 0; + virtual void debug_capture_end() = 0; + virtual void *debug_capture_scope_create(const char *name) = 0; + virtual bool debug_capture_scope_begin(void *scope) = 0; + virtual void debug_capture_scope_end(void *scope) = 0; + bool is_active_on_thread(); }; diff --git a/source/blender/gpu/intern/gpu_debug.cc b/source/blender/gpu/intern/gpu_debug.cc index 055207eace8..d40e5a02a73 100644 --- a/source/blender/gpu/intern/gpu_debug.cc +++ b/source/blender/gpu/intern/gpu_debug.cc @@ -73,3 +73,96 @@ bool GPU_debug_group_match(const char *ref) } return false; } + +void GPU_debug_capture_begin() +{ + /* GPU Frame capture is only enabled when --debug-gpu is specified. */ + if (!(G.debug & G_DEBUG_GPU)) { + return; + } + + Context *ctx = Context::get(); + if (ctx && !ctx->debug_is_capturing) { + ctx->debug_is_capturing = ctx->debug_capture_begin(); + if (!ctx->debug_is_capturing) { + printf("Failed to start GPU frame capture!\n"); + } + /* Call GPU_finish to ensure all desired GPU commands occur within the capture boundary. */ + GPU_finish(); + } +} + +void GPU_debug_capture_end() +{ + /* GPU Frame capture is only enabled when --debug-gpu is specified. */ + if (!(G.debug & G_DEBUG_GPU)) { + return; + } + + Context *ctx = Context::get(); + if (ctx && ctx->debug_is_capturing) { + /* Call GPU_finish to ensure all desired GPU commands occur within the capture boundary. */ + GPU_finish(); + ctx->debug_capture_end(); + ctx->debug_is_capturing = false; + } +} + +void *GPU_debug_capture_scope_create(const char *name) +{ + /* GPU Frame capture is only enabled when --debug-gpu is specified. */ + if (!(G.debug & G_DEBUG_GPU)) { + return nullptr; + } + + Context *ctx = Context::get(); + if (!ctx) { + return nullptr; + } + return ctx->debug_capture_scope_create(name); +} + +bool GPU_debug_capture_scope_begin(void *scope) +{ + /* Early exit if scope does not exist or not in debug mode. */ + if (!(G.debug & G_DEBUG_GPU) || !scope) { + return false; + } + + Context *ctx = Context::get(); + if (!ctx) { + return false; + } + + /* Declare beginning of capture scope region. */ + bool scope_capturing = ctx->debug_capture_scope_begin(scope); + if (scope_capturing && !ctx->debug_is_capturing) { + /* Call GPU_finish to ensure all desired GPU commands occur within the capture boundary. */ + GPU_finish(); + ctx->debug_is_capturing = true; + } + return ctx->debug_is_capturing; +} + +void GPU_debug_capture_scope_end(void *scope) +{ + /* Early exit if scope does not exist or not in debug mode. */ + if (!(G.debug & G_DEBUG_GPU) || !scope) { + return; + } + + Context *ctx = Context::get(); + if (!ctx) { + return; + } + + /* If capturing, call GPU_finish to ensure all desired GPU commands occur within the capture + * boundary. */ + if (ctx->debug_is_capturing) { + GPU_finish(); + ctx->debug_is_capturing = false; + } + + /* Declare end of capture scope region. */ + ctx->debug_capture_scope_end(scope); +} diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index c216124824c..c464cf55e86 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -1006,7 +1006,7 @@ void GPU_material_optimize(GPUMaterial *mat) * NOTE(Threading): Need to verify if GPU_generate_pass can cause side-effects, especially when * used with "thunk". So far, this appears to work, and deferring optimized pass creation is more * optimal, as these do not benefit from caching, due to baked constants. However, this could - * possibly be cause for concern for certain cases. */ + * possibly be cause for concern for certain cases. */ if (!mat->optimized_pass) { mat->optimized_pass = GPU_generate_pass( mat, &mat->graph, mat->optimize_pass_info.callback, mat->optimize_pass_info.thunk, true); diff --git a/source/blender/gpu/intern/gpu_node_graph.cc b/source/blender/gpu/intern/gpu_node_graph.cc index a00f621d106..6e67d28b352 100644 --- a/source/blender/gpu/intern/gpu_node_graph.cc +++ b/source/blender/gpu/intern/gpu_node_graph.cc @@ -476,7 +476,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, ImageUser *iuser, struct GPUTexture **colorband, struct GPUTexture **sky, - GPUNodeLinkType link_type, + bool is_tiled, eGPUSamplerState sampler_state) { /* Find existing texture. */ @@ -502,7 +502,7 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, tex->sky = sky; tex->sampler_state = sampler_state; BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures); - if (ELEM(link_type, GPU_NODE_LINK_IMAGE_TILED, GPU_NODE_LINK_IMAGE_TILED_MAPPING)) { + if (is_tiled) { BLI_snprintf( tex->tiled_mapping_name, sizeof(tex->tiled_mapping_name), "tsamp%d", num_textures); } @@ -631,7 +631,7 @@ GPUNodeLink *GPU_image(GPUMaterial *mat, GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE; link->texture = gpu_node_graph_add_texture( - graph, ima, iuser, nullptr, nullptr, link->link_type, sampler_state); + graph, ima, iuser, nullptr, nullptr, false, sampler_state); return link; } @@ -648,31 +648,28 @@ GPUNodeLink *GPU_image_sky(GPUMaterial *mat, GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_IMAGE_SKY; link->texture = gpu_node_graph_add_texture( - graph, nullptr, nullptr, nullptr, sky, link->link_type, sampler_state); + graph, nullptr, nullptr, nullptr, sky, false, sampler_state); return link; } -GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, - Image *ima, - ImageUser *iuser, - eGPUSamplerState sampler_state) +void GPU_image_tiled(GPUMaterial *mat, + struct Image *ima, + struct ImageUser *iuser, + eGPUSamplerState sampler_state, + GPUNodeLink **r_image_tiled_link, + GPUNodeLink **r_image_tiled_mapping_link) { GPUNodeGraph *graph = gpu_material_node_graph(mat); - GPUNodeLink *link = gpu_node_link_create(); - link->link_type = GPU_NODE_LINK_IMAGE_TILED; - link->texture = gpu_node_graph_add_texture( - graph, ima, iuser, nullptr, nullptr, link->link_type, sampler_state); - return link; -} + GPUMaterialTexture *texture = gpu_node_graph_add_texture( + graph, ima, iuser, nullptr, nullptr, true, sampler_state); -GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, Image *ima, ImageUser *iuser) -{ - GPUNodeGraph *graph = gpu_material_node_graph(mat); - GPUNodeLink *link = gpu_node_link_create(); - link->link_type = GPU_NODE_LINK_IMAGE_TILED_MAPPING; - link->texture = gpu_node_graph_add_texture( - graph, ima, iuser, nullptr, nullptr, link->link_type, GPU_SAMPLER_MAX); - return link; + (*r_image_tiled_link) = gpu_node_link_create(); + (*r_image_tiled_link)->link_type = GPU_NODE_LINK_IMAGE_TILED; + (*r_image_tiled_link)->texture = texture; + + (*r_image_tiled_mapping_link) = gpu_node_link_create(); + (*r_image_tiled_mapping_link)->link_type = GPU_NODE_LINK_IMAGE_TILED_MAPPING; + (*r_image_tiled_mapping_link)->texture = texture; } GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *row) @@ -684,7 +681,7 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro GPUNodeLink *link = gpu_node_link_create(); link->link_type = GPU_NODE_LINK_COLORBAND; link->texture = gpu_node_graph_add_texture( - graph, nullptr, nullptr, colorband, nullptr, link->link_type, GPU_SAMPLER_MAX); + graph, nullptr, nullptr, colorband, nullptr, false, GPU_SAMPLER_MAX); return link; } diff --git a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc index bbd71d4e3fe..2c08d0f4061 100644 --- a/source/blender/gpu/intern/gpu_shader_builder_stubs.cc +++ b/source/blender/gpu/intern/gpu_shader_builder_stubs.cc @@ -16,7 +16,7 @@ #include "BKE_customdata.h" #include "BKE_global.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_node.h" #include "BKE_paint.h" #include "BKE_pbvh.h" @@ -146,14 +146,6 @@ bool paint_is_grid_face_hidden(const uint * /*grid_hidden*/, /* -------------------------------------------------------------------- */ /** \name Stubs of BKE_mesh.h * \{ */ -void BKE_mesh_calc_poly_normal(const struct MPoly * /*polys*/, - const struct MLoop * /*loopstart*/, - const float (*vert_positions)[3], - float[3] /*col*/) -{ - UNUSED_VARS(vert_positions); - BLI_assert_unreachable(); -} void BKE_mesh_looptri_get_real_edges(const struct MEdge * /*edges*/, const struct MLoop * /*loops*/, diff --git a/source/blender/gpu/intern/gpu_storage_buffer.cc b/source/blender/gpu/intern/gpu_storage_buffer.cc index 460a643089c..d82f6fa6237 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer.cc +++ b/source/blender/gpu/intern/gpu_storage_buffer.cc @@ -89,18 +89,14 @@ void GPU_storagebuf_unbind_all() /* FIXME */ } -void GPU_storagebuf_clear(GPUStorageBuf *ssbo, - eGPUTextureFormat internal_format, - eGPUDataFormat data_format, - void *data) -{ - unwrap(ssbo)->clear(internal_format, data_format, data); -} - void GPU_storagebuf_clear_to_zero(GPUStorageBuf *ssbo) { - uint32_t data = 0u; - GPU_storagebuf_clear(ssbo, GPU_R32UI, GPU_DATA_UINT, &data); + GPU_storagebuf_clear(ssbo, 0); +} + +void GPU_storagebuf_clear(GPUStorageBuf *ssbo, uint32_t clear_value) +{ + unwrap(ssbo)->clear(clear_value); } void GPU_storagebuf_copy_sub_from_vertbuf( diff --git a/source/blender/gpu/intern/gpu_storage_buffer_private.hh b/source/blender/gpu/intern/gpu_storage_buffer_private.hh index c05d8dc5b98..6f0a97117ef 100644 --- a/source/blender/gpu/intern/gpu_storage_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_storage_buffer_private.hh @@ -7,6 +7,7 @@ #pragma once +#include "BLI_span.hh" #include "BLI_sys_types.h" struct GPUStorageBuf; @@ -42,9 +43,7 @@ class StorageBuf { virtual void update(const void *data) = 0; virtual void bind(int slot) = 0; virtual void unbind() = 0; - virtual void clear(eGPUTextureFormat internal_format, - eGPUDataFormat data_format, - void *data) = 0; + virtual void clear(uint32_t clear_value) = 0; virtual void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) = 0; virtual void read(void *data) = 0; }; diff --git a/source/blender/gpu/metal/kernels/compute_texture_read.msl b/source/blender/gpu/metal/kernels/compute_texture_read.msl index 41d7b312dbd..6c099024f7a 100644 --- a/source/blender/gpu/metal/kernels/compute_texture_read.msl +++ b/source/blender/gpu/metal/kernels/compute_texture_read.msl @@ -62,11 +62,24 @@ template<> uint denormalize(float val) return uint(float(DEPTH_SCALE_FACTOR) * val); } +/* Float to other type case. */ template T convert_type(float type) { return T(type); } +/* Uint to other types. */ +template T convert_type(uint type) +{ + return T(type); +} + +/* Int to other types. */ +template T convert_type(int type) +{ + return T(type); +} + template<> uchar convert_type(float val) { return uchar(val * float(0xFF)); @@ -141,8 +154,8 @@ kernel void compute_texture_read(constant TextureReadParams ¶ms [[buffer(0)] uint xx = position[0]; uint yy = position[1]; uint zz = position[2]; - int index = (zz * (params.extent[0] * params.extent[1]) + yy * params.extnt[0] + xx) * - COMPONENT_COUNT_INPUT; + int index = (zz * (params.extent[0] * params.extent[1]) + yy * params.extent[0] + xx) * + COMPONENT_COUNT_OUTPUT; read_colour = read_tex.read(uint3(params.offset[0], params.offset[1], params.offset[2]) + uint3(xx, yy, zz)); @@ -163,7 +176,7 @@ kernel void compute_texture_read(constant TextureReadParams ¶ms [[buffer(0)] uint yy = position[1]; uint layer = position[2]; int index = (layer * (params.extent[0] * params.extent[1]) + yy * params.extent[0] + xx) * - COMPONENT_COUNT_INPUT; + COMPONENT_COUNT_OUTPUT; /* Read data */ # if IS_DEPTH_FORMAT == 1 diff --git a/source/blender/gpu/metal/mtl_batch.hh b/source/blender/gpu/metal/mtl_batch.hh index 9e179e662b5..107fbe91c9c 100644 --- a/source/blender/gpu/metal/mtl_batch.hh +++ b/source/blender/gpu/metal/mtl_batch.hh @@ -40,7 +40,7 @@ class MTLBatch : public Batch { VertexBufferID bufferIds[GPU_BATCH_VBO_MAX_LEN] = {}; /* Cache life index compares a cache entry with the active MTLBatch state. * This is initially set to the cache life index of MTLBatch. If the batch has been modified, - * this index is incremented to cheaply invalidate existing cache entries. */ + * this index is incremented to cheaply invalidate existing cache entries. */ uint32_t cache_life_index = 0; }; diff --git a/source/blender/gpu/metal/mtl_batch.mm b/source/blender/gpu/metal/mtl_batch.mm index 07aaa5cfe62..00610eefab0 100644 --- a/source/blender/gpu/metal/mtl_batch.mm +++ b/source/blender/gpu/metal/mtl_batch.mm @@ -619,7 +619,7 @@ void MTLBatch::prepare_vertex_descriptor_and_bindings( * Vertex Descriptors are required to generate a pipeline state, based on the current Batch's * buffer bindings. These bindings are a unique matching, depending on what input attributes a * batch has in its buffers, and those which are supported by the shader interface. - + * * We iterate through the buffers and resolve which attributes satisfy the requirements of the * currently bound shader. We cache this data, for a given Batch<->ShderInterface pairing in a * VAO cache to avoid the need to recalculate this data. */ diff --git a/source/blender/gpu/metal/mtl_context.hh b/source/blender/gpu/metal/mtl_context.hh index 3523cd47614..80103987fca 100644 --- a/source/blender/gpu/metal/mtl_context.hh +++ b/source/blender/gpu/metal/mtl_context.hh @@ -740,6 +740,11 @@ class MTLContext : public Context { void debug_group_begin(const char *name, int index) override; void debug_group_end() override; + bool debug_capture_begin() override; + void debug_capture_end() override; + void *debug_capture_scope_create(const char *name) override; + bool debug_capture_scope_begin(void *scope) override; + void debug_capture_scope_end(void *scope) override; /*** MTLContext Utility functions. */ /* diff --git a/source/blender/gpu/metal/mtl_debug.mm b/source/blender/gpu/metal/mtl_debug.mm index 8ca4a0cc6e3..77637052f7b 100644 --- a/source/blender/gpu/metal/mtl_debug.mm +++ b/source/blender/gpu/metal/mtl_debug.mm @@ -57,6 +57,63 @@ void MTLContext::debug_group_end() } } +bool MTLContext::debug_capture_begin() +{ + MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager]; + if (!capture_manager) { + /* Early exit if frame capture is disabled. */ + return false; + } + MTLCaptureDescriptor *capture_descriptor = [[MTLCaptureDescriptor alloc] init]; + capture_descriptor.captureObject = this->device; + NSError *error; + if (![capture_manager startCaptureWithDescriptor:capture_descriptor error:&error]) { + NSLog(@"Failed to start Metal frame capture, error %@", error); + return false; + } + return true; +} + +void MTLContext::debug_capture_end() +{ + MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager]; + if (!capture_manager) { + /* Early exit if frame capture is disabled. */ + return; + } + [capture_manager stopCapture]; +} + +void *MTLContext::debug_capture_scope_create(const char *name) +{ + /* Create a capture scope visible to xCode Metal Frame capture utility. */ + MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager]; + if (!capture_manager) { + /* Early exit if frame capture is disabled. */ + return nullptr; + } + id capture_scope = [capture_manager newCaptureScopeWithDevice:this->device]; + capture_scope.label = [NSString stringWithUTF8String:name]; + [capture_scope retain]; + + return reinterpret_cast(capture_scope); +} + +bool MTLContext::debug_capture_scope_begin(void *scope) +{ + /* Declare opening boundary of scope. + * When scope is selected for capture, GPU commands between begin/end scope will be captured. */ + [(id)scope beginScope]; + + MTLCaptureManager *capture_manager = [MTLCaptureManager sharedCaptureManager]; + return [capture_manager isCapturing]; +} + +void MTLContext::debug_capture_scope_end(void *scope) +{ + [(id)scope endScope]; +} + /** \} */ } // namespace blender::gpu diff --git a/source/blender/gpu/metal/mtl_drawlist.mm b/source/blender/gpu/metal/mtl_drawlist.mm index 3a1fe405c49..03f7f3dbf7f 100644 --- a/source/blender/gpu/metal/mtl_drawlist.mm +++ b/source/blender/gpu/metal/mtl_drawlist.mm @@ -27,7 +27,7 @@ namespace blender::gpu { * uint32_t instanceCount; * uint32_t vertexStart; * uint32_t baseInstance; -};*/ + * }; */ /* MTLDrawIndexedPrimitivesIndirectArguments -- * https://developer.apple.com/documentation/metal/mtldrawindexedprimitivesindirectarguments?language=objc @@ -38,7 +38,7 @@ namespace blender::gpu { * uint32_t indexStart; * uint32_t baseVertex; * uint32_t baseInstance; -};*/ + * }; */ #define MDI_ENABLED (buffer_size_ != 0) #define MDI_DISABLED (buffer_size_ == 0) diff --git a/source/blender/gpu/metal/mtl_framebuffer.mm b/source/blender/gpu/metal/mtl_framebuffer.mm index 5e3a4136d88..86b7601a3cc 100644 --- a/source/blender/gpu/metal/mtl_framebuffer.mm +++ b/source/blender/gpu/metal/mtl_framebuffer.mm @@ -606,17 +606,6 @@ void MTLFrameBuffer::update_attachments(bool update_viewport) if (!dirty_attachments_) { return; } - - /* Cache viewport and scissor (If we have existing attachments). */ - int t_viewport[4], t_scissor[4]; - update_viewport = update_viewport && - (this->get_attachment_count() > 0 && this->has_depth_attachment() && - this->has_stencil_attachment()); - if (update_viewport) { - this->viewport_get(t_viewport); - this->scissor_get(t_scissor); - } - /* Clear current attachments state. */ this->remove_all_attachments(); @@ -738,22 +727,25 @@ void MTLFrameBuffer::update_attachments(bool update_viewport) } } - /* Check whether the first attachment is SRGB. */ + /* Extract attachment size and determine if framebuffer is SRGB. */ if (first_attachment != GPU_FB_MAX_ATTACHMENT) { - srgb_ = (first_attachment_mtl.texture->format_get() == GPU_SRGB8_A8); - } - - /* Reset viewport and Scissor (If viewport is smaller or equal to the framebuffer size). */ - if (update_viewport && t_viewport[2] <= width_ && t_viewport[3] <= height_) { - - this->viewport_set(t_viewport); - this->scissor_set(t_viewport); + /* Ensure size is correctly assigned. */ + GPUAttachment &attach = attachments_[first_attachment]; + int size[3]; + GPU_texture_get_mipmap_size(attach.tex, attach.mip, size); + this->size_set(size[0], size[1]); + srgb_ = (GPU_texture_format(attach.tex) == GPU_SRGB8_A8); } else { - this->viewport_reset(); - this->scissor_reset(); + /* Empty frame-buffer. */ + width_ = 0; + height_ = 0; } + /* Reset viewport and Scissor. */ + this->viewport_reset(); + this->scissor_reset(); + /* We have now updated our internal structures. */ dirty_attachments_ = false; } diff --git a/source/blender/gpu/metal/mtl_memory.hh b/source/blender/gpu/metal/mtl_memory.hh index e763eff24b9..e7da1a6d4fd 100644 --- a/source/blender/gpu/metal/mtl_memory.hh +++ b/source/blender/gpu/metal/mtl_memory.hh @@ -288,17 +288,17 @@ class MTLSafeFreeList { std::atomic in_free_queue_; std::atomic referenced_by_workload_; std::recursive_mutex lock_; - /* Linked list of next MTLSafeFreeList chunk if current chunk is full. */ - std::atomic has_next_pool_; std::atomic next_; /* Lockless list. MAX_NUM_BUFFERS_ within a chunk based on considerations - * for performance and memory. + * for performance and memory. Higher chunk counts are preferable for efficiently + * performing block operations such as copying several objects simultaneously. + * * MIN_BUFFER_FLUSH_COUNT refers to the minimum count of buffers in the MTLSafeFreeList * before buffers are returned to global memory pool. This is set at a point to reduce * overhead of small pool flushes, while ensuring floating memory overhead is not excessive. */ - static const int MAX_NUM_BUFFERS_ = 1024; + static const int MAX_NUM_BUFFERS_ = 8192; static const int MIN_BUFFER_FLUSH_COUNT = 120; std::atomic current_list_index_; gpu::MTLBuffer *safe_free_pool_[MAX_NUM_BUFFERS_]; @@ -306,8 +306,8 @@ class MTLSafeFreeList { public: MTLSafeFreeList(); - /* Add buffer to Safe Free List, can be called from secondary threads. - * Performs a lockless list insert. */ + /* Can be used from multiple threads. Performs insertion into Safe Free List with the least + * amount of threading synchronization. */ void insert_buffer(gpu::MTLBuffer *buffer); /* Whether we need to start a new safe free list, or can carry on using the existing one. */ @@ -322,10 +322,11 @@ class MTLSafeFreeList { void flag_in_queue() { in_free_queue_ = true; - if (has_next_pool_) { + if (current_list_index_ >= MTLSafeFreeList::MAX_NUM_BUFFERS_) { MTLSafeFreeList *next_pool = next_.load(); - BLI_assert(next_pool != nullptr); - next_pool->flag_in_queue(); + if (next_pool) { + next_pool->flag_in_queue(); + } } } }; diff --git a/source/blender/gpu/metal/mtl_memory.mm b/source/blender/gpu/metal/mtl_memory.mm index 1d6d4ad7330..dc5ea26c12b 100644 --- a/source/blender/gpu/metal/mtl_memory.mm +++ b/source/blender/gpu/metal/mtl_memory.mm @@ -257,10 +257,7 @@ void MTLBufferPool::update_memory_pools() } /* Fetch next MTLSafeFreeList chunk, if any. */ - MTLSafeFreeList *next_list = nullptr; - if (current_pool->has_next_pool_ > 0) { - next_list = current_pool->next_.load(); - } + MTLSafeFreeList *next_list = current_pool->next_.load(); /* Delete current MTLSafeFreeList */ current_pool->lock_.unlock(); @@ -396,7 +393,6 @@ MTLSafeFreeList::MTLSafeFreeList() in_free_queue_ = false; current_list_index_ = 0; next_ = nullptr; - has_next_pool_ = 0; } void MTLSafeFreeList::insert_buffer(gpu::MTLBuffer *buffer) @@ -410,12 +406,19 @@ void MTLSafeFreeList::insert_buffer(gpu::MTLBuffer *buffer) * insert the buffer into the next available chunk. */ if (insert_index >= MTLSafeFreeList::MAX_NUM_BUFFERS_) { - /* Check if first caller to generate next pool. */ - int has_next = has_next_pool_++; - if (has_next == 0) { - next_ = new MTLSafeFreeList(); - } + /* Check if first caller to generate next pool in chain. + * Otherwise, ensure pool exists or wait for first caller to create next pool. */ MTLSafeFreeList *next_list = next_.load(); + + if (!next_list) { + std::unique_lock lock(lock_); + + next_list = next_.load(); + if (!next_list) { + next_list = new MTLSafeFreeList(); + next_.store(next_list); + } + } BLI_assert(next_list); next_list->insert_buffer(buffer); diff --git a/source/blender/gpu/metal/mtl_shader_generator.hh b/source/blender/gpu/metal/mtl_shader_generator.hh index c52d39ba348..333c70a6fcb 100644 --- a/source/blender/gpu/metal/mtl_shader_generator.hh +++ b/source/blender/gpu/metal/mtl_shader_generator.hh @@ -490,8 +490,12 @@ class MSLGeneratorInterface { std::string generate_msl_uniform_undefs(ShaderStage stage); std::string generate_ubo_block_undef_chain(ShaderStage stage); std::string generate_msl_texture_vars(ShaderStage shader_stage); - void generate_msl_textures_input_string(std::stringstream &out, ShaderStage stage); - void generate_msl_uniforms_input_string(std::stringstream &out, ShaderStage stage); + void generate_msl_textures_input_string(std::stringstream &out, + ShaderStage stage, + bool &is_first_parameter); + void generate_msl_uniforms_input_string(std::stringstream &out, + ShaderStage stage, + bool &is_first_parameter); /* Location is not always specified, so this will resolve outstanding locations. */ void resolve_input_attribute_locations(); diff --git a/source/blender/gpu/metal/mtl_shader_generator.mm b/source/blender/gpu/metal/mtl_shader_generator.mm index 5810ed79f33..8a2cb59ee05 100644 --- a/source/blender/gpu/metal/mtl_shader_generator.mm +++ b/source/blender/gpu/metal/mtl_shader_generator.mm @@ -1268,6 +1268,11 @@ bool MTLShader::generate_msl_from_glsl(const shader::ShaderCreateInfo *info) ss_fragment << "uint gl_PrimitiveID;" << std::endl; } + /* Global barycentrics. */ + if (msl_iface.uses_barycentrics) { + ss_fragment << "vec3 gpu_BaryCoord;\n"; + } + /* Add Texture members. */ for (const MSLTextureSampler &tex : msl_iface.texture_samplers) { if (bool(tex.stage & ShaderStage::FRAGMENT)) { @@ -2036,33 +2041,7 @@ std::string MSLGeneratorInterface::generate_msl_fragment_entry_stub() /* Barycentrics. */ if (this->uses_barycentrics) { - - /* Main barycentrics. */ out << shader_stage_inst_name << ".gpu_BaryCoord = mtl_barycentric_coord.xyz;" << std::endl; - - /* barycentricDist represents the world-space distance from the current world-space position - * to the opposite edge of the vertex. */ - out << "float3 worldPos = " << shader_stage_inst_name << ".worldPosition.xyz;" << std::endl; - out << "float3 wpChange = (length(dfdx(worldPos))+length(dfdy(worldPos)));" << std::endl; - out << "float3 bcChange = " - "(length(dfdx(mtl_barycentric_coord))+length(dfdy(mtl_barycentric_coord)));" - << std::endl; - out << "float3 rateOfChange = wpChange/bcChange;" << std::endl; - - /* Distance to edge using inverse barycentric value, as rather than the length of 0.7 - * contribution, we'd want the distance to the opposite side. */ - out << shader_stage_inst_name - << ".gpu_BarycentricDist.x = length(rateOfChange * " - "(1.0-mtl_barycentric_coord.x));" - << std::endl; - out << shader_stage_inst_name - << ".gpu_BarycentricDist.y = length(rateOfChange * " - "(1.0-mtl_barycentric_coord.y));" - << std::endl; - out << shader_stage_inst_name - << ".gpu_BarycentricDist.z = length(rateOfChange * " - "(1.0-mtl_barycentric_coord.z));" - << std::endl; } /* Populate Uniforms and uniform blocks. */ @@ -2166,8 +2145,20 @@ std::string MSLGeneratorInterface::generate_msl_compute_entry_stub() return out.str(); } +/* If first parameter in function signature, do not print out a comma. + * Update first parameter flag to false for future invocations. */ +static char parameter_delimiter(bool &is_first_parameter) +{ + if (is_first_parameter) { + is_first_parameter = false; + return ' '; + } + return ','; +} + void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream &out, - ShaderStage stage) + ShaderStage stage, + bool &is_first_parameter) { /* Note: Shader stage must be specified as the singular stage index for which the input * is generating. Compound stages are not valid inputs. */ @@ -2177,7 +2168,8 @@ void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream BLI_assert(this->texture_samplers.size() <= GPU_max_textures_vert()); for (const MSLTextureSampler &tex : this->texture_samplers) { if (bool(tex.stage & stage)) { - out << ",\n\t" << tex.get_msl_typestring(false) << " [[texture(" << tex.location << ")]]"; + out << parameter_delimiter(is_first_parameter) << "\n\t" << tex.get_msl_typestring(false) + << " [[texture(" << tex.location << ")]]"; } } @@ -2187,7 +2179,8 @@ void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream * If we exceed the hardware-supported limit, then follow a bind-less model using argument * buffers. */ if (this->use_argument_buffer_for_samplers()) { - out << ",\n\tconstant SStruct& samplers [[buffer(MTL_uniform_buffer_base_index+" + out << parameter_delimiter(is_first_parameter) + << "\n\tconstant SStruct& samplers [[buffer(MTL_uniform_buffer_base_index+" << (this->get_sampler_argument_buffer_bind_index(stage)) << ")]]"; } else { @@ -2196,7 +2189,8 @@ void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream BLI_assert(this->texture_samplers.size() <= MTL_MAX_DEFAULT_SAMPLERS); for (const MSLTextureSampler &tex : this->texture_samplers) { if (bool(tex.stage & stage)) { - out << ",\n\tsampler " << tex.name << "_sampler [[sampler(" << tex.location << ")]]"; + out << parameter_delimiter(is_first_parameter) << "\n\tsampler " << tex.name + << "_sampler [[sampler(" << tex.location << ")]]"; } } @@ -2210,12 +2204,13 @@ void MSLGeneratorInterface::generate_msl_textures_input_string(std::stringstream } void MSLGeneratorInterface::generate_msl_uniforms_input_string(std::stringstream &out, - ShaderStage stage) + ShaderStage stage, + bool &is_first_parameter) { for (const MSLUniformBlock &ubo : this->uniform_blocks) { if (bool(ubo.stage & stage)) { /* For literal/existing global types, we do not need the class name-space accessor. */ - out << ",\n\tconstant "; + out << parameter_delimiter(is_first_parameter) << "\n\tconstant "; if (!is_builtin_type(ubo.type_name)) { out << get_stage_class_name(stage) << "::"; } @@ -2232,104 +2227,135 @@ void MSLGeneratorInterface::generate_msl_uniforms_input_string(std::stringstream std::string MSLGeneratorInterface::generate_msl_vertex_inputs_string() { std::stringstream out; + bool is_first_parameter = true; if (this->uses_ssbo_vertex_fetch_mode) { /* Vertex Buffers bound as raw buffers. */ for (int i = 0; i < MTL_SSBO_VERTEX_FETCH_MAX_VBOS; i++) { - out << "\tconstant uchar* MTL_VERTEX_DATA_" << i << " [[buffer(" << i << ")]],\n"; + out << parameter_delimiter(is_first_parameter) << "\tconstant uchar* MTL_VERTEX_DATA_" << i + << " [[buffer(" << i << ")]]\n"; } - out << "\tconstant ushort* MTL_INDEX_DATA[[buffer(MTL_SSBO_VERTEX_FETCH_IBO_INDEX)]],"; + out << parameter_delimiter(is_first_parameter) + << "\tconstant ushort* MTL_INDEX_DATA[[buffer(MTL_SSBO_VERTEX_FETCH_IBO_INDEX)]]"; } else { if (this->vertex_input_attributes.size() > 0) { /* Vertex Buffers use input assembly. */ - out << get_stage_class_name(ShaderStage::VERTEX) << "::VertexIn v_in [[stage_in]],"; + out << get_stage_class_name(ShaderStage::VERTEX) << "::VertexIn v_in [[stage_in]]"; + is_first_parameter = false; } } - out << "\n\tconstant " << get_stage_class_name(ShaderStage::VERTEX) - << "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]"; - this->generate_msl_uniforms_input_string(out, ShaderStage::VERTEX); + if (this->uniforms.size() > 0) { + out << parameter_delimiter(is_first_parameter) << "\n\tconstant " + << get_stage_class_name(ShaderStage::VERTEX) + << "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]"; + is_first_parameter = false; + } + + this->generate_msl_uniforms_input_string(out, ShaderStage::VERTEX, is_first_parameter); /* Transform feedback buffer binding. */ if (this->uses_transform_feedback) { - out << ",\n\tdevice " << get_stage_class_name(ShaderStage::VERTEX) + out << parameter_delimiter(is_first_parameter) << "\n\tdevice " + << get_stage_class_name(ShaderStage::VERTEX) << "::VertexOut_TF* " "transform_feedback_results[[buffer(MTL_transform_feedback_buffer_index)]]"; } /* Generate texture signatures. */ - this->generate_msl_textures_input_string(out, ShaderStage::VERTEX); + this->generate_msl_textures_input_string(out, ShaderStage::VERTEX, is_first_parameter); /* Entry point parameters for gl Globals. */ if (this->uses_gl_VertexID) { - out << ",\n\tconst uint32_t gl_VertexID [[vertex_id]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint32_t gl_VertexID [[vertex_id]]"; } if (this->uses_gl_InstanceID) { - out << ",\n\tconst uint32_t gl_InstanceID [[instance_id]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint32_t gl_InstanceID [[instance_id]]"; } if (this->uses_gl_BaseInstanceARB) { - out << ",\n\tconst uint32_t gl_BaseInstanceARB [[base_instance]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint32_t gl_BaseInstanceARB [[base_instance]]"; } return out.str(); } std::string MSLGeneratorInterface::generate_msl_fragment_inputs_string() { + bool is_first_parameter = true; std::stringstream out; - out << get_stage_class_name(ShaderStage::FRAGMENT) - << "::VertexOut v_in [[stage_in]],\n\tconstant " - << get_stage_class_name(ShaderStage::FRAGMENT) - << "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]"; + out << parameter_delimiter(is_first_parameter) << get_stage_class_name(ShaderStage::FRAGMENT) + << "::VertexOut v_in [[stage_in]]"; - this->generate_msl_uniforms_input_string(out, ShaderStage::FRAGMENT); + if (this->uniforms.size() > 0) { + out << parameter_delimiter(is_first_parameter) << "\n\tconstant " + << get_stage_class_name(ShaderStage::FRAGMENT) + << "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]"; + } + + this->generate_msl_uniforms_input_string(out, ShaderStage::FRAGMENT, is_first_parameter); /* Generate texture signatures. */ - this->generate_msl_textures_input_string(out, ShaderStage::FRAGMENT); + this->generate_msl_textures_input_string(out, ShaderStage::FRAGMENT, is_first_parameter); if (this->uses_gl_PointCoord) { - out << ",\n\tconst float2 gl_PointCoord [[point_coord]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst float2 gl_PointCoord [[point_coord]]"; } if (this->uses_gl_FrontFacing) { - out << ",\n\tconst MTLBOOL gl_FrontFacing [[front_facing]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst MTLBOOL gl_FrontFacing [[front_facing]]"; } if (this->uses_gl_PrimitiveID) { - out << ",\n\tconst uint gl_PrimitiveID [[primitive_id]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint gl_PrimitiveID [[primitive_id]]"; } /* Barycentrics. */ if (this->uses_barycentrics) { - out << ",\n\tconst float3 mtl_barycentric_coord [[barycentric_coord]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst float3 mtl_barycentric_coord [[barycentric_coord]]"; } return out.str(); } std::string MSLGeneratorInterface::generate_msl_compute_inputs_string() { + bool is_first_parameter = true; std::stringstream out; - out << "constant " << get_stage_class_name(ShaderStage::COMPUTE) - << "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]"; + if (this->uniforms.size() > 0) { + out << parameter_delimiter(is_first_parameter) << "constant " + << get_stage_class_name(ShaderStage::COMPUTE) + << "::PushConstantBlock* uniforms[[buffer(MTL_uniform_buffer_base_index)]]"; + } - this->generate_msl_uniforms_input_string(out, ShaderStage::COMPUTE); + this->generate_msl_uniforms_input_string(out, ShaderStage::COMPUTE, is_first_parameter); /* Generate texture signatures. */ - this->generate_msl_textures_input_string(out, ShaderStage::COMPUTE); + this->generate_msl_textures_input_string(out, ShaderStage::COMPUTE, is_first_parameter); /* Entry point parameters for gl Globals. */ if (this->uses_gl_GlobalInvocationID) { - out << ",\n\tconst uint3 gl_GlobalInvocationID [[thread_position_in_grid]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint3 gl_GlobalInvocationID [[thread_position_in_grid]]"; } if (this->uses_gl_WorkGroupID) { - out << ",\n\tconst uint3 gl_WorkGroupID [[threadgroup_position_in_grid]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint3 gl_WorkGroupID [[threadgroup_position_in_grid]]"; } if (this->uses_gl_NumWorkGroups) { - out << ",\n\tconst uint3 gl_NumWorkGroups [[threadgroups_per_grid]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint3 gl_NumWorkGroups [[threadgroups_per_grid]]"; } if (this->uses_gl_LocalInvocationIndex) { - out << ",\n\tconst uint gl_LocalInvocationIndex [[thread_index_in_threadgroup]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint gl_LocalInvocationIndex [[thread_index_in_threadgroup]]"; } if (this->uses_gl_LocalInvocationID) { - out << ",\n\tconst uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]"; + out << parameter_delimiter(is_first_parameter) + << "\n\tconst uint3 gl_LocalInvocationID [[thread_position_in_threadgroup]]"; } return out.str(); @@ -2337,6 +2363,10 @@ std::string MSLGeneratorInterface::generate_msl_compute_inputs_string() std::string MSLGeneratorInterface::generate_msl_uniform_structs(ShaderStage shader_stage) { + /* Only generate PushConstantBlock if we have uniforms. */ + if (this->uniforms.size() == 0) { + return ""; + } BLI_assert(shader_stage == ShaderStage::VERTEX || shader_stage == ShaderStage::FRAGMENT); std::stringstream out; @@ -2645,6 +2675,9 @@ std::string MSLGeneratorInterface::generate_msl_fragment_out_struct() std::string MSLGeneratorInterface::generate_msl_global_uniform_population(ShaderStage stage) { + if (this->uniforms.size() == 0) { + return ""; + } /* Populate Global Uniforms. */ std::stringstream out; diff --git a/source/blender/gpu/metal/mtl_texture.mm b/source/blender/gpu/metal/mtl_texture.mm index 252f8ac70a0..0915cdc00db 100644 --- a/source/blender/gpu/metal/mtl_texture.mm +++ b/source/blender/gpu/metal/mtl_texture.mm @@ -497,7 +497,7 @@ void gpu::MTLTexture::update_sub( } /* Early exit if update size is zero. update_sub sometimes has a zero-sized - * extent when called from texture painting. */ + * extent when called from texture painting. */ if (totalsize <= 0 || extent[0] <= 0) { MTL_LOG_WARNING( "MTLTexture::update_sub called with extent size of zero for one or more dimensions. " @@ -594,17 +594,6 @@ void gpu::MTLTexture::update_sub( } } - /* Prepare staging buffer for data. */ - id staging_buffer = nil; - uint64_t staging_buffer_offset = 0; - - /* Fetch allocation from scratch buffer. */ - MTLTemporaryBuffer allocation = - ctx->get_scratchbuffer_manager().scratch_buffer_allocate_range_aligned(totalsize, 256); - memcpy(allocation.data, data, totalsize); - staging_buffer = allocation.metal_buffer; - staging_buffer_offset = allocation.buffer_offset; - /* Common Properties. */ MTLPixelFormat compatible_write_format = mtl_format_get_writeable_view_format( destination_format); @@ -616,6 +605,12 @@ void gpu::MTLTexture::update_sub( return; } + /* Fetch allocation from memory pool. */ + MTLBuffer *temp_allocation = MTLContext::get_global_memory_manager()->allocate_with_data( + totalsize, true, data); + id staging_buffer = temp_allocation->get_metal_buffer(); + BLI_assert(staging_buffer != nil); + /* Prepare command encoders. */ id blit_encoder = nil; id compute_encoder = nil; @@ -643,7 +638,7 @@ void gpu::MTLTexture::update_sub( /* For compute, we should use a stating texture to avoid texture write usage, * if it has not been specified for the texture. Using shader-write disables - * lossless texture compression, so this is best to avoid where possible. */ + * lossless texture compression, so this is best to avoid where possible. */ if (!(gpu_image_usage_flags_ & GPU_TEXTURE_USAGE_SHADER_WRITE)) { use_staging_texture = true; } @@ -697,7 +692,7 @@ void gpu::MTLTexture::update_sub( int max_array_index = ((type_ == GPU_TEXTURE_1D_ARRAY) ? extent[1] : 1); for (int array_index = 0; array_index < max_array_index; array_index++) { - int buffer_array_offset = staging_buffer_offset + (bytes_per_image * array_index); + int buffer_array_offset = (bytes_per_image * array_index); [blit_encoder copyFromBuffer:staging_buffer sourceOffset:buffer_array_offset @@ -727,7 +722,7 @@ void gpu::MTLTexture::update_sub( MTLComputeState &cs = ctx->main_command_buffer.get_compute_state(); cs.bind_pso(pso); cs.bind_compute_bytes(¶ms, sizeof(params), 0); - cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1); + cs.bind_compute_buffer(staging_buffer, 0, 1); cs.bind_compute_texture(texture_handle, 0); [compute_encoder dispatchThreads:MTLSizeMake(extent[0], 1, 1) /* Width, Height, Layer */ @@ -747,7 +742,7 @@ void gpu::MTLTexture::update_sub( MTLComputeState &cs = ctx->main_command_buffer.get_compute_state(); cs.bind_pso(pso); cs.bind_compute_bytes(¶ms, sizeof(params), 0); - cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1); + cs.bind_compute_buffer(staging_buffer, 0, 1); cs.bind_compute_texture(texture_handle, 0); [compute_encoder dispatchThreads:MTLSizeMake(extent[0], extent[1], 1) /* Width, layers, nil */ @@ -779,7 +774,7 @@ void gpu::MTLTexture::update_sub( } [blit_encoder copyFromBuffer:staging_buffer - sourceOffset:staging_buffer_offset + texture_array_relative_offset + sourceOffset:texture_array_relative_offset sourceBytesPerRow:bytes_per_row sourceBytesPerImage:bytes_per_image sourceSize:MTLSizeMake(extent[0], extent[1], 1) @@ -807,7 +802,7 @@ void gpu::MTLTexture::update_sub( MTLComputeState &cs = ctx->main_command_buffer.get_compute_state(); cs.bind_pso(pso); cs.bind_compute_bytes(¶ms, sizeof(params), 0); - cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1); + cs.bind_compute_buffer(staging_buffer, 0, 1); cs.bind_compute_texture(texture_handle, 0); [compute_encoder dispatchThreads:MTLSizeMake( @@ -828,7 +823,7 @@ void gpu::MTLTexture::update_sub( MTLComputeState &cs = ctx->main_command_buffer.get_compute_state(); cs.bind_pso(pso); cs.bind_compute_bytes(¶ms, sizeof(params), 0); - cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1); + cs.bind_compute_buffer(staging_buffer, 0, 1); cs.bind_compute_texture(texture_handle, 0); [compute_encoder dispatchThreads:MTLSizeMake(extent[0], extent[1], @@ -848,7 +843,7 @@ void gpu::MTLTexture::update_sub( ctx->pipeline_state.unpack_row_length); int bytes_per_image = bytes_per_row * extent[1]; [blit_encoder copyFromBuffer:staging_buffer - sourceOffset:staging_buffer_offset + sourceOffset:0 sourceBytesPerRow:bytes_per_row sourceBytesPerImage:bytes_per_image sourceSize:MTLSizeMake(extent[0], extent[1], extent[2]) @@ -871,7 +866,7 @@ void gpu::MTLTexture::update_sub( MTLComputeState &cs = ctx->main_command_buffer.get_compute_state(); cs.bind_pso(pso); cs.bind_compute_bytes(¶ms, sizeof(params), 0); - cs.bind_compute_buffer(staging_buffer, staging_buffer_offset, 1); + cs.bind_compute_buffer(staging_buffer, 0, 1); cs.bind_compute_texture(texture_handle, 0); [compute_encoder dispatchThreads:MTLSizeMake( @@ -896,7 +891,7 @@ void gpu::MTLTexture::update_sub( int face_index = offset[2] + i; [blit_encoder copyFromBuffer:staging_buffer - sourceOffset:staging_buffer_offset + texture_array_relative_offset + sourceOffset:texture_array_relative_offset sourceBytesPerRow:bytes_per_row sourceBytesPerImage:bytes_per_image sourceSize:MTLSizeMake(extent[0], extent[1], 1) @@ -930,7 +925,7 @@ void gpu::MTLTexture::update_sub( for (int i = 0; i < extent[2]; i++) { int face_index = offset[2] + i; [blit_encoder copyFromBuffer:staging_buffer - sourceOffset:staging_buffer_offset + texture_array_relative_offset + sourceOffset:texture_array_relative_offset sourceBytesPerRow:bytes_per_row sourceBytesPerImage:bytes_per_image sourceSize:MTLSizeMake(extent[0], extent[1], 1) @@ -1058,6 +1053,11 @@ void gpu::MTLTexture::update_sub( /* Decrement texture reference counts. This ensures temporary texture views are released. */ [texture_handle release]; + + /* Release temporary staging buffer allocation. + * NOTE: Allocation will be tracked with command submission and released once no longer in use. + */ + temp_allocation->free(); } } diff --git a/source/blender/gpu/metal/mtl_texture_util.mm b/source/blender/gpu/metal/mtl_texture_util.mm index dde1816220f..1a27557fb44 100644 --- a/source/blender/gpu/metal/mtl_texture_util.mm +++ b/source/blender/gpu/metal/mtl_texture_util.mm @@ -176,7 +176,7 @@ MTLPixelFormat gpu_texture_format_to_metal(eGPUTextureFormat tex_format) return MTLPixelFormatDepth32Float; case GPU_DEPTH_COMPONENT24: /* This formal is not supported on Metal. - * Use 32Float depth instead with some conversion steps for download and upload. */ + * Use 32Float depth instead with some conversion steps for download and upload. */ return MTLPixelFormatDepth32Float; case GPU_DEPTH_COMPONENT16: return MTLPixelFormatDepth16Unorm; @@ -402,9 +402,13 @@ id gpu::MTLTexture::mtl_texture_update_impl( options:options error:&error] autorelease]; if (error) { - NSLog(@"Compile Error - Metal Shader Library error %@ ", error); - BLI_assert(false); - return nullptr; + /* Only exit out if genuine error and not warning. */ + if ([[error localizedDescription] rangeOfString:@"Compilation succeeded"].location == + NSNotFound) { + NSLog(@"Compile Error - Metal Shader Library error %@ ", error); + BLI_assert(false); + return nil; + } } /* Fetch compute function. */ @@ -718,9 +722,13 @@ id gpu::MTLTexture::mtl_texture_read_impl( options:options error:&error] autorelease]; if (error) { - NSLog(@"Compile Error - Metal Shader Library error %@ ", error); - BLI_assert(false); - return nil; + /* Only exit out if genuine error and not warning. */ + if ([[error localizedDescription] rangeOfString:@"Compilation succeeded"].location == + NSNotFound) { + NSLog(@"Compile Error - Metal Shader Library error %@ ", error); + BLI_assert(false); + return nil; + } } /* Fetch compute function. */ diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index 1d413750fd4..2d19bc9a10d 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -134,6 +134,11 @@ class GLContext : public Context { void debug_group_begin(const char *name, int index) override; void debug_group_end() override; + bool debug_capture_begin() override; + void debug_capture_end() override; + void *debug_capture_scope_create(const char *name) override; + bool debug_capture_scope_begin(void *scope) override; + void debug_capture_scope_end(void *scope) override; private: static void orphans_add(Vector &orphan_list, std::mutex &list_mutex, GLuint id); diff --git a/source/blender/gpu/opengl/gl_debug.cc b/source/blender/gpu/opengl/gl_debug.cc index 5c23286c166..00f11934804 100644 --- a/source/blender/gpu/opengl/gl_debug.cc +++ b/source/blender/gpu/opengl/gl_debug.cc @@ -380,6 +380,29 @@ void GLContext::debug_group_end() } } +bool GLContext::debug_capture_begin() +{ + return false; +} + +void GLContext::debug_capture_end() +{ +} + +void *GLContext::debug_capture_scope_create(const char * /*name*/) +{ + return nullptr; +} + +bool GLContext::debug_capture_scope_begin(void * /*scope*/) +{ + return false; +} + +void GLContext::debug_capture_scope_end(void * /*scope*/) +{ +} + /** \} */ } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 7fe0d878798..579b105c0d7 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -360,9 +360,16 @@ static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifie return os; } -static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res) +static void print_resource(std::ostream &os, + const ShaderCreateInfo::Resource &res, + bool auto_resource_location) { - if (GLContext::explicit_location_support) { + if (auto_resource_location && res.bind_type == ShaderCreateInfo::Resource::BindType::SAMPLER) { + /* Skip explicit binding location for samplers when not needed, since drivers can usually + * handle more sampler declarations this way (as long as they're not actually used by the + * shader). See #105661. */ + } + else if (GLContext::explicit_location_support) { os << "layout(binding = " << res.slot; if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { os << ", " << to_string(res.image.format); @@ -466,14 +473,14 @@ std::string GLShader::resources_declare(const ShaderCreateInfo &info) const ss << "\n/* Pass Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { - print_resource(ss, res); + print_resource(ss, res, info.auto_resource_location_); } for (const ShaderCreateInfo::Resource &res : info.pass_resources_) { print_resource_alias(ss, res); } ss << "\n/* Batch Resources. */\n"; for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { - print_resource(ss, res); + print_resource(ss, res, info.auto_resource_location_); } for (const ShaderCreateInfo::Resource &res : info.batch_resources_) { print_resource_alias(ss, res); diff --git a/source/blender/gpu/opengl/gl_storage_buffer.cc b/source/blender/gpu/opengl/gl_storage_buffer.cc index 5d876308b3c..5ad2ef00bd4 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.cc +++ b/source/blender/gpu/opengl/gl_storage_buffer.cc @@ -117,27 +117,20 @@ void GLStorageBuf::unbind() slot_ = 0; } -void GLStorageBuf::clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) +void GLStorageBuf::clear(uint32_t clear_value) { if (ssbo_id_ == 0) { this->init(); } if (GLContext::direct_state_access_support) { - glClearNamedBufferData(ssbo_id_, - to_gl_internal_format(internal_format), - to_gl_data_format(internal_format), - to_gl(data_format), - data); + glClearNamedBufferData(ssbo_id_, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value); } else { /* WATCH(@fclem): This should be ok since we only use clear outside of drawing functions. */ glBindBuffer(GL_SHADER_STORAGE_BUFFER, ssbo_id_); - glClearBufferData(GL_SHADER_STORAGE_BUFFER, - to_gl_internal_format(internal_format), - to_gl_data_format(internal_format), - to_gl(data_format), - data); + glClearBufferData( + GL_SHADER_STORAGE_BUFFER, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT, &clear_value); glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0); } } diff --git a/source/blender/gpu/opengl/gl_storage_buffer.hh b/source/blender/gpu/opengl/gl_storage_buffer.hh index 680ce911bc7..3932698ea2d 100644 --- a/source/blender/gpu/opengl/gl_storage_buffer.hh +++ b/source/blender/gpu/opengl/gl_storage_buffer.hh @@ -33,7 +33,7 @@ class GLStorageBuf : public StorageBuf { void update(const void *data) override; void bind(int slot) override; void unbind() override; - void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; + void clear(uint32_t clear_value) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; void read(void *data) override; diff --git a/source/blender/gpu/shaders/common/gpu_shader_bicubic_sampler_lib.glsl b/source/blender/gpu/shaders/common/gpu_shader_bicubic_sampler_lib.glsl new file mode 100644 index 00000000000..62dd0faae6f --- /dev/null +++ b/source/blender/gpu/shaders/common/gpu_shader_bicubic_sampler_lib.glsl @@ -0,0 +1,68 @@ +/** \param f: Offset from texel center in pixel space. */ +void cubic_bspline_coefficients(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3) +{ + vec2 f2 = f * f; + vec2 f3 = f2 * f; + /* Optimized formulae for cubic B-Spline coefficients. */ + w3 = f3 / 6.0; + w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0; + w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0; + w2 = 1.0 - w0 - w1 - w3; +} + +/* Samples the given 2D sampler at the given coordinates using Bicubic interpolation. This function + * uses an optimized algorithm which assumes a linearly filtered sampler, so the caller needs to + * take that into account when setting up the sampler. */ +vec4 texture_bicubic(sampler2D sampler_2d, vec2 coordinates) +{ + vec2 texture_size = vec2(textureSize(sampler_2d, 0).xy); + coordinates.xy *= texture_size; + + vec2 w0, w1, w2, w3; + vec2 texel_center = floor(coordinates.xy - 0.5) + 0.5; + cubic_bspline_coefficients(coordinates.xy - texel_center, w0, w1, w2, w3); + +#if 1 /* Optimized version using 4 filtered taps. */ + vec2 s0 = w0 + w1; + vec2 s1 = w2 + w3; + + vec2 f0 = w1 / (w0 + w1); + vec2 f1 = w3 / (w2 + w3); + + vec4 sampling_coordinates; + sampling_coordinates.xy = texel_center - 1.0 + f0; + sampling_coordinates.zw = texel_center + 1.0 + f1; + + sampling_coordinates /= texture_size.xyxy; + + vec4 sampled_color = textureLod(sampler_2d, sampling_coordinates.xy, 0.0) * s0.x * s0.y; + sampled_color += textureLod(sampler_2d, sampling_coordinates.zy, 0.0) * s1.x * s0.y; + sampled_color += textureLod(sampler_2d, sampling_coordinates.xw, 0.0) * s0.x * s1.y; + sampled_color += textureLod(sampler_2d, sampling_coordinates.zw, 0.0) * s1.x * s1.y; + + return sampled_color; + +#else /* Reference brute-force 16 taps. */ + vec4 color = texelFetch(sampler_2d, ivec2(texel_center + vec2(-1.0, -1.0)), 0) * w0.x * w0.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(0.0, -1.0)), 0) * w1.x * w0.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(1.0, -1.0)), 0) * w2.x * w0.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(2.0, -1.0)), 0) * w3.x * w0.y; + + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(-1.0, 0.0)), 0) * w0.x * w1.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(0.0, 0.0)), 0) * w1.x * w1.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(1.0, 0.0)), 0) * w2.x * w1.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(2.0, 0.0)), 0) * w3.x * w1.y; + + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(-1.0, 1.0)), 0) * w0.x * w2.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(0.0, 1.0)), 0) * w1.x * w2.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(1.0, 1.0)), 0) * w2.x * w2.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(2.0, 1.0)), 0) * w3.x * w2.y; + + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(-1.0, 2.0)), 0) * w0.x * w3.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(0.0, 2.0)), 0) * w1.x * w3.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(1.0, 2.0)), 0) * w2.x * w3.y; + color += texelFetch(sampler_2d, ivec2(texel_center + vec2(2.0, 2.0)), 0) * w3.x * w3.y; + + return color; +#endif +} diff --git a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl index 81e132e6286..760715c8c85 100644 --- a/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl +++ b/source/blender/gpu/shaders/gpu_shader_gpencil_stroke_vert_no_geom.glsl @@ -341,4 +341,4 @@ void main(void) default: DISCARD_VERTEX } -} \ No newline at end of file +} diff --git a/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl index 61bbe6ecb2e..3756900d5c7 100644 --- a/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_icon_frag.glsl @@ -23,7 +23,7 @@ void main() vec2 circle_center = vec2(circle_radius_outer - text_width, 0.5); - /* radius in icon space (1 is the icon width). */ + /* Radius in icon space (1 is the icon width). */ float radius = length(mask_coord_interp - circle_center); float mask = smoothstep(circle_radius_inner, circle_radius_outer, radius); diff --git a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh index d6b74def77e..2e1949d4f28 100644 --- a/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh +++ b/source/blender/gpu/shaders/infos/gpu_shader_test_info.hh @@ -55,7 +55,7 @@ GPU_SHADER_CREATE_INFO(gpu_compute_ssbo_binding_test) .compute_source("gpu_compute_dummy_test.glsl") .do_static_compilation(true); -/* Push constants*/ +/* Push constants. */ GPU_SHADER_CREATE_INFO(gpu_push_constants_base_test) .local_group_size(1) .storage_buf(0, Qualifier::WRITE, "float", "data_out[]") diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl index b24f9ab65f0..1e7d8124700 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_hair.glsl @@ -7,13 +7,24 @@ void node_bsdf_hair(vec4 color, float weight, out Closure result) { +#if 0 + /* NOTE(fclem): This is the way it should be. But we don't have proper implementation of the hair + * closure yet. For now fall back to a simpler diffuse surface so that we have at least a color + * feedback. */ ClosureHair hair_data; hair_data.weight = weight; hair_data.color = color.rgb; hair_data.offset = offset; hair_data.roughness = vec2(roughness_u, roughness_v); hair_data.T = T; - +#else + ClosureDiffuse hair_data; + hair_data.weight = weight; + hair_data.color = color.rgb; + hair_data.N = g_data.N; + hair_data.sss_radius = vec3(0.0); + hair_data.sss_id = 0u; +#endif result = closure_eval(hair_data); } @@ -34,13 +45,22 @@ void node_bsdf_hair_principled(vec4 color, out Closure result) { /* Placeholder closure. - * Some computation will have to happen here just like the Principled BSDF. */ + * Some computation will have to happen here just like the Principled BSDF. + * For now fall back to a simpler diffuse surface so that we have at least a color feedback. */ +#if 0 ClosureHair hair_data; hair_data.weight = weight; hair_data.color = color.rgb; hair_data.offset = offset; hair_data.roughness = vec2(0.0); hair_data.T = g_data.curve_B; - +#else + ClosureDiffuse hair_data; + hair_data.weight = weight; + hair_data.color = color.rgb; + hair_data.N = g_data.N; + hair_data.sss_radius = vec3(0.0); + hair_data.sss_id = 0u; +#endif result = closure_eval(hair_data); } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl index df949f7358b..acf24596f84 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl @@ -1,3 +1,5 @@ +#pragma BLENDER_REQUIRE(gpu_shader_bicubic_sampler_lib.glsl) + void point_texco_remap_square(vec3 vin, out vec3 vout) { vout = vin * 2.0 - 1.0; @@ -54,68 +56,9 @@ void node_tex_image_linear(vec3 co, sampler2D ima, out vec4 color, out float alp alpha = color.a; } -/** \param f: Signed distance to texel center. */ -void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3) -{ - vec2 f2 = f * f; - vec2 f3 = f2 * f; - /* Bspline coefs (optimized) */ - w3 = f3 / 6.0; - w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0; - w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0; - w2 = 1.0 - w0 - w1 - w3; -} - void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha) { - vec2 tex_size = vec2(textureSize(ima, 0).xy); - - co.xy *= tex_size; - /* texel center */ - vec2 tc = floor(co.xy - 0.5) + 0.5; - vec2 w0, w1, w2, w3; - cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3); - -#if 1 /* Optimized version using 4 filtered tap. */ - vec2 s0 = w0 + w1; - vec2 s1 = w2 + w3; - - vec2 f0 = w1 / (w0 + w1); - vec2 f1 = w3 / (w2 + w3); - - vec4 final_co; - final_co.xy = tc - 1.0 + f0; - final_co.zw = tc + 1.0 + f1; - - final_co /= tex_size.xyxy; - - color = safe_color(textureLod(ima, final_co.xy, 0.0)) * s0.x * s0.y; - color += safe_color(textureLod(ima, final_co.zy, 0.0)) * s1.x * s0.y; - color += safe_color(textureLod(ima, final_co.xw, 0.0)) * s0.x * s1.y; - color += safe_color(textureLod(ima, final_co.zw, 0.0)) * s1.x * s1.y; - -#else /* Reference bruteforce 16 tap. */ - color = texelFetch(ima, ivec2(tc + vec2(-1.0, -1.0)), 0) * w0.x * w0.y; - color += texelFetch(ima, ivec2(tc + vec2(0.0, -1.0)), 0) * w1.x * w0.y; - color += texelFetch(ima, ivec2(tc + vec2(1.0, -1.0)), 0) * w2.x * w0.y; - color += texelFetch(ima, ivec2(tc + vec2(2.0, -1.0)), 0) * w3.x * w0.y; - - color += texelFetch(ima, ivec2(tc + vec2(-1.0, 0.0)), 0) * w0.x * w1.y; - color += texelFetch(ima, ivec2(tc + vec2(0.0, 0.0)), 0) * w1.x * w1.y; - color += texelFetch(ima, ivec2(tc + vec2(1.0, 0.0)), 0) * w2.x * w1.y; - color += texelFetch(ima, ivec2(tc + vec2(2.0, 0.0)), 0) * w3.x * w1.y; - - color += texelFetch(ima, ivec2(tc + vec2(-1.0, 1.0)), 0) * w0.x * w2.y; - color += texelFetch(ima, ivec2(tc + vec2(0.0, 1.0)), 0) * w1.x * w2.y; - color += texelFetch(ima, ivec2(tc + vec2(1.0, 1.0)), 0) * w2.x * w2.y; - color += texelFetch(ima, ivec2(tc + vec2(2.0, 1.0)), 0) * w3.x * w2.y; - - color += texelFetch(ima, ivec2(tc + vec2(-1.0, 2.0)), 0) * w0.x * w3.y; - color += texelFetch(ima, ivec2(tc + vec2(0.0, 2.0)), 0) * w1.x * w3.y; - color += texelFetch(ima, ivec2(tc + vec2(1.0, 2.0)), 0) * w2.x * w3.y; - color += texelFetch(ima, ivec2(tc + vec2(2.0, 2.0)), 0) * w3.x * w3.y; -#endif - + color = safe_color(texture_bicubic(ima, co.xy)); alpha = color.a; } @@ -263,7 +206,7 @@ void node_tex_tile_cubic( /* texel center */ vec2 tc = floor(co.xy - 0.5) + 0.5; vec2 w0, w1, w2, w3; - cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3); + cubic_bspline_coefficients(co.xy - tc, w0, w1, w2, w3); vec2 s0 = w0 + w1; vec2 s1 = w2 + w3; diff --git a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl index 5cb9c47f36f..a192e51a0ec 100644 --- a/source/blender/gpu/shaders/metal/mtl_shader_defines.msl +++ b/source/blender/gpu/shaders/metal/mtl_shader_defines.msl @@ -7,6 +7,10 @@ * and texture2d types in metal). */ +/* Suppress unhelpful shader compiler warnings. */ +#pragma clang diagnostic ignored "-Wunused-variable" +#pragma clang diagnostic ignored "-Wcomment" + /* Base instance with offsets. */ #define gpu_BaseInstance gl_BaseInstanceARB #define gpu_InstanceIndex (gl_InstanceID + gpu_BaseInstance) diff --git a/source/blender/gpu/tests/gpu_shader_builtin_test.cc b/source/blender/gpu/tests/gpu_shader_builtin_test.cc deleted file mode 100644 index be6068ac084..00000000000 --- a/source/blender/gpu/tests/gpu_shader_builtin_test.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - -#include "gpu_testing.hh" - -#include "GPU_shader.h" - -namespace blender::gpu::tests { - -static void test_compile_builtin_shader(eGPUBuiltinShader shader_type, eGPUShaderConfig sh_cfg) -{ - GPUShader *sh = GPU_shader_get_builtin_shader_with_config(shader_type, sh_cfg); - EXPECT_NE(sh, nullptr); -} - -static void test_compile_builtin_shader(eGPUBuiltinShader shader_type) -{ - test_compile_builtin_shader(shader_type, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(shader_type, GPU_SHADER_CFG_CLIPPED); -} - -static void test_shader_builtin() -{ - GPU_shader_free_builtin_shaders(); - - test_compile_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); - test_compile_builtin_shader(GPU_SHADER_3D_SMOOTH_COLOR); - test_compile_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY); - test_compile_builtin_shader(GPU_SHADER_3D_FLAT_COLOR); - test_compile_builtin_shader(GPU_SHADER_3D_LINE_DASHED_UNIFORM_COLOR); - test_compile_builtin_shader(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA); - - test_compile_builtin_shader(GPU_SHADER_TEXT, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_KEYFRAME_SHAPE, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_3D_IMAGE, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_3D_IMAGE_COLOR, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_DESATURATE_COLOR, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_ICON_MULTI, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_CHECKER, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_DIAG_STRIPES, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR, - GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_3D_POLYLINE_FLAT_COLOR, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA, - GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA, - GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR, - GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_GPENCIL_STROKE, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_AREA_BORDERS, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_BASE, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_BASE_INST, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_WIDGET_SHADOW, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_NODELINK, GPU_SHADER_CFG_DEFAULT); - test_compile_builtin_shader(GPU_SHADER_2D_NODELINK_INST, GPU_SHADER_CFG_DEFAULT); -} - -GPU_TEST(shader_builtin) - -} // namespace blender::gpu::tests diff --git a/source/blender/gpu/tests/gpu_storage_buffer_test.cc b/source/blender/gpu/tests/gpu_storage_buffer_test.cc deleted file mode 100644 index 79b23e29407..00000000000 --- a/source/blender/gpu/tests/gpu_storage_buffer_test.cc +++ /dev/null @@ -1,50 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 */ - -#include "testing/testing.h" - -#include "GPU_storage_buffer.h" - -#include "BLI_vector.hh" - -#include "gpu_testing.hh" - -namespace blender::gpu::tests { - -constexpr size_t SIZE = 128; -constexpr size_t SIZE_IN_BYTES = SIZE * sizeof(int); - -static Vector test_data() -{ - Vector data; - for (int i : IndexRange(SIZE)) { - data.append(i); - } - return data; -} - -static void test_gpu_storage_buffer_create_update_read() -{ - GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( - SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__); - EXPECT_NE(ssbo, nullptr); - - /* Upload some dummy data. */ - const Vector data = test_data(); - GPU_storagebuf_update(ssbo, data.data()); - - /* Read back data from SSBO. */ - Vector read_data; - read_data.resize(SIZE, 0); - GPU_storagebuf_read(ssbo, read_data.data()); - - /* Check if data is the same. */ - for (int i : IndexRange(SIZE)) { - EXPECT_EQ(data[i], read_data[i]); - } - - GPU_storagebuf_free(ssbo); -} - -GPU_TEST(gpu_storage_buffer_create_update_read); - -} // namespace blender::gpu::tests diff --git a/source/blender/gpu/tests/gpu_index_buffer_test.cc b/source/blender/gpu/tests/index_buffer_test.cc similarity index 94% rename from source/blender/gpu/tests/gpu_index_buffer_test.cc rename to source/blender/gpu/tests/index_buffer_test.cc index bce5fda9061..bf1643d84a0 100644 --- a/source/blender/gpu/tests/gpu_index_buffer_test.cc +++ b/source/blender/gpu/tests/index_buffer_test.cc @@ -10,7 +10,7 @@ namespace blender::gpu::tests { -static void test_gpu_index_buffer_subbuilders() +static void test_index_buffer_subbuilders() { const uint num_subbuilders = 10; const uint verts_per_subbuilders = 100; @@ -44,6 +44,6 @@ static void test_gpu_index_buffer_subbuilders() GPU_INDEXBUF_DISCARD_SAFE(index_buffer); } -GPU_TEST(gpu_index_buffer_subbuilders) +GPU_TEST(index_buffer_subbuilders) } // namespace blender::gpu::tests diff --git a/source/blender/gpu/tests/memory_layout_test.cc b/source/blender/gpu/tests/memory_layout_test.cc index 55d7f336701..37972f7825d 100644 --- a/source/blender/gpu/tests/memory_layout_test.cc +++ b/source/blender/gpu/tests/memory_layout_test.cc @@ -97,4 +97,4 @@ TEST(std140, fl_vec2) EXPECT_EQ(offset, 16); } -} // namespace blender::gpu \ No newline at end of file +} // namespace blender::gpu diff --git a/source/blender/gpu/tests/gpu_push_constants_test.cc b/source/blender/gpu/tests/push_constants_test.cc similarity index 100% rename from source/blender/gpu/tests/gpu_push_constants_test.cc rename to source/blender/gpu/tests/push_constants_test.cc diff --git a/source/blender/gpu/tests/gpu_shader_test.cc b/source/blender/gpu/tests/shader_test.cc similarity index 87% rename from source/blender/gpu/tests/gpu_shader_test.cc rename to source/blender/gpu/tests/shader_test.cc index 14f25cda36d..26536dd221f 100644 --- a/source/blender/gpu/tests/gpu_shader_test.cc +++ b/source/blender/gpu/tests/shader_test.cc @@ -19,6 +19,7 @@ #include "MEM_guardedalloc.h" #include "gpu_shader_create_info.hh" +#include "gpu_shader_create_info_private.hh" #include "gpu_shader_dependency_private.h" #include "gpu_testing.hh" @@ -26,7 +27,13 @@ namespace blender::gpu::tests { using namespace blender::gpu::shader; -static void test_gpu_shader_compute_2d() +static void test_shader_compile_statically_defined() +{ + EXPECT_TRUE(gpu_shader_create_info_compile_all()); +} +GPU_TEST(shader_compile_statically_defined) + +static void test_shader_compute_2d() { if (!GPU_compute_shader_support()) { @@ -70,9 +77,9 @@ static void test_gpu_shader_compute_2d() GPU_texture_free(texture); GPU_shader_free(shader); } -GPU_TEST(gpu_shader_compute_2d) +GPU_TEST(shader_compute_2d) -static void test_gpu_shader_compute_1d() +static void test_shader_compute_1d() { if (!GPU_compute_shader_support()) { @@ -119,9 +126,9 @@ static void test_gpu_shader_compute_1d() GPU_texture_free(texture); GPU_shader_free(shader); } -GPU_TEST(gpu_shader_compute_1d) +GPU_TEST(shader_compute_1d) -static void test_gpu_shader_compute_vbo() +static void test_shader_compute_vbo() { if (!GPU_compute_shader_support()) { @@ -166,9 +173,9 @@ static void test_gpu_shader_compute_vbo() GPU_vertbuf_discard(vbo); GPU_shader_free(shader); } -GPU_TEST(gpu_shader_compute_vbo) +GPU_TEST(shader_compute_vbo) -static void test_gpu_shader_compute_ibo() +static void test_shader_compute_ibo() { if (!GPU_compute_shader_support()) { @@ -207,9 +214,9 @@ static void test_gpu_shader_compute_ibo() GPU_indexbuf_discard(ibo); GPU_shader_free(shader); } -GPU_TEST(gpu_shader_compute_ibo) +GPU_TEST(shader_compute_ibo) -static void test_gpu_shader_compute_ssbo() +static void test_shader_compute_ssbo() { if (!GPU_compute_shader_support() && !GPU_shader_storage_buffer_objects_support()) { @@ -249,9 +256,9 @@ static void test_gpu_shader_compute_ssbo() GPU_storagebuf_free(ssbo); GPU_shader_free(shader); } -GPU_TEST(gpu_shader_compute_ssbo) +GPU_TEST(shader_compute_ssbo) -static void test_gpu_shader_ssbo_binding() +static void test_shader_ssbo_binding() { if (!GPU_compute_shader_support()) { /* We can't test as a the platform does not support compute shaders. */ @@ -262,53 +269,15 @@ static void test_gpu_shader_ssbo_binding() /* Build compute shader. */ GPUShader *shader = GPU_shader_create_from_info_name("gpu_compute_ssbo_binding_test"); EXPECT_NE(shader, nullptr); - GPU_shader_bind(shader); + /* Perform tests. */ EXPECT_EQ(0, GPU_shader_get_ssbo_binding(shader, "data0")); EXPECT_EQ(1, GPU_shader_get_ssbo_binding(shader, "data1")); /* Cleanup. */ - GPU_shader_unbind(); GPU_shader_free(shader); } -GPU_TEST(gpu_shader_ssbo_binding) - -static void test_gpu_texture_read() -{ - GPU_render_begin(); - - eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; - GPUTexture *rgba32u = GPU_texture_create_2d("rgba32u", 1, 1, 1, GPU_RGBA32UI, usage, nullptr); - GPUTexture *rgba16u = GPU_texture_create_2d("rgba16u", 1, 1, 1, GPU_RGBA16UI, usage, nullptr); - GPUTexture *rgba32f = GPU_texture_create_2d("rgba32f", 1, 1, 1, GPU_RGBA32F, usage, nullptr); - - const float4 fcol = {0.0f, 1.3f, -231.0f, 1000.0f}; - const uint4 ucol = {0, 1, 2, 12223}; - GPU_texture_clear(rgba32u, GPU_DATA_UINT, ucol); - GPU_texture_clear(rgba16u, GPU_DATA_UINT, ucol); - GPU_texture_clear(rgba32f, GPU_DATA_FLOAT, fcol); - - GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); - - uint4 *rgba32u_data = (uint4 *)GPU_texture_read(rgba32u, GPU_DATA_UINT, 0); - uint4 *rgba16u_data = (uint4 *)GPU_texture_read(rgba16u, GPU_DATA_UINT, 0); - float4 *rgba32f_data = (float4 *)GPU_texture_read(rgba32f, GPU_DATA_FLOAT, 0); - - EXPECT_EQ(ucol, *rgba32u_data); - EXPECT_EQ(ucol, *rgba16u_data); - EXPECT_EQ(fcol, *rgba32f_data); - - MEM_freeN(rgba32u_data); - MEM_freeN(rgba16u_data); - MEM_freeN(rgba32f_data); - - GPU_texture_free(rgba32u); - GPU_texture_free(rgba16u); - GPU_texture_free(rgba32f); - - GPU_render_end(); -} -GPU_TEST(gpu_texture_read) +GPU_TEST(shader_ssbo_binding) static std::string print_test_data(const TestOutputRawData &raw, TestType type) { @@ -481,11 +450,11 @@ static void gpu_shader_lib_test(const char *test_src_name, const char *additiona GPU_render_end(); } -static void test_gpu_math_lib() +static void test_math_lib() { gpu_shader_lib_test("gpu_math_test.glsl"); } -GPU_TEST(gpu_math_lib) +GPU_TEST(math_lib) static void test_eevee_lib() { diff --git a/source/blender/gpu/tests/storage_buffer_test.cc b/source/blender/gpu/tests/storage_buffer_test.cc new file mode 100644 index 00000000000..3903fade393 --- /dev/null +++ b/source/blender/gpu/tests/storage_buffer_test.cc @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +#include "testing/testing.h" + +#include "GPU_storage_buffer.h" + +#include "BLI_vector.hh" + +#include "gpu_testing.hh" + +namespace blender::gpu::tests { + +constexpr size_t SIZE = 128; +constexpr size_t SIZE_IN_BYTES = SIZE * sizeof(int); + +static Vector test_data() +{ + Vector data; + for (int i : IndexRange(SIZE)) { + data.append(i); + } + return data; +} + +static void test_storage_buffer_create_update_read() +{ + GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( + SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__); + EXPECT_NE(ssbo, nullptr); + + /* Upload some dummy data. */ + const Vector data = test_data(); + GPU_storagebuf_update(ssbo, data.data()); + + /* Read back data from SSBO. */ + Vector read_data; + read_data.resize(SIZE, 0); + GPU_storagebuf_read(ssbo, read_data.data()); + + /* Check if data is the same. */ + for (int i : IndexRange(SIZE)) { + EXPECT_EQ(data[i], read_data[i]); + } + + GPU_storagebuf_free(ssbo); +} + +GPU_TEST(storage_buffer_create_update_read); + +static void test_storage_buffer_clear_zero() +{ + GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( + SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__); + EXPECT_NE(ssbo, nullptr); + + /* Upload some dummy data. */ + const Vector data = test_data(); + GPU_storagebuf_update(ssbo, data.data()); + GPU_storagebuf_clear_to_zero(ssbo); + + /* Read back data from SSBO. */ + Vector read_data; + read_data.resize(SIZE, 0); + GPU_storagebuf_read(ssbo, read_data.data()); + + /* Check if data is the same. */ + for (int i : IndexRange(SIZE)) { + EXPECT_EQ(0, read_data[i]); + } + + GPU_storagebuf_free(ssbo); +} +GPU_TEST(storage_buffer_clear_zero); + +static void test_storage_buffer_clear() +{ + GPUStorageBuf *ssbo = GPU_storagebuf_create_ex( + SIZE_IN_BYTES, nullptr, GPU_USAGE_STATIC, __func__); + EXPECT_NE(ssbo, nullptr); + + GPU_storagebuf_clear(ssbo, 157255); + + /* Read back data from SSBO. */ + Vector read_data; + read_data.resize(SIZE, 0); + GPU_storagebuf_read(ssbo, read_data.data()); + + /* Check if datatest_ is the same. */ + for (int i : IndexRange(SIZE)) { + EXPECT_EQ(157255, read_data[i]); + } + + GPU_storagebuf_free(ssbo); +} + +GPU_TEST(storage_buffer_clear); + +} // namespace blender::gpu::tests diff --git a/source/blender/gpu/tests/texture_test.cc b/source/blender/gpu/tests/texture_test.cc new file mode 100644 index 00000000000..c453e9eb2d2 --- /dev/null +++ b/source/blender/gpu/tests/texture_test.cc @@ -0,0 +1,49 @@ +#include "gpu_testing.hh" + +#include "MEM_guardedalloc.h" + +#include "BLI_math_vector.hh" + +#include "GPU_context.h" +#include "GPU_texture.h" + +namespace blender::gpu::tests { + +static void test_texture_read() +{ + GPU_render_begin(); + + eGPUTextureUsage usage = GPU_TEXTURE_USAGE_ATTACHMENT | GPU_TEXTURE_USAGE_HOST_READ; + GPUTexture *rgba32u = GPU_texture_create_2d("rgba32u", 1, 1, 1, GPU_RGBA32UI, usage, nullptr); + GPUTexture *rgba16u = GPU_texture_create_2d("rgba16u", 1, 1, 1, GPU_RGBA16UI, usage, nullptr); + GPUTexture *rgba32f = GPU_texture_create_2d("rgba32f", 1, 1, 1, GPU_RGBA32F, usage, nullptr); + + const float4 fcol = {0.0f, 1.3f, -231.0f, 1000.0f}; + const uint4 ucol = {0, 1, 2, 12223}; + GPU_texture_clear(rgba32u, GPU_DATA_UINT, ucol); + GPU_texture_clear(rgba16u, GPU_DATA_UINT, ucol); + GPU_texture_clear(rgba32f, GPU_DATA_FLOAT, fcol); + + GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); + + uint4 *rgba32u_data = (uint4 *)GPU_texture_read(rgba32u, GPU_DATA_UINT, 0); + uint4 *rgba16u_data = (uint4 *)GPU_texture_read(rgba16u, GPU_DATA_UINT, 0); + float4 *rgba32f_data = (float4 *)GPU_texture_read(rgba32f, GPU_DATA_FLOAT, 0); + + EXPECT_EQ(ucol, *rgba32u_data); + EXPECT_EQ(ucol, *rgba16u_data); + EXPECT_EQ(fcol, *rgba32f_data); + + MEM_freeN(rgba32u_data); + MEM_freeN(rgba16u_data); + MEM_freeN(rgba32f_data); + + GPU_texture_free(rgba32u); + GPU_texture_free(rgba16u); + GPU_texture_free(rgba32f); + + GPU_render_end(); +} +GPU_TEST(texture_read) + +} // namespace blender::gpu::tests \ No newline at end of file diff --git a/source/blender/gpu/vulkan/vk_buffer.cc b/source/blender/gpu/vulkan/vk_buffer.cc index f882783041d..feb5ca9c9a0 100644 --- a/source/blender/gpu/vulkan/vk_buffer.cc +++ b/source/blender/gpu/vulkan/vk_buffer.cc @@ -70,35 +70,65 @@ bool VKBuffer::create(VKContext &context, VkResult result = vmaCreateBuffer( allocator, &create_info, &vma_create_info, &vk_buffer_, &allocation_, nullptr); - return result == VK_SUCCESS; -} - -bool VKBuffer::update(VKContext &context, const void *data) -{ - void *mapped_memory; - bool result = map(context, &mapped_memory); - if (result) { - memcpy(mapped_memory, data, size_in_bytes_); - unmap(context); + if (result != VK_SUCCESS) { + return false; } - return result; + + /* All buffers are mapped to virtual memory. */ + return map(context); } -bool VKBuffer::map(VKContext &context, void **r_mapped_memory) const +void VKBuffer::update(const void *data) const { + BLI_assert_msg(is_mapped(), "Cannot update a non-mapped buffer."); + memcpy(mapped_memory_, data, size_in_bytes_); +} + +void VKBuffer::clear(VKContext &context, uint32_t clear_value) +{ + VKCommandBuffer &command_buffer = context.command_buffer_get(); + command_buffer.fill(*this, clear_value); +} + +void VKBuffer::read(void *data) const +{ + BLI_assert_msg(is_mapped(), "Cannot read a non-mapped buffer."); + memcpy(data, mapped_memory_, size_in_bytes_); +} + +void *VKBuffer::mapped_memory_get() const +{ + BLI_assert_msg(is_mapped(), "Cannot access a non-mapped buffer."); + return mapped_memory_; +} + +bool VKBuffer::is_mapped() const +{ + return mapped_memory_ != nullptr; +} + +bool VKBuffer::map(VKContext &context) +{ + BLI_assert(!is_mapped()); VmaAllocator allocator = context.mem_allocator_get(); - VkResult result = vmaMapMemory(allocator, allocation_, r_mapped_memory); + VkResult result = vmaMapMemory(allocator, allocation_, &mapped_memory_); return result == VK_SUCCESS; } -void VKBuffer::unmap(VKContext &context) const +void VKBuffer::unmap(VKContext &context) { + BLI_assert(is_mapped()); VmaAllocator allocator = context.mem_allocator_get(); vmaUnmapMemory(allocator, allocation_); + mapped_memory_ = nullptr; } bool VKBuffer::free(VKContext &context) { + if (is_mapped()) { + unmap(context); + } + VmaAllocator allocator = context.mem_allocator_get(); vmaDestroyBuffer(allocator, vk_buffer_, allocation_); return true; diff --git a/source/blender/gpu/vulkan/vk_buffer.hh b/source/blender/gpu/vulkan/vk_buffer.hh index 23a8c18aa39..dac3519fbb8 100644 --- a/source/blender/gpu/vulkan/vk_buffer.hh +++ b/source/blender/gpu/vulkan/vk_buffer.hh @@ -21,6 +21,8 @@ class VKBuffer { int64_t size_in_bytes_; VkBuffer vk_buffer_ = VK_NULL_HANDLE; VmaAllocation allocation_ = VK_NULL_HANDLE; + /* Pointer to the virtually mapped memory. */ + void *mapped_memory_ = nullptr; public: VKBuffer() = default; @@ -33,10 +35,10 @@ class VKBuffer { int64_t size, GPUUsageType usage, VkBufferUsageFlagBits buffer_usage); - bool update(VKContext &context, const void *data); + void clear(VKContext &context, uint32_t clear_value); + void update(const void *data) const; + void read(void *data) const; bool free(VKContext &context); - bool map(VKContext &context, void **r_mapped_memory) const; - void unmap(VKContext &context) const; int64_t size_in_bytes() const { @@ -47,5 +49,18 @@ class VKBuffer { { return vk_buffer_; } + + /** + * Get the reference to the mapped memory. + * + * Can only be called when the buffer is (still) mapped. + */ + void *mapped_memory_get() const; + + private: + /** Check if this buffer is mapped. */ + bool is_mapped() const; + bool map(VKContext &context); + void unmap(VKContext &context); }; } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_command_buffer.cc b/source/blender/gpu/vulkan/vk_command_buffer.cc index b4526df6aba..af8d39bcf7b 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.cc +++ b/source/blender/gpu/vulkan/vk_command_buffer.cc @@ -86,6 +86,11 @@ void VKCommandBuffer::push_constants(const VKPushConstants &push_constants, push_constants.data()); } +void VKCommandBuffer::fill(VKBuffer &buffer, uint32_t clear_data) +{ + vkCmdFillBuffer(vk_command_buffer_, buffer.vk_handle(), 0, buffer.size_in_bytes(), clear_data); +} + void VKCommandBuffer::copy(VKBuffer &dst_buffer, VKTexture &src_texture, Span regions) diff --git a/source/blender/gpu/vulkan/vk_command_buffer.hh b/source/blender/gpu/vulkan/vk_command_buffer.hh index 0f5f47a423a..103f4ac2300 100644 --- a/source/blender/gpu/vulkan/vk_command_buffer.hh +++ b/source/blender/gpu/vulkan/vk_command_buffer.hh @@ -51,6 +51,7 @@ class VKCommandBuffer : NonCopyable, NonMovable { void pipeline_barrier(VkPipelineStageFlags source_stages, VkPipelineStageFlags destination_stages); void pipeline_barrier(Span image_memory_barriers); + void fill(VKBuffer &buffer, uint32_t data); /** * Stop recording commands, encode + send the recordings to Vulkan, wait for the until the diff --git a/source/blender/gpu/vulkan/vk_context.cc b/source/blender/gpu/vulkan/vk_context.cc index ca03073313b..42b8d9fbd9a 100644 --- a/source/blender/gpu/vulkan/vk_context.cc +++ b/source/blender/gpu/vulkan/vk_context.cc @@ -128,4 +128,27 @@ void VKContext::debug_group_end() { } +bool VKContext::debug_capture_begin() +{ + return false; +} + +void VKContext::debug_capture_end() +{ +} + +void *VKContext::debug_capture_scope_create(const char * /*name*/) +{ + return nullptr; +} + +bool VKContext::debug_capture_scope_begin(void * /*scope*/) +{ + return false; +} + +void VKContext::debug_capture_scope_end(void * /*scope*/) +{ +} + } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_context.hh b/source/blender/gpu/vulkan/vk_context.hh index 912ab1e8dd9..b646492faec 100644 --- a/source/blender/gpu/vulkan/vk_context.hh +++ b/source/blender/gpu/vulkan/vk_context.hh @@ -49,6 +49,11 @@ class VKContext : public Context { void debug_group_begin(const char *, int) override; void debug_group_end() override; + bool debug_capture_begin() override; + void debug_capture_end() override; + void *debug_capture_scope_create(const char *name) override; + bool debug_capture_scope_begin(void *scope) override; + void debug_capture_scope_end(void *scope) override; static VKContext *get(void) { diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.cc b/source/blender/gpu/vulkan/vk_descriptor_pools.cc index d525cd918e7..9e6042114c1 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.cc +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.cc @@ -114,4 +114,4 @@ void VKDescriptorPools::free(VKDescriptorSet &descriptor_set) descriptor_set.mark_freed(); } -} // namespace blender::gpu \ No newline at end of file +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_descriptor_pools.hh b/source/blender/gpu/vulkan/vk_descriptor_pools.hh index 8e90fafa87b..c5c2617cc3a 100644 --- a/source/blender/gpu/vulkan/vk_descriptor_pools.hh +++ b/source/blender/gpu/vulkan/vk_descriptor_pools.hh @@ -62,4 +62,4 @@ class VKDescriptorPools { bool is_last_pool_active(); void add_new_pool(); }; -} // namespace blender::gpu \ No newline at end of file +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_index_buffer.cc b/source/blender/gpu/vulkan/vk_index_buffer.cc index 32b5659b8db..4824d9cc7ec 100644 --- a/source/blender/gpu/vulkan/vk_index_buffer.cc +++ b/source/blender/gpu/vulkan/vk_index_buffer.cc @@ -35,11 +35,7 @@ void VKIndexBuffer::read(uint32_t *data) const VKCommandBuffer &command_buffer = context.command_buffer_get(); command_buffer.submit(); - void *mapped_memory; - if (buffer_.map(context, &mapped_memory)) { - memcpy(data, mapped_memory, size_get()); - buffer_.unmap(context); - } + buffer_.read(data); } void VKIndexBuffer::update_sub(uint /*start*/, uint /*len*/, const void * /*data*/) diff --git a/source/blender/gpu/vulkan/vk_memory_layout.hh b/source/blender/gpu/vulkan/vk_memory_layout.hh index 1641c49e20d..7029e1c4833 100644 --- a/source/blender/gpu/vulkan/vk_memory_layout.hh +++ b/source/blender/gpu/vulkan/vk_memory_layout.hh @@ -15,13 +15,13 @@ namespace blender::gpu { * Information about alignment/components and memory size for types when using std140 layout. */ struct Std140 { - /** Get the memory size in bytes of a single component using by the given type.*/ + /** Get the memory size in bytes of a single component using by the given type. */ static uint32_t component_mem_size(const shader::Type type); - /** Get to alignment of the given type in bytes.*/ + /** Get to alignment of the given type in bytes. */ static uint32_t element_alignment(const shader::Type type, bool is_array); - /** Get the number of components that should be allocated for the given type.*/ + /** Get the number of components that should be allocated for the given type. */ static uint32_t element_components_len(const shader::Type type); - /** Get the number of components of the given type when used in an array.*/ + /** Get the number of components of the given type when used in an array. */ static uint32_t array_components_len(const shader::Type type); }; @@ -29,13 +29,13 @@ struct Std140 { * Information about alignment/components and memory size for types when using std430 layout. */ struct Std430 { - /** Get the memory size in bytes of a single component using by the given type.*/ + /** Get the memory size in bytes of a single component using by the given type. */ static uint32_t component_mem_size(const shader::Type type); - /** Get to alignment of the given type in bytes.*/ + /** Get to alignment of the given type in bytes. */ static uint32_t element_alignment(const shader::Type type, bool is_array); - /** Get the number of components that should be allocated for the given type.*/ + /** Get the number of components that should be allocated for the given type. */ static uint32_t element_components_len(const shader::Type type); - /** Get the number of components of the given type when used in an array.*/ + /** Get the number of components of the given type when used in an array. */ static uint32_t array_components_len(const shader::Type type); }; diff --git a/source/blender/gpu/vulkan/vk_pixel_buffer.cc b/source/blender/gpu/vulkan/vk_pixel_buffer.cc index 609c6ec68a8..f673d444f27 100644 --- a/source/blender/gpu/vulkan/vk_pixel_buffer.cc +++ b/source/blender/gpu/vulkan/vk_pixel_buffer.cc @@ -11,20 +11,28 @@ namespace blender::gpu { VKPixelBuffer::VKPixelBuffer(int64_t size) : PixelBuffer(size) { + VKContext &context = *VKContext::get(); + buffer_.create(context, + size, + GPU_USAGE_STATIC, + static_cast(VK_BUFFER_USAGE_TRANSFER_SRC_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT)); } void *VKPixelBuffer::map() { - return nullptr; + /* Vulkan buffers are always mapped between allocation and freeing. */ + return buffer_.mapped_memory_get(); } void VKPixelBuffer::unmap() { + /* Vulkan buffers are always mapped between allocation and freeing. */ } int64_t VKPixelBuffer::get_native_handle() { - return -1; + return int64_t(buffer_.vk_handle()); } uint VKPixelBuffer::get_size() diff --git a/source/blender/gpu/vulkan/vk_pixel_buffer.hh b/source/blender/gpu/vulkan/vk_pixel_buffer.hh index 7ea1529fd46..c5430444052 100644 --- a/source/blender/gpu/vulkan/vk_pixel_buffer.hh +++ b/source/blender/gpu/vulkan/vk_pixel_buffer.hh @@ -9,9 +9,13 @@ #include "gpu_texture_private.hh" +#include "vk_buffer.hh" + namespace blender::gpu { class VKPixelBuffer : public PixelBuffer { + VKBuffer buffer_; + public: VKPixelBuffer(int64_t size); void *map() override; diff --git a/source/blender/gpu/vulkan/vk_push_constants.hh b/source/blender/gpu/vulkan/vk_push_constants.hh index 9625320b239..f0ea3322dc5 100644 --- a/source/blender/gpu/vulkan/vk_push_constants.hh +++ b/source/blender/gpu/vulkan/vk_push_constants.hh @@ -45,12 +45,12 @@ class VKContext; */ class VKPushConstants : NonCopyable { public: - /** Different methods to store push constants.*/ + /** Different methods to store push constants. */ enum class StorageType { - /** Push constants aren't in use.*/ + /** Push constants aren't in use. */ NONE, - /** Store push constants as regular vulkan push constants.*/ + /** Store push constants as regular vulkan push constants. */ PUSH_CONSTANTS, /** @@ -67,7 +67,7 @@ class VKPushConstants : NonCopyable { static constexpr StorageType STORAGE_TYPE_FALLBACK = StorageType::UNIFORM_BUFFER; struct PushConstant { - /* Used as lookup based on ShaderInput.*/ + /* Used as lookup based on ShaderInput. */ int32_t location; /** Offset in the push constant data (in bytes). */ @@ -213,7 +213,7 @@ class VKPushConstants : NonCopyable { } /* Store elements in uniform buffer as array. In Std140 arrays have an element stride of 16 - * bytes.*/ + * bytes. */ BLI_assert(sizeof(T) == 4); const T *src = input_data; for (const int i : IndexRange(array_size)) { diff --git a/source/blender/gpu/vulkan/vk_shader.cc b/source/blender/gpu/vulkan/vk_shader.cc index bacb87b1dfd..cd502b7d085 100644 --- a/source/blender/gpu/vulkan/vk_shader.cc +++ b/source/blender/gpu/vulkan/vk_shader.cc @@ -909,7 +909,7 @@ static void add_descriptor_set_layout_bindings( r_bindings.append(create_descriptor_set_layout_binding(location, resource)); } - /* Add push constants to the descriptor when push constants are stored in an uniform buffer.*/ + /* Add push constants to the descriptor when push constants are stored in an uniform buffer. */ const VKPushConstants::Layout &push_constants_layout = interface.push_constants_layout_get(); if (push_constants_layout.storage_type_get() == VKPushConstants::StorageType::UNIFORM_BUFFER) { r_bindings.append(create_descriptor_set_layout_binding(push_constants_layout)); diff --git a/source/blender/gpu/vulkan/vk_shader_interface.cc b/source/blender/gpu/vulkan/vk_shader_interface.cc index 64d55065c80..5d1fe1476a0 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.cc +++ b/source/blender/gpu/vulkan/vk_shader_interface.cc @@ -138,8 +138,8 @@ void VKShaderInterface::init(const shader::ShaderCreateInfo &info) descriptor_set_location_update(input, descriptor_set_location++); } - /* Post initializing push constants.*/ - /* Determine the binding location of push constants fallback buffer.*/ + /* Post initializing push constants. */ + /* Determine the binding location of push constants fallback buffer. */ int32_t push_constant_descriptor_set_location = -1; if (push_constants_storage_type == VKPushConstants::StorageType::UNIFORM_BUFFER) { push_constant_descriptor_set_location = descriptor_set_location++; diff --git a/source/blender/gpu/vulkan/vk_shader_interface.hh b/source/blender/gpu/vulkan/vk_shader_interface.hh index 29278b4c5b4..bd41ff382d7 100644 --- a/source/blender/gpu/vulkan/vk_shader_interface.hh +++ b/source/blender/gpu/vulkan/vk_shader_interface.hh @@ -41,7 +41,7 @@ class VKShaderInterface : public ShaderInterface { const VKDescriptorSet::Location descriptor_set_location( const shader::ShaderCreateInfo::Resource::BindType &bind_type, int binding) const; - /** Get the Layout of the shader.*/ + /** Get the Layout of the shader. */ const VKPushConstants::Layout &push_constants_layout_get() const { return push_constants_layout_; diff --git a/source/blender/gpu/vulkan/vk_state_manager.cc b/source/blender/gpu/vulkan/vk_state_manager.cc index 4e6eb3298bd..c970b3d6748 100644 --- a/source/blender/gpu/vulkan/vk_state_manager.cc +++ b/source/blender/gpu/vulkan/vk_state_manager.cc @@ -56,4 +56,4 @@ void VKStateManager::texture_unpack_row_length_set(uint /*len*/) { } -} // namespace blender::gpu \ No newline at end of file +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_state_manager.hh b/source/blender/gpu/vulkan/vk_state_manager.hh index 4d2643485c1..c1c50d0b62e 100644 --- a/source/blender/gpu/vulkan/vk_state_manager.hh +++ b/source/blender/gpu/vulkan/vk_state_manager.hh @@ -27,4 +27,4 @@ class VKStateManager : public StateManager { void texture_unpack_row_length_set(uint len) override; }; -} // namespace blender::gpu \ No newline at end of file +} // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.cc b/source/blender/gpu/vulkan/vk_storage_buffer.cc index 8b5545f223f..fd89fc38296 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.cc +++ b/source/blender/gpu/vulkan/vk_storage_buffer.cc @@ -14,16 +14,20 @@ namespace blender::gpu { void VKStorageBuffer::update(const void *data) { - VKContext &context = *VKContext::get(); if (!buffer_.is_allocated()) { + VKContext &context = *VKContext::get(); allocate(context); } - buffer_.update(context, data); + buffer_.update(data); } void VKStorageBuffer::allocate(VKContext &context) { - buffer_.create(context, size_in_bytes_, usage_, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT); + buffer_.create(context, + size_in_bytes_, + usage_, + static_cast(VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | + VK_BUFFER_USAGE_TRANSFER_DST_BIT)); } void VKStorageBuffer::bind(int slot) @@ -43,11 +47,15 @@ void VKStorageBuffer::unbind() { } -void VKStorageBuffer::clear(eGPUTextureFormat /*internal_format*/, - eGPUDataFormat /*data_format*/, - void * /*data*/) +void VKStorageBuffer::clear(uint32_t clear_value) { + VKContext &context = *VKContext::get(); + if (!buffer_.is_allocated()) { + allocate(context); + } + buffer_.clear(context, clear_value); } + void VKStorageBuffer::copy_sub(VertBuf * /*src*/, uint /*dst_offset*/, uint /*src_offset*/, @@ -65,11 +73,7 @@ void VKStorageBuffer::read(void *data) VKCommandBuffer &command_buffer = context.command_buffer_get(); command_buffer.submit(); - void *mapped_memory; - if (buffer_.map(context, &mapped_memory)) { - memcpy(data, mapped_memory, size_in_bytes_); - buffer_.unmap(context); - } + buffer_.read(data); } } // namespace blender::gpu diff --git a/source/blender/gpu/vulkan/vk_storage_buffer.hh b/source/blender/gpu/vulkan/vk_storage_buffer.hh index a9ee1a6256b..b35e9d990c3 100644 --- a/source/blender/gpu/vulkan/vk_storage_buffer.hh +++ b/source/blender/gpu/vulkan/vk_storage_buffer.hh @@ -30,7 +30,7 @@ class VKStorageBuffer : public StorageBuf { void update(const void *data) override; void bind(int slot) override; void unbind() override; - void clear(eGPUTextureFormat internal_format, eGPUDataFormat data_format, void *data) override; + void clear(uint32_t clear_value) override; void copy_sub(VertBuf *src, uint dst_offset, uint src_offset, uint copy_size) override; void read(void *data) override; diff --git a/source/blender/gpu/vulkan/vk_texture.cc b/source/blender/gpu/vulkan/vk_texture.cc index 7816ea8a8f2..1732d54a949 100644 --- a/source/blender/gpu/vulkan/vk_texture.cc +++ b/source/blender/gpu/vulkan/vk_texture.cc @@ -78,17 +78,13 @@ void *VKTexture::read(int mip, eGPUDataFormat format) command_buffer.copy(staging_buffer, *this, Span(®ion, 1)); command_buffer.submit(); - void *mapped_data; - staging_buffer.map(context, &mapped_data); - void *data = MEM_mallocN(host_memory_size, __func__); /* TODO: add conversion when data format is different. */ BLI_assert_msg(device_memory_size == host_memory_size, "Memory data conversions not implemented yet"); - memcpy(data, mapped_data, host_memory_size); - staging_buffer.unmap(context); + staging_buffer.read(data); return data; } diff --git a/source/blender/gpu/vulkan/vk_uniform_buffer.cc b/source/blender/gpu/vulkan/vk_uniform_buffer.cc index 1aee3c3eee4..398dfb68466 100644 --- a/source/blender/gpu/vulkan/vk_uniform_buffer.cc +++ b/source/blender/gpu/vulkan/vk_uniform_buffer.cc @@ -12,11 +12,11 @@ namespace blender::gpu { void VKUniformBuffer::update(const void *data) { - VKContext &context = *VKContext::get(); if (!buffer_.is_allocated()) { + VKContext &context = *VKContext::get(); allocate(context); } - buffer_.update(context, data); + buffer_.update(data); } void VKUniformBuffer::allocate(VKContext &context) diff --git a/source/blender/gpu/vulkan/vk_vertex_buffer.cc b/source/blender/gpu/vulkan/vk_vertex_buffer.cc index b28822ab705..e667473cb2f 100644 --- a/source/blender/gpu/vulkan/vk_vertex_buffer.cc +++ b/source/blender/gpu/vulkan/vk_vertex_buffer.cc @@ -49,12 +49,7 @@ void VKVertexBuffer::read(void *data) const VKContext &context = *VKContext::get(); VKCommandBuffer &command_buffer = context.command_buffer_get(); command_buffer.submit(); - - void *mapped_memory; - if (buffer_.map(context, &mapped_memory)) { - memcpy(data, mapped_memory, size_used_get()); - buffer_.unmap(context); - } + buffer_.read(data); } void VKVertexBuffer::acquire_data() diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt index e8e8bc580c1..abf111961bd 100644 --- a/source/blender/imbuf/CMakeLists.txt +++ b/source/blender/imbuf/CMakeLists.txt @@ -18,6 +18,7 @@ set(INC_SYS ${JPEG_INCLUDE_DIR} ${PNG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} + ${OPENIMAGEIO_INCLUDE_DIRS} ) set(SRC @@ -29,6 +30,7 @@ set(SRC intern/divers.c intern/filetype.c intern/filter.c + intern/format_psd.cc intern/imageprocess.c intern/indexer.c intern/iris.c diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 79be739a205..40c7c113129 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -677,8 +677,10 @@ void IMB_sampleImageAtLocation( /** * \attention defined in readimage.c */ -struct ImBuf *IMB_loadifffile( - int file, const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr); +struct ImBuf *IMB_loadifffile(int file, + int flags, + char colorspace[IM_MAX_SPACE], + const char *descr); /** * \attention defined in scaling.c diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h index 5d4b8e453b3..c5bd60358b0 100644 --- a/source/blender/imbuf/IMB_imbuf_types.h +++ b/source/blender/imbuf/IMB_imbuf_types.h @@ -318,9 +318,6 @@ extern const char *imb_ext_image[]; extern const char *imb_ext_movie[]; extern const char *imb_ext_audio[]; -/** Image formats that can only be loaded via filepath. */ -extern const char *imb_ext_image_filepath_only[]; - /* -------------------------------------------------------------------- */ /** \name Imbuf Color Management Flag * diff --git a/source/blender/imbuf/intern/IMB_filetype.h b/source/blender/imbuf/intern/IMB_filetype.h index 8252b0dd0b3..4a226cbc9fd 100644 --- a/source/blender/imbuf/intern/IMB_filetype.h +++ b/source/blender/imbuf/intern/IMB_filetype.h @@ -8,6 +8,10 @@ #include "IMB_imbuf.h" +#ifdef __cplusplus +extern "C" { +#endif + /* -------------------------------------------------------------------- */ /** \name Generic File Type * \{ */ @@ -256,3 +260,20 @@ struct ImBuf *imb_load_filepath_thumbnail_webp(const char *filepath, bool imb_savewebp(struct ImBuf *ibuf, const char *name, int flags); /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Format: PSD (#IMB_FTYPE_PSD) + * \{ */ + +bool imb_is_a_psd(const unsigned char *buf, size_t size); + +struct ImBuf *imb_load_psd(const uchar *mem, + size_t size, + int flags, + char colorspace[IM_MAX_SPACE]); + +/** \} */ + +#ifdef __cplusplus +}; +#endif diff --git a/source/blender/imbuf/intern/filetype.c b/source/blender/imbuf/intern/filetype.c index 06b70d354a9..aef1088efd4 100644 --- a/source/blender/imbuf/intern/filetype.c +++ b/source/blender/imbuf/intern/filetype.c @@ -184,9 +184,9 @@ const ImFileType IMB_FILE_TYPES[] = { { .init = NULL, .exit = NULL, - .is_a = imb_is_a_photoshop, - .load = NULL, - .load_filepath = imb_load_photoshop, + .is_a = imb_is_a_psd, + .load = imb_load_psd, + .load_filepath = NULL, .load_filepath_thumbnail = NULL, .save = NULL, .flag = IM_FTYPE_FLOAT, diff --git a/source/blender/imbuf/intern/format_psd.cc b/source/blender/imbuf/intern/format_psd.cc new file mode 100644 index 00000000000..21c97108d75 --- /dev/null +++ b/source/blender/imbuf/intern/format_psd.cc @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "oiio/openimageio_support.hh" + +#include "IMB_filetype.h" + +#include "IMB_imbuf_types.h" + +OIIO_NAMESPACE_USING +using namespace blender::imbuf; + +extern "C" { + +bool imb_is_a_psd(const uchar *mem, size_t size) +{ + return imb_oiio_check(mem, size, "psd"); +} + +ImBuf *imb_load_psd(const uchar *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) +{ + ImageSpec config, spec; + config.attribute("oiio:UnassociatedAlpha", 1); + + ReadContext ctx{mem, size, "psd", IMB_FTYPE_PSD, flags}; + + /* PSD should obey color space information embedded in the file. */ + ctx.use_embedded_colorspace = true; + + return imb_oiio_read(ctx, config, colorspace, spec); +} +} diff --git a/source/blender/imbuf/intern/oiio/CMakeLists.txt b/source/blender/imbuf/intern/oiio/CMakeLists.txt index 03a38928537..ef505cb85e9 100644 --- a/source/blender/imbuf/intern/oiio/CMakeLists.txt +++ b/source/blender/imbuf/intern/oiio/CMakeLists.txt @@ -18,8 +18,10 @@ set(INC_SYS set(SRC openimageio_api.h + openimageio_support.hh openimageio_api.cpp + openimageio_support.cc ) set(LIB diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.cpp b/source/blender/imbuf/intern/oiio/openimageio_api.cpp index 7ed084b7144..b803eff36b0 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_api.cpp +++ b/source/blender/imbuf/intern/oiio/openimageio_api.cpp @@ -5,278 +5,16 @@ * \ingroup openimageio */ -#include - -#if defined(WIN32) -# include "utfconv.h" -# define _USE_MATH_DEFINES -#endif - -/* NOTE: Keep first, #BLI_path_util conflicts with OIIO's format. */ #include "openimageio_api.h" #include -#include - -#include "MEM_guardedalloc.h" - -#include "BLI_blenlib.h" - -#include "IMB_allocimbuf.h" -#include "IMB_colormanagement.h" -#include "IMB_colormanagement_intern.h" -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" OIIO_NAMESPACE_USING -using std::string; -using std::unique_ptr; - -using uchar = uchar; - -template -static void fill_all_channels(T *pixels, int width, int height, int components, Q alpha) -{ - if (components == 2) { - for (int i = width * height - 1; i >= 0; i--) { - pixels[i * 4 + 3] = pixels[i * 2 + 1]; - pixels[i * 4 + 2] = pixels[i * 2 + 0]; - pixels[i * 4 + 1] = pixels[i * 2 + 0]; - pixels[i * 4 + 0] = pixels[i * 2 + 0]; - } - } - else if (components == 3) { - for (int i = width * height - 1; i >= 0; i--) { - pixels[i * 4 + 3] = alpha; - pixels[i * 4 + 2] = pixels[i * 3 + 2]; - pixels[i * 4 + 1] = pixels[i * 3 + 1]; - pixels[i * 4 + 0] = pixels[i * 3 + 0]; - } - } - else if (components == 1) { - for (int i = width * height - 1; i >= 0; i--) { - pixels[i * 4 + 3] = alpha; - pixels[i * 4 + 2] = pixels[i]; - pixels[i * 4 + 1] = pixels[i]; - pixels[i * 4 + 0] = pixels[i]; - } - } -} - -static ImBuf *imb_oiio_load_image( - ImageInput *in, int width, int height, int components, int flags, bool is_alpha) -{ - ImBuf *ibuf; - int scanlinesize = width * components * sizeof(uchar); - - /* allocate the memory for the image */ - ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, flags | IB_rect); - - try { - if (!in->read_image(0, - 0, - 0, - components, - TypeDesc::UINT8, - (uchar *)ibuf->rect + (height - 1) * scanlinesize, - AutoStride, - -scanlinesize, - AutoStride)) { - std::cerr << __func__ << ": ImageInput::read_image() failed:" << std::endl - << in->geterror() << std::endl; - - if (ibuf) { - IMB_freeImBuf(ibuf); - } - - return nullptr; - } - } - catch (const std::exception &exc) { - std::cerr << exc.what() << std::endl; - if (ibuf) { - IMB_freeImBuf(ibuf); - } - - return nullptr; - } - - /* ImBuf always needs 4 channels */ - fill_all_channels((uchar *)ibuf->rect, width, height, components, 0xFF); - - return ibuf; -} - -static ImBuf *imb_oiio_load_image_float( - ImageInput *in, int width, int height, int components, int flags, bool is_alpha) -{ - ImBuf *ibuf; - int scanlinesize = width * components * sizeof(float); - - /* allocate the memory for the image */ - ibuf = IMB_allocImBuf(width, height, is_alpha ? 32 : 24, flags | IB_rectfloat); - - try { - if (!in->read_image(0, - 0, - 0, - components, - TypeDesc::FLOAT, - (uchar *)ibuf->rect_float + (height - 1) * scanlinesize, - AutoStride, - -scanlinesize, - AutoStride)) { - std::cerr << __func__ << ": ImageInput::read_image() failed:" << std::endl - << in->geterror() << std::endl; - - if (ibuf) { - IMB_freeImBuf(ibuf); - } - - return nullptr; - } - } - catch (const std::exception &exc) { - std::cerr << exc.what() << std::endl; - if (ibuf) { - IMB_freeImBuf(ibuf); - } - - return nullptr; - } - - /* ImBuf always needs 4 channels */ - fill_all_channels((float *)ibuf->rect_float, width, height, components, 1.0f); - - /* NOTE: Photoshop 16 bit files never has alpha with it, - * so no need to handle associated/unassociated alpha. */ - return ibuf; -} - extern "C" { -bool imb_is_a_photoshop(const uchar *mem, size_t size) -{ - const uchar magic[4] = {'8', 'B', 'P', 'S'}; - if (size < sizeof(magic)) { - return false; - } - return memcmp(magic, mem, sizeof(magic)) == 0; -} - -int imb_save_photoshop(struct ImBuf *ibuf, const char * /*name*/, int flags) -{ - if (flags & IB_mem) { - std::cerr << __func__ << ": Photoshop PSD-save: Create PSD in memory" - << " currently not supported" << std::endl; - imb_addencodedbufferImBuf(ibuf); - ibuf->encodedsize = 0; - return 0; - } - - return 0; -} - -struct ImBuf *imb_load_photoshop(const char *filename, int flags, char colorspace[IM_MAX_SPACE]) -{ - struct ImBuf *ibuf = nullptr; - int width, height, components; - bool is_float, is_alpha, is_half; - int basesize; - char file_colorspace[IM_MAX_SPACE]; - const bool is_colorspace_manually_set = (colorspace[0] != '\0'); - - /* load image from file through OIIO */ - if (IMB_ispic_type_matches(filename, IMB_FTYPE_PSD) == 0) { - return nullptr; - } - - colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); - - unique_ptr in(ImageInput::create(filename)); - if (!in) { - std::cerr << __func__ << ": ImageInput::create() failed:" << std::endl - << OIIO_NAMESPACE::geterror() << std::endl; - return nullptr; - } - - ImageSpec spec, config; - config.attribute("oiio:UnassociatedAlpha", int(1)); - - if (!in->open(filename, spec, config)) { - std::cerr << __func__ << ": ImageInput::open() failed:" << std::endl - << in->geterror() << std::endl; - return nullptr; - } - - if (!is_colorspace_manually_set) { - string ics = spec.get_string_attribute("oiio:ColorSpace"); - BLI_strncpy(file_colorspace, ics.c_str(), IM_MAX_SPACE); - - /* Only use color-spaces exist. */ - if (colormanage_colorspace_get_named(file_colorspace)) { - strcpy(colorspace, file_colorspace); - } - else { - std::cerr << __func__ << ": The embed colorspace (\"" << file_colorspace - << "\") not supported in existent OCIO configuration file. Fallback " - << "to system default colorspace (\"" << colorspace << "\")." << std::endl; - } - } - - width = spec.width; - height = spec.height; - components = spec.nchannels; - is_alpha = spec.alpha_channel != -1; - basesize = spec.format.basesize(); - is_float = basesize > 1; - is_half = spec.format == TypeDesc::HALF; - - /* we only handle certain number of components */ - if (!(components >= 1 && components <= 4)) { - if (in) { - in->close(); - } - return nullptr; - } - - if (is_float) { - ibuf = imb_oiio_load_image_float(in.get(), width, height, components, flags, is_alpha); - } - else { - ibuf = imb_oiio_load_image(in.get(), width, height, components, flags, is_alpha); - } - - if (in) { - in->close(); - } - - if (!ibuf) { - return nullptr; - } - - /* ImBuf always needs 4 channels */ - ibuf->ftype = IMB_FTYPE_PSD; - ibuf->channels = 4; - ibuf->planes = (3 + (is_alpha ? 1 : 0)) * 4 << basesize; - ibuf->flags |= (is_float && is_half) ? IB_halffloat : 0; - - try { - return ibuf; - } - catch (const std::exception &exc) { - std::cerr << exc.what() << std::endl; - if (ibuf) { - IMB_freeImBuf(ibuf); - } - - return nullptr; - } -} - int OIIO_getVersionHex(void) { return openimageio_version(); } -} /* export "C" */ +} /* extern "C" */ diff --git a/source/blender/imbuf/intern/oiio/openimageio_api.h b/source/blender/imbuf/intern/oiio/openimageio_api.h index 523c28ddeab..daae3f15f20 100644 --- a/source/blender/imbuf/intern/oiio/openimageio_api.h +++ b/source/blender/imbuf/intern/oiio/openimageio_api.h @@ -7,20 +7,10 @@ #pragma once -#include - #ifdef __cplusplus extern "C" { #endif -struct ImBuf; - -bool imb_is_a_photoshop(const unsigned char *mem, size_t size); - -int imb_save_photoshop(struct ImBuf *ibuf, const char *name, int flags); - -struct ImBuf *imb_load_photoshop(const char *name, int flags, char *colorspace); - int OIIO_getVersionHex(void); #ifdef __cplusplus diff --git a/source/blender/imbuf/intern/oiio/openimageio_support.cc b/source/blender/imbuf/intern/oiio/openimageio_support.cc new file mode 100644 index 00000000000..cdfe74aa4f9 --- /dev/null +++ b/source/blender/imbuf/intern/oiio/openimageio_support.cc @@ -0,0 +1,398 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "openimageio_support.hh" + +#include "BLI_blenlib.h" + +#include "BKE_idprop.h" +#include "DNA_ID.h" /* ID property definitions. */ + +#include "IMB_allocimbuf.h" +#include "IMB_colormanagement.h" +#include "IMB_metadata.h" + +OIIO_NAMESPACE_USING + +using std::string; +using std::unique_ptr; + +namespace blender::imbuf { + +/* An OIIO IOProxy used during file packing to write into an in-memory #ImBuf buffer. */ +class ImBufMemWriter : public Filesystem::IOProxy { + public: + ImBufMemWriter(ImBuf *ibuf) : IOProxy("", Write), ibuf_(ibuf) + { + } + + const char *proxytype() const override + { + return "ImBufMemWriter"; + } + + size_t write(const void *buf, size_t size) override + { + size = pwrite(buf, size, m_pos); + m_pos += size; + return size; + } + + size_t pwrite(const void *buf, size_t size, int64_t offset) override + { + /* If buffer is too small increase it. */ + size_t end = offset + size; + while (end > ibuf_->encodedbuffersize) { + if (!imb_enlargeencodedbufferImBuf(ibuf_)) { + /* Out of memory. */ + return 0; + } + } + + memcpy(ibuf_->encodedbuffer + offset, buf, size); + + if (end > ibuf_->encodedsize) { + ibuf_->encodedsize = end; + } + + return size; + } + + size_t size() const override + { + return ibuf_->encodedsize; + } + + private: + ImBuf *ibuf_; +}; + +/* Utility to in-place expand an n-component pixel buffer into a 4-component buffer. */ +template +static void fill_all_channels(T *pixels, int width, int height, int components, T alpha) +{ + const int64_t pixel_count = int64_t(width) * height; + if (components == 3) { + for (int64_t i = 0; i < pixel_count; i++) { + pixels[i * 4 + 3] = alpha; + } + } + else if (components == 1) { + for (int64_t i = 0; i < pixel_count; i++) { + pixels[i * 4 + 3] = alpha; + pixels[i * 4 + 2] = pixels[i * 4 + 0]; + pixels[i * 4 + 1] = pixels[i * 4 + 0]; + } + } + else if (components == 2) { + for (int64_t i = 0; i < pixel_count; i++) { + pixels[i * 4 + 3] = pixels[i * 4 + 1]; + pixels[i * 4 + 2] = pixels[i * 4 + 0]; + pixels[i * 4 + 1] = pixels[i * 4 + 0]; + } + } +} + +template +static ImBuf *load_pixels( + ImageInput *in, int width, int height, int channels, int flags, bool use_all_planes) +{ + /* Allocate the ImBuf for the image. */ + constexpr bool is_float = sizeof(T) > 1; + const uint format_flag = is_float ? IB_rectfloat : IB_rect; + const uint ibuf_flags = (flags & IB_test) ? 0 : format_flag; + const int planes = use_all_planes ? 32 : 8 * channels; + ImBuf *ibuf = IMB_allocImBuf(width, height, planes, ibuf_flags); + if (!ibuf) { + return nullptr; + } + + /* No need to load actual pixel data during the test phase. */ + if (flags & IB_test) { + return ibuf; + } + + /* Calculate an appropriate stride to read n-channels directly into + * the ImBuf 4-channel layout. */ + const stride_t ibuf_xstride = sizeof(T) * 4; + const stride_t ibuf_ystride = ibuf_xstride * width; + const TypeDesc format = is_float ? TypeDesc::FLOAT : TypeDesc::UINT8; + uchar *rect = is_float ? reinterpret_cast(ibuf->rect_float) : + reinterpret_cast(ibuf->rect); + void *ibuf_data = rect + ((stride_t(height) - 1) * ibuf_ystride); + + bool ok = in->read_image( + 0, 0, 0, channels, format, ibuf_data, ibuf_xstride, -ibuf_ystride, AutoStride); + if (!ok) { + fprintf(stderr, "ImageInput::read_image() failed: %s\n", in->geterror().c_str()); + + IMB_freeImBuf(ibuf); + return nullptr; + } + + /* ImBuf always needs 4 channels */ + const T alpha_fill = is_float ? 1.0f : 0xFF; + fill_all_channels(reinterpret_cast(rect), width, height, channels, alpha_fill); + + return ibuf; +} + +static void set_colorspace_name(char colorspace[IM_MAX_SPACE], + const ReadContext &ctx, + const ImageSpec &spec, + bool is_float) +{ + const bool is_colorspace_set = (colorspace[0] != '\0'); + if (is_colorspace_set) { + return; + } + + /* Use a default role unless otherwise specified. */ + if (ctx.use_colorspace_role >= 0) { + colorspace_set_default_role(colorspace, IM_MAX_SPACE, ctx.use_colorspace_role); + } + else if (is_float) { + colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_FLOAT); + } + else { + colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); + } + + /* Override if necessary. */ + if (ctx.use_embedded_colorspace) { + string ics = spec.get_string_attribute("oiio:ColorSpace"); + char file_colorspace[IM_MAX_SPACE]; + BLI_strncpy(file_colorspace, ics.c_str(), IM_MAX_SPACE); + + /* Only use color-spaces that exist. */ + if (colormanage_colorspace_get_named(file_colorspace)) { + BLI_strncpy(colorspace, file_colorspace, IM_MAX_SPACE); + } + } +} + +/** + * Get an #ImBuf filled in with pixel data and associated metadata using the provided ImageInput. + */ +static ImBuf *get_oiio_ibuf(ImageInput *in, const ReadContext &ctx, char colorspace[IM_MAX_SPACE]) +{ + const ImageSpec &spec = in->spec(); + const int width = spec.width; + const int height = spec.height; + const int channels = spec.nchannels; + const bool has_alpha = spec.alpha_channel != -1; + const bool is_float = spec.format.basesize() > 1; + + if (channels < 1 || channels > 4) { + return nullptr; + } + + const bool use_all_planes = has_alpha || ctx.use_all_planes; + + ImBuf *ibuf = nullptr; + if (is_float) { + ibuf = load_pixels(in, width, height, channels, ctx.flags, use_all_planes); + ibuf->channels = 4; + } + else { + ibuf = load_pixels(in, width, height, channels, ctx.flags, use_all_planes); + } + + /* Fill in common ibuf properties. */ + if (ibuf) { + ibuf->ftype = ctx.file_type; + ibuf->flags |= (spec.format == TypeDesc::HALF) ? IB_halffloat : 0; + + set_colorspace_name(colorspace, ctx, spec, is_float); + + float x_res = spec.get_float_attribute("XResolution", 0.0f); + float y_res = spec.get_float_attribute("YResolution", 0.0f); + if (x_res > 0.0f && y_res > 0.0f) { + double scale = 1.0; + auto unit = spec.get_string_attribute("ResolutionUnit", ""); + if (ELEM(unit, "in", "inch")) { + scale = 100.0 / 2.54; + } + else if (unit == "cm") { + scale = 100.0; + } + ibuf->ppm[0] = scale * x_res; + ibuf->ppm[1] = scale * y_res; + } + + /* Transfer metadata to the ibuf if necessary. */ + if (ctx.flags & IB_metadata) { + IMB_metadata_ensure(&ibuf->metadata); + ibuf->flags |= (spec.extra_attribs.empty()) ? 0 : IB_metadata; + + for (const auto &attrib : spec.extra_attribs) { + IMB_metadata_set_field(ibuf->metadata, attrib.name().c_str(), attrib.get_string().c_str()); + } + } + } + + return ibuf; +} + +/** + * Returns an #ImageInput for the precise `format` requested using the provided #IOMemReader. + * If successful, the #ImageInput will be opened and ready for operations. Null will be returned if + * the format was not found or if the open call fails. + */ +static unique_ptr get_oiio_reader(const char *format, + const ImageSpec &config, + Filesystem::IOMemReader &mem_reader, + ImageSpec &r_newspec) +{ + /* Attempt to create a reader based on the passed in format. */ + unique_ptr in = ImageInput::create(format); + if (!in) { + return nullptr; + } + + /* Open the reader using the ioproxy. */ + in->set_ioproxy(&mem_reader); + bool ok = in->open("", r_newspec, config); + if (!ok) { + in.reset(); + } + + return in; +} + +bool imb_oiio_check(const uchar *mem, size_t mem_size, const char *file_format) +{ + ImageSpec config, spec; + + /* This memory proxy must remain alive for the full duration of the read. */ + Filesystem::IOMemReader mem_reader(cspan(mem, mem_size)); + unique_ptr in = get_oiio_reader(file_format, config, mem_reader, spec); + return in ? true : false; +} + +ImBuf *imb_oiio_read(const ReadContext &ctx, + const ImageSpec &config, + char colorspace[IM_MAX_SPACE], + ImageSpec &r_newspec) +{ + /* This memory proxy must remain alive for the full duration of the read. */ + Filesystem::IOMemReader mem_reader(cspan(ctx.mem_start, ctx.mem_size)); + unique_ptr in = get_oiio_reader(ctx.file_format, config, mem_reader, r_newspec); + if (!in) { + return nullptr; + } + + return get_oiio_ibuf(in.get(), ctx, colorspace); +} + +bool imb_oiio_write(const WriteContext &ctx, const char *filepath, const ImageSpec &file_spec) +{ + unique_ptr out = ImageOutput::create(ctx.file_format); + if (!out) { + return false; + } + + auto write_op = [&out, &ctx]() { + return out->write_image( + ctx.mem_format, ctx.mem_start, ctx.mem_xstride, -ctx.mem_ystride, AutoStride); + }; + + bool ok = false; + if (ctx.flags & IB_mem) { + /* This memory proxy must remain alive for the full duration of the write. */ + ImBufMemWriter writer(ctx.ibuf); + + imb_addencodedbufferImBuf(ctx.ibuf); + out->set_ioproxy(&writer); + out->open("", file_spec); + ok = write_op(); + } + else { + out->open(filepath, file_spec); + ok = write_op(); + } + + out->close(); + return ok; +} + +WriteContext imb_create_write_context(const char *file_format, + ImBuf *ibuf, + int flags, + bool prefer_float) +{ + WriteContext ctx{}; + ctx.file_format = file_format; + ctx.ibuf = ibuf; + ctx.flags = flags; + + const int width = ibuf->x; + const int height = ibuf->y; + const bool use_float = prefer_float && (ibuf->rect_float != nullptr); + if (use_float) { + const int mem_channels = ibuf->channels ? ibuf->channels : 4; + ctx.mem_xstride = sizeof(float) * mem_channels; + ctx.mem_ystride = width * ctx.mem_xstride; + ctx.mem_format = TypeDesc::FLOAT; + ctx.mem_start = reinterpret_cast(ibuf->rect_float); + } + else { + const int mem_channels = 4; + ctx.mem_xstride = sizeof(uchar) * mem_channels; + ctx.mem_ystride = width * ctx.mem_xstride; + ctx.mem_format = TypeDesc::UINT8; + ctx.mem_start = reinterpret_cast(ibuf->rect); + } + + /* We always write using a negative y-stride so ensure we start at the end. */ + ctx.mem_start = ctx.mem_start + ((stride_t(height) - 1) * ctx.mem_ystride); + + return ctx; +} + +ImageSpec imb_create_write_spec(const WriteContext &ctx, int file_channels, TypeDesc data_format) +{ + const int width = ctx.ibuf->x; + const int height = ctx.ibuf->y; + ImageSpec file_spec(width, height, file_channels, data_format); + + /* Populate the spec with all common attributes. + * + * Care must be taken with the metadata: + * - It should be processed first, before the "Resolution" metadata below, to + * ensure the proper values end up in the #ImageSpec + * - It needs to filter format-specific metadata that may no longer apply to + * the current format being written (e.g. metadata for tiff being written to a `PNG`) + */ + + if (ctx.ibuf->metadata) { + for (IDProperty *prop = static_cast(ctx.ibuf->metadata->data.group.first); prop; + prop = prop->next) { + if (prop->type == IDP_STRING) { + /* If this property has a prefixed name (oiio:, tiff:, etc.) and it belongs to + * oiio or a different format, then skip. */ + if (char *colon = strchr(prop->name, ':')) { + std::string prefix(prop->name, colon); + Strutil::to_lower(prefix); + if (prefix == "oiio" || + (!STREQ(prefix.c_str(), ctx.file_format) && OIIO::is_imageio_format_name(prefix))) { + /* Skip this attribute. */ + continue; + } + } + + file_spec.attribute(prop->name, IDP_String(prop)); + } + } + } + + if (ctx.ibuf->ppm[0] > 0.0 && ctx.ibuf->ppm[1] > 0.0) { + /* More OIIO formats support inch than meter. */ + file_spec.attribute("ResolutionUnit", "in"); + file_spec.attribute("XResolution", float(ctx.ibuf->ppm[0] * 0.0254)); + file_spec.attribute("YResolution", float(ctx.ibuf->ppm[1] * 0.0254)); + } + + return file_spec; +} + +} // namespace blender::imbuf diff --git a/source/blender/imbuf/intern/oiio/openimageio_support.hh b/source/blender/imbuf/intern/oiio/openimageio_support.hh new file mode 100644 index 00000000000..f6bf8bda9bc --- /dev/null +++ b/source/blender/imbuf/intern/oiio/openimageio_support.hh @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +#include +#include + +#include "BLI_sys_types.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +namespace blender::imbuf { + +/** + * Parameters and settings used while reading image formats. + */ +struct ReadContext { + const uchar *mem_start; + const size_t mem_size; + const char *file_format; + const eImbFileType file_type; + const int flags; + + /** Override the automatic color-role choice with the value specified here. */ + int use_colorspace_role = -1; + + /** Allocate and use all #ImBuf image planes even if the image has fewer. */ + bool use_all_planes = false; + + /** Use the `colorspace` provided in the image metadata when available. */ + bool use_embedded_colorspace = false; +}; + +/** + * Parameters and settings used while writing image formats. + */ +struct WriteContext { + const char *file_format; + ImBuf *ibuf; + + OIIO::stride_t mem_xstride; + OIIO::stride_t mem_ystride; + OIIO::TypeDesc mem_format; + uchar *mem_start; + + int flags; +}; + +/** + * Check to see if we can load and open the given file format. + */ +bool imb_oiio_check(const uchar *mem, size_t mem_size, const char *file_format); + +/** + * The primary method for reading data into an #ImBuf. + * + * During the `IB_test` phase of loading, the `colorspace` parameter will be populated + * with the appropriate `colorspace` name. + * + * Upon return, the `r_newspec` parameter will contain image format information + * which can be inspected afterwards if necessary. + */ +ImBuf *imb_oiio_read(const ReadContext &ctx, + const OIIO::ImageSpec &config, + char colorspace[IM_MAX_SPACE], + OIIO::ImageSpec &r_newspec); + +/** + * The primary method for writing data from an #ImBuf to either a physical or in-memory + * destination. + * + * The `file_spec` parameter will typically come from #imb_create_write_spec. + */ +bool imb_oiio_write(const WriteContext &ctx, + const char *filepath, + const OIIO::ImageSpec &file_spec); + +/** + * Create a #WriteContext based on the provided #ImBuf and format information. + * + * If the provided #ImBuf contains both byte and float buffers, the `prefer_float` + * flag controls which buffer to use. By default, if a float buffer exists it will + * be used. + */ +WriteContext imb_create_write_context(const char *file_format, + ImBuf *ibuf, + int flags, + bool prefer_float = true); + +/** + * Returns an #ImageSpec filled in with all common attributes associated with the #ImBuf + * provided as part of the #WriteContext. + * + * This includes optional metadata that has been attached to the #ImBuf and which should be + * written to the new file as necessary. + */ +OIIO::ImageSpec imb_create_write_spec(const WriteContext &ctx, + int file_channels, + OIIO::TypeDesc data_format); + +} // namespace blender::imbuf diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index e7d7ae973e4..244a02dcd3c 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -441,7 +441,7 @@ static void openexr_header_metadata(Header *header, struct ImBuf *ibuf) IDProperty *prop; for (prop = (IDProperty *)ibuf->metadata->data.group.first; prop; prop = prop->next) { - if (prop->type == IDP_STRING) { + if (prop->type == IDP_STRING && !STREQ(prop->name, "compression")) { header->insert(prop->name, StringAttribute(IDP_String(prop))); } } diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index 4a662ffba8c..bc472457896 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -114,44 +114,7 @@ ImBuf *IMB_ibImageFromMemory( return NULL; } -static ImBuf *IMB_ibImageFromFile(const char *filepath, - int flags, - char colorspace[IM_MAX_SPACE], - const char *descr) -{ - ImBuf *ibuf; - const ImFileType *type; - char effective_colorspace[IM_MAX_SPACE] = ""; - - if (colorspace) { - BLI_strncpy(effective_colorspace, colorspace, sizeof(effective_colorspace)); - } - - for (type = IMB_FILE_TYPES; type < IMB_FILE_TYPES_LAST; type++) { - if (type->load_filepath) { - ibuf = type->load_filepath(filepath, flags, effective_colorspace); - if (ibuf) { - imb_handle_alpha(ibuf, flags, colorspace, effective_colorspace); - return ibuf; - } - } - } - - if ((flags & IB_test) == 0) { - fprintf(stderr, "%s: unknown fileformat (%s)\n", __func__, descr); - } - - return NULL; -} - -static bool imb_is_filepath_format(const char *filepath) -{ - /* return true if this is one of the formats that can't be loaded from memory */ - return BLI_path_extension_check_array(filepath, imb_ext_image_filepath_only); -} - -ImBuf *IMB_loadifffile( - int file, const char *filepath, int flags, char colorspace[IM_MAX_SPACE], const char *descr) +ImBuf *IMB_loadifffile(int file, int flags, char colorspace[IM_MAX_SPACE], const char *descr) { ImBuf *ibuf; uchar *mem; @@ -161,10 +124,6 @@ ImBuf *IMB_loadifffile( return NULL; } - if (imb_is_filepath_format(filepath)) { - return IMB_ibImageFromFile(filepath, flags, colorspace, descr); - } - size = BLI_file_descriptor_size(file); imb_mmap_lock(); @@ -198,7 +157,7 @@ ImBuf *IMB_loadiffname(const char *filepath, int flags, char colorspace[IM_MAX_S return NULL; } - ibuf = IMB_loadifffile(file, filepath, flags, colorspace, filepath); + ibuf = IMB_loadifffile(file, flags, colorspace, filepath); if (ibuf) { BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name)); @@ -277,7 +236,7 @@ ImBuf *IMB_testiffname(const char *filepath, int flags) return NULL; } - ibuf = IMB_loadifffile(file, filepath, flags | IB_test | IB_multilayer, colorspace, filepath); + ibuf = IMB_loadifffile(file, flags | IB_test | IB_multilayer, colorspace, filepath); if (ibuf) { BLI_strncpy(ibuf->name, filepath, sizeof(ibuf->name)); diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 29bac03654f..3c4eef83b15 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -10,6 +10,8 @@ #include "MEM_guardedalloc.h" +#include "BKE_blendfile.h" + #include "BLI_fileops.h" #include "BLI_ghash.h" #include "BLI_hash_md5.h" @@ -22,8 +24,6 @@ #include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */ -#include "BLO_readfile.h" - #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" #include "IMB_metadata.h" @@ -527,7 +527,7 @@ ImBuf *IMB_thumb_manage(const char *filepath, ThumbSize size, ThumbSource source path = file_path = filepath; if (source == THB_SOURCE_BLEND) { - if (BLO_library_path_explode(path, path_buff, &blen_group, &blen_id)) { + if (BKE_blendfile_library_path_explode(path, path_buff, &blen_group, &blen_id)) { if (blen_group) { if (!blen_id) { /* No preview for blen groups */ diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c index 7967c7c0fa5..138a933e6a3 100644 --- a/source/blender/imbuf/intern/util.c +++ b/source/blender/imbuf/intern/util.c @@ -67,13 +67,6 @@ const char *imb_ext_image[] = { NULL, }; -const char *imb_ext_image_filepath_only[] = { - ".psd", - ".pdd", - ".psb", - NULL, -}; - const char *imb_ext_movie[] = { ".avi", ".flc", ".mov", ".movie", ".mp4", ".m4v", ".m2v", ".m2t", ".m2ts", ".mts", ".ts", ".mv", ".avs", ".wmv", ".ogv", ".ogg", ".r3d", ".dv", ".mpeg", ".mpg", diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc index ab62694b802..968dd651b96 100644 --- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc +++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.cc @@ -211,7 +211,7 @@ ABCAbstractWriter *ABCHierarchyIterator::create_data_writer_for_object_type( case OB_LIGHTPROBE: case OB_LATTICE: case OB_ARMATURE: - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return nullptr; case OB_TYPE_MAX: BLI_assert_msg(0, "OB_TYPE_MAX should not be used"); diff --git a/source/blender/io/alembic/exporter/abc_writer_curves.cc b/source/blender/io/alembic/exporter/abc_writer_curves.cc index e5e8053d7d3..03cd6e2120a 100644 --- a/source/blender/io/alembic/exporter/abc_writer_curves.cc +++ b/source/blender/io/alembic/exporter/abc_writer_curves.cc @@ -12,7 +12,7 @@ #include "DNA_object_types.h" #include "BKE_curve.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "CLG_log.h" diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.cc b/source/blender/io/alembic/exporter/abc_writer_hair.cc index 9b043cf0583..86fb1821bde 100644 --- a/source/blender/io/alembic/exporter/abc_writer_hair.cc +++ b/source/blender/io/alembic/exporter/abc_writer_hair.cc @@ -17,7 +17,7 @@ #include "BLI_math_geom.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_particle.h" @@ -124,7 +124,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context, &mesh->fdata, CD_MTFACE, mesh->totface); const MFace *mface = (const MFace *)CustomData_get_layer(&mesh->fdata, CD_MFACE); const float(*positions)[3] = BKE_mesh_vert_positions(mesh); - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh); + const Span vert_normals = mesh->vert_normals(); if ((!mtface || !mface) && !uv_warning_shown_) { std::fprintf(stderr, @@ -165,7 +165,7 @@ void ABCHairWriter::write_hair_sample(const HierarchyContext &context, psys_interpolate_face(mesh, positions, - vert_normals, + reinterpret_cast(vert_normals.data()), face, tface, nullptr, @@ -249,7 +249,7 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context, MTFace *mtface = (MTFace *)CustomData_get_layer_for_write( &mesh->fdata, CD_MTFACE, mesh->totface); const float(*positions)[3] = BKE_mesh_vert_positions(mesh); - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh); + const Span vert_normals = mesh->vert_normals(); ParticleSystem *psys = context.particle_system; ParticleSettings *part = psys->part; @@ -283,7 +283,7 @@ void ABCHairWriter::write_hair_child_sample(const HierarchyContext &context, psys_interpolate_face(mesh, positions, - vert_normals, + reinterpret_cast(vert_normals.data()), face, tface, nullptr, diff --git a/source/blender/io/alembic/exporter/abc_writer_mball.cc b/source/blender/io/alembic/exporter/abc_writer_mball.cc index e1d4e9c7494..d92e3ed6bd4 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mball.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mball.cc @@ -12,7 +12,7 @@ #include "BKE_displist.h" #include "BKE_lib_id.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "DNA_mesh_types.h" diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 7dab627acc2..af619db9417 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -16,7 +16,7 @@ #include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_object.h" @@ -451,7 +451,15 @@ static void get_topology(struct Mesh *mesh, { const Span polys = mesh->polys(); const Span loops = mesh->loops(); - r_has_flat_shaded_poly = false; + const bke::AttributeAccessor attributes = mesh->attributes(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); + for (const int i : sharp_faces.index_range()) { + if (sharp_faces[i]) { + r_has_flat_shaded_poly = true; + break; + } + } poly_verts.clear(); loop_counts.clear(); @@ -463,8 +471,6 @@ static void get_topology(struct Mesh *mesh, const MPoly &poly = polys[i]; loop_counts.push_back(poly.totloop); - r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0; - const MLoop *loop = &loops[poly.loopstart + (poly.totloop - 1)]; for (int j = 0; j < poly.totloop; j++, loop--) { diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index c39619d7aff..bf7c1fdea06 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -20,7 +20,7 @@ #include "BLI_utildefines.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" /* NOTE: for now only UVs and Vertex Colors are supported for streaming. * Although Alembic only allows for a single UV layer per {I|O}Schema, and does @@ -538,7 +538,7 @@ void read_generated_coordinates(const ICompoundProperty &prop, cd_data = CustomData_get_layer_for_write(&mesh->vdata, CD_ORCO, mesh->totvert); } else { - cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CONSTRUCT, nullptr, totvert); + cd_data = CustomData_add_layer(&mesh->vdata, CD_ORCO, CD_CONSTRUCT, totvert); } float(*orcodata)[3] = static_cast(cd_data); diff --git a/source/blender/io/alembic/intern/abc_reader_curves.cc b/source/blender/io/alembic/intern/abc_reader_curves.cc index 24bdae3ac50..e898b932e3f 100644 --- a/source/blender/io/alembic/intern/abc_reader_curves.cc +++ b/source/blender/io/alembic/intern/abc_reader_curves.cc @@ -20,7 +20,7 @@ #include "BLI_listbase.h" #include "BKE_curve.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" using Alembic::Abc::FloatArraySamplePtr; diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index ba2259ad322..ed9de7ea227 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -29,7 +29,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_object.h" @@ -203,7 +203,6 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data) /* Polygons are always assumed to be smooth-shaded. If the Alembic mesh should be flat-shaded, * this is encoded in custom loop normals. See #71246. */ - poly.flag |= ME_SMOOTH; /* NOTE: Alembic data is stored in the reverse order. */ rev_loop_index = loop_index + (face_size - 1); @@ -393,8 +392,7 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type) /* Create a new layer. */ int numloops = mesh->totloop; - cd_ptr = CustomData_add_layer_named( - &mesh->ldata, cd_data_type, CD_SET_DEFAULT, nullptr, numloops, name); + cd_ptr = CustomData_add_layer_named(&mesh->ldata, cd_data_type, CD_SET_DEFAULT, numloops, name); return cd_ptr; } @@ -892,7 +890,7 @@ static void read_vertex_creases(Mesh *mesh, } float *vertex_crease_data = (float *)CustomData_add_layer( - &mesh->vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh->totvert); + &mesh->vdata, CD_CREASE, CD_SET_DEFAULT, mesh->totvert); const int totvert = mesh->totvert; for (int i = 0, v = indices->size(); i < v; ++i) { @@ -918,7 +916,7 @@ static void read_edge_creases(Mesh *mesh, EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, edges.size()); float *creases = static_cast( - CustomData_add_layer(&mesh->edata, CD_CREASE, CD_SET_DEFAULT, nullptr, edges.size())); + CustomData_add_layer(&mesh->edata, CD_CREASE, CD_SET_DEFAULT, edges.size())); for (const int i : edges.index_range()) { MEdge *edge = &edges[i]; diff --git a/source/blender/io/alembic/intern/abc_reader_points.cc b/source/blender/io/alembic/intern/abc_reader_points.cc index 85dad608d89..5588cb54cc4 100644 --- a/source/blender/io/alembic/intern/abc_reader_points.cc +++ b/source/blender/io/alembic/intern/abc_reader_points.cc @@ -15,7 +15,7 @@ #include "DNA_object_types.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" using Alembic::AbcGeom::kWrapExisting; diff --git a/source/blender/io/collada/ArmatureExporter.cpp b/source/blender/io/collada/ArmatureExporter.cpp index 3cc98917116..57686d2181f 100644 --- a/source/blender/io/collada/ArmatureExporter.cpp +++ b/source/blender/io/collada/ArmatureExporter.cpp @@ -16,7 +16,7 @@ #include "BKE_action.h" #include "BKE_armature.h" #include "BKE_global.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "ED_armature.h" diff --git a/source/blender/io/collada/ControllerExporter.cpp b/source/blender/io/collada/ControllerExporter.cpp index 62bcdc5bf4c..994ffb00084 100644 --- a/source/blender/io/collada/ControllerExporter.cpp +++ b/source/blender/io/collada/ControllerExporter.cpp @@ -19,7 +19,7 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "ED_armature.h" diff --git a/source/blender/io/collada/EffectExporter.cpp b/source/blender/io/collada/EffectExporter.cpp index d53f8c0997c..2f796a14818 100644 --- a/source/blender/io/collada/EffectExporter.cpp +++ b/source/blender/io/collada/EffectExporter.cpp @@ -23,7 +23,7 @@ #include "BKE_collection.h" #include "BKE_customdata.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" static std::string getActiveUVLayerName(Object *ob) { diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp index c68bac9e627..59038c41863 100644 --- a/source/blender/io/collada/GeometryExporter.cpp +++ b/source/blender/io/collada/GeometryExporter.cpp @@ -23,7 +23,7 @@ #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "collada_internal.h" #include "collada_utils.h" @@ -615,6 +615,7 @@ void GeometryExporter::create_normals(std::vector &normals, std::vector &polygons_normals, Mesh *me) { + using namespace blender; std::map shared_normal_indices; int last_normal_index = -1; @@ -625,6 +626,10 @@ void GeometryExporter::create_normals(std::vector &normals, const float(*lnors)[3] = nullptr; bool use_custom_normals = false; + const bke::AttributeAccessor attributes = me->attributes(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); + BKE_mesh_calc_normals_split(me); if (CustomData_has_layer(&me->ldata, CD_NORMAL)) { lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL); @@ -633,16 +638,13 @@ void GeometryExporter::create_normals(std::vector &normals, for (const int poly_index : polys.index_range()) { const MPoly *poly = &polys[poly_index]; - bool use_vert_normals = use_custom_normals || poly->flag & ME_SMOOTH; + bool use_vert_normals = use_custom_normals || !sharp_faces[poly_index]; if (!use_vert_normals) { /* For flat faces use face normal as vertex normal: */ - float vector[3]; - BKE_mesh_calc_poly_normal(poly, - &loops[poly->loopstart], - reinterpret_cast(positions.data()), - vector); + const float3 vector = blender::bke::mesh::poly_normal_calc( + positions, loops.slice(poly->loopstart, poly->totloop)); Normal n = {vector[0], vector[1], vector[2]}; normals.push_back(n); diff --git a/source/blender/io/collada/ImageExporter.cpp b/source/blender/io/collada/ImageExporter.cpp index 070eb36de31..a5c14ec3377 100644 --- a/source/blender/io/collada/ImageExporter.cpp +++ b/source/blender/io/collada/ImageExporter.cpp @@ -16,7 +16,7 @@ #include "BKE_image.h" #include "BKE_image_format.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_fileops.h" #include "BLI_path_util.h" diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index 7290d2c76de..5d88c6fd0c0 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -22,7 +22,7 @@ #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BLI_edgehash.h" @@ -351,8 +351,7 @@ void MeshImporter::read_vertices(COLLADAFW::Mesh *mesh, Mesh *me) } me->totvert = pos.getFloatValues()->getCount() / stride; - CustomData_add_layer_named( - &me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, me->totvert, "position"); + CustomData_add_layer_named(&me->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, me->totvert, "position"); MutableSpan positions = me->vert_positions_for_write(); for (const int i : positions.index_range()) { get_vector(positions[i], pos, i, stride); @@ -456,8 +455,8 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) if (total_poly_count > 0) { me->totpoly = total_poly_count; me->totloop = total_loop_count; - CustomData_add_layer(&me->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, me->totpoly); - CustomData_add_layer(&me->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, me->totloop); + CustomData_add_layer(&me->pdata, CD_MPOLY, CD_SET_DEFAULT, me->totpoly); + CustomData_add_layer(&me->ldata, CD_MLOOP, CD_SET_DEFAULT, me->totloop); uint totuvset = collada_mesh->getUVCoords().getInputInfosArray().getCount(); for (int i = 0; i < totuvset; i++) { @@ -474,7 +473,7 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) COLLADAFW::String &uvname = info->mName; /* Allocate space for UV_data */ CustomData_add_layer_named( - &me->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, me->totloop, uvname.c_str()); + &me->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, me->totloop, uvname.c_str()); } /* activate the first uv map */ CustomData_set_layer_active(&me->ldata, CD_PROP_FLOAT2, 0); @@ -487,7 +486,7 @@ void MeshImporter::allocate_poly_data(COLLADAFW::Mesh *collada_mesh, Mesh *me) collada_mesh->getColors().getInputInfosArray()[i]; COLLADAFW::String colname = extract_vcolname(info->mName); CustomData_add_layer_named( - &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, nullptr, me->totloop, colname.c_str()); + &me->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, me->totloop, colname.c_str()); } BKE_id_attributes_active_color_set( &me->id, CustomData_get_layer_name(&me->ldata, CD_PROP_BYTE_COLOR, 0)); @@ -558,7 +557,7 @@ void MeshImporter::mesh_add_edges(Mesh *mesh, int len) CustomData_copy_data(&mesh->edata, &edata, 0, 0, mesh->totedge); if (!CustomData_has_layer(&edata, CD_MEDGE)) { - CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, totedge); + CustomData_add_layer(&edata, CD_MEDGE, CD_SET_DEFAULT, totedge); } CustomData_free(&mesh->edata, mesh->totedge); @@ -617,6 +616,12 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, MaterialIdPrimitiveArrayMap mat_prim_map; int *material_indices = BKE_mesh_material_indices_for_write(me); + bool *sharp_faces = static_cast( + CustomData_get_layer_named_for_write(&me->pdata, CD_PROP_BOOL, "sharp_face", me->totpoly)); + if (!sharp_faces) { + sharp_faces = static_cast(CustomData_add_layer_named( + &me->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, me->totpoly, "sharp_face")); + } COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives(); COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals(); @@ -659,9 +664,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, if (mp_has_normals) { /* vertex normals, same implementation as for the triangles */ /* The same for vertices normals. */ uint vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]}; - if (!is_flat_face(vertex_normal_indices, nor, 3)) { - polys[poly_index].flag |= ME_SMOOTH; - } + sharp_faces[poly_index] = is_flat_face(vertex_normal_indices, nor, 3); normal_indices++; } @@ -729,9 +732,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, if (mp_has_normals) { /* If it turns out that we have complete custom normals for each MPoly * and we want to use custom normals, this will be overridden. */ - if (!is_flat_face(normal_indices, nor, vcount)) { - polys[poly_index].flag |= ME_SMOOTH; - } + sharp_faces[poly_index] = is_flat_face(normal_indices, nor, vcount); if (use_custom_normals) { /* Store the custom normals for later application. */ diff --git a/source/blender/io/collada/SceneExporter.cpp b/source/blender/io/collada/SceneExporter.cpp index b98ff27c89e..1d389247ea3 100644 --- a/source/blender/io/collada/SceneExporter.cpp +++ b/source/blender/io/collada/SceneExporter.cpp @@ -46,7 +46,7 @@ void SceneExporter::exportHierarchy() case OB_CAMERA: case OB_LAMP: case OB_EMPTY: - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: case OB_ARMATURE: base_objects.add(ob); break; diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index a71fbd50a2e..6b6afdfda2f 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -39,7 +39,7 @@ #include "BKE_layer.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.h" #include "BKE_mesh_runtime.h" #include "BKE_node.h" diff --git a/source/blender/io/gpencil/intern/gpencil_io_base.cc b/source/blender/io/gpencil/intern/gpencil_io_base.cc index 215dc20c5b4..17d9129b31d 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_base.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_base.cc @@ -9,7 +9,7 @@ #include "BLI_path_util.h" #include "BLI_span.hh" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_layer_types.h" #include "DNA_material_types.h" #include "DNA_scene_types.h" @@ -17,8 +17,8 @@ #include "BKE_camera.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" @@ -136,7 +136,7 @@ void GpencilIO::create_object_list() LISTBASE_FOREACH (Base *, base, BKE_view_layer_object_bases_get(view_layer)) { Object *object = base->object; - if (object->type != OB_GPENCIL) { + if (object->type != OB_GPENCIL_LEGACY) { continue; } if ((params_.select_mode == GP_EXPORT_ACTIVE) && (params_.ob != object)) { diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc index 96a6cc66b25..b005b30f435 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_capi.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc @@ -9,12 +9,12 @@ #include "BLI_listbase.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_scene.h" diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc index e52e92bc218..ebf48167a18 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc @@ -7,7 +7,7 @@ #include "BLI_math_vector.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -15,8 +15,8 @@ #include "DNA_view3d_types.h" #include "BKE_context.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc index b9197fe8c21..8570eab1371 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc @@ -9,14 +9,14 @@ #include "BLI_string.h" #include "BLI_utildefines.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "BKE_main.h" #include "BKE_material.h" diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_base.cc b/source/blender/io/gpencil/intern/gpencil_io_import_base.cc index f6d02d36a17..bf5fcc93d01 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_import_base.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_import_base.cc @@ -10,7 +10,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BKE_gpencil.h" +#include "BKE_gpencil_legacy.h" #include "BKE_material.h" #include "ED_gpencil.h" @@ -34,7 +34,7 @@ Object *GpencilImporter::create_object() ushort(0); Object *ob_gpencil = ED_object_add_type(params_.C, - OB_GPENCIL, + OB_GPENCIL_LEGACY, (params_.filename[0] != '\0') ? params_.filename : nullptr, cur_loc, diff --git a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc index e18f4df9c52..84299dfb641 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_import_svg.cc @@ -9,10 +9,10 @@ #include "BLI_math_vector_types.hh" #include "BLI_span.hh" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" -#include "BKE_gpencil.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_geom_legacy.h" +#include "BKE_gpencil_legacy.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" diff --git a/source/blender/io/ply/CMakeLists.txt b/source/blender/io/ply/CMakeLists.txt index 12c1d842ab4..a3235dd7170 100644 --- a/source/blender/io/ply/CMakeLists.txt +++ b/source/blender/io/ply/CMakeLists.txt @@ -10,10 +10,11 @@ set(INC ../../blenlib ../../bmesh ../../depsgraph + ../../geometry ../../makesdna ../../makesrna ../../windowmanager - ../../geometry + ../../../../extern/fast_float ../../../../extern/fmtlib/include ../../../../intern/guardedalloc ) @@ -23,37 +24,33 @@ set(INC_SYS ) set(SRC + exporter/ply_export.cc exporter/ply_export_data.cc exporter/ply_export_header.cc exporter/ply_export_load_plydata.cc - exporter/ply_export.cc + exporter/ply_file_buffer.cc exporter/ply_file_buffer_ascii.cc exporter/ply_file_buffer_binary.cc - exporter/ply_file_buffer.cc - importer/ply_import_ascii.cc - importer/ply_import_binary.cc - importer/ply_import_mesh.cc importer/ply_import.cc + importer/ply_import_buffer.cc + importer/ply_import_data.cc + importer/ply_import_mesh.cc IO_ply.cc - - + exporter/ply_export.hh exporter/ply_export_data.hh exporter/ply_export_header.hh exporter/ply_export_load_plydata.hh - exporter/ply_export.hh + exporter/ply_file_buffer.hh exporter/ply_file_buffer_ascii.hh exporter/ply_file_buffer_binary.hh - exporter/ply_file_buffer.hh - importer/ply_import_ascii.hh - importer/ply_import_binary.hh - importer/ply_import_mesh.hh importer/ply_import.hh + importer/ply_import_buffer.hh + importer/ply_import_data.hh + importer/ply_import_mesh.hh IO_ply.h intern/ply_data.hh - intern/ply_functions.hh - intern/ply_functions.cc ) set(LIB @@ -65,10 +62,8 @@ blender_add_lib(bf_ply "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if (WITH_GTESTS) set(TEST_SRC - tests/io_ply_importer_test.cc - - tests/io_ply_exporter_test.cc - + tests/io_ply_importer_test.cc + tests/io_ply_exporter_test.cc ) set(TEST_INC ../../blenloader diff --git a/source/blender/io/ply/exporter/ply_export_data.cc b/source/blender/io/ply/exporter/ply_export_data.cc index 1c4379f24ec..28204339eb3 100644 --- a/source/blender/io/ply/exporter/ply_export_data.cc +++ b/source/blender/io/ply/exporter/ply_export_data.cc @@ -39,8 +39,10 @@ void write_vertices(FileBuffer &buffer, const PlyData &ply_data) void write_faces(FileBuffer &buffer, const PlyData &ply_data) { - for (const Array &face : ply_data.faces) { - buffer.write_face(char(face.size()), face); + const uint32_t *indices = ply_data.face_vertices.data(); + for (uint32_t face_size : ply_data.face_sizes) { + buffer.write_face(char(face_size), Span(indices, face_size)); + indices += face_size; } buffer.write_to_file(); } diff --git a/source/blender/io/ply/exporter/ply_export_header.cc b/source/blender/io/ply/exporter/ply_export_header.cc index 014aa9de897..8dac491e298 100644 --- a/source/blender/io/ply/exporter/ply_export_header.cc +++ b/source/blender/io/ply/exporter/ply_export_header.cc @@ -49,13 +49,13 @@ void write_header(FileBuffer &buffer, buffer.write_header_scalar_property("float", "t"); } - if (!ply_data.faces.is_empty()) { - buffer.write_header_element("face", int32_t(ply_data.faces.size())); + if (!ply_data.face_sizes.is_empty()) { + buffer.write_header_element("face", int(ply_data.face_sizes.size())); buffer.write_header_list_property("uchar", "uint", "vertex_indices"); } if (!ply_data.edges.is_empty()) { - buffer.write_header_element("edge", int32_t(ply_data.edges.size())); + buffer.write_header_element("edge", int(ply_data.edges.size())); buffer.write_header_scalar_property("int", "vertex1"); buffer.write_header_scalar_property("int", "vertex2"); } diff --git a/source/blender/io/ply/exporter/ply_export_load_plydata.cc b/source/blender/io/ply/exporter/ply_export_load_plydata.cc index 959efe41bf6..37db9089d14 100644 --- a/source/blender/io/ply/exporter/ply_export_load_plydata.cc +++ b/source/blender/io/ply/exporter/ply_export_load_plydata.cc @@ -9,7 +9,7 @@ #include "BKE_attribute.hh" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_object.h" @@ -120,11 +120,12 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams &export_object_eval_, export_params.forward_axis, export_params.up_axis); /* Load faces into plyData. */ + plyData.face_vertices.reserve(mesh->totloop); + plyData.face_sizes.reserve(mesh->totpoly); int loop_offset = 0; const Span loops = mesh->loops(); for (const MPoly &poly : mesh->polys()) { const Span poly_loops = loops.slice(poly.loopstart, poly.totloop); - Array poly_verts(poly_loops.size()); for (int i = 0; i < poly_loops.size(); ++i) { float2 uv; @@ -136,11 +137,10 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams } UV_vertex_key key = UV_vertex_key(uv, poly_loops[i].v); int ply_vertex_index = vertex_map.lookup(key); - poly_verts[i] = (uint32_t(ply_vertex_index + vertex_offset)); + plyData.face_vertices.append(ply_vertex_index + vertex_offset); } - loop_offset += poly_loops.size(); - - plyData.faces.append(std::move(poly_verts)); + loop_offset += poly.totloop; + plyData.face_sizes.append(poly.totloop); } Array mesh_vertex_index_LUT(vertex_map.size()); diff --git a/source/blender/io/ply/importer/ply_import.cc b/source/blender/io/ply/importer/ply_import.cc index 45d07b006fd..1ddb31837d7 100644 --- a/source/blender/io/ply/importer/ply_import.cc +++ b/source/blender/io/ply/importer/ply_import.cc @@ -6,7 +6,7 @@ #include "BKE_layer.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_report.h" @@ -14,7 +14,6 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" -#include "BLI_fileops.hh" #include "BLI_math_vector.h" #include "BLI_memory_utils.hh" @@ -22,53 +21,137 @@ #include "DEG_depsgraph_build.h" #include "ply_data.hh" -#include "ply_functions.hh" #include "ply_import.hh" -#include "ply_import_ascii.hh" -#include "ply_import_binary.hh" +#include "ply_import_buffer.hh" +#include "ply_import_data.hh" #include "ply_import_mesh.hh" namespace blender::io::ply { -void splitstr(std::string str, Vector &words, const StringRef &deli) +/* If line starts with keyword, returns true and drops it from the line. */ +static bool parse_keyword(Span &str, StringRef keyword) { - int pos; - - while ((pos = int(str.find(deli))) != std::string::npos) { - words.append(str.substr(0, pos)); - str.erase(0, pos + deli.size()); + const size_t keyword_len = keyword.size(); + if (str.size() < keyword_len) { + return false; } - /* We add the final word to the vector. */ - words.append(str.substr()); + if (memcmp(str.data(), keyword.data(), keyword_len) != 0) { + return false; + } + str = str.drop_front(keyword_len); + return true; } -enum PlyDataTypes from_string(const StringRef &input) +static Span parse_word(Span &str) { - if (input == "uchar") { + size_t len = 0; + while (len < str.size() && str[len] > ' ') { + ++len; + } + Span word(str.begin(), len); + str = str.drop_front(len); + return word; +} + +static void skip_space(Span &str) +{ + while (!str.is_empty() && str[0] <= ' ') + str = str.drop_front(1); +} + +static PlyDataTypes type_from_string(Span word) +{ + StringRef input(word.data(), word.size()); + if (input == "uchar" || input == "uint8") { return PlyDataTypes::UCHAR; } - if (input == "char") { + if (input == "char" || input == "int8") { return PlyDataTypes::CHAR; } - if (input == "ushort") { + if (input == "ushort" || input == "uint16") { return PlyDataTypes::USHORT; } - if (input == "short") { + if (input == "short" || input == "int16") { return PlyDataTypes::SHORT; } - if (input == "uint") { + if (input == "uint" || input == "uint32") { return PlyDataTypes::UINT; } - if (input == "int") { + if (input == "int" || input == "int32") { return PlyDataTypes::INT; } - if (input == "float") { + if (input == "float" || input == "float32") { return PlyDataTypes::FLOAT; } - if (input == "double") { + if (input == "double" || input == "float64") { return PlyDataTypes::DOUBLE; } - return PlyDataTypes::FLOAT; + return PlyDataTypes::NONE; +} + +const char *read_header(PlyReadBuffer &file, PlyHeader &r_header) +{ + Span word, line; + line = file.read_line(); + if (StringRef(line.data(), line.size()) != "ply") { + return "Invalid PLY header."; + } + + while (true) { /* We break when end_header is encountered. */ + line = file.read_line(); + + if (parse_keyword(line, "format")) { + skip_space(line); + if (parse_keyword(line, "ascii")) { + r_header.type = PlyFormatType::ASCII; + } + else if (parse_keyword(line, "binary_big_endian")) { + r_header.type = PlyFormatType::BINARY_BE; + } + else if (parse_keyword(line, "binary_little_endian")) { + r_header.type = PlyFormatType::BINARY_LE; + } + } + else if (parse_keyword(line, "element")) { + PlyElement element; + + skip_space(line); + word = parse_word(line); + element.name = std::string(word.data(), word.size()); + skip_space(line); + word = parse_word(line); + element.count = std::stoi(std::string(word.data(), word.size())); + r_header.elements.append(element); + } + else if (parse_keyword(line, "property")) { + PlyProperty property; + skip_space(line); + if (parse_keyword(line, "list")) { + skip_space(line); + property.count_type = type_from_string(parse_word(line)); + } + skip_space(line); + property.type = type_from_string(parse_word(line)); + skip_space(line); + word = parse_word(line); + property.name = std::string(word.data(), word.size()); + r_header.elements.last().properties.append(property); + } + else if (parse_keyword(line, "end_header")) { + break; + } + else if (line.is_empty() || (line.first() >= '0' && line.first() <= '9') || + line.first() == '-') { + /* A value was found before we broke out of the loop. No end_header. */ + return "No end_header."; + } + } + + file.after_header(r_header.type != PlyFormatType::ASCII); + for (PlyElement &el : r_header.elements) { + el.calc_stride(); + } + return nullptr; } void importer_main(bContext *C, const PLYImportParams &import_params, wmOperator *op) @@ -85,75 +168,42 @@ void importer_main(Main *bmain, const PLYImportParams &import_params, wmOperator *op) { - - std::string line; - fstream infile(import_params.filepath, std::ios::in | std::ios::binary); - - PlyHeader header; - - while (true) { /* We break when end_header is encountered. */ - safe_getline(infile, line); - if (header.header_size == 0 && line != "ply") { - fprintf(stderr, "PLY Importer: failed to read file. Invalid PLY header.\n"); - BKE_report(op->reports, RPT_ERROR, "PLY Importer: Invalid PLY header."); - return; - } - header.header_size++; - Vector words{}; - splitstr(line, words, " "); - - if (strcmp(words[0].c_str(), "format") == 0) { - if (strcmp(words[1].c_str(), "ascii") == 0) { - header.type = PlyFormatType::ASCII; - } - else if (strcmp(words[1].c_str(), "binary_big_endian") == 0) { - header.type = PlyFormatType::BINARY_BE; - } - else if (strcmp(words[1].c_str(), "binary_little_endian") == 0) { - header.type = PlyFormatType::BINARY_LE; - } - } - else if (strcmp(words[0].c_str(), "element") == 0) { - header.elements.append(std::make_pair(words[1], std::stoi(words[2]))); - if (strcmp(words[1].c_str(), "vertex") == 0) { - header.vertex_count = std::stoi(words[2]); - } - else if (strcmp(words[1].c_str(), "face") == 0) { - header.face_count = std::stoi(words[2]); - } - else if (strcmp(words[1].c_str(), "edge") == 0) { - header.edge_count = std::stoi(words[2]); - } - } - else if (strcmp(words[0].c_str(), "property") == 0) { - std::pair property; - property.first = words[2]; - property.second = from_string(words[1]); - - while (header.properties.size() < header.elements.size()) { - Vector> temp; - header.properties.append(temp); - } - header.properties[header.elements.size() - 1].append(property); - } - else if (words[0] == "end_header") { - break; - } - else if ((words[0][0] >= '0' && words[0][0] <= '9') || words[0][0] == '-' || line.empty() || - infile.eof()) { - /* A value was found before we broke out of the loop. No end_header. */ - BKE_report(op->reports, RPT_ERROR, "PLY Importer: No end_header"); - return; - } - } - - /* Name used for both mesh and object. */ + /* File base name used for both mesh and object. */ char ob_name[FILE_MAX]; BLI_strncpy(ob_name, BLI_path_basename(import_params.filepath), FILE_MAX); BLI_path_extension_replace(ob_name, FILE_MAX, ""); - Mesh *mesh = BKE_mesh_add(bmain, ob_name); + /* Parse header. */ + PlyReadBuffer file(import_params.filepath, 64 * 1024); + PlyHeader header; + const char *err = read_header(file, header); + if (err != nullptr) { + fprintf(stderr, "PLY Importer: %s: %s\n", ob_name, err); + BKE_reportf(op->reports, RPT_ERROR, "PLY Importer: %s: %s", ob_name, err); + return; + } + + /* Parse actual file data. */ + std::unique_ptr data = import_ply_data(file, header); + if (data == nullptr) { + fprintf(stderr, "PLY Importer: failed importing %s, unknown error\n", ob_name); + BKE_report(op->reports, RPT_ERROR, "PLY Importer: failed importing, unknown error."); + return; + } + if (!data->error.empty()) { + fprintf(stderr, "PLY Importer: failed importing %s: %s\n", ob_name, data->error.c_str()); + BKE_report(op->reports, RPT_ERROR, "PLY Importer: failed importing, unknown error."); + return; + } + if (data->vertices.is_empty()) { + fprintf(stderr, "PLY Importer: file %s contains no vertices\n", ob_name); + BKE_report(op->reports, RPT_ERROR, "PLY Importer: failed importing, no vertices."); + return; + } + + /* Create mesh and do all prep work. */ + Mesh *mesh = BKE_mesh_add(bmain, ob_name); BKE_view_layer_base_deselect_all(scene, view_layer); LayerCollection *lc = BKE_layer_collection_get_active(view_layer); Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name); @@ -163,26 +213,13 @@ void importer_main(Main *bmain, Base *base = BKE_view_layer_base_find(view_layer, obj); BKE_view_layer_base_select_and_set_active(view_layer, base); - try { - std::unique_ptr data; - if (header.type == PlyFormatType::ASCII) { - data = import_ply_ascii(infile, &header); - } - else { - data = import_ply_binary(infile, &header); - } - - Mesh *temp_val = convert_ply_to_mesh(*data, mesh, import_params); - if (import_params.merge_verts && temp_val != mesh) { - BKE_mesh_nomain_to_mesh(temp_val, mesh, obj); - } - } - catch (std::exception &e) { - fprintf(stderr, "PLY Importer: failed to read file. %s.\n", e.what()); - BKE_report(op->reports, RPT_ERROR, "PLY Importer: failed to parse file."); - return; + /* Stuff ply data into the mesh. */ + Mesh *temp_val = convert_ply_to_mesh(*data, mesh, import_params); + if (import_params.merge_verts && temp_val != mesh) { + BKE_mesh_nomain_to_mesh(temp_val, mesh, obj); } + /* Object matrix and finishing up. */ float global_scale = import_params.global_scale; if ((scene->unit.system != USER_UNIT_NONE) && import_params.use_scene_unit) { global_scale *= scene->unit.scale_length; @@ -205,7 +242,5 @@ void importer_main(Main *bmain, DEG_id_tag_update_ex(bmain, &obj->id, flags); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); DEG_relations_tag_update(bmain); - - infile.close(); } } // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import.hh b/source/blender/io/ply/importer/ply_import.hh index a19f32cc5ad..c10482377e9 100644 --- a/source/blender/io/ply/importer/ply_import.hh +++ b/source/blender/io/ply/importer/ply_import.hh @@ -11,7 +11,7 @@ namespace blender::io::ply { -enum PlyDataTypes from_string(const StringRef &input); +class PlyReadBuffer; void splitstr(std::string str, Vector &words, const StringRef &deli); @@ -25,4 +25,6 @@ void importer_main(Main *bmain, const PLYImportParams &import_params, wmOperator *op); +const char *read_header(PlyReadBuffer &file, PlyHeader &r_header); + } // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_ascii.cc b/source/blender/io/ply/importer/ply_import_ascii.cc deleted file mode 100644 index 0579255eec7..00000000000 --- a/source/blender/io/ply/importer/ply_import_ascii.cc +++ /dev/null @@ -1,222 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup ply - */ - -#include "ply_import_ascii.hh" -#include "ply_functions.hh" - -#include -#include - -namespace blender::io::ply { - -std::unique_ptr import_ply_ascii(fstream &file, PlyHeader *header) -{ - std::unique_ptr data = std::make_unique(load_ply_ascii(file, header)); - return data; -} - -PlyData load_ply_ascii(fstream &file, const PlyHeader *header) -{ - PlyData data; - /* Check if header contains alpha. */ - std::pair alpha = {"alpha", PlyDataTypes::UCHAR}; - bool has_alpha = std::find(header->properties[0].begin(), header->properties[0].end(), alpha) != - header->properties[0].end(); - - /* Check if header contains colors. */ - std::pair red = {"red", PlyDataTypes::UCHAR}; - bool has_color = std::find(header->properties[0].begin(), header->properties[0].end(), red) != - header->properties[0].end(); - - /* Check if header contains normals. */ - std::pair normalx = {"nx", PlyDataTypes::FLOAT}; - bool has_normals = std::find(header->properties[0].begin(), - header->properties[0].end(), - normalx) != header->properties[0].end(); - - /* Check if header contains uv data. */ - std::pair uv = {"s", PlyDataTypes::FLOAT}; - const bool has_uv = std::find(header->properties[0].begin(), header->properties[0].end(), uv) != - header->properties[0].end(); - - int3 vertex_index = get_vertex_index(header); - int alpha_index; - int3 color_index; - int3 normal_index; - int2 uv_index; - - if (has_alpha) { - alpha_index = get_index(header, "alpha", PlyDataTypes::UCHAR); - } - - if (has_color) { - /* x=red, y=green, z=blue */ - color_index = get_color_index(header); - } - - if (has_normals) { - normal_index = get_normal_index(header); - } - - if (has_uv) { - uv_index = get_uv_index(header); - } - - for (int i = 0; i < header->vertex_count; i++) { - std::string line; - safe_getline(file, line); - Vector value_vec = explode(line, ' '); - - /* Vertex coords */ - float3 vertex3; - vertex3.x = std::stof(value_vec[vertex_index.x]); - vertex3.y = std::stof(value_vec[vertex_index.y]); - vertex3.z = std::stof(value_vec[vertex_index.z]); - - data.vertices.append(vertex3); - - /* Vertex colors */ - if (has_color) { - float4 colors4; - colors4.x = std::stof(value_vec[color_index.x]) / 255.0f; - colors4.y = std::stof(value_vec[color_index.y]) / 255.0f; - colors4.z = std::stof(value_vec[color_index.z]) / 255.0f; - if (has_alpha) { - colors4.w = std::stof(value_vec[alpha_index]) / 255.0f; - } - else { - colors4.w = 1.0f; - } - - data.vertex_colors.append(colors4); - } - - /* If normals */ - if (has_normals) { - float3 normals3; - normals3.x = std::stof(value_vec[normal_index.x]); - normals3.y = std::stof(value_vec[normal_index.y]); - normals3.z = std::stof(value_vec[normal_index.z]); - - data.vertex_normals.append(normals3); - } - - /* If uv */ - if (has_uv) { - float2 uvmap; - uvmap.x = std::stof(value_vec[uv_index.x]); - uvmap.y = std::stof(value_vec[uv_index.y]); - - data.uv_coordinates.append(uvmap); - } - } - for (int i = 0; i < header->face_count; i++) { - std::string line; - getline(file, line); - Vector value_vec = explode(line, ' '); - int count = std::stoi(value_vec[0]); - Array vertex_indices(count); - - for (int j = 1; j <= count; j++) { - int index = std::stoi(value_vec[j]); - /* If the face has a vertex index that is outside the range. */ - if (index >= data.vertices.size()) { - throw std::runtime_error("Vertex index out of bounds"); - } - vertex_indices[j - 1] = index; - } - data.faces.append(vertex_indices); - } - - for (int i = 0; i < header->edge_count; i++) { - std::string line; - getline(file, line); - Vector value_vec = explode(line, ' '); - - std::pair edge = std::make_pair(stoi(value_vec[0]), stoi(value_vec[1])); - data.edges.append(edge); - } - - return data; -} - -int3 get_vertex_index(const PlyHeader *header) -{ - int3 vertex_index; - vertex_index.x = get_index(header, "x", PlyDataTypes::FLOAT); - vertex_index.y = get_index(header, "y", PlyDataTypes::FLOAT); - vertex_index.z = get_index(header, "z", PlyDataTypes::FLOAT); - - return vertex_index; -} - -int3 get_color_index(const PlyHeader *header) -{ - int3 color_index; - color_index.x = get_index(header, "red", PlyDataTypes::UCHAR); - color_index.y = get_index(header, "green", PlyDataTypes::UCHAR); - color_index.z = get_index(header, "blue", PlyDataTypes::UCHAR); - - return color_index; -} - -int3 get_normal_index(const PlyHeader *header) -{ - int3 normal_index; - normal_index.x = get_index(header, "nx", PlyDataTypes::FLOAT); - normal_index.y = get_index(header, "ny", PlyDataTypes::FLOAT); - normal_index.z = get_index(header, "nz", PlyDataTypes::FLOAT); - - return normal_index; -} - -int2 get_uv_index(const PlyHeader *header) -{ - int2 uv_index; - uv_index.x = get_index(header, "s", PlyDataTypes::FLOAT); - uv_index.y = get_index(header, "t", PlyDataTypes::FLOAT); - - return uv_index; -} - -int get_index(const PlyHeader *header, std::string property, PlyDataTypes datatype) -{ - std::pair pair = {property, datatype}; - const std::pair *it = std::find( - header->properties[0].begin(), header->properties[0].end(), pair); - return (int)(it - header->properties[0].begin()); -} - -Vector explode(const StringRef str, const char &ch) -{ - std::string next; - Vector result; - - /* For each character in the string. */ - for (char c : str) { - /* If we've hit the terminal character. */ - if (c == ch) { - /* If we have some characters accumulated. */ - if (!next.empty()) { - /* Add them to the result vector. */ - result.append(next); - next.clear(); - } - } - else { - /* Accumulate the next character into the sequence. */ - next += c; - } - } - - if (!next.empty()) { - result.append(next); - } - - return result; -} - -} // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_ascii.hh b/source/blender/io/ply/importer/ply_import_ascii.hh deleted file mode 100644 index 3506dd3ed54..00000000000 --- a/source/blender/io/ply/importer/ply_import_ascii.hh +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup ply - */ - -#pragma once - -#include "BLI_fileops.hh" - -#include "DNA_mesh_types.h" - -#include "IO_ply.h" -#include "ply_data.hh" - -namespace blender::io::ply { - -/** - * The function that gets called from the importer. - * \param file: The PLY file that was opened. - * \param header: The information in the PLY header. - */ -std::unique_ptr import_ply_ascii(fstream &file, PlyHeader *header); - -/** - * Loads the information from the PLY file in ASCII format to the #PlyData data-structure. - * \param file: The PLY file that was opened. - * \param header: The information in the PLY header. - * \return The #PlyData data-structure that can be used for conversion to a Mesh. - */ -PlyData load_ply_ascii(fstream &file, const PlyHeader *header); - -int3 get_vertex_index(const PlyHeader *header); -int3 get_color_index(const PlyHeader *header); -int3 get_normal_index(const PlyHeader *header); -int2 get_uv_index(const PlyHeader *header); -int get_index(const PlyHeader *header, std::string property, PlyDataTypes datatype); -Vector explode(const StringRef str, const char &ch); -} // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_binary.cc b/source/blender/io/ply/importer/ply_import_binary.cc deleted file mode 100644 index 163d3fdbeb7..00000000000 --- a/source/blender/io/ply/importer/ply_import_binary.cc +++ /dev/null @@ -1,215 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup ply - */ -#include "BLI_array.hh" - -#include "ply_import_binary.hh" - -#include - -namespace blender::io::ply { -std::unique_ptr import_ply_binary(fstream &file, const PlyHeader *header) -{ - std::unique_ptr data = std::make_unique(load_ply_binary(file, header)); - return data; -} - -template T read(fstream &file, bool is_big_endian) -{ - T returnVal; - file.read((char *)&returnVal, sizeof(returnVal)); - check_file_errors(file); - if (is_big_endian) { - returnVal = swap_bytes(returnVal); - } - return returnVal; -} - -template uint8_t read(fstream &file, bool is_big_endian); -template int8_t read(fstream &file, bool is_big_endian); -template uint16_t read(fstream &file, bool is_big_endian); -template int16_t read(fstream &file, bool is_big_endian); -template uint32_t read(fstream &file, bool is_big_endian); -template int32_t read(fstream &file, bool is_big_endian); -template float read(fstream &file, bool is_big_endian); -template double read(fstream &file, bool is_big_endian); - -void check_file_errors(const fstream &file) -{ - if (file.bad()) { - throw std::ios_base::failure("Read/Write error on io operation"); - } - if (file.fail()) { - throw std::ios_base::failure("Logical error on io operation"); - } - if (file.eof()) { - throw std::ios_base::failure("Reached end of the file"); - } -} - -void discard_value(fstream &file, const PlyDataTypes type) -{ - switch (type) { - case CHAR: - read(file, false); - break; - case UCHAR: - read(file, false); - break; - case SHORT: - read(file, false); - break; - case USHORT: - read(file, false); - break; - case INT: - read(file, false); - break; - case UINT: - read(file, false); - break; - case FLOAT: - read(file, false); - break; - case DOUBLE: - read(file, false); - break; - } -} - -PlyData load_ply_binary(fstream &file, const PlyHeader *header) -{ - PlyData data; - bool is_big_endian = header->type == PlyFormatType::BINARY_BE; - - for (int i = 0; i < header->elements.size(); i++) { - if (header->elements[i].first == "vertex") { - /* Import vertices. */ - load_vertex_data(file, header, &data, i); - } - else if (header->elements[i].first == "edge") { - /* Import edges. */ - for (int j = 0; j < header->elements[i].second; j++) { - std::pair vertex_indices; - for (auto [name, type] : header->properties[i]) { - if (name == "vertex1") { - vertex_indices.first = int(read(file, is_big_endian)); - } - else if (name == "vertex2") { - vertex_indices.second = int(read(file, is_big_endian)); - } - else { - discard_value(file, type); - } - } - data.edges.append(vertex_indices); - } - } - else if (header->elements[i].first == "face") { - - /* Import faces. */ - for (int j = 0; j < header->elements[i].second; j++) { - /* Assume vertex_index_count_type is uchar. */ - uint8_t count = read(file, is_big_endian); - Array vertex_indices(count); - - /* Loop over the amount of vertex indices in this face. */ - for (uint8_t k = 0; k < count; k++) { - uint32_t index = read(file, is_big_endian); - /* If the face has a vertex index that is outside the range. */ - if (index >= data.vertices.size()) { - throw std::runtime_error("Vertex index out of bounds"); - } - vertex_indices[k] = index; - } - data.faces.append(vertex_indices); - } - } - else { - /* Nothing else is supported. */ - for (int j = 0; j < header->elements[i].second; j++) { - for (auto [name, type] : header->properties[i]) { - discard_value(file, type); - } - } - } - } - - return data; -} - -void load_vertex_data(fstream &file, const PlyHeader *header, PlyData *r_data, int index) -{ - bool hasNormal = false; - bool hasColor = false; - bool hasUv = false; - bool is_big_endian = header->type == PlyFormatType::BINARY_BE; - - for (int i = 0; i < header->vertex_count; i++) { - float3 coord{0}; - float3 normal{0}; - float4 color{1}; - float2 uv{0}; - - for (auto [name, type] : header->properties[index]) { - if (name == "x") { - coord.x = read(file, is_big_endian); - } - else if (name == "y") { - coord.y = read(file, is_big_endian); - } - else if (name == "z") { - coord.z = read(file, is_big_endian); - } - else if (name == "nx") { - normal.x = read(file, is_big_endian); - hasNormal = true; - } - else if (name == "ny") { - normal.y = read(file, is_big_endian); - } - else if (name == "nz") { - normal.z = read(file, is_big_endian); - } - else if (name == "red") { - color.x = read(file, is_big_endian) / 255.0f; - hasColor = true; - } - else if (name == "green") { - color.y = read(file, is_big_endian) / 255.0f; - } - else if (name == "blue") { - color.z = read(file, is_big_endian) / 255.0f; - } - else if (name == "alpha") { - color.w = read(file, is_big_endian) / 255.0f; - } - else if (name == "s") { - uv.x = read(file, is_big_endian); - hasUv = true; - } - else if (name == "t") { - uv.y = read(file, is_big_endian); - } - else { - /* No other properties are supported yet. */ - discard_value(file, type); - } - } - - r_data->vertices.append(coord); - if (hasNormal) { - r_data->vertex_normals.append(normal); - } - if (hasColor) { - r_data->vertex_colors.append(color); - } - if (hasUv) { - r_data->uv_coordinates.append(uv); - } - } -} - -} // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_binary.hh b/source/blender/io/ply/importer/ply_import_binary.hh deleted file mode 100644 index 91f471e5eb2..00000000000 --- a/source/blender/io/ply/importer/ply_import_binary.hh +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup ply - */ - -#pragma once - -#include "BLI_endian_switch.h" -#include "BLI_fileops.hh" - -#include "ply_data.hh" - -namespace blender::io::ply { - -/** - * The function that gets called from the importer. - * \param file: The PLY file that was opened. - * \param header: The information in the PLY header. - * \return The #PlyData data-structure that can be used for conversion to a #Mesh. - */ -std::unique_ptr import_ply_binary(fstream &file, const PlyHeader *header); - -/** - * Loads the information from the PLY file in binary format to the #PlyData data-structure. - * \param file: The PLY file that was opened. - * \param header: The information in the PLY header. - * \return The #PlyData data-structure that can be used for conversion to a Mesh. - */ -PlyData load_ply_binary(fstream &file, const PlyHeader *header); - -void load_vertex_data(fstream &file, const PlyHeader *header, PlyData *r_data, int index); - -void check_file_errors(const fstream &file); - -void discard_value(fstream &file, const PlyDataTypes type); - -template T swap_bytes(T input) -{ - /* In big endian, the most-significant byte is first. - * So, we need to swap the byte order. */ - - /* 0xAC in LE should become 0xCA in BE. */ - if (sizeof(T) == 1) { - return input; - } - - if constexpr (sizeof(T) == 2) { - uint16_t value = reinterpret_cast(input); - BLI_endian_switch_uint16(&value); - return reinterpret_cast(value); - } - - if constexpr (sizeof(T) == 4) { - /* Reinterpret this data as uint32 for easy rearranging of bytes. */ - uint32_t value = reinterpret_cast(input); - BLI_endian_switch_uint32(&value); - return reinterpret_cast(value); - } - - if constexpr (sizeof(T) == 8) { - /* Reinterpret this data as uint64 for easy rearranging of bytes. */ - uint64_t value = reinterpret_cast(input); - BLI_endian_switch_uint64(&value); - return reinterpret_cast(value); - } -} - -template T read(fstream &file, bool isBigEndian); - -} // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_buffer.cc b/source/blender/io/ply/importer/ply_import_buffer.cc new file mode 100644 index 00000000000..3b1d5de9eb7 --- /dev/null +++ b/source/blender/io/ply/importer/ply_import_buffer.cc @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "ply_import_buffer.hh" + +#include "BLI_fileops.h" + +#include + +static inline bool is_newline(char ch) +{ + return ch == '\n' || ch == '\r'; +} + +namespace blender::io::ply { + +PlyReadBuffer::PlyReadBuffer(const char *file_path, size_t read_buffer_size) + : buffer_(read_buffer_size), read_buffer_size_(read_buffer_size) +{ + file_ = BLI_fopen(file_path, "rb"); +} + +PlyReadBuffer::~PlyReadBuffer() +{ + if (file_ != nullptr) { + fclose(file_); + } +} + +void PlyReadBuffer::after_header(bool is_binary) +{ + is_binary_ = is_binary; +} + +Span PlyReadBuffer::read_line() +{ + if (is_binary_) { + throw std::runtime_error("PLY read_line should not be used in binary mode"); + } + if (pos_ >= last_newline_) { + refill_buffer(); + } + BLI_assert(last_newline_ <= buffer_.size()); + int res_begin = pos_; + while (pos_ < last_newline_ && !is_newline(buffer_[pos_])) { + pos_++; + } + int res_end = pos_; + /* Move past newlines (possibly multiple for different line endings). */ + while (pos_ < buf_used_ && is_newline(buffer_[pos_])) { + pos_++; + } + return Span(buffer_.data() + res_begin, res_end - res_begin); +} + +bool PlyReadBuffer::read_bytes(void *dst, size_t size) +{ + while (size > 0) { + if (pos_ + size > buf_used_) { + if (!refill_buffer()) { + return false; + } + } + int to_copy = int(size); + if (to_copy > buf_used_) + to_copy = buf_used_; + memcpy(dst, buffer_.data() + pos_, to_copy); + pos_ += to_copy; + dst = (char *)dst + to_copy; + size -= to_copy; + } + return true; +} + +bool PlyReadBuffer::refill_buffer() +{ + BLI_assert(pos_ <= buf_used_); + BLI_assert(pos_ <= buffer_.size()); + BLI_assert(buf_used_ <= buffer_.size()); + + if (file_ == nullptr || at_eof_) { + return false; /* File is fully read. */ + } + + /* Move any leftover to start of buffer. */ + int keep = buf_used_ - pos_; + if (keep > 0) { + memmove(buffer_.data(), buffer_.data() + pos_, keep); + } + /* Read in data from the file. */ + size_t read = fread(buffer_.data() + keep, 1, read_buffer_size_ - keep, file_) + keep; + at_eof_ = read < read_buffer_size_; + pos_ = 0; + buf_used_ = int(read); + + /* Find last newline. */ + if (!is_binary_) { + int last_nl = buf_used_; + if (!at_eof_) { + while (last_nl > 0) { + --last_nl; + if (is_newline(buffer_[last_nl])) { + break; + } + } + if (!is_newline(buffer_[last_nl])) { + /* Whole line did not fit into our read buffer. */ + throw std::runtime_error("PLY text line did not fit into the read buffer"); + } + } + last_newline_ = last_nl; + } + + return true; +} + +} // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_buffer.hh b/source/blender/io/ply/importer/ply_import_buffer.hh new file mode 100644 index 00000000000..692ca806495 --- /dev/null +++ b/source/blender/io/ply/importer/ply_import_buffer.hh @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup ply + */ + +#pragma once + +#include +#include + +#include "BLI_array.hh" +#include "BLI_span.hh" + +namespace blender::io::ply { + +/** + * Reads underlying PLY file in large chunks, and provides interface for ascii/header + * parsing to read individual lines, and for binary parsing to read chunks of bytes. + */ +class PlyReadBuffer { + public: + PlyReadBuffer(const char *file_path, size_t read_buffer_size = 64 * 1024); + ~PlyReadBuffer(); + + /** After header is parsed, indicate whether the rest of reading will be ascii or binary. */ + void after_header(bool is_binary); + + /** Gets the next line from the file as a Span. The line does not include any newline characters. + */ + Span read_line(); + + /** Reads a number of bytes into provided destination pointer. Returns false if this amount of + * bytes can not be read. */ + bool read_bytes(void *dst, size_t size); + + private: + bool refill_buffer(); + + private: + FILE *file_ = nullptr; + Array buffer_; + int pos_ = 0; + int buf_used_ = 0; + int last_newline_ = 0; + size_t read_buffer_size_ = 0; + bool at_eof_ = false; + bool is_binary_ = false; +}; + +} // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_data.cc b/source/blender/io/ply/importer/ply_import_data.cc new file mode 100644 index 00000000000..fc396d5aad2 --- /dev/null +++ b/source/blender/io/ply/importer/ply_import_data.cc @@ -0,0 +1,606 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup ply + */ + +#include "ply_import_data.hh" +#include "ply_data.hh" +#include "ply_import_buffer.hh" + +#include "BLI_endian_switch.h" + +#include "fast_float.h" + +#include +#include + +static bool is_whitespace(char c) +{ + return c <= ' '; +} + +static const char *drop_whitespace(const char *p, const char *end) +{ + while (p < end && is_whitespace(*p)) { + ++p; + } + return p; +} + +static const char *drop_non_whitespace(const char *p, const char *end) +{ + while (p < end && !is_whitespace(*p)) { + ++p; + } + return p; +} + +static const char *drop_plus(const char *p, const char *end) +{ + if (p < end && *p == '+') { + ++p; + } + return p; +} + +static const char *parse_float(const char *p, const char *end, float fallback, float &dst) +{ + p = drop_whitespace(p, end); + p = drop_plus(p, end); + fast_float::from_chars_result res = fast_float::from_chars(p, end, dst); + if (ELEM(res.ec, std::errc::invalid_argument, std::errc::result_out_of_range)) { + dst = fallback; + } + return res.ptr; +} + +static const char *parse_int(const char *p, const char *end, int fallback, int &dst) +{ + p = drop_whitespace(p, end); + p = drop_plus(p, end); + std::from_chars_result res = std::from_chars(p, end, dst); + if (ELEM(res.ec, std::errc::invalid_argument, std::errc::result_out_of_range)) { + dst = fallback; + } + return res.ptr; +} + +static void endian_switch(uint8_t *ptr, int type_size) +{ + if (type_size == 2) { + BLI_endian_switch_uint16((uint16_t *)ptr); + } + else if (type_size == 4) { + BLI_endian_switch_uint32((uint32_t *)ptr); + } + else if (type_size == 8) { + BLI_endian_switch_uint64((uint64_t *)ptr); + } +} + +static void endian_switch_array(uint8_t *ptr, int type_size, int size) +{ + if (type_size == 2) { + BLI_endian_switch_uint16_array((uint16_t *)ptr, size); + } + else if (type_size == 4) { + BLI_endian_switch_uint32_array((uint32_t *)ptr, size); + } + else if (type_size == 8) { + BLI_endian_switch_uint64_array((uint64_t *)ptr, size); + } +} + +namespace blender::io::ply { + +static const int data_type_size[] = {0, 1, 1, 2, 2, 4, 4, 4, 8}; +static_assert(std::size(data_type_size) == PLY_TYPE_COUNT, "PLY data type size table mismatch"); + +static const float data_type_normalizer[] = { + 1.0f, 127.0f, 255.0f, 32767.0f, 65535.0f, float(INT_MAX), float(UINT_MAX), 1.0f, 1.0f}; +static_assert(std::size(data_type_normalizer) == PLY_TYPE_COUNT, + "PLY data type normalization factor table mismatch"); + +void PlyElement::calc_stride() +{ + stride = 0; + for (PlyProperty &p : properties) { + if (p.count_type != PlyDataTypes::NONE) { + stride = 0; + return; + } + stride += data_type_size[p.type]; + } +} + +static int get_index(const PlyElement &element, StringRef property) +{ + for (int i = 0, n = int(element.properties.size()); i != n; i++) { + const PlyProperty &prop = element.properties[i]; + if (prop.name == property) { + return i; + } + } + return -1; +} + +static const char *parse_row_ascii(PlyReadBuffer &file, Vector &r_values) +{ + Span line = file.read_line(); + + /* Parse whole line as floats. */ + const char *p = line.data(); + const char *end = p + line.size(); + int value_idx = 0; + while (p < end && value_idx < r_values.size()) { + float val; + p = parse_float(p, end, 0.0f, val); + r_values[value_idx++] = val; + } + return nullptr; +} + +template static T get_binary_value(PlyDataTypes type, const uint8_t *&r_ptr) +{ + T val = 0; + switch (type) { + case NONE: + break; + case CHAR: + val = *(int8_t *)r_ptr; + r_ptr += 1; + break; + case UCHAR: + val = *(uint8_t *)r_ptr; + r_ptr += 1; + break; + case SHORT: + val = *(int16_t *)r_ptr; + r_ptr += 2; + break; + case USHORT: + val = *(uint16_t *)r_ptr; + r_ptr += 2; + break; + case INT: + val = *(int32_t *)r_ptr; + r_ptr += 4; + break; + case UINT: + val = *(int32_t *)r_ptr; + r_ptr += 4; + break; + case FLOAT: + val = *(float *)r_ptr; + r_ptr += 4; + break; + case DOUBLE: + val = *(double *)r_ptr; + r_ptr += 8; + break; + default: + BLI_assert_msg(false, "Unknown property type"); + } + return val; +} + +static const char *parse_row_binary(PlyReadBuffer &file, + const PlyHeader &header, + const PlyElement &element, + Vector &r_scratch, + Vector &r_values) +{ + if (element.stride == 0) { + return "Vertex/Edge element contains list properties, this is not supported"; + } + BLI_assert(r_scratch.size() == element.stride); + BLI_assert(r_values.size() == element.properties.size()); + if (!file.read_bytes(r_scratch.data(), r_scratch.size())) { + return "Could not read row of binary property"; + } + + const uint8_t *ptr = r_scratch.data(); + if (header.type == PlyFormatType::BINARY_LE) { + /* Little endian: just read/convert the values. */ + for (int i = 0, n = int(element.properties.size()); i != n; i++) { + const PlyProperty &prop = element.properties[i]; + float val = get_binary_value(prop.type, ptr); + r_values[i] = val; + } + } + else if (header.type == PlyFormatType::BINARY_BE) { + /* Big endian: read, switch endian, convert the values. */ + for (int i = 0, n = int(element.properties.size()); i != n; i++) { + const PlyProperty &prop = element.properties[i]; + endian_switch((uint8_t *)ptr, data_type_size[prop.type]); + float val = get_binary_value(prop.type, ptr); + r_values[i] = val; + } + } + else { + return "Unknown binary ply format for vertex element"; + } + return nullptr; +} + +static const char *load_vertex_element(PlyReadBuffer &file, + const PlyHeader &header, + const PlyElement &element, + PlyData *data) +{ + /* Figure out vertex component indices. */ + int3 vertex_index = {get_index(element, "x"), get_index(element, "y"), get_index(element, "z")}; + int3 color_index = { + get_index(element, "red"), get_index(element, "green"), get_index(element, "blue")}; + int3 normal_index = { + get_index(element, "nx"), get_index(element, "ny"), get_index(element, "nz")}; + int2 uv_index = {get_index(element, "s"), get_index(element, "t")}; + int alpha_index = get_index(element, "alpha"); + + bool has_vertex = vertex_index.x >= 0 && vertex_index.y >= 0 && vertex_index.z >= 0; + bool has_color = color_index.x >= 0 && color_index.y >= 0 && color_index.z >= 0; + bool has_normal = normal_index.x >= 0 && normal_index.y >= 0 && normal_index.z >= 0; + bool has_uv = uv_index.x >= 0 && uv_index.y >= 0; + bool has_alpha = alpha_index >= 0; + + if (!has_vertex) { + return "Vertex positions are not present in the file"; + } + + data->vertices.reserve(element.count); + if (has_color) { + data->vertex_colors.reserve(element.count); + } + if (has_normal) { + data->vertex_normals.reserve(element.count); + } + if (has_uv) { + data->uv_coordinates.reserve(element.count); + } + + float4 color_norm = {1, 1, 1, 1}; + if (has_color) { + color_norm.x = data_type_normalizer[element.properties[color_index.x].type]; + color_norm.y = data_type_normalizer[element.properties[color_index.y].type]; + color_norm.z = data_type_normalizer[element.properties[color_index.z].type]; + } + if (has_alpha) { + color_norm.w = data_type_normalizer[element.properties[alpha_index].type]; + } + + Vector value_vec(element.properties.size()); + Vector scratch; + if (header.type != PlyFormatType::ASCII) { + scratch.resize(element.stride); + } + + for (int i = 0; i < element.count; i++) { + + const char *error = nullptr; + if (header.type == PlyFormatType::ASCII) { + error = parse_row_ascii(file, value_vec); + } + else { + error = parse_row_binary(file, header, element, scratch, value_vec); + } + if (error != nullptr) { + return error; + } + + /* Vertex coord */ + float3 vertex3; + vertex3.x = value_vec[vertex_index.x]; + vertex3.y = value_vec[vertex_index.y]; + vertex3.z = value_vec[vertex_index.z]; + data->vertices.append(vertex3); + + /* Vertex color */ + if (has_color) { + float4 colors4; + colors4.x = value_vec[color_index.x] / color_norm.x; + colors4.y = value_vec[color_index.y] / color_norm.y; + colors4.z = value_vec[color_index.z] / color_norm.z; + if (has_alpha) { + colors4.w = value_vec[alpha_index] / color_norm.w; + } + else { + colors4.w = 1.0f; + } + data->vertex_colors.append(colors4); + } + + /* If normals */ + if (has_normal) { + float3 normals3; + normals3.x = value_vec[normal_index.x]; + normals3.y = value_vec[normal_index.y]; + normals3.z = value_vec[normal_index.z]; + data->vertex_normals.append(normals3); + } + + /* If uv */ + if (has_uv) { + float2 uvmap; + uvmap.x = value_vec[uv_index.x]; + uvmap.y = value_vec[uv_index.y]; + data->uv_coordinates.append(uvmap); + } + } + return nullptr; +} + +static uint32_t read_list_count(PlyReadBuffer &file, + const PlyProperty &prop, + Vector &scratch, + bool big_endian) +{ + scratch.resize(8); + file.read_bytes(scratch.data(), data_type_size[prop.count_type]); + const uint8_t *ptr = scratch.data(); + if (big_endian) + endian_switch((uint8_t *)ptr, data_type_size[prop.count_type]); + uint32_t count = get_binary_value(prop.count_type, ptr); + return count; +} + +static void skip_property(PlyReadBuffer &file, + const PlyProperty &prop, + Vector &scratch, + bool big_endian) +{ + if (prop.count_type == PlyDataTypes::NONE) { + scratch.resize(8); + file.read_bytes(scratch.data(), data_type_size[prop.type]); + } + else { + uint32_t count = read_list_count(file, prop, scratch, big_endian); + scratch.resize(count * data_type_size[prop.type]); + file.read_bytes(scratch.data(), scratch.size()); + } +} + +static const char *load_face_element(PlyReadBuffer &file, + const PlyHeader &header, + const PlyElement &element, + PlyData *data) +{ + int prop_index = get_index(element, "vertex_indices"); + if (prop_index < 0) { + prop_index = get_index(element, "vertex_index"); + } + if (prop_index < 0 && element.properties.size() == 1) { + prop_index = 0; + } + if (prop_index < 0) { + return "Face element does not contain vertex indices property"; + } + const PlyProperty &prop = element.properties[prop_index]; + if (prop.count_type == PlyDataTypes::NONE) { + return "Face element vertex indices property must be a list"; + } + + data->face_vertices.reserve(element.count * 3); + data->face_sizes.reserve(element.count); + + if (header.type == PlyFormatType::ASCII) { + for (int i = 0; i < element.count; i++) { + /* Read line */ + Span line = file.read_line(); + + const char *p = line.data(); + const char *end = p + line.size(); + int count = 0; + + /* Skip any properties before vertex indices. */ + for (int j = 0; j < prop_index; j++) { + p = drop_whitespace(p, end); + if (element.properties[j].count_type == PlyDataTypes::NONE) { + p = drop_non_whitespace(p, end); + } + else { + p = parse_int(p, end, 0, count); + for (int k = 0; k < count; ++k) { + p = drop_whitespace(p, end); + p = drop_non_whitespace(p, end); + } + } + } + + /* Parse vertex indices list. */ + p = parse_int(p, end, 0, count); + if (count < 1 || count > 255) { + return "Invalid face size, must be between 1 and 255"; + } + + for (int j = 0; j < count; j++) { + int index; + p = parse_int(p, end, 0, index); + data->face_vertices.append(index); + } + data->face_sizes.append(count); + } + } + else { + Vector scratch(64); + + for (int i = 0; i < element.count; i++) { + const uint8_t *ptr; + + /* Skip any properties before vertex indices. */ + for (int j = 0; j < prop_index; j++) { + skip_property( + file, element.properties[j], scratch, header.type == PlyFormatType::BINARY_BE); + } + + /* Read vertex indices list. */ + uint32_t count = read_list_count( + file, prop, scratch, header.type == PlyFormatType::BINARY_BE); + if (count < 1 || count > 255) { + return "Invalid face size, must be between 1 and 255"; + } + + scratch.resize(count * data_type_size[prop.type]); + file.read_bytes(scratch.data(), scratch.size()); + ptr = scratch.data(); + if (header.type == PlyFormatType::BINARY_BE) + endian_switch_array((uint8_t *)ptr, data_type_size[prop.type], count); + for (int j = 0; j < count; ++j) { + uint32_t index = get_binary_value(prop.type, ptr); + data->face_vertices.append(index); + } + data->face_sizes.append(count); + + /* Skip any properties after vertex indices. */ + for (int j = prop_index + 1; j < element.properties.size(); j++) { + skip_property( + file, element.properties[j], scratch, header.type == PlyFormatType::BINARY_BE); + } + } + } + return nullptr; +} + +static const char *load_tristrips_element(PlyReadBuffer &file, + const PlyHeader &header, + const PlyElement &element, + PlyData *data) +{ + if (element.count != 1) { + return "Tristrips element should contain one row"; + } + if (element.properties.size() != 1) { + return "Tristrips element should contain one property"; + } + const PlyProperty &prop = element.properties[0]; + if (prop.count_type == PlyDataTypes::NONE) { + return "Tristrips element property must be a list"; + } + + Vector strip; + + if (header.type == PlyFormatType::ASCII) { + Span line = file.read_line(); + + const char *p = line.data(); + const char *end = p + line.size(); + int count = 0; + p = parse_int(p, end, 0, count); + + strip.resize(count); + for (int j = 0; j < count; j++) { + int index; + p = parse_int(p, end, 0, index); + strip[j] = index; + } + } + else { + Vector scratch(64); + + const uint8_t *ptr; + + uint32_t count = read_list_count(file, prop, scratch, header.type == PlyFormatType::BINARY_BE); + + strip.resize(count); + scratch.resize(count * data_type_size[prop.type]); + file.read_bytes(scratch.data(), scratch.size()); + ptr = scratch.data(); + if (header.type == PlyFormatType::BINARY_BE) + endian_switch_array((uint8_t *)ptr, data_type_size[prop.type], count); + for (int j = 0; j < count; ++j) { + int index = get_binary_value(prop.type, ptr); + strip[j] = index; + } + } + + /* Decode triangle strip (with possible -1 restart indices) into faces. */ + size_t start = 0; + + for (size_t i = 0; i < strip.size(); i++) { + if (strip[i] == -1) { + /* Restart strip. */ + start = i + 1; + } + else if (i - start >= 2) { + int a = strip[i - 2], b = strip[i - 1], c = strip[i]; + /* Flip odd triangles. */ + if ((i - start) & 1) { + SWAP(int, a, b); + } + /* Add triangle if it's not degenerate. */ + if (a != b && a != c && b != c) { + data->face_vertices.append(a); + data->face_vertices.append(b); + data->face_vertices.append(c); + data->face_sizes.append(3); + } + } + } + return nullptr; +} + +static const char *load_edge_element(PlyReadBuffer &file, + const PlyHeader &header, + const PlyElement &element, + PlyData *data) +{ + int prop_vertex1 = get_index(element, "vertex1"); + int prop_vertex2 = get_index(element, "vertex2"); + if (prop_vertex1 < 0 || prop_vertex2 < 0) { + return "Edge element does not contain vertex1 and vertex2 properties"; + } + + data->edges.reserve(element.count); + + Vector value_vec(element.properties.size()); + Vector scratch; + if (header.type != PlyFormatType::ASCII) { + scratch.resize(element.stride); + } + + for (int i = 0; i < element.count; i++) { + const char *error = nullptr; + if (header.type == PlyFormatType::ASCII) { + error = parse_row_ascii(file, value_vec); + } + else { + error = parse_row_binary(file, header, element, scratch, value_vec); + } + if (error != nullptr) { + return error; + } + int index1 = value_vec[prop_vertex1]; + int index2 = value_vec[prop_vertex2]; + data->edges.append(std::make_pair(index1, index2)); + } + return nullptr; +} + +std::unique_ptr import_ply_data(PlyReadBuffer &file, PlyHeader &header) +{ + std::unique_ptr data = std::make_unique(); + + for (const PlyElement &element : header.elements) { + const char *error = nullptr; + if (element.name == "vertex") { + error = load_vertex_element(file, header, element, data.get()); + } + else if (element.name == "face") { + error = load_face_element(file, header, element, data.get()); + } + else if (element.name == "tristrips") { + error = load_tristrips_element(file, header, element, data.get()); + } + else if (element.name == "edge") { + error = load_edge_element(file, header, element, data.get()); + } + if (error != nullptr) { + data->error = error; + return data; + } + } + + return data; +} + +} // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_data.hh b/source/blender/io/ply/importer/ply_import_data.hh new file mode 100644 index 00000000000..7531d648941 --- /dev/null +++ b/source/blender/io/ply/importer/ply_import_data.hh @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup ply + */ + +#pragma once + +#include "ply_data.hh" + +namespace blender::io::ply { + +class PlyReadBuffer; + +/** + * Loads the information from a PLY file to a #PlyData data-structure. + * \param file: The PLY file that was opened. + * \param header: The information in the PLY header. + * \return The #PlyData data-structure that can be used for conversion to a Mesh. + */ +std::unique_ptr import_ply_data(PlyReadBuffer &file, PlyHeader &header); + +} // namespace blender::io::ply diff --git a/source/blender/io/ply/importer/ply_import_mesh.cc b/source/blender/io/ply/importer/ply_import_mesh.cc index b281af75d3d..efefebb6930 100644 --- a/source/blender/io/ply/importer/ply_import_mesh.cc +++ b/source/blender/io/ply/importer/ply_import_mesh.cc @@ -7,7 +7,7 @@ #include "BKE_attribute.h" #include "BKE_attribute.hh" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "GEO_mesh_merge_by_distance.hh" @@ -23,46 +23,54 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ /* Add vertices to the mesh. */ mesh->totvert = int(data.vertices.size()); CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, mesh->totvert, "position"); + &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); mesh->vert_positions_for_write().copy_from(data.vertices); bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); if (!data.edges.is_empty()) { mesh->totedge = int(data.edges.size()); - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_SET_DEFAULT, nullptr, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_SET_DEFAULT, mesh->totedge); MutableSpan edges = mesh->edges_for_write(); for (int i = 0; i < mesh->totedge; i++) { - edges[i].v1 = data.edges[i].first; - edges[i].v2 = data.edges[i].second; + uint32_t v1 = data.edges[i].first; + uint32_t v2 = data.edges[i].second; + if (v1 >= mesh->totvert) { + fprintf(stderr, "Invalid PLY vertex index in edge %i/1: %u\n", i, v1); + v1 = 0; + } + if (v2 >= mesh->totvert) { + fprintf(stderr, "Invalid PLY vertex index in edge %i/2: %u\n", i, v2); + v2 = 0; + } + edges[i].v1 = v1; + edges[i].v2 = v2; } } /* Add faces to the mesh. */ - if (!data.faces.is_empty()) { - /* Specify amount of total faces. */ - mesh->totpoly = int(data.faces.size()); - mesh->totloop = 0; - for (int i = 0; i < data.faces.size(); i++) { - /* Add number of loops from the vertex indices in the face. */ - mesh->totloop += data.faces[i].size(); - } - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); + if (!data.face_sizes.is_empty()) { + /* Create poly and loop layers. */ + mesh->totpoly = int(data.face_sizes.size()); + mesh->totloop = int(data.face_vertices.size()); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, mesh->totpoly); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, mesh->totloop); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); - int offset = 0; - /* Iterate over amount of faces. */ + /* Fill in face data. */ + uint32_t offset = 0; for (int i = 0; i < mesh->totpoly; i++) { - int size = int(data.faces[i].size()); - /* Set the index from where this face starts and specify the amount of edges it has. */ + uint32_t size = data.face_sizes[i]; polys[i].loopstart = offset; polys[i].totloop = size; - for (int j = 0; j < size; j++) { - /* Set the vertex index of the loop to the one in PlyData. */ - loops[offset + j].v = data.faces[i][j]; + uint32_t v = data.face_vertices[offset + j]; + if (v >= mesh->totvert) { + fprintf(stderr, "Invalid PLY vertex index in face %i loop %i: %u\n", i, j, v); + v = 0; + } + loops[offset + j].v = v; } offset += size; } @@ -93,12 +101,8 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ if (!data.uv_coordinates.is_empty()) { bke::SpanAttributeWriter uv_map = attributes.lookup_or_add_for_write_only_span( "UVMap", ATTR_DOMAIN_CORNER); - int counter = 0; - for (int i = 0; i < data.faces.size(); i++) { - for (int j = 0; j < data.faces[i].size(); j++) { - uv_map.span[counter] = data.uv_coordinates[data.faces[i][j]]; - counter++; - } + for (size_t i = 0; i < data.face_vertices.size(); i++) { + uv_map.span[i] = data.uv_coordinates[data.face_vertices[i]]; } uv_map.finish(); } @@ -121,6 +125,8 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ } } + BKE_mesh_smooth_flag_set(mesh, false); + return mesh; } } // namespace blender::io::ply diff --git a/source/blender/io/ply/intern/ply_data.hh b/source/blender/io/ply/intern/ply_data.hh index 087d6e61269..db14fdeefc0 100644 --- a/source/blender/io/ply/intern/ply_data.hh +++ b/source/blender/io/ply/intern/ply_data.hh @@ -12,30 +12,38 @@ namespace blender::io::ply { -enum PlyDataTypes { CHAR, UCHAR, SHORT, USHORT, INT, UINT, FLOAT, DOUBLE }; +enum PlyDataTypes { NONE, CHAR, UCHAR, SHORT, USHORT, INT, UINT, FLOAT, DOUBLE, PLY_TYPE_COUNT }; struct PlyData { Vector vertices; Vector vertex_normals; - /* Value between 0 and 1. */ - Vector vertex_colors; + Vector vertex_colors; /* Linear space, 0..1 range colors. */ Vector> edges; - Vector edge_colors; - Vector> faces; + Vector face_vertices; + Vector face_sizes; Vector uv_coordinates; + std::string error; }; enum PlyFormatType { ASCII, BINARY_LE, BINARY_BE }; +struct PlyProperty { + std::string name; + PlyDataTypes type = PlyDataTypes::NONE; + PlyDataTypes count_type = PlyDataTypes::NONE; /* NONE means it's not a list property */ +}; + +struct PlyElement { + std::string name; + int count = 0; + Vector properties; + int stride = 0; + + void calc_stride(); +}; + struct PlyHeader { - int vertex_count = 0; - int edge_count = 0; - int face_count = 0; - int header_size = 0; - /* List of elements in ply file with their count. */ - Vector> elements; - /* List of properties (Name, type) per element. */ - Vector>> properties; + Vector elements; PlyFormatType type; }; diff --git a/source/blender/io/ply/intern/ply_functions.cc b/source/blender/io/ply/intern/ply_functions.cc deleted file mode 100644 index 5cc61547dbe..00000000000 --- a/source/blender/io/ply/intern/ply_functions.cc +++ /dev/null @@ -1,51 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup ply - */ - -#include "ply_functions.hh" - -namespace blender::io::ply { - -line_ending safe_getline(fstream &file, std::string &line) -{ - line.clear(); - std::streambuf *sb = file.rdbuf(); - std::istream::sentry se(file, true); - - line_ending possible = UNSET; - char c; - while (sb->sgetc() != std::streambuf::traits_type::eof()) { - c = char(sb->sgetc()); - switch (c) { - case '\n': - if (possible == UNSET) { - possible = LF; - } - else if (possible == CR) { - possible = CR_LF; - } - break; - case '\r': - if (possible == UNSET) { - possible = CR; - } - else if (possible == LF) { - possible = LF_CR; - } - break; - default: - /* If a different character is encountered after the line ending is set, we know to return. - */ - if (possible != UNSET) { - return possible; - } - line += c; - break; - } - sb->sbumpc(); - } - return possible; -} -} // namespace blender::io::ply diff --git a/source/blender/io/ply/intern/ply_functions.hh b/source/blender/io/ply/intern/ply_functions.hh deleted file mode 100644 index e454167be87..00000000000 --- a/source/blender/io/ply/intern/ply_functions.hh +++ /dev/null @@ -1,26 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -/** \file - * \ingroup ply - */ - -#pragma once - -#include "BLI_fileops.hh" -#include - -namespace blender::io::ply { - -enum line_ending { CR_LF, LF, CR, LF_CR, UNSET }; - -/** - * Reads a line in the ply file in a line-ending safe manner. All different line endings are - * supported. This also supports a mix of different line endings in the same file. CR (\\r), LF - * (\\n), CR/LF (\\r\\n), LF/CR (\\n\\r). - * \param file: The file stream. - * \param line: The string you want to read to. - * \return The line ending enum if you're interested. - */ -line_ending safe_getline(fstream &file, std::string &line); - -} // namespace blender::io::ply diff --git a/source/blender/io/ply/tests/io_ply_exporter_test.cc b/source/blender/io/ply/tests/io_ply_exporter_test.cc index 388ea066a40..d8f163bdfc4 100644 --- a/source/blender/io/ply/tests/io_ply_exporter_test.cc +++ b/source/blender/io/ply/tests/io_ply_exporter_test.cc @@ -21,7 +21,7 @@ namespace blender::io::ply { -class PlyExportTest : public BlendfileLoadingBaseTest { +class ply_export_test : public BlendfileLoadingBaseTest { public: bool load_file_and_depsgraph(const std::string &filepath, const eEvaluationMode eval_mode = DAG_EVAL_VIEWPORT) @@ -50,34 +50,39 @@ class PlyExportTest : public BlendfileLoadingBaseTest { std::string get_temp_ply_filename(const std::string &filename) { - return std::string(BKE_tempdir_session()) + "/" + filename; + return std::string(BKE_tempdir_session()) + SEP_STR + filename; } }; static std::unique_ptr load_cube(PLYExportParams ¶ms) { std::unique_ptr plyData = std::make_unique(); - plyData->vertices = {{1.122082, 1.122082, 1.122082}, - {1.122082, 1.122082, -1.122082}, - {1.122082, -1.122082, 1.122082}, - {1.122082, -1.122082, -1.122082}, - {-1.122082, 1.122082, 1.122082}, - {-1.122082, 1.122082, -1.122082}, - {-1.122082, -1.122082, 1.122082}, - {-1.122082, -1.122082, -1.122082}}; + plyData->vertices = { + {1.122082, 1.122082, 1.122082}, + {1.122082, 1.122082, -1.122082}, + {1.122082, -1.122082, 1.122082}, + {1.122082, -1.122082, -1.122082}, + {-1.122082, 1.122082, 1.122082}, + {-1.122082, 1.122082, -1.122082}, + {-1.122082, -1.122082, 1.122082}, + {-1.122082, -1.122082, -1.122082}, + }; - plyData->faces = { - {0, 2, 6, 4}, {3, 7, 6, 2}, {7, 5, 4, 6}, {5, 7, 3, 1}, {1, 3, 2, 0}, {5, 1, 0, 4}}; + plyData->face_sizes = {4, 4, 4, 4, 4, 4}; + plyData->face_vertices = {0, 2, 6, 4, 3, 7, 6, 2, 7, 5, 4, 6, + 5, 7, 3, 1, 1, 3, 2, 0, 5, 1, 0, 4}; if (params.export_normals) - plyData->vertex_normals = {{-0.5773503, -0.5773503, -0.5773503}, - {-0.5773503, -0.5773503, 0.5773503}, - {-0.5773503, 0.5773503, -0.5773503}, - {-0.5773503, 0.5773503, 0.5773503}, - {0.5773503, -0.5773503, -0.5773503}, - {0.5773503, -0.5773503, 0.5773503}, - {0.5773503, 0.5773503, -0.5773503}, - {0.5773503, 0.5773503, 0.5773503}}; + plyData->vertex_normals = { + {-0.5773503, -0.5773503, -0.5773503}, + {-0.5773503, -0.5773503, 0.5773503}, + {-0.5773503, 0.5773503, -0.5773503}, + {-0.5773503, 0.5773503, 0.5773503}, + {0.5773503, -0.5773503, -0.5773503}, + {0.5773503, -0.5773503, 0.5773503}, + {0.5773503, 0.5773503, -0.5773503}, + {0.5773503, 0.5773503, 0.5773503}, + }; return plyData; } @@ -122,10 +127,10 @@ static std::vector read_temp_file_in_vectorchar(const std::string &file_pa return res; } -TEST_F(PlyExportTest, WriteHeaderAscii) +TEST_F(ply_export_test, WriteHeaderAscii) { std::string filePath = get_temp_ply_filename(temp_file_path); - PLYExportParams _params; + PLYExportParams _params = {}; _params.ascii_format = true; _params.export_normals = false; _params.vertex_colors = PLY_VERTEX_COLOR_NONE; @@ -160,10 +165,10 @@ TEST_F(PlyExportTest, WriteHeaderAscii) ASSERT_STREQ(result.c_str(), expected.c_str()); } -TEST_F(PlyExportTest, WriteHeaderBinary) +TEST_F(ply_export_test, WriteHeaderBinary) { std::string filePath = get_temp_ply_filename(temp_file_path); - PLYExportParams _params; + PLYExportParams _params = {}; _params.ascii_format = false; _params.export_normals = false; _params.vertex_colors = PLY_VERTEX_COLOR_NONE; @@ -198,10 +203,10 @@ TEST_F(PlyExportTest, WriteHeaderBinary) ASSERT_STREQ(result.c_str(), expected.c_str()); } -TEST_F(PlyExportTest, WriteVerticesAscii) +TEST_F(ply_export_test, WriteVerticesAscii) { std::string filePath = get_temp_ply_filename(temp_file_path); - PLYExportParams _params; + PLYExportParams _params = {}; _params.ascii_format = true; _params.export_normals = false; _params.vertex_colors = PLY_VERTEX_COLOR_NONE; @@ -230,10 +235,10 @@ TEST_F(PlyExportTest, WriteVerticesAscii) ASSERT_STREQ(result.c_str(), expected.c_str()); } -TEST_F(PlyExportTest, WriteVerticesBinary) +TEST_F(ply_export_test, WriteVerticesBinary) { std::string filePath = get_temp_ply_filename(temp_file_path); - PLYExportParams _params; + PLYExportParams _params = {}; _params.ascii_format = false; _params.export_normals = false; _params.vertex_colors = PLY_VERTEX_COLOR_NONE; @@ -249,21 +254,15 @@ TEST_F(PlyExportTest, WriteVerticesBinary) std::vector result = read_temp_file_in_vectorchar(filePath); - std::vector expected( - {(char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, - (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, - (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, - (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, - (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, - (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, - (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, - (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, - (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, - (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, - (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, - (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, - (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, - (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF}); + std::vector expected({ + 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, + 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, + 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, + 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, + 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, + 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, + 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, + }); ASSERT_EQ(result.size(), expected.size()); @@ -272,10 +271,10 @@ TEST_F(PlyExportTest, WriteVerticesBinary) } } -TEST_F(PlyExportTest, WriteFacesAscii) +TEST_F(ply_export_test, WriteFacesAscii) { std::string filePath = get_temp_ply_filename(temp_file_path); - PLYExportParams _params; + PLYExportParams _params = {}; _params.ascii_format = true; _params.export_normals = false; _params.vertex_colors = PLY_VERTEX_COLOR_NONE; @@ -302,10 +301,10 @@ TEST_F(PlyExportTest, WriteFacesAscii) ASSERT_STREQ(result.c_str(), expected.c_str()); } -TEST_F(PlyExportTest, WriteFacesBinary) +TEST_F(ply_export_test, WriteFacesBinary) { std::string filePath = get_temp_ply_filename(temp_file_path); - PLYExportParams _params; + PLYExportParams _params = {}; _params.ascii_format = false; _params.export_normals = false; _params.vertex_colors = PLY_VERTEX_COLOR_NONE; @@ -321,22 +320,15 @@ TEST_F(PlyExportTest, WriteFacesBinary) std::vector result = read_temp_file_in_vectorchar(filePath); - std::vector expected( - {(char)0x04, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x02, (char)0x00, - (char)0x00, (char)0x00, (char)0x06, (char)0x00, (char)0x00, (char)0x00, (char)0x04, - (char)0x00, (char)0x00, (char)0x00, (char)0x04, (char)0x03, (char)0x00, (char)0x00, - (char)0x00, (char)0x07, (char)0x00, (char)0x00, (char)0x00, (char)0x06, (char)0x00, - (char)0x00, (char)0x00, (char)0x02, (char)0x00, (char)0x00, (char)0x00, (char)0x04, - (char)0x07, (char)0x00, (char)0x00, (char)0x00, (char)0x05, (char)0x00, (char)0x00, - (char)0x00, (char)0x04, (char)0x00, (char)0x00, (char)0x00, (char)0x06, (char)0x00, - (char)0x00, (char)0x00, (char)0x04, (char)0x05, (char)0x00, (char)0x00, (char)0x00, - (char)0x07, (char)0x00, (char)0x00, (char)0x00, (char)0x03, (char)0x00, (char)0x00, - (char)0x00, (char)0x01, (char)0x00, (char)0x00, (char)0x00, (char)0x04, (char)0x01, - (char)0x00, (char)0x00, (char)0x00, (char)0x03, (char)0x00, (char)0x00, (char)0x00, - (char)0x02, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, - (char)0x00, (char)0x04, (char)0x05, (char)0x00, (char)0x00, (char)0x00, (char)0x01, - (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, (char)0x00, - (char)0x04, (char)0x00, (char)0x00, (char)0x00}); + std::vector expected({ + 0x04, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x04, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x07, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + }); ASSERT_EQ(result.size(), expected.size()); @@ -345,10 +337,10 @@ TEST_F(PlyExportTest, WriteFacesBinary) } } -TEST_F(PlyExportTest, WriteVertexNormalsAscii) +TEST_F(ply_export_test, WriteVertexNormalsAscii) { std::string filePath = get_temp_ply_filename(temp_file_path); - PLYExportParams _params; + PLYExportParams _params = {}; _params.ascii_format = true; _params.export_normals = true; _params.vertex_colors = PLY_VERTEX_COLOR_NONE; @@ -377,10 +369,10 @@ TEST_F(PlyExportTest, WriteVertexNormalsAscii) ASSERT_STREQ(result.c_str(), expected.c_str()); } -TEST_F(PlyExportTest, WriteVertexNormalsBinary) +TEST_F(ply_export_test, WriteVertexNormalsBinary) { std::string filePath = get_temp_ply_filename(temp_file_path); - PLYExportParams _params; + PLYExportParams _params = {}; _params.ascii_format = false; _params.export_normals = true; _params.vertex_colors = PLY_VERTEX_COLOR_NONE; @@ -396,35 +388,21 @@ TEST_F(PlyExportTest, WriteVertexNormalsBinary) std::vector result = read_temp_file_in_vectorchar(filePath); - std::vector expected( - {(char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, - (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x3B, (char)0xCD, - (char)0x13, (char)0xBF, (char)0x3B, (char)0xCD, (char)0x13, (char)0xBF, (char)0x3B, - (char)0xCD, (char)0x13, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, - (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, - (char)0xBF, (char)0x3B, (char)0xCD, (char)0x13, (char)0xBF, (char)0x3B, (char)0xCD, - (char)0x13, (char)0xBF, (char)0x3B, (char)0xCD, (char)0x13, (char)0x3F, (char)0x62, - (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, - (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x3B, (char)0xCD, (char)0x13, - (char)0xBF, (char)0x3B, (char)0xCD, (char)0x13, (char)0x3F, (char)0x3B, (char)0xCD, - (char)0x13, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, - (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, - (char)0x3B, (char)0xCD, (char)0x13, (char)0xBF, (char)0x3B, (char)0xCD, (char)0x13, - (char)0x3F, (char)0x3B, (char)0xCD, (char)0x13, (char)0x3F, (char)0x62, (char)0xA0, - (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0x3F, (char)0x62, - (char)0xA0, (char)0x8F, (char)0x3F, (char)0x3B, (char)0xCD, (char)0x13, (char)0x3F, - (char)0x3B, (char)0xCD, (char)0x13, (char)0xBF, (char)0x3B, (char)0xCD, (char)0x13, - (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, - (char)0x8F, (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x3B, - (char)0xCD, (char)0x13, (char)0x3F, (char)0x3B, (char)0xCD, (char)0x13, (char)0xBF, - (char)0x3B, (char)0xCD, (char)0x13, (char)0x3F, (char)0x62, (char)0xA0, (char)0x8F, - (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, - (char)0x8F, (char)0x3F, (char)0x3B, (char)0xCD, (char)0x13, (char)0x3F, (char)0x3B, - (char)0xCD, (char)0x13, (char)0x3F, (char)0x3B, (char)0xCD, (char)0x13, (char)0xBF, - (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, - (char)0xBF, (char)0x62, (char)0xA0, (char)0x8F, (char)0xBF, (char)0x3B, (char)0xCD, - (char)0x13, (char)0x3F, (char)0x3B, (char)0xCD, (char)0x13, (char)0x3F, (char)0x3B, - (char)0xCD, (char)0x13, (char)0x3F}); + std::vector expected({ + 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0x3F, 0x3B, 0xCD, 0x13, + 0xBF, 0x3B, 0xCD, 0x13, 0xBF, 0x3B, 0xCD, 0x13, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, + 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0xBF, 0x3B, 0xCD, 0x13, 0xBF, 0x3B, 0xCD, 0x13, 0xBF, 0x3B, + 0xCD, 0x13, 0x3F, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, + 0x3B, 0xCD, 0x13, 0xBF, 0x3B, 0xCD, 0x13, 0x3F, 0x3B, 0xCD, 0x13, 0xBF, 0x62, 0xA0, 0x8F, + 0x3F, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, 0x3B, 0xCD, 0x13, 0xBF, 0x3B, 0xCD, + 0x13, 0x3F, 0x3B, 0xCD, 0x13, 0x3F, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, 0x62, + 0xA0, 0x8F, 0x3F, 0x3B, 0xCD, 0x13, 0x3F, 0x3B, 0xCD, 0x13, 0xBF, 0x3B, 0xCD, 0x13, 0xBF, + 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, 0x62, 0xA0, 0x8F, 0xBF, 0x3B, 0xCD, 0x13, + 0x3F, 0x3B, 0xCD, 0x13, 0xBF, 0x3B, 0xCD, 0x13, 0x3F, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, + 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0x3F, 0x3B, 0xCD, 0x13, 0x3F, 0x3B, 0xCD, 0x13, 0x3F, 0x3B, + 0xCD, 0x13, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, 0x62, 0xA0, 0x8F, 0xBF, + 0x3B, 0xCD, 0x13, 0x3F, 0x3B, 0xCD, 0x13, 0x3F, 0x3B, 0xCD, 0x13, 0x3F, + }); ASSERT_EQ(result.size(), expected.size()); @@ -433,7 +411,7 @@ TEST_F(PlyExportTest, WriteVertexNormalsBinary) } } -class ply_exporter_ply_data_test : public PlyExportTest { +class ply_exporter_ply_data_test : public ply_export_test { public: PlyData load_ply_data_from_blendfile(const std::string &blendfile, PLYExportParams ¶ms) { @@ -450,34 +428,34 @@ class ply_exporter_ply_data_test : public PlyExportTest { TEST_F(ply_exporter_ply_data_test, CubeLoadPLYDataVertices) { - PLYExportParams params; - PlyData plyData = load_ply_data_from_blendfile("io_tests/blend_geometry/cube_all_data.blend", - params); + PLYExportParams params = {}; + PlyData plyData = load_ply_data_from_blendfile( + "io_tests" SEP_STR "blend_geometry" SEP_STR "cube_all_data.blend", params); EXPECT_EQ(plyData.vertices.size(), 8); } TEST_F(ply_exporter_ply_data_test, CubeLoadPLYDataUV) { - PLYExportParams params; + PLYExportParams params = {}; params.export_uv = true; - PlyData plyData = load_ply_data_from_blendfile("io_tests/blend_geometry/cube_all_data.blend", - params); + PlyData plyData = load_ply_data_from_blendfile( + "io_tests" SEP_STR "blend_geometry" SEP_STR "cube_all_data.blend", params); EXPECT_EQ(plyData.uv_coordinates.size(), 8); } TEST_F(ply_exporter_ply_data_test, SuzanneLoadPLYDataUV) { - PLYExportParams params; + PLYExportParams params = {}; params.export_uv = true; - PlyData plyData = load_ply_data_from_blendfile("io_tests/blend_geometry/suzanne_all_data.blend", - params); - EXPECT_EQ(plyData.uv_coordinates.size(), 541); + PlyData plyData = load_ply_data_from_blendfile( + "io_tests" SEP_STR "blend_geometry" SEP_STR "suzanne_all_data.blend", params); + EXPECT_EQ(plyData.uv_coordinates.size(), 542); } TEST_F(ply_exporter_ply_data_test, CubeLoadPLYDataUVDisabled) { - PLYExportParams params; + PLYExportParams params = {}; params.export_uv = false; - PlyData plyData = load_ply_data_from_blendfile("io_tests/blend_geometry/cube_all_data.blend", - params); + PlyData plyData = load_ply_data_from_blendfile( + "io_tests" SEP_STR "blend_geometry" SEP_STR "cube_all_data.blend", params); EXPECT_EQ(plyData.uv_coordinates.size(), 0); } diff --git a/source/blender/io/ply/tests/io_ply_importer_test.cc b/source/blender/io/ply/tests/io_ply_importer_test.cc index 32ba55f1eaa..73c9580e419 100644 --- a/source/blender/io/ply/tests/io_ply_importer_test.cc +++ b/source/blender/io/ply/tests/io_ply_importer_test.cc @@ -1,249 +1,278 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "tests/blendfile_loading_base_test.h" +#include "testing/testing.h" -#include "BKE_attribute.hh" -#include "BKE_mesh.h" -#include "BKE_object.h" +#include "BLI_fileops.hh" +#include "BLI_hash_mm2a.h" -#include "BLO_readfile.h" - -#include "DEG_depsgraph_query.h" - -#include "IO_ply.h" -#include "ply_data.hh" #include "ply_import.hh" -#include "ply_import_binary.hh" +#include "ply_import_buffer.hh" +#include "ply_import_data.hh" namespace blender::io::ply { struct Expectation { - std::string name; - PlyFormatType type; - int totvert, totpoly, totedge; + int totvert, totpoly, totindex, totedge; + uint16_t polyhash = 0, edgehash = 0; float3 vert_first, vert_last; float3 normal_first = {0, 0, 0}; - float2 uv_first; + float2 uv_first = {0, 0}; float4 color_first = {-1, -1, -1, -1}; }; -class PlyImportTest : public BlendfileLoadingBaseTest { +class ply_import_test : public testing::Test { public: - void import_and_check(const char *path, const Expectation *expect, size_t expect_count) + void import_and_check(const char *path, const Expectation &exp) { - if (!blendfile_load("io_tests/blend_geometry/all_quads.blend")) { + std::string ply_path = blender::tests::flags_test_asset_dir() + "/io_tests/ply/" + path; + + /* Use a small read buffer size for better coverage of buffer refilling behavior. */ + PlyReadBuffer infile(ply_path.c_str(), 128); + PlyHeader header; + const char *header_err = read_header(infile, header); + if (header_err != nullptr) { ADD_FAILURE(); return; } - - PLYImportParams params; - params.global_scale = 1.0f; - params.forward_axis = IO_AXIS_NEGATIVE_Z; - params.up_axis = IO_AXIS_Y; - params.merge_verts = false; - params.vertex_colors = PLY_VERTEX_COLOR_NONE; - - /* Import the test file. */ - std::string ply_path = blender::tests::flags_test_asset_dir() + "/io_tests/ply/" + path; - strncpy(params.filepath, ply_path.c_str(), FILE_MAX - 1); - importer_main(bfile->main, bfile->curscene, bfile->cur_view_layer, params, nullptr); - - depsgraph_create(DAG_EVAL_VIEWPORT); - - DEGObjectIterSettings deg_iter_settings{}; - deg_iter_settings.depsgraph = depsgraph; - deg_iter_settings.flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | - DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET | DEG_ITER_OBJECT_FLAG_VISIBLE | - DEG_ITER_OBJECT_FLAG_DUPLI; - size_t object_index = 0; - - /* Iterate over the objects in the viewport */ - DEG_OBJECT_ITER_BEGIN (°_iter_settings, object) { - if (object_index >= expect_count) { - ADD_FAILURE(); - break; - } - - const Expectation &exp = expect[object_index]; - - ASSERT_STREQ(object->id.name, exp.name.c_str()); - EXPECT_V3_NEAR(object->loc, float3(0, 0, 0), 0.0001f); - - EXPECT_V3_NEAR(object->scale, float3(1, 1, 1), 0.0001f); - if (object->type == OB_MESH) { - Mesh *mesh = BKE_object_get_evaluated_mesh(object); - - /* Test if mesh has expected amount of vertices, edges, and faces. */ - ASSERT_EQ(mesh->totvert, exp.totvert); - ASSERT_EQ(mesh->totedge, exp.totedge); - ASSERT_EQ(mesh->totpoly, exp.totpoly); - - /* Test if first and last vertices match. */ - const Span verts = mesh->vert_positions(); - EXPECT_V3_NEAR(verts.first(), exp.vert_first, 0.0001f); - EXPECT_V3_NEAR(verts.last(), exp.vert_last, 0.0001f); - - /* Fetch normal data from mesh and test if it matches expectation. */ - if (BKE_mesh_has_custom_loop_normals(mesh)) { - const Span vertex_normals = mesh->vert_normals(); - ASSERT_FALSE(vertex_normals.is_empty()); - EXPECT_V3_NEAR(vertex_normals[0], exp.normal_first, 0.0001f); - } - - /* Fetch UV data from mesh and test if it matches expectation. */ - blender::bke::AttributeAccessor attributes = mesh->attributes(); - VArray uvs = attributes.lookup("UVMap"); - float2 uv_first = !uvs.is_empty() ? uvs[0] : float2(0, 0); - EXPECT_V2_NEAR(uv_first, exp.uv_first, 0.0001f); - - /* Check if expected mesh has vertex colors, and tests if it matches. */ - if (CustomData_has_layer(&mesh->vdata, CD_PROP_COLOR)) { - const float4 *colors = (const float4 *)CustomData_get_layer(&mesh->vdata, CD_PROP_COLOR); - ASSERT_TRUE(colors != nullptr); - EXPECT_V4_NEAR(colors[0], exp.color_first, 0.0001f); - } - } - ++object_index; + std::unique_ptr data = import_ply_data(infile, header); + if (!data->error.empty()) { + fprintf(stderr, "%s\n", data->error.c_str()); + ASSERT_EQ(0, exp.totvert); + ASSERT_EQ(0, exp.totpoly); + return; } - DEG_OBJECT_ITER_END; - EXPECT_EQ(object_index, expect_count); + /* Test expected amount of vertices, edges, and faces. */ + ASSERT_EQ(data->vertices.size(), exp.totvert); + ASSERT_EQ(data->edges.size(), exp.totedge); + ASSERT_EQ(data->face_sizes.size(), exp.totpoly); + ASSERT_EQ(data->face_vertices.size(), exp.totindex); + + /* Test hash of face and edge index data. */ + BLI_HashMurmur2A hash; + BLI_hash_mm2a_init(&hash, 0); + uint32_t offset = 0; + for (uint32_t face_size : data->face_sizes) { + BLI_hash_mm2a_add(&hash, (const unsigned char *)&data->face_vertices[offset], face_size * 4); + offset += face_size; + } + uint16_t face_hash = BLI_hash_mm2a_end(&hash); + if (!data->face_vertices.is_empty()) { + ASSERT_EQ(face_hash, exp.polyhash); + } + + if (!data->edges.is_empty()) { + uint16_t edge_hash = BLI_hash_mm2((const unsigned char *)data->edges.data(), + data->edges.size() * sizeof(data->edges[0]), + 0); + ASSERT_EQ(edge_hash, exp.edgehash); + } + + /* Test if first and last vertices match. */ + EXPECT_V3_NEAR(data->vertices.first(), exp.vert_first, 0.0001f); + EXPECT_V3_NEAR(data->vertices.last(), exp.vert_last, 0.0001f); + + /* Check if first normal matches. */ + float3 got_normal = data->vertex_normals.is_empty() ? float3(0, 0, 0) : + data->vertex_normals.first(); + EXPECT_V3_NEAR(got_normal, exp.normal_first, 0.0001f); + + /* Check if first UV matches. */ + float2 got_uv = data->uv_coordinates.is_empty() ? float2(0, 0) : data->uv_coordinates.first(); + EXPECT_V2_NEAR(got_uv, exp.uv_first, 0.0001f); + + /* Check if first color matches. */ + float4 got_color = data->vertex_colors.is_empty() ? float4(-1, -1, -1, -1) : + data->vertex_colors.first(); + EXPECT_V4_NEAR(got_color, exp.color_first, 0.0001f); } }; -TEST_F(PlyImportTest, PLYImportCube) +TEST_F(ply_import_test, PLYImportCube) { - Expectation expect[] = {{"OBCube", - ASCII, - 8, - 6, - 12, - float3(1, 1, -1), - float3(-1, 1, 1), - float3(0.5773, 0.5773, -0.5773), - float2(0, 0)}, - {"OBcube_ascii", - ASCII, - 24, - 6, - 24, - float3(1, 1, -1), - float3(-1, 1, 1), - float3(0, 0, -1), - float2(0.979336, 0.844958), - float4(1, 0.8470, 0, 1)}}; - import_and_check("cube_ascii.ply", expect, 2); + Expectation expect = {24, + 6, + 24, + 0, + 26429, + 0, + float3(1, 1, -1), + float3(-1, 1, 1), + float3(0, 0, -1), + float2(0.979336, 0.844958), + float4(1, 0.8470, 0, 1)}; + import_and_check("cube_ascii.ply", expect); } -TEST_F(PlyImportTest, PLYImportASCIIEdgeTest) +TEST_F(ply_import_test, PLYImportWireframeCube) { - Expectation expect[] = {{"OBCube", - ASCII, - 8, - 6, - 12, - float3(1, 1, -1), - float3(-1, 1, 1), - float3(0.5773, 0.5773, -0.5773)}, - {"OBASCII_wireframe_cube", - ASCII, - 8, - 0, - 12, - float3(-1, -1, -1), - float3(1, 1, 1), - float3(-2, 0, -1)}}; - - import_and_check("ASCII_wireframe_cube.ply", expect, 2); + Expectation expect = {8, 0, 0, 12, 0, 31435, float3(-1, -1, -1), float3(1, 1, 1)}; + import_and_check("ASCII_wireframe_cube.ply", expect); + import_and_check("wireframe_cube.ply", expect); } -TEST_F(PlyImportTest, PLYImportBunny) +TEST_F(ply_import_test, PLYImportBunny) { - Expectation expect[] = {{"OBCube", - ASCII, - 8, - 6, - 12, - float3(1, 1, -1), - float3(-1, 1, 1), - float3(0.5773, 0.5773, -0.5773)}, - {"OBbunny2", - BINARY_LE, - 1623, - 1000, - 1513, - float3(0.0380425, 0.109755, 0.0161689), - float3(-0.0722821, 0.143895, -0.0129091), - float3(-2, -2, -2)}}; - import_and_check("bunny2.ply", expect, 2); + Expectation expect = {1623, + 1000, + 3000, + 0, + 62556, + 0, + float3(0.0380425, 0.109755, 0.0161689), + float3(-0.0722821, 0.143895, -0.0129091)}; + import_and_check("bunny2.ply", expect); } -TEST_F(PlyImportTest, PlyImportManySmallHoles) +TEST_F(ply_import_test, PlyImportManySmallHoles) { - Expectation expect[] = {{"OBCube", - ASCII, - 8, - 6, - 12, - float3(1, 1, -1), - float3(-1, 1, 1), - float3(0.5773, 0.5773, -0.5773)}, - {"OBmany_small_holes", - BINARY_LE, - 2004, - 3524, - 5564, - float3(-0.0131592, -0.0598382, 1.58958), - float3(-0.0177622, 0.0105153, 1.61977), - float3(-2, -2, -2), - float2(0, 0), - float4(0.7215, 0.6784, 0.6627, 1)}}; - import_and_check("many_small_holes.ply", expect, 2); + Expectation expect = {2004, + 3524, + 10572, + 0, + 15143, + 0, + float3(-0.0131592, -0.0598382, 1.58958), + float3(-0.0177622, 0.0105153, 1.61977), + float3(0, 0, 0), + float2(0, 0), + float4(0.7215, 0.6784, 0.6627, 1)}; + import_and_check("many_small_holes.ply", expect); } -TEST_F(PlyImportTest, PlyImportWireframeCube) +TEST_F(ply_import_test, PlyImportColorNotFull) { - Expectation expect[] = {{"OBCube", - ASCII, - 8, - 6, - 12, - float3(1, 1, -1), - float3(-1, 1, 1), - float3(0.5773, 0.5773, -0.5773)}, - {"OBwireframe_cube", - BINARY_LE, - 8, - 0, - 12, - float3(-1, -1, -1), - float3(1, 1, 1), - float3(-2, -2, -2)}}; - import_and_check("wireframe_cube.ply", expect, 2); + Expectation expect = {4, 1, 4, 0, 37235, 0, float3(1, 0, 1), float3(-1, 0, 1)}; + import_and_check("color_not_full_a.ply", expect); + import_and_check("color_not_full_b.ply", expect); } -TEST(PlyImportFunctionsTest, PlySwapBytes) +TEST_F(ply_import_test, PlyImportDoubleXYZ) { - /* Individual bits shouldn't swap with each other. */ - uint8_t val8 = 0xA8; - uint8_t exp8 = 0xA8; - uint8_t actual8 = swap_bytes(val8); - ASSERT_EQ(exp8, actual8); - - uint16_t val16 = 0xFEB0; - uint16_t exp16 = 0xB0FE; - uint16_t actual16 = swap_bytes(val16); - ASSERT_EQ(exp16, actual16); - - uint32_t val32 = 0x80A37B0A; - uint32_t exp32 = 0x0A7BA380; - uint32_t actual32 = swap_bytes(val32); - ASSERT_EQ(exp32, actual32); - - uint64_t val64 = 0x0102030405060708; - uint64_t exp64 = 0x0807060504030201; - uint64_t actual64 = swap_bytes(val64); - ASSERT_EQ(exp64, actual64); + Expectation expect = {4, + 1, + 4, + 0, + 37235, + 0, + float3(1, 0, 1), + float3(-1, 0, 1), + float3(0, 0, 0), + float2(0, 0), + float4(1, 0, 0, 1)}; + import_and_check("double_xyz_a.ply", expect); + import_and_check("double_xyz_b.ply", expect); } +TEST_F(ply_import_test, PlyImportFaceIndicesNotFirstProp) +{ + Expectation expect = {4, 2, 6, 0, 4136, 0, float3(1, 0, 1), float3(-1, 0, 1)}; + import_and_check("face_indices_not_first_prop_a.ply", expect); + import_and_check("face_indices_not_first_prop_b.ply", expect); +} + +TEST_F(ply_import_test, PlyImportFaceIndicesPrecededByList) +{ + Expectation expect = {4, 2, 6, 0, 4136, 0, float3(1, 0, 1), float3(-1, 0, 1)}; + import_and_check("face_indices_preceded_by_list_a.ply", expect); + import_and_check("face_indices_preceded_by_list_b.ply", expect); +} + +TEST_F(ply_import_test, PlyImportFaceUVsColors) +{ + Expectation expect = {4, 1, 4, 0, 37235, 0, float3(1, 0, 1), float3(-1, 0, 1)}; + import_and_check("face_uvs_colors_a.ply", expect); + import_and_check("face_uvs_colors_b.ply", expect); +} + +TEST_F(ply_import_test, PlyImportFacesFirst) +{ + Expectation expect = {4, + 1, + 4, + 0, + 37235, + 0, + float3(1, 0, 1), + float3(-1, 0, 1), + float3(0, 0, 0), + float2(0, 0), + float4(1, 0, 0, 1)}; + import_and_check("faces_first_a.ply", expect); + import_and_check("faces_first_b.ply", expect); +} + +TEST_F(ply_import_test, PlyImportFloatFormats) +{ + Expectation expect = {4, + 1, + 4, + 0, + 37235, + 0, + float3(1, 0, 1), + float3(-1, 0, 1), + float3(0, 0, 0), + float2(0, 0), + float4(0.5f, 0, 0.25f, 1)}; + import_and_check("float_formats_a.ply", expect); + import_and_check("float_formats_b.ply", expect); +} + +TEST_F(ply_import_test, PlyImportPositionNotFull) +{ + Expectation expect = {0, 0, 0, 0}; + import_and_check("position_not_full_a.ply", expect); + import_and_check("position_not_full_b.ply", expect); +} + +TEST_F(ply_import_test, PlyImportTristrips) +{ + Expectation expect = {6, 4, 12, 0, 3404, 0, float3(1, 0, 1), float3(-3, 0, 1)}; + import_and_check("tristrips_a.ply", expect); + import_and_check("tristrips_b.ply", expect); +} + +TEST_F(ply_import_test, PlyImportTypeAliases) +{ + Expectation expect = {4, + 1, + 4, + 0, + 37235, + 0, + float3(1, 0, 1), + float3(-1, 0, 1), + float3(0, 0, 0), + float2(0, 0), + float4(220 / 255.0f, 20 / 255.0f, 20 / 255.0f, 1)}; + import_and_check("type_aliases_a.ply", expect); + import_and_check("type_aliases_b.ply", expect); + import_and_check("type_aliases_be_b.ply", expect); +} + +TEST_F(ply_import_test, PlyImportVertexCompOrder) +{ + Expectation expect = {4, + 1, + 4, + 0, + 37235, + 0, + float3(1, 0, 1), + float3(-1, 0, 1), + float3(0, 0, 0), + float2(0, 0), + float4(0.8f, 0.2f, 0, 1)}; + import_and_check("vertex_comp_order_a.ply", expect); + import_and_check("vertex_comp_order_b.ply", expect); +} + +//@TODO: test with vertex element having list properties +//@TODO: test with edges starting with non-vertex index properties +//@TODO: test various malformed headers +//@TODO: UVs with: s,t; u,v; texture_u,texture_v; texture_s,texture_t (from miniply) +//@TODO: colors with: r,g,b in addition to red,green,blue (from miniply) +//@TODO: importing bunny2 with old importer results in smooth shading; flat shading with new one + } // namespace blender::io::ply diff --git a/source/blender/io/stl/importer/stl_import.cc b/source/blender/io/stl/importer/stl_import.cc index e5fde6658ab..2f32b9270f3 100644 --- a/source/blender/io/stl/importer/stl_import.cc +++ b/source/blender/io/stl/importer/stl_import.cc @@ -8,7 +8,7 @@ #include "BKE_customdata.h" #include "BKE_layer.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "DNA_collection_types.h" diff --git a/source/blender/io/stl/importer/stl_import_ascii_reader.cc b/source/blender/io/stl/importer/stl_import_ascii_reader.cc index 6a976a2fd2c..8bfe4924cc5 100644 --- a/source/blender/io/stl/importer/stl_import_ascii_reader.cc +++ b/source/blender/io/stl/importer/stl_import_ascii_reader.cc @@ -7,7 +7,7 @@ #include #include -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_fileops.hh" #include "BLI_memory_utils.hh" diff --git a/source/blender/io/stl/importer/stl_import_binary_reader.cc b/source/blender/io/stl/importer/stl_import_binary_reader.cc index fb9dcea0a1d..26d9e3406e7 100644 --- a/source/blender/io/stl/importer/stl_import_binary_reader.cc +++ b/source/blender/io/stl/importer/stl_import_binary_reader.cc @@ -8,7 +8,7 @@ #include #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_array.hh" #include "BLI_memory_utils.hh" diff --git a/source/blender/io/stl/importer/stl_import_mesh.cc b/source/blender/io/stl/importer/stl_import_mesh.cc index 3a87c4e3559..2a7b074b094 100644 --- a/source/blender/io/stl/importer/stl_import_mesh.cc +++ b/source/blender/io/stl/importer/stl_import_mesh.cc @@ -7,7 +7,7 @@ #include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_array.hh" #include "BLI_math_vector.h" @@ -77,13 +77,13 @@ Mesh *STLMeshHelper::to_mesh(Main *bmain, char *mesh_name) mesh->totvert = verts_.size(); CustomData_add_layer_named( - &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, mesh->totvert, "position"); + &mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, mesh->totvert, "position"); mesh->vert_positions_for_write().copy_from(verts_); mesh->totpoly = tris_.size(); mesh->totloop = tris_.size() * 3; - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, nullptr, mesh->totpoly); - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, nullptr, mesh->totloop); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_SET_DEFAULT, mesh->totpoly); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_SET_DEFAULT, mesh->totloop); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); threading::parallel_for(tris_.index_range(), 2048, [&](IndexRange tris_range) { diff --git a/source/blender/io/usd/CMakeLists.txt b/source/blender/io/usd/CMakeLists.txt index 21017d1be88..568ed4c7641 100644 --- a/source/blender/io/usd/CMakeLists.txt +++ b/source/blender/io/usd/CMakeLists.txt @@ -35,6 +35,13 @@ if(USD_IMAGING_HEADERS) add_definitions(-DUSD_HAS_IMAGING) endif() +if(WIN32) + # Some USD library headers trigger the "unreferenced formal parameter" + # warning alert. + # Silence them by restore warn C4100 back to w4 + remove_cc_flag(/w34100) +endif() + set(INC . ../common diff --git a/source/blender/io/usd/intern/usd_common.cc b/source/blender/io/usd/intern/usd_common.cc index 2cfd3c5196e..607e64f0c4b 100644 --- a/source/blender/io/usd/intern/usd_common.cc +++ b/source/blender/io/usd/intern/usd_common.cc @@ -11,9 +11,9 @@ namespace blender::io::usd { void ensure_usd_plugin_path_registered() { - /* if PXR_PYTHON_SUPPORT_ENABLED is defined, we *must* be dynamic and - the plugins are placed relative to the USD shared library hence no - hinting is required. */ + /* If #PXR_PYTHON_SUPPORT_ENABLED is defined, we *must* be dynamic and + * the plugins are placed relative to the USD shared library hence no + * hinting is required. */ #ifndef PXR_PYTHON_SUPPORT_ENABLED static bool plugin_path_registered = false; if (plugin_path_registered) { diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc index abf6c0cb0f9..8b7af8e076f 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.cc @@ -117,7 +117,7 @@ AbstractHierarchyWriter *USDHierarchyIterator::create_data_writer(const Hierarch case OB_LIGHTPROBE: case OB_LATTICE: case OB_ARMATURE: - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: case OB_POINTCLOUD: case OB_CURVES: return nullptr; diff --git a/source/blender/io/usd/intern/usd_reader_curve.cc b/source/blender/io/usd/intern/usd_reader_curve.cc index 32bbfc83c17..e967b258ae9 100644 --- a/source/blender/io/usd/intern/usd_reader_curve.cc +++ b/source/blender/io/usd/intern/usd_reader_curve.cc @@ -5,7 +5,7 @@ #include "usd_reader_curve.h" #include "BKE_curve.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BLI_listbase.h" diff --git a/source/blender/io/usd/intern/usd_reader_material.h b/source/blender/io/usd/intern/usd_reader_material.h index 7eedcf9eb12..4d9908755b5 100644 --- a/source/blender/io/usd/intern/usd_reader_material.h +++ b/source/blender/io/usd/intern/usd_reader_material.h @@ -145,10 +145,10 @@ void build_material_map(const Main *bmain, std::map *r_ * Returns an existing Blender material that corresponds to the USD material with the given path. * Returns null if no such material exists. * - * \param mat_map Map a material name to a Blender material. Note that the name key + * \param mat_map: Map a material name to a Blender material. Note that the name key * might be the Blender material name modified to be a valid USD identifier, * to match the material names in the imported USD. - * \param usd_path_to_mat_name Map a USD material path to the imported Blender material name. + * \param usd_path_to_mat_name: Map a USD material path to the imported Blender material name. * * The usd_path_to_mat_name is needed to determine the name of the Blender * material imported from a USD path in the case when a unique name was generated diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index cd452f972b4..79446728acb 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -10,7 +10,7 @@ #include "BKE_customdata.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BLI_math.h" @@ -162,8 +162,7 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, const int data_type /* Create a new layer. */ numloops = mesh->totloop; - cd_ptr = CustomData_add_layer_named( - loopdata, cd_data_type, CD_SET_DEFAULT, nullptr, numloops, name); + cd_ptr = CustomData_add_layer_named(loopdata, cd_data_type, CD_SET_DEFAULT, numloops, name); return cd_ptr; } @@ -277,7 +276,6 @@ void USDMeshReader::read_mpolys(Mesh *mesh) /* Polygons are always assumed to be smooth-shaded. If the mesh should be flat-shaded, * this is encoded in custom loop normals. */ - poly.flag |= ME_SMOOTH; if (is_left_handed_) { int loop_end_index = loop_index + (face_size - 1); @@ -533,7 +531,7 @@ void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTim } float *creases = static_cast( - CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_SET_DEFAULT, nullptr, mesh->totvert)); + CustomData_add_layer(&mesh->vdata, CD_CREASE, CD_SET_DEFAULT, mesh->totvert)); for (size_t i = 0; i < corner_indices.size(); i++) { creases[corner_indices[i]] = corner_sharpnesses[i]; diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.cc b/source/blender/io/usd/intern/usd_reader_nurbs.cc index 8e070dea915..7e644632980 100644 --- a/source/blender/io/usd/intern/usd_reader_nurbs.cc +++ b/source/blender/io/usd/intern/usd_reader_nurbs.cc @@ -5,7 +5,7 @@ #include "usd_reader_nurbs.h" #include "BKE_curve.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BLI_listbase.h" diff --git a/source/blender/io/usd/intern/usd_reader_shape.cc b/source/blender/io/usd/intern/usd_reader_shape.cc index 19df18c8b02..58ef6d5cd36 100644 --- a/source/blender/io/usd/intern/usd_reader_shape.cc +++ b/source/blender/io/usd/intern/usd_reader_shape.cc @@ -2,7 +2,7 @@ * Copyright 2023 Nvidia. All rights reserved. */ #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_object.h" @@ -145,7 +145,8 @@ Mesh *USDShapeReader::read_mesh(struct Mesh *existing_mesh, MutableSpan polys = active_mesh->polys_for_write(); MutableSpan loops = active_mesh->loops_for_write(); - const char should_smooth = prim_.IsA() ? 0 : ME_SMOOTH; + /* Don't smooth-shade cubes; we're not worrying about sharpness for Gprims. */ + BKE_mesh_smooth_flag_set(active_mesh, !prim_.IsA()); int loop_index = 0; for (int i = 0; i < face_counts.size(); i++) { @@ -155,9 +156,6 @@ Mesh *USDShapeReader::read_mesh(struct Mesh *existing_mesh, poly.loopstart = loop_index; poly.totloop = face_size; - /* Don't smooth-shade cubes; we're not worrying about sharpness for Gprims. */ - poly.flag |= should_smooth; - for (int f = 0; f < face_size; ++f, ++loop_index) { loops[loop_index].v = face_indices[loop_index]; } diff --git a/source/blender/io/usd/intern/usd_reader_stage.cc b/source/blender/io/usd/intern/usd_reader_stage.cc index ef3608ea936..d19249ab94d 100644 --- a/source/blender/io/usd/intern/usd_reader_stage.cc +++ b/source/blender/io/usd/intern/usd_reader_stage.cc @@ -277,7 +277,7 @@ USDPrimReader *USDStageReader::collect_readers(Main *bmain, const pxr::UsdPrim & if (prim.IsA()) { /* Record material path for later processing, if needed, - * e.g., when importing all materials. */ + * e.g., when importing all materials. */ material_paths_.push_back(prim.GetPath().GetAsString()); /* We don't create readers for materials, so return early. */ diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 9472946e680..b71997df8ef 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -18,7 +18,7 @@ #include "BKE_customdata.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -440,14 +440,17 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_ } else { /* Compute the loop normals based on the 'smooth' flag. */ - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh); - const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh); + bke::AttributeAccessor attributes = mesh->attributes(); + const Span vert_normals = mesh->vert_normals(); + const Span poly_normals = mesh->poly_normals(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); for (const int i : polys.index_range()) { const MPoly &poly = polys[i]; - if ((poly.flag & ME_SMOOTH) == 0) { + if (sharp_faces[i]) { /* Flat shaded, use common normal for all verts. */ - pxr::GfVec3f pxr_normal(face_normals[i]); + pxr::GfVec3f pxr_normal(&poly_normals[i].x); for (int loop_idx = 0; loop_idx < poly.totloop; ++loop_idx) { loop_normals.push_back(pxr_normal); } @@ -455,7 +458,7 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_ else { /* Smooth shaded, use individual vert normals. */ for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { - loop_normals.push_back(pxr::GfVec3f(vert_normals[loop.v])); + loop_normals.push_back(pxr::GfVec3f(&vert_normals[loop.v].x)); } } } diff --git a/source/blender/io/usd/intern/usd_writer_metaball.cc b/source/blender/io/usd/intern/usd_writer_metaball.cc index b83dd191869..e42da192b61 100644 --- a/source/blender/io/usd/intern/usd_writer_metaball.cc +++ b/source/blender/io/usd/intern/usd_writer_metaball.cc @@ -12,7 +12,7 @@ #include "BKE_displist.h" #include "BKE_lib_id.h" #include "BKE_mball.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "DNA_mesh_types.h" diff --git a/source/blender/io/usd/tests/usd_export_test.cc b/source/blender/io/usd/tests/usd_export_test.cc index 580e65a378b..fe9d35254ca 100644 --- a/source/blender/io/usd/tests/usd_export_test.cc +++ b/source/blender/io/usd/tests/usd_export_test.cc @@ -21,7 +21,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_node.h" #include "BLI_fileops.h" #include "BLI_math.h" diff --git a/source/blender/io/usd/tests/usd_tests_common.cc b/source/blender/io/usd/tests/usd_tests_common.cc index 6c73788d866..3def0e04122 100644 --- a/source/blender/io/usd/tests/usd_tests_common.cc +++ b/source/blender/io/usd/tests/usd_tests_common.cc @@ -36,9 +36,9 @@ std::string register_usd_plugins_for_tests() BLI_assert(path_len + 1 < FILE_MAX); usd_datafiles_dir[path_len] = '/'; usd_datafiles_dir[path_len + 1] = '\0'; - /* if PXR_PYTHON_SUPPORT_ENABLED is defined, we *must* be dynamic and - the plugins are placed relative to the USD shared library hence no - hinting is required. */ + /* If #PXR_PYTHON_SUPPORT_ENABLED is defined, we *must* be dynamic and + * the plugins are placed relative to the USD shared library hence no + * hinting is required. */ #ifndef PXR_PYTHON_SUPPORT_ENABLED pxr::PlugRegistry::GetInstance().RegisterPlugins(usd_datafiles_dir); #endif diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc index 6957e07dadd..8ae878f2222 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -9,7 +9,7 @@ #include "BKE_attribute.hh" #include "BKE_blender_version.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_color.hh" #include "BLI_enumerable_thread_specific.hh" diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index d915fcc8aa9..53c82330f74 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -9,7 +9,7 @@ #include "BKE_deform.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_object.h" @@ -44,6 +44,8 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj mesh_edges_ = export_mesh_->edges(); mesh_polys_ = export_mesh_->polys(); mesh_loops_ = export_mesh_->loops(); + sharp_faces_ = export_mesh_->attributes().lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); } else { /* Curves and NURBS surfaces need a new mesh when they're @@ -76,6 +78,8 @@ void OBJMesh::set_mesh(Mesh *mesh) mesh_edges_ = mesh->edges(); mesh_polys_ = mesh->polys(); mesh_loops_ = mesh->loops(); + sharp_faces_ = export_mesh_->attributes().lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); } void OBJMesh::clear() @@ -194,12 +198,15 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags) { const bool *sharp_edges = static_cast( CustomData_get_layer_named(&export_mesh_->edata, CD_PROP_BOOL, "sharp_edge")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&export_mesh_->pdata, CD_PROP_BOOL, "sharp_face")); poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.size(), mesh_polys_.data(), mesh_polys_.size(), mesh_loops_.data(), mesh_loops_.size(), sharp_edges, + sharp_faces, &tot_smooth_groups_, use_bitflags); } @@ -245,7 +252,7 @@ const Material *OBJMesh::get_object_material(const int16_t mat_nr) const bool OBJMesh::is_ith_poly_smooth(const int poly_index) const { - return mesh_polys_[poly_index].flag & ME_SMOOTH; + return !sharp_faces_[poly_index]; } const char *OBJMesh::get_object_name() const @@ -354,12 +361,9 @@ Span OBJMesh::calc_poly_uv_indices(const int poly_index) const float3 OBJMesh::calc_poly_normal(const int poly_index) const { - float3 r_poly_normal; const MPoly &poly = mesh_polys_[poly_index]; - BKE_mesh_calc_poly_normal(&poly, - &mesh_loops_[poly.loopstart], - reinterpret_cast(mesh_positions_.data()), - r_poly_normal); + float3 r_poly_normal = bke::mesh::poly_normal_calc( + mesh_positions_, mesh_loops_.slice(poly.loopstart, poly.totloop)); mul_m3_v3(world_and_axes_normal_transform_, r_poly_normal); normalize_v3(r_poly_normal); return r_poly_normal; @@ -399,7 +403,7 @@ void OBJMesh::store_normal_coords_and_indices() CustomData_get_layer(&export_mesh_->ldata, CD_NORMAL)); for (int poly_index = 0; poly_index < export_mesh_->totpoly; ++poly_index) { const MPoly &poly = mesh_polys_[poly_index]; - bool need_per_loop_normals = lnors != nullptr || (poly.flag & ME_SMOOTH); + bool need_per_loop_normals = lnors != nullptr || !(sharp_faces_[poly_index]); if (need_per_loop_normals) { for (int loop_of_poly = 0; loop_of_poly < poly.totloop; ++loop_of_poly) { float3 loop_normal; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index 0c151cb4454..21d212f5575 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -11,6 +11,7 @@ #include "BLI_math_vector_types.hh" #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" +#include "BLI_virtual_array.hh" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -40,6 +41,7 @@ class OBJMesh : NonCopyable { Span mesh_edges_; Span mesh_polys_; Span mesh_loops_; + VArray sharp_faces_; /** * Final transform of an object obtained from export settings (up_axis, forward_axis) and the diff --git a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc index 204237088ab..19fe1465e85 100644 --- a/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc +++ b/source/blender/io/wavefront_obj/importer/importer_mesh_utils.cc @@ -4,7 +4,7 @@ * \ingroup obj */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BLI_delaunay_2d.h" diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index e68d4fc54fb..5a24020d0e4 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -12,7 +12,7 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_node_tree_update.h" #include "BKE_object.h" #include "BKE_object_deform.h" @@ -185,9 +185,11 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); bke::SpanAttributeWriter material_indices = - mesh->attributes_for_write().lookup_or_add_for_write_only_span("material_index", - ATTR_DOMAIN_FACE); + attributes.lookup_or_add_for_write_only_span("material_index", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span( + "sharp_face", ATTR_DOMAIN_FACE); const int64_t tot_face_elems{mesh->totpoly}; int tot_loop_idx = 0; @@ -203,9 +205,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) MPoly &poly = polys[poly_idx]; poly.totloop = curr_face.corner_count_; poly.loopstart = tot_loop_idx; - if (curr_face.shaded_smooth) { - poly.flag |= ME_SMOOTH; - } + sharp_faces.span[poly_idx] = !curr_face.shaded_smooth; material_indices.span[poly_idx] = curr_face.material_index; /* Importing obj files without any materials would result in negative indices, which is not * supported. */ @@ -233,6 +233,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) } material_indices.finish(); + sharp_faces.finish(); } void MeshFromGeometry::create_vertex_groups(Object *obj) diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc index 1591faa4738..50ed1e56711 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc @@ -315,6 +315,7 @@ static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial } if (do_tranparency || (alpha >= 0.0f && alpha < 1.0f)) { mat->blend_method = MA_BM_BLEND; + mat->blend_flag |= MA_BL_HIDE_BACKFACE; } if (mtl_mat.sheen >= 0) { @@ -393,6 +394,7 @@ static void add_image_textures(Main *bmain, else if (key == int(MTLTexMapType::Alpha)) { link_sockets(ntree, image_node, "Alpha", bsdf, tex_map_type_to_socket_id[key]); mat->blend_method = MA_BM_BLEND; + mat->blend_flag |= MA_BL_HIDE_BACKFACE; } else { link_sockets(ntree, image_node, "Color", bsdf, tex_map_type_to_socket_id[key]); diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc index 5de3cdcd851..5be3bf781ac 100644 --- a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -50,7 +50,7 @@ class obj_exporter_test : public BlendfileLoadingBaseTest { } }; -const std::string all_objects_file = "io_tests/blend_scene/all_objects.blend"; +const std::string all_objects_file = "io_tests" SEP_STR "blend_scene" SEP_STR "all_objects.blend"; TEST_F(obj_exporter_test, filter_objects_curves_as_mesh) { @@ -93,8 +93,8 @@ TEST_F(obj_exporter_test, filter_objects_selected) TEST(obj_exporter_utils, append_negative_frame_to_filename) { - const char path_original[FILE_MAX] = "/my_file.obj"; - const char path_truth[FILE_MAX] = "/my_file-123.obj"; + const char path_original[FILE_MAX] = SEP_STR "my_file.obj"; + const char path_truth[FILE_MAX] = SEP_STR "my_file-123.obj"; const int frame = -123; char path_with_frame[FILE_MAX] = {0}; const bool ok = append_frame_to_filename(path_original, frame, path_with_frame); @@ -104,8 +104,8 @@ TEST(obj_exporter_utils, append_negative_frame_to_filename) TEST(obj_exporter_utils, append_positive_frame_to_filename) { - const char path_original[FILE_MAX] = "/my_file.obj"; - const char path_truth[FILE_MAX] = "/my_file123.obj"; + const char path_original[FILE_MAX] = SEP_STR "my_file.obj"; + const char path_truth[FILE_MAX] = SEP_STR "my_file123.obj"; const int frame = 123; char path_with_frame[FILE_MAX] = {0}; const bool ok = append_frame_to_filename(path_original, frame, path_with_frame); @@ -148,7 +148,7 @@ TEST(obj_exporter_writer, header) { /* Because testing doesn't fully initialize Blender, we need the following. */ BKE_tempdir_init(nullptr); - std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path; + std::string out_file_path = blender::tests::flags_test_release_dir() + SEP_STR + temp_file_path; { OBJExportParamsDefault _export; std::unique_ptr writer = init_writer(_export.params, out_file_path); @@ -166,7 +166,7 @@ TEST(obj_exporter_writer, header) TEST(obj_exporter_writer, mtllib) { - std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path; + std::string out_file_path = blender::tests::flags_test_release_dir() + SEP_STR + temp_file_path; { OBJExportParamsDefault _export; std::unique_ptr writer = init_writer(_export.params, out_file_path); @@ -263,7 +263,7 @@ class obj_exporter_regression_test : public obj_exporter_test { std::string out_file_path = tempdir + BLI_path_basename(golden_obj.c_str()); strncpy(params.filepath, out_file_path.c_str(), FILE_MAX - 1); params.blen_filepath = bfile->main->filepath; - std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj; + std::string golden_file_path = blender::tests::flags_test_asset_dir() + SEP_STR + golden_obj; BLI_split_dir_part(golden_file_path.c_str(), params.file_base_for_tests, PATH_MAX); export_frame(depsgraph, params, out_file_path.c_str()); std::string output_str = read_temp_file_in_string(out_file_path); @@ -280,7 +280,8 @@ class obj_exporter_regression_test : public obj_exporter_test { if (!golden_mtl.empty()) { std::string out_mtl_file_path = tempdir + BLI_path_basename(golden_mtl.c_str()); std::string output_mtl_str = read_temp_file_in_string(out_mtl_file_path); - std::string golden_mtl_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_mtl; + std::string golden_mtl_file_path = blender::tests::flags_test_asset_dir() + SEP_STR + + golden_mtl; std::string golden_mtl_str = read_temp_file_in_string(golden_mtl_file_path); are_equal = strings_equal_after_first_lines(output_mtl_str, golden_mtl_str); if (save_failing_test_output && !are_equal) { @@ -297,9 +298,9 @@ class obj_exporter_regression_test : public obj_exporter_test { TEST_F(obj_exporter_regression_test, all_tris) { OBJExportParamsDefault _export; - compare_obj_export_to_golden("io_tests/blend_geometry/all_tris.blend", - "io_tests/obj/all_tris.obj", - "io_tests/obj/all_tris.mtl", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "all_tris.blend", + "io_tests" SEP_STR "obj" SEP_STR "all_tris.obj", + "io_tests" SEP_STR "obj" SEP_STR "all_tris.mtl", _export.params); } @@ -308,8 +309,10 @@ TEST_F(obj_exporter_regression_test, all_quads) OBJExportParamsDefault _export; _export.params.global_scale = 2.0f; _export.params.export_materials = false; - compare_obj_export_to_golden( - "io_tests/blend_geometry/all_quads.blend", "io_tests/obj/all_quads.obj", "", _export.params); + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "all_quads.blend", + "io_tests" SEP_STR "obj" SEP_STR "all_quads.obj", + "", + _export.params); } TEST_F(obj_exporter_regression_test, fgons) @@ -318,8 +321,10 @@ TEST_F(obj_exporter_regression_test, fgons) _export.params.forward_axis = IO_AXIS_Y; _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; - compare_obj_export_to_golden( - "io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params); + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "fgons.blend", + "io_tests" SEP_STR "obj" SEP_STR "fgons.obj", + "", + _export.params); } TEST_F(obj_exporter_regression_test, edges) @@ -328,8 +333,10 @@ TEST_F(obj_exporter_regression_test, edges) _export.params.forward_axis = IO_AXIS_Y; _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; - compare_obj_export_to_golden( - "io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params); + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "edges.blend", + "io_tests" SEP_STR "obj" SEP_STR "edges.obj", + "", + _export.params); } TEST_F(obj_exporter_regression_test, vertices) @@ -338,16 +345,19 @@ TEST_F(obj_exporter_regression_test, vertices) _export.params.forward_axis = IO_AXIS_Y; _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; - compare_obj_export_to_golden( - "io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params); + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "vertices.blend", + "io_tests" SEP_STR "obj" SEP_STR "vertices.obj", + "", + _export.params); } TEST_F(obj_exporter_regression_test, non_uniform_scale) { OBJExportParamsDefault _export; _export.params.export_materials = false; - compare_obj_export_to_golden("io_tests/blend_geometry/non_uniform_scale.blend", - "io_tests/obj/non_uniform_scale.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "non_uniform_scale.blend", + "io_tests" SEP_STR "obj" SEP_STR "non_uniform_scale.obj", "", _export.params); } @@ -359,8 +369,10 @@ TEST_F(obj_exporter_regression_test, nurbs_as_nurbs) _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = true; - compare_obj_export_to_golden( - "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs.obj", "", _export.params); + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "nurbs.blend", + "io_tests" SEP_STR "obj" SEP_STR "nurbs.obj", + "", + _export.params); } TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs) @@ -370,8 +382,8 @@ TEST_F(obj_exporter_regression_test, nurbs_curves_as_nurbs) _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = true; - compare_obj_export_to_golden("io_tests/blend_geometry/nurbs_curves.blend", - "io_tests/obj/nurbs_curves.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "nurbs_curves.blend", + "io_tests" SEP_STR "obj" SEP_STR "nurbs_curves.obj", "", _export.params); } @@ -383,8 +395,10 @@ TEST_F(obj_exporter_regression_test, nurbs_as_mesh) _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = false; - compare_obj_export_to_golden( - "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs_mesh.obj", "", _export.params); + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "nurbs.blend", + "io_tests" SEP_STR "obj" SEP_STR "nurbs_mesh.obj", + "", + _export.params); } TEST_F(obj_exporter_regression_test, cube_all_data_triangulated) @@ -394,8 +408,8 @@ TEST_F(obj_exporter_regression_test, cube_all_data_triangulated) _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_triangulated_mesh = true; - compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend", - "io_tests/obj/cube_all_data_triangulated.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "cube_all_data.blend", + "io_tests" SEP_STR "obj" SEP_STR "cube_all_data_triangulated.obj", "", _export.params); } @@ -406,8 +420,9 @@ TEST_F(obj_exporter_regression_test, cube_normal_edit) _export.params.forward_axis = IO_AXIS_Y; _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; - compare_obj_export_to_golden("io_tests/blend_geometry/cube_normal_edit.blend", - "io_tests/obj/cube_normal_edit.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "cube_normal_edit.blend", + "io_tests" SEP_STR "obj" SEP_STR "cube_normal_edit.obj", "", _export.params); } @@ -419,8 +434,9 @@ TEST_F(obj_exporter_regression_test, cube_vertex_groups) _export.params.export_normals = false; _export.params.export_uv = false; _export.params.export_vertex_groups = true; - compare_obj_export_to_golden("io_tests/blend_geometry/cube_vertex_groups.blend", - "io_tests/obj/cube_vertex_groups.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "cube_vertex_groups.blend", + "io_tests" SEP_STR "obj" SEP_STR "cube_vertex_groups.obj", "", _export.params); } @@ -430,8 +446,9 @@ TEST_F(obj_exporter_regression_test, cubes_positioned) OBJExportParamsDefault _export; _export.params.export_materials = false; _export.params.global_scale = 2.0f; - compare_obj_export_to_golden("io_tests/blend_geometry/cubes_positioned.blend", - "io_tests/obj/cubes_positioned.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "cubes_positioned.blend", + "io_tests" SEP_STR "obj" SEP_STR "cubes_positioned.obj", "", _export.params); } @@ -443,8 +460,9 @@ TEST_F(obj_exporter_regression_test, cubes_vertex_colors) _export.params.export_normals = false; _export.params.export_uv = false; _export.params.export_materials = false; - compare_obj_export_to_golden("io_tests/blend_geometry/cubes_vertex_colors.blend", - "io_tests/obj/cubes_vertex_colors.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "cubes_vertex_colors.blend", + "io_tests" SEP_STR "obj" SEP_STR "cubes_vertex_colors.obj", "", _export.params); } @@ -453,9 +471,10 @@ TEST_F(obj_exporter_regression_test, cubes_with_textures_strip) { OBJExportParamsDefault _export; _export.params.path_mode = PATH_REFERENCE_STRIP; - compare_obj_export_to_golden("io_tests/blend_geometry/cubes_with_textures.blend", - "io_tests/obj/cubes_with_textures.obj", - "io_tests/obj/cubes_with_textures.mtl", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "cubes_with_textures.blend", + "io_tests" SEP_STR "obj" SEP_STR "cubes_with_textures.obj", + "io_tests" SEP_STR "obj" SEP_STR "cubes_with_textures.mtl", _export.params); } @@ -463,9 +482,10 @@ TEST_F(obj_exporter_regression_test, cubes_with_textures_relative) { OBJExportParamsDefault _export; _export.params.path_mode = PATH_REFERENCE_RELATIVE; - compare_obj_export_to_golden("io_tests/blend_geometry/cubes_with_textures.blend", - "io_tests/obj/cubes_with_textures_rel.obj", - "io_tests/obj/cubes_with_textures_rel.mtl", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "cubes_with_textures.blend", + "io_tests" SEP_STR "obj" SEP_STR "cubes_with_textures_rel.obj", + "io_tests" SEP_STR "obj" SEP_STR "cubes_with_textures_rel.mtl", _export.params); } @@ -476,8 +496,9 @@ TEST_F(obj_exporter_regression_test, suzanne_all_data) _export.params.up_axis = IO_AXIS_Z; _export.params.export_materials = false; _export.params.export_smooth_groups = true; - compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend", - "io_tests/obj/suzanne_all_data.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR + "suzanne_all_data.blend", + "io_tests" SEP_STR "obj" SEP_STR "suzanne_all_data.obj", "", _export.params); } @@ -486,8 +507,10 @@ TEST_F(obj_exporter_regression_test, all_curves) { OBJExportParamsDefault _export; _export.params.export_materials = false; - compare_obj_export_to_golden( - "io_tests/blend_scene/all_curves.blend", "io_tests/obj/all_curves.obj", "", _export.params); + compare_obj_export_to_golden("io_tests" SEP_STR "blend_scene" SEP_STR "all_curves.blend", + "io_tests" SEP_STR "obj" SEP_STR "all_curves.obj", + "", + _export.params); } TEST_F(obj_exporter_regression_test, all_curves_as_nurbs) @@ -495,8 +518,8 @@ TEST_F(obj_exporter_regression_test, all_curves_as_nurbs) OBJExportParamsDefault _export; _export.params.export_materials = false; _export.params.export_curves_as_nurbs = true; - compare_obj_export_to_golden("io_tests/blend_scene/all_curves.blend", - "io_tests/obj/all_curves_as_nurbs.obj", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_scene" SEP_STR "all_curves.blend", + "io_tests" SEP_STR "obj" SEP_STR "all_curves_as_nurbs.obj", "", _export.params); } @@ -508,9 +531,9 @@ TEST_F(obj_exporter_regression_test, all_objects) _export.params.up_axis = IO_AXIS_Z; _export.params.export_smooth_groups = true; _export.params.export_colors = true; - compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend", - "io_tests/obj/all_objects.obj", - "io_tests/obj/all_objects.mtl", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_scene" SEP_STR "all_objects.blend", + "io_tests" SEP_STR "obj" SEP_STR "all_objects.obj", + "io_tests" SEP_STR "obj" SEP_STR "all_objects.mtl", _export.params); } @@ -521,9 +544,9 @@ TEST_F(obj_exporter_regression_test, all_objects_mat_groups) _export.params.up_axis = IO_AXIS_Z; _export.params.export_smooth_groups = true; _export.params.export_material_groups = true; - compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend", - "io_tests/obj/all_objects_mat_groups.obj", - "io_tests/obj/all_objects_mat_groups.mtl", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_scene" SEP_STR "all_objects.blend", + "io_tests" SEP_STR "obj" SEP_STR "all_objects_mat_groups.obj", + "io_tests" SEP_STR "obj" SEP_STR "all_objects_mat_groups.mtl", _export.params); } @@ -532,9 +555,9 @@ TEST_F(obj_exporter_regression_test, materials_without_pbr) OBJExportParamsDefault _export; _export.params.export_normals = false; _export.params.path_mode = PATH_REFERENCE_RELATIVE; - compare_obj_export_to_golden("io_tests/blend_geometry/materials_pbr.blend", - "io_tests/obj/materials_without_pbr.obj", - "io_tests/obj/materials_without_pbr.mtl", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "materials_pbr.blend", + "io_tests" SEP_STR "obj" SEP_STR "materials_without_pbr.obj", + "io_tests" SEP_STR "obj" SEP_STR "materials_without_pbr.mtl", _export.params); } @@ -544,9 +567,9 @@ TEST_F(obj_exporter_regression_test, materials_pbr) _export.params.export_normals = false; _export.params.path_mode = PATH_REFERENCE_RELATIVE; _export.params.export_pbr_extensions = true; - compare_obj_export_to_golden("io_tests/blend_geometry/materials_pbr.blend", - "io_tests/obj/materials_pbr.obj", - "io_tests/obj/materials_pbr.mtl", + compare_obj_export_to_golden("io_tests" SEP_STR "blend_geometry" SEP_STR "materials_pbr.blend", + "io_tests" SEP_STR "obj" SEP_STR "materials_pbr.obj", + "io_tests" SEP_STR "obj" SEP_STR "materials_pbr.mtl", _export.params); } diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc index 62998a51d76..1fbafef84cb 100644 --- a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc +++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc @@ -9,7 +9,7 @@ #include "BKE_customdata.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_scene.h" diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 44e8ea517cf..bc1954c0206 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -1063,7 +1063,7 @@ typedef enum IDRecalcFlag { #define FILTER_ID_BR (1ULL << 2) #define FILTER_ID_CA (1ULL << 3) #define FILTER_ID_CU_LEGACY (1ULL << 4) -#define FILTER_ID_GD (1ULL << 5) +#define FILTER_ID_GD_LEGACY (1ULL << 5) #define FILTER_ID_GR (1ULL << 6) #define FILTER_ID_IM (1ULL << 7) #define FILTER_ID_LA (1ULL << 8) @@ -1100,12 +1100,12 @@ typedef enum IDRecalcFlag { #define FILTER_ID_ALL \ (FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU_LEGACY | \ - FILTER_ID_GD | FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | FILTER_ID_LT | \ - FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | FILTER_ID_NT | \ - FILTER_ID_OB | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | FILTER_ID_SPK | \ - FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | FILTER_ID_CF | \ - FILTER_ID_WS | FILTER_ID_LP | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO | FILTER_ID_SIM | \ - FILTER_ID_KE | FILTER_ID_SCR | FILTER_ID_WM | FILTER_ID_LI) + FILTER_ID_GD_LEGACY | FILTER_ID_GR | FILTER_ID_IM | FILTER_ID_LA | FILTER_ID_LS | \ + FILTER_ID_LT | FILTER_ID_MA | FILTER_ID_MB | FILTER_ID_MC | FILTER_ID_ME | FILTER_ID_MSK | \ + FILTER_ID_NT | FILTER_ID_OB | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_SCE | \ + FILTER_ID_SPK | FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | \ + FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO | \ + FILTER_ID_SIM | FILTER_ID_KE | FILTER_ID_SCR | FILTER_ID_WM | FILTER_ID_LI) /** * This enum defines the index assigned to each type of IDs in the array returned by @@ -1149,7 +1149,7 @@ enum { * other ID types, including node trees e.g. * So there is no proper place for those, for now keep close to the lower end of the processing * hierarchy, but we may want to re-evaluate that at some point. */ - INDEX_ID_GD, + INDEX_ID_GD_LEGACY, /* Node trees, abstraction for procedural data, potentially used by many other ID types. * diff --git a/source/blender/makesdna/DNA_ID_enums.h b/source/blender/makesdna/DNA_ID_enums.h index 94ab24511d8..d632c062a1a 100644 --- a/source/blender/makesdna/DNA_ID_enums.h +++ b/source/blender/makesdna/DNA_ID_enums.h @@ -68,7 +68,7 @@ typedef enum ID_Type { ID_NT = MAKE_ID2('N', 'T'), /* bNodeTree */ ID_BR = MAKE_ID2('B', 'R'), /* Brush */ ID_PA = MAKE_ID2('P', 'A'), /* ParticleSettings */ - ID_GD = MAKE_ID2('G', 'D'), /* bGPdata, (Grease Pencil) */ + ID_GD_LEGACY = MAKE_ID2('G', 'D'), /* bGPdata, (legacy Grease Pencil) */ ID_WM = MAKE_ID2('W', 'M'), /* WindowManager */ ID_MC = MAKE_ID2('M', 'C'), /* MovieClip */ ID_MSK = MAKE_ID2('M', 'S'), /* Mask */ diff --git a/source/blender/makesdna/DNA_asset_types.h b/source/blender/makesdna/DNA_asset_types.h index 5ab24b2db4a..0857d92cff7 100644 --- a/source/blender/makesdna/DNA_asset_types.h +++ b/source/blender/makesdna/DNA_asset_types.h @@ -72,6 +72,12 @@ typedef struct AssetMetaData { /** Optional description of this asset for display in the UI. Dynamic length. */ char *description; + /** Optional copyright of this asset for display in the UI. Dynamic length. */ + char *copyright; + + /** Optional license of this asset for display in the UI. Dynamic length. */ + char *license; + /** User defined tags for this asset. The asset manager uses these for filtering, but how they * function exactly (e.g. how they are registered to provide a list of searchable available tags) * is up to the asset-engine. */ @@ -134,6 +140,10 @@ typedef struct AssetLibraryReference { * Not part of the core design, we should try to get rid of it. Only needed to wrap FileDirEntry * into a type with PropertyGroup as base, so we can have an RNA collection of #AssetHandle's to * pass to the UI. + * + * \warning Never store this! When using #ED_assetlist_iterate(), only access it within the + * iterator function. The contained file data can be freed since the file cache has a + * maximum number of items. */ # # diff --git a/source/blender/makesdna/DNA_collection_types.h b/source/blender/makesdna/DNA_collection_types.h index 9d6fdbdb200..0ed992e84d7 100644 --- a/source/blender/makesdna/DNA_collection_types.h +++ b/source/blender/makesdna/DNA_collection_types.h @@ -128,6 +128,13 @@ enum { * Using a generic tag like #LIB_TAG_DOIT for this is just impossible, we need our very own. */ COLLECTION_TAG_RELATION_REBUILD = (1 << 0), + /** + * Mark the `gobject` list and/or its `runtime.gobject_hash` mapping as dirty, i.e. that their + * data is not reliable and should be cleaned-up or updated. + * + * This should typically only be set by ID remapping code. + */ + COLLECTION_TAG_COLLECTION_OBJECT_DIRTY = (1 << 1), }; /** #Collection.color_tag */ diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_legacy_types.h similarity index 99% rename from source/blender/makesdna/DNA_gpencil_types.h rename to source/blender/makesdna/DNA_gpencil_legacy_types.h index 8b3f4956cfe..0243e7720a9 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_legacy_types.h @@ -505,7 +505,7 @@ typedef struct bGPDlayer { struct Object *parent; /** Inverse matrix (only used if parented). */ float inverse[4][4]; - /** String describing subobject info, MAX_ID_NAME-2. */ + /** String describing sub-object info, `MAX_ID_NAME - 2`. */ char parsubstr[64]; short partype; @@ -574,7 +574,7 @@ typedef enum eGPDlayer_Flag { GP_LAYER_SELECT = (1 << 5), /* current frame for layer can't be changed */ GP_LAYER_FRAMELOCK = (1 << 6), - /* don't render xray (which is default) */ + /* Don't render X-ray (which is default). */ GP_LAYER_NO_XRAY = (1 << 7), /* "volumetric" strokes */ GP_LAYER_VOLUMETRIC = (1 << 10), @@ -852,7 +852,7 @@ typedef enum eGP_OnionModes { GP_ONION_MODE_SELECTED = 2, } eGP_OnionModes; -/* xray modes (Depth Ordering) */ +/* X-ray modes (Depth Ordering). */ typedef enum eGP_DepthOrdering { GP_XRAY_FRONT = 0, GP_XRAY_3DSPACE = 1, diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index d9c034c132d..87c21447fa4 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -16,6 +16,7 @@ /** Workaround to forward-declare C++ type in C header. */ #ifdef __cplusplus +# include "BLI_bounds_types.hh" # include "BLI_math_vector_types.hh" namespace blender { @@ -261,6 +262,9 @@ typedef struct Mesh { */ blender::Span looptris() const; + /** Set cached mesh bounds to a known-correct value to avoid their lazy calculation later on. */ + void bounds_set_eager(const blender::Bounds &bounds); + /** * Cached information about loose edges, calculated lazily when necessary. */ @@ -275,13 +279,12 @@ typedef struct Mesh { void loose_edges_tag_none() const; /** - * Normal direction of every polygon, which is defined by the winding direction of its corners. + * Normal direction of polygons, defined by positions and the winding direction of face corners. */ blender::Span poly_normals() const; /** - * Normal direction for each vertex, which is defined as the weighted average of the normals - * from a vertices surrounding faces, or the normalized position of vertices connected to no - * faces. + * Normal direction of vertices, defined as the weighted average of face normals + * surrounding each vertex and the normalized position for loose vertices. */ blender::Span vert_normals() const; #endif diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 7bb2c3fbd54..e2bfef9629d 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -63,19 +63,20 @@ typedef struct MPoly { int totloop; /** Deprecated material index. Now stored in the "material_index" attribute, but kept for IO. */ short mat_nr_legacy; - char flag, _pad; + char flag_legacy, _pad; } MPoly; /** #MPoly.flag */ -enum { - ME_SMOOTH = (1 << 0), #ifdef DNA_DEPRECATED_ALLOW +enum { + /** Deprecated smooth shading status. Now stored reversed in "sharp_face" attribute. */ + ME_SMOOTH = (1 << 0), /** Deprecated selection status. Now stored in ".select_poly" attribute. */ ME_FACE_SEL = (1 << 1), -#endif /** Deprecated hide status. Now stored in ".hide_poly" attribute. */ /* ME_HIDE = (1 << 4), */ }; +#endif /** * Mesh Face Corners. diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index e217ff3ad9c..ad84ab716c0 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -113,12 +113,7 @@ typedef struct Object_Runtime { /** Did last modifier stack generation need mapping support? */ char last_need_mapping; - /** Opaque data reserved for management of objects in collection context. - * E.g. used currently to check for potential duplicates of objects in a collection, after - * remapping process. */ - char collection_management; - - char _pad0[2]; + char _pad0[3]; /** Only used for drawing the parent/child help-line. */ float parent_display_origin[3]; @@ -514,7 +509,7 @@ enum { OB_ARMATURE = 25, /** Grease Pencil object used in 3D view but not used for annotation in 2D. */ - OB_GPENCIL = 26, + OB_GPENCIL_LEGACY = 26, OB_CURVES = 27, @@ -528,7 +523,8 @@ enum { /* check if the object type supports materials */ #define OB_TYPE_SUPPORT_MATERIAL(_type) \ - (((_type) >= OB_MESH && (_type) <= OB_MBALL) || ((_type) >= OB_GPENCIL && (_type) <= OB_VOLUME)) + (((_type) >= OB_MESH && (_type) <= OB_MBALL) || \ + ((_type) >= OB_GPENCIL_LEGACY && (_type) <= OB_VOLUME)) /** Does the object have some render-able geometry (unlike empties, cameras, etc.). */ #define OB_TYPE_IS_GEOMETRY(_type) \ (ELEM(_type, \ @@ -536,11 +532,11 @@ enum { OB_SURF, \ OB_FONT, \ OB_MBALL, \ - OB_GPENCIL, \ + OB_GPENCIL_LEGACY, \ OB_CURVES, \ OB_POINTCLOUD, \ OB_VOLUME)) -#define OB_TYPE_SUPPORT_VGROUP(_type) (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL)) +#define OB_TYPE_SUPPORT_VGROUP(_type) (ELEM(_type, OB_MESH, OB_LATTICE, OB_GPENCIL_LEGACY)) #define OB_TYPE_SUPPORT_EDITMODE(_type) \ (ELEM(_type, \ OB_MESH, \ @@ -569,7 +565,7 @@ enum { ID_LP, \ ID_CA, \ ID_LT, \ - ID_GD, \ + ID_GD_LEGACY, \ ID_AR, \ ID_CV, \ ID_PT, \ @@ -584,7 +580,7 @@ enum { case ID_LP: \ case ID_CA: \ case ID_LT: \ - case ID_GD: \ + case ID_GD_LEGACY: \ case ID_AR: \ case ID_CV: \ case ID_PT: \ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index ca1d878110f..6fb38eae744 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2296,10 +2296,6 @@ typedef enum eSnapMode { SCE_SNAP_MODE_EDGE_PERPENDICULAR = (1 << 5), SCE_SNAP_MODE_FACE_NEAREST = (1 << 8), - SCE_SNAP_MODE_GEOM = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST | - SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT | - SCE_SNAP_MODE_FACE_NEAREST), - /** #ToolSettings.snap_node_mode */ SCE_SNAP_MODE_NODE_X = (1 << 0), SCE_SNAP_MODE_NODE_Y = (1 << 1), @@ -2314,6 +2310,10 @@ typedef enum eSnapMode { ENUM_OPERATORS(eSnapMode, SCE_SNAP_MODE_GRID) #endif +#define SCE_SNAP_MODE_GEOM \ + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE_RAYCAST | \ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_FACE_NEAREST) + /** #SequencerToolSettings.snap_mode */ #define SEQ_SNAP_TO_STRIPS (1 << 0) #define SEQ_SNAP_TO_CURRENT_FRAME (1 << 1) diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 9872e30f0a2..cc7360ae6a4 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -455,6 +455,10 @@ typedef struct ARegion { rcti drawrct; /** Size. */ short winx, winy; + /* This is a Y offset on the panel tabs that represents pixels, where zero represents no scroll - + * the first category always shows first at the top. */ + int category_scroll; + char _pad0[4]; /** Region is currently visible on screen. */ short visible; @@ -466,7 +470,7 @@ typedef struct ARegion { short flag; /** Current split size in unscaled pixels (if zero it uses regiontype). - * To convert to pixels use: `UI_DPI_FAC * region->sizex + 0.5f`. + * To convert to pixels use: `UI_SCALE_FAC * region->sizex + 0.5f`. * However to get the current region size, you should usually use winx/winy from above, not this! */ short sizex, sizey; diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index e64f3f1ab24..a601ed4ee25 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -580,7 +580,7 @@ enum { SEQ_USE_PROXY = (1 << 15), SEQ_IGNORE_CHANNEL_LOCK = (1 << 16), SEQ_AUTO_PLAYBACK_RATE = (1 << 17), - SEQ_FLAG_UNUSED_18 = (1 << 18), /* cleared */ + SEQ_SINGLE_FRAME_CONTENT = (1 << 18), SEQ_FLAG_UNUSED_19 = (1 << 19), /* cleared */ SEQ_FLAG_UNUSED_21 = (1 << 21), /* cleared */ diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 94fa1d8f287..2bdb3f09583 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -341,12 +341,12 @@ typedef enum eSpaceOutliner_Filter { SO_FILTER_ID_TYPE = (1 << 19), - SO_FILTER_NO_OB_GPENCIL = (1 << 20), + SO_FILTER_NO_OB_GPENCIL_LEGACY = (1 << 20), } eSpaceOutliner_Filter; #define SO_FILTER_OB_TYPE \ (SO_FILTER_NO_OB_MESH | SO_FILTER_NO_OB_ARMATURE | SO_FILTER_NO_OB_EMPTY | \ - SO_FILTER_NO_OB_LAMP | SO_FILTER_NO_OB_CAMERA | SO_FILTER_NO_OB_GPENCIL | \ + SO_FILTER_NO_OB_LAMP | SO_FILTER_NO_OB_CAMERA | SO_FILTER_NO_OB_GPENCIL_LEGACY | \ SO_FILTER_NO_OB_OTHERS) #define SO_FILTER_OB_STATE \ @@ -488,8 +488,6 @@ typedef enum eGraphEdit_Flag { /* SIPO_NODRAWCFRANUM = (1 << 3), DEPRECATED */ /* show timing in seconds instead of frames */ SIPO_DRAWTIME = (1 << 4), - /* only show keyframes for selected F-Curves */ - SIPO_SELCUVERTSONLY = (1 << 5), /* draw names of F-Curves beside the respective curves */ /* NOTE: currently not used */ /* SIPO_DRAWNAMES = (1 << 6), */ /* UNUSED */ @@ -501,8 +499,6 @@ typedef enum eGraphEdit_Flag { SIPO_SELVHANDLESONLY = (1 << 9), /* don't perform realtime updates */ SIPO_NOREALTIMEUPDATES = (1 << 11), - /* don't draw curves with AA ("beauty-draw") for performance */ - SIPO_BEAUTYDRAW_OFF = (1 << 12), /* draw grouped channels with colors set in group */ /* SIPO_NODRAWGCOLORS = (1 << 13), DEPRECATED */ /* normalize curves on display */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 16fc0989282..5b0e9c166df 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -15,6 +15,20 @@ extern "C" { #endif +/** + * Scaling factor for all UI elements, based on the "Resolution Scale" user preference and the + * DPI/OS Scale of each monitor. This is a read-only, run-time value calculated by + * `WM_window_set_dpi` at various times, including between the drawing of each window and so can + * vary between monitors. + */ +#define UI_SCALE_FAC ((void)0, U.scale_factor) + +/* Inverse of UI_SCALE_FAC ( 1 / UI_SCALE_FAC). */ +#define UI_INV_SCALE_FAC ((void)0, U.inv_scale_factor) + +/* 16 to copy ICON_DEFAULT_HEIGHT */ +#define UI_ICON_SIZE ((float)16 * U.scale_factor) + /* Themes; defines in `BIF_resource.h`. */ struct ColorBand; @@ -747,10 +761,10 @@ typedef struct UserDef { int ui_line_width; /** Runtime, full DPI divided by `pixelsize`. */ int dpi; - /** Runtime, multiplier to scale UI elements based on DPI (fractional). */ - float dpi_fac; - /** Runtime, `1.0 / dpi_fac` */ - float inv_dpi_fac; + /** Runtime multiplier to scale UI elements. Use macro UI_SCALE_FAC instead of this. */ + float scale_factor; + /** Runtime, `1.0 / scale_factor` */ + float inv_scale_factor; /** Runtime, calculated from line-width and point-size based on DPI (rounded to int). */ float pixelsize; /** Deprecated, for forward compatibility. */ @@ -1220,6 +1234,8 @@ typedef enum eAutokey_Flag { */ typedef enum eUserpref_Anim_Flags { USER_ANIM_SHOW_CHANNEL_GROUP_COLORS = (1 << 0), + USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS = (1 << 1), + USER_ANIM_HIGH_QUALITY_DRAWING = (1 << 2), } eUserpref_Anim_Flags; /** #UserDef.transopts */ diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index e6f48c2da46..50b3c6fc432 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -22,6 +22,7 @@ extern "C" { struct wmWindow; struct wmWindowManager; +struct wmEvent_ConsecutiveData; struct wmEvent; struct wmKeyConfig; struct wmKeyMap; @@ -280,6 +281,15 @@ typedef struct wmWindow { short grabcursor; /** Internal: tag this for extra mouse-move event, * makes cursors/buttons active on UI switching. */ + + /** Internal, lock pie creation from this event until released. */ + short pie_event_type_lock; + /** + * Exception to the above rule for nested pies, store last pie event for operators + * that spawn a new pie right after destruction of last pie. + */ + short pie_event_type_last; + char addmousemove; char tag_cursor_refresh; @@ -296,15 +306,12 @@ typedef struct wmWindow { */ char event_queue_check_drag_handled; - char _pad0[1]; - - /** Internal, lock pie creation from this event until released. */ - short pie_event_type_lock; - /** - * Exception to the above rule for nested pies, store last pie event for operators - * that spawn a new pie right after destruction of last pie. - */ - short pie_event_type_last; + /** The last event type (that passed #WM_event_consecutive_gesture_test check). */ + char event_queue_consecutive_gesture_type; + /** The cursor location when `event_queue_consecutive_gesture_type` was set. */ + int event_queue_consecutive_gesture_xy[2]; + /** See #WM_event_consecutive_data_get and related API. Freed when consecutive events end. */ + struct wmEvent_ConsecutiveData *event_queue_consecutive_gesture_data; /** * Storage for event system. @@ -323,7 +330,12 @@ typedef struct wmWindow { * left/right modifiers then release one. See note in #wm_event_add_ghostevent for details. */ struct wmEvent *eventstate; - /** Keep the last handled event in `event_queue` here (owned and must be freed). */ + /** + * Keep the last handled event in `event_queue` here (owned and must be freed). + * + * \warning This must only to be used for event queue logic. + * User interactions should use `eventstate` instead (if the event isn't passed to the function). + */ struct wmEvent *event_last_handled; /* Input Method Editor data - complex character input (especially for Asian character input) diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index e1386dbab79..3318603ffd3 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -90,6 +90,7 @@ DNA_STRUCT_RENAME_ELEM(MDefCell, totinfluence, influences_num) DNA_STRUCT_RENAME_ELEM(MEdge, bweight, bweight_legacy) DNA_STRUCT_RENAME_ELEM(MEdge, crease, crease_legacy) DNA_STRUCT_RENAME_ELEM(MEdge, flag, flag_legacy) +DNA_STRUCT_RENAME_ELEM(MPoly, flag, flag_legacy) DNA_STRUCT_RENAME_ELEM(MPoly, mat_nr, mat_nr_legacy) DNA_STRUCT_RENAME_ELEM(MVert, bweight, bweight_legacy) DNA_STRUCT_RENAME_ELEM(MVert, co, co_legacy) diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index 5e096cda20b..a9d7aa4eb83 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -64,6 +64,14 @@ void RNA_def_struct_register_funcs(StructRNA *srna, const char *reg, const char *unreg, const char *instance); +/** + * Return an allocated string for the RNA data-path: + * + * - Double quotes must be used for string access, e.g: `collection["%s"]`. + * - Strings containing arbitrary characters must be escaped using #BLI_str_escape. + * + * Paths must be compatible with #RNA_path_resolve & related functions. + */ void RNA_def_struct_path_func(StructRNA *srna, const char *path); /** * Only used in one case when we name the struct for the purpose of useful error messages. diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 78a23eaaa81..568eea48ec1 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -774,6 +774,24 @@ typedef struct ExtensionRNA { StructFreeFunc free; } ExtensionRNA; +/* Primitive types. */ + +typedef struct PrimitiveStringRNA { + const char *value; +} PrimitiveStringRNA; + +typedef struct PrimitiveIntRNA { + int value; +} PrimitiveIntRNA; + +typedef struct PrimitiveFloatRNA { + float value; +} PrimitiveFloatRNA; + +typedef struct PrimitiveBooleanRNA { + bool value; +} PrimitiveBooleanRNA; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 2988b7e2e35..98c2b2e53fd 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -140,6 +140,9 @@ if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang")) endif() if(CMAKE_C_COMPILER_ID MATCHES "Clang") string(APPEND GENSRC_CFLAGS " -Wno-missing-variable-declarations") +elseif(MSVC) + # Restore warn C4100 (unreferenced formal parameter) back to w4 + remove_cc_flag(/w34100) endif() if(GENSRC_CFLAGS) diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index a1e1448314d..b430bf2a931 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -40,7 +40,7 @@ const EnumPropertyItem rna_enum_id_type_items[] = { {ID_CU_LEGACY, "CURVE", ICON_CURVE_DATA, "Curve", ""}, {ID_CV, "CURVES", ICON_CURVES_DATA, "Curves", ""}, {ID_VF, "FONT", ICON_FONT_DATA, "Font", ""}, - {ID_GD, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""}, + {ID_GD_LEGACY, "GREASEPENCIL", ICON_GREASEPENCIL, "Grease Pencil", ""}, {ID_IM, "IMAGE", ICON_IMAGE_DATA, "Image", ""}, {ID_KE, "KEY", ICON_SHAPEKEY_DATA, "Key", ""}, {ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""}, @@ -128,7 +128,7 @@ const struct IDFilterEnumPropertyItem rna_enum_id_type_filter_items[] = { {FILTER_ID_CA, "filter_camera", ICON_CAMERA_DATA, "Cameras", "Show Camera data-blocks"}, {FILTER_ID_CF, "filter_cachefile", ICON_FILE, "Cache Files", "Show Cache File data-blocks"}, {FILTER_ID_CU_LEGACY, "filter_curve", ICON_CURVE_DATA, "Curves", "Show Curve data-blocks"}, - {FILTER_ID_GD, + {FILTER_ID_GD_LEGACY, "filter_grease_pencil", ICON_GREASEPENCIL, "Grease Pencil", @@ -361,7 +361,7 @@ short RNA_type_to_ID_code(const StructRNA *type) return ID_CU_LEGACY; } if (base_type == &RNA_GreasePencil) { - return ID_GD; + return ID_GD_LEGACY; } if (base_type == &RNA_Collection) { return ID_GR; @@ -482,7 +482,7 @@ StructRNA *ID_code_to_RNA_type(short idcode) return &RNA_CacheFile; case ID_CU_LEGACY: return &RNA_Curve; - case ID_GD: + case ID_GD_LEGACY: return &RNA_GreasePencil; case ID_GR: return &RNA_Collection; diff --git a/source/blender/makesrna/intern/rna_access.cc b/source/blender/makesrna/intern/rna_access.cc index 831a675f2bd..c1030d80196 100644 --- a/source/blender/makesrna/intern/rna_access.cc +++ b/source/blender/makesrna/intern/rna_access.cc @@ -2390,7 +2390,7 @@ void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bo } else if (idprop->subtype == IDP_INT) { /* Support writing to integer and boolean IDProperties, since boolean - RNA properties used to be stored with integer IDProperties. */ + * RNA properties used to be stored with integer IDProperties. */ int *values_dst = static_cast(IDP_Array(idprop)); for (uint i = 0; i < idprop->len; i++) { values_dst[i] = int(values[i]); diff --git a/source/blender/makesrna/intern/rna_asset.c b/source/blender/makesrna/intern/rna_asset.c index b95800fe934..b88322e7c25 100644 --- a/source/blender/makesrna/intern/rna_asset.c +++ b/source/blender/makesrna/intern/rna_asset.c @@ -64,7 +64,9 @@ int rna_AssetMetaData_editable(PointerRNA *ptr, const char **r_info) static char *rna_AssetTag_path(const PointerRNA *ptr) { const AssetTag *asset_tag = ptr->data; - return BLI_sprintfN("asset_data.tags['%s']", asset_tag->name); + char asset_tag_name_esc[sizeof(asset_tag->name) * 2]; + BLI_str_escape(asset_tag_name_esc, asset_tag->name, sizeof(asset_tag_name_esc)); + return BLI_sprintfN("asset_data.tags[\"%s\"]", asset_tag_name_esc); } static int rna_AssetTag_editable(PointerRNA *ptr, const char **r_info) @@ -205,6 +207,74 @@ static void rna_AssetMetaData_description_set(PointerRNA *ptr, const char *value } } +static void rna_AssetMetaData_copyright_get(PointerRNA *ptr, char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->copyright) { + strcpy(value, asset_data->copyright); + } + else { + value[0] = '\0'; + } +} + +static int rna_AssetMetaData_copyright_length(PointerRNA *ptr) +{ + AssetMetaData *asset_data = ptr->data; + return asset_data->copyright ? strlen(asset_data->copyright) : 0; +} + +static void rna_AssetMetaData_copyright_set(PointerRNA *ptr, const char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->copyright) { + MEM_freeN(asset_data->copyright); + } + + if (value[0]) { + asset_data->copyright = BLI_strdup(value); + } + else { + asset_data->copyright = NULL; + } +} + +static void rna_AssetMetaData_license_get(PointerRNA *ptr, char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->license) { + strcpy(value, asset_data->license); + } + else { + value[0] = '\0'; + } +} + +static int rna_AssetMetaData_license_length(PointerRNA *ptr) +{ + AssetMetaData *asset_data = ptr->data; + return asset_data->license ? strlen(asset_data->license) : 0; +} + +static void rna_AssetMetaData_license_set(PointerRNA *ptr, const char *value) +{ + AssetMetaData *asset_data = ptr->data; + + if (asset_data->license) { + MEM_freeN(asset_data->license); + } + + if (value[0]) { + asset_data->license = BLI_strdup(value); + } + else { + asset_data->license = NULL; + } +} + static void rna_AssetMetaData_active_tag_range( PointerRNA *ptr, int *min, int *max, int *softmin, int *softmax) { @@ -397,6 +467,30 @@ static void rna_def_asset_data(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Description", "A description of the asset to be displayed for the user"); + prop = RNA_def_property(srna, "copyright", PROP_STRING, PROP_NONE); + RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable"); + RNA_def_property_string_funcs(prop, + "rna_AssetMetaData_copyright_get", + "rna_AssetMetaData_copyright_length", + "rna_AssetMetaData_copyright_set"); + RNA_def_property_ui_text( + prop, + "Copyright", + "Copyright notice for this asset. An empty copyright notice does not necessarily indicate " + "that this is copyright-free. Contact the author if any clarification is needed"); + + prop = RNA_def_property(srna, "license", PROP_STRING, PROP_NONE); + RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable"); + RNA_def_property_string_funcs(prop, + "rna_AssetMetaData_license_get", + "rna_AssetMetaData_license_length", + "rna_AssetMetaData_license_set"); + RNA_def_property_ui_text(prop, + "License", + "The type of license this asset is distributed under. An empty license " + "name does not necessarily indicate that this is free of licensing " + "terms. Contact the author if any clarification is needed"); + prop = RNA_def_property(srna, "tags", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "AssetTag"); RNA_def_property_editable_func(prop, "rna_AssetMetaData_editable"); @@ -484,6 +578,17 @@ static void rna_def_asset_handle(BlenderRNA *brna) rna_def_asset_handle_api(srna); } +static void rna_def_asset_representation(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "AssetRepresentation", NULL); + RNA_def_struct_ui_text(srna, + "Asset Representation", + "Information about an entity that makes it possible for the asset system " + "to deal with the entity as asset"); +} + static void rna_def_asset_catalog_path(BlenderRNA *brna) { StructRNA *srna = RNA_def_struct(brna, "AssetCatalogPath", NULL); @@ -516,6 +621,7 @@ void RNA_def_asset(BlenderRNA *brna) rna_def_asset_data(brna); rna_def_asset_library_reference(brna); rna_def_asset_handle(brna); + rna_def_asset_representation(brna); rna_def_asset_catalog_path(brna); RNA_define_animate_sdna(true); diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index 13d3e08c462..3aedc92a248 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -136,7 +136,9 @@ const EnumPropertyItem rna_enum_attribute_curves_domain_items[] = { static char *rna_Attribute_path(const PointerRNA *ptr) { const CustomDataLayer *layer = ptr->data; - return BLI_sprintfN("attributes['%s']", layer->name); + char layer_name_esc[sizeof(layer->name) * 2]; + BLI_str_escape(layer_name_esc, layer->name, sizeof(layer_name_esc)); + return BLI_sprintfN("attributes[\"%s\"]", layer_name_esc); } static StructRNA *srna_by_custom_data_layer_type(const eCustomDataType type) diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 9a8ce819236..d145e7c9f5b 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -7,7 +7,7 @@ #include #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_material_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -376,7 +376,7 @@ static EnumPropertyItem rna_enum_gpencil_brush_vertex_icons_items[] = { # include "BKE_brush.h" # include "BKE_colorband.h" -# include "BKE_gpencil.h" +# include "BKE_gpencil_legacy.h" # include "BKE_icons.h" # include "BKE_material.h" # include "BKE_paint.h" @@ -2556,8 +2556,7 @@ static void rna_def_brush(BlenderRNA *brna) prop = RNA_def_property(srna, "curve_preset", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, brush_curve_preset_items); RNA_def_property_ui_text(prop, "Curve Preset", ""); - RNA_def_property_translation_context(prop, - BLT_I18NCONTEXT_ID_CURVES); /* Abusing id_curves :/ */ + RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVES); /* Abusing id_curves :/ */ RNA_def_property_update(prop, 0, "rna_Brush_update"); prop = RNA_def_property(srna, "deform_target", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index e2b218a86c5..02882f08e11 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -161,7 +161,7 @@ const EnumPropertyItem rna_enum_driver_target_rotation_mode_items[] = { {0, NULL, 0, NULL, NULL}, }; -const EnumPropertyItem rna_enum_driver_target_context_property_items[] = { +static const EnumPropertyItem rna_enum_driver_target_context_property_items[] = { {DTAR_CONTEXT_PROPERTY_ACTIVE_SCENE, "ACTIVE_SCENE", ICON_NONE, @@ -218,6 +218,51 @@ static StructRNA *rna_FModifierType_refine(struct PointerRNA *ptr) # include "DEG_depsgraph.h" # include "DEG_depsgraph_build.h" +/** + * \warning this isn't efficient but it's unavoidable + * when only the #ID and the #DriverVar are known. + */ +static FCurve *rna_FCurve_find_driver_by_variable(ID *owner_id, DriverVar *dvar) +{ + AnimData *adt = BKE_animdata_from_id(owner_id); + BLI_assert(adt != NULL); + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + ChannelDriver *driver = fcu->driver; + if (driver == NULL) { + continue; + } + if (BLI_findindex(&driver->variables, dvar) != -1) { + return fcu; + } + } + return NULL; +} + +/** + * \warning this isn't efficient but it's unavoidable + * when only the #ID and the #DriverTarget are known. + */ +static FCurve *rna_FCurve_find_driver_by_target(ID *owner_id, DriverTarget *dtar) +{ + AnimData *adt = BKE_animdata_from_id(owner_id); + BLI_assert(adt != NULL); + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + ChannelDriver *driver = fcu->driver; + if (driver == NULL) { + continue; + } + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + /* NOTE: Use #MAX_DRIVER_TARGETS instead of `dvar->num_targets` because + * it's possible RNA holds a reference to a target that has been removed. + * In this case it's best to return the #FCurve it belongs to instead of nothing. */ + if (ARRAY_HAS_ITEM(dtar, &dvar->targets[0], MAX_DRIVER_TARGETS)) { + return fcu; + } + } + } + return NULL; +} + static bool rna_ChannelDriver_is_simple_expression_get(PointerRNA *ptr) { ChannelDriver *driver = ptr->data; @@ -225,20 +270,27 @@ static bool rna_ChannelDriver_is_simple_expression_get(PointerRNA *ptr) return BKE_driver_has_simple_expression(driver); } -static void rna_ChannelDriver_update_data(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_ChannelDriver_update_data_impl(Main *bmain, + Scene *scene, + ID *owner_id, + ChannelDriver *driver) { - ID *id = ptr->owner_id; - ChannelDriver *driver = ptr->data; - driver->flag &= ~DRIVER_FLAG_INVALID; /* TODO: this really needs an update guard... */ DEG_relations_tag_update(bmain); - DEG_id_tag_update(id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + DEG_id_tag_update(owner_id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_SCENE | ND_FRAME, scene); } +static void rna_ChannelDriver_update_data(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + ID *id = ptr->owner_id; + ChannelDriver *driver = ptr->data; + rna_ChannelDriver_update_data_impl(bmain, scene, id, driver); +} + static void rna_ChannelDriver_update_expr(Main *bmain, Scene *scene, PointerRNA *ptr) { ChannelDriver *driver = ptr->data; @@ -252,33 +304,47 @@ static void rna_ChannelDriver_update_expr(Main *bmain, Scene *scene, PointerRNA static void rna_DriverTarget_update_data(Main *bmain, Scene *scene, PointerRNA *ptr) { - PointerRNA driverptr; - ChannelDriver *driver; - FCurve *fcu; - AnimData *adt = BKE_animdata_from_id(ptr->owner_id); - - /* find the driver this belongs to and update it */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - driver = fcu->driver; - fcu->flag &= ~FCURVE_DISABLED; - - if (driver) { - /* FIXME: need to be able to search targets for required one. */ - // BLI_findindex(&driver->targets, ptr->data) != -1) - RNA_pointer_create(ptr->owner_id, &RNA_Driver, driver, &driverptr); - rna_ChannelDriver_update_data(bmain, scene, &driverptr); - } + DriverTarget *dtar = (DriverTarget *)ptr->data; + FCurve *fcu = rna_FCurve_find_driver_by_target(ptr->owner_id, dtar); + BLI_assert(fcu); /* This hints at an internal error, data may be corrupt. */ + if (UNLIKELY(fcu == NULL)) { + return; } + /* Find function ensures it's never NULL. */ + ChannelDriver *driver = fcu->driver; + fcu->flag &= ~FCURVE_DISABLED; + rna_ChannelDriver_update_data_impl(bmain, scene, ptr->owner_id, driver); } -static void rna_DriverTarget_update_name(Main *bmain, Scene *scene, PointerRNA *ptr) +static void rna_DriverVariable_update_name(Main *bmain, Scene *scene, PointerRNA *ptr) { - ChannelDriver *driver = ptr->data; - rna_DriverTarget_update_data(bmain, scene, ptr); - + DriverVar *dvar = (DriverVar *)ptr->data; + FCurve *fcu = rna_FCurve_find_driver_by_variable(ptr->owner_id, dvar); + BLI_assert(fcu); /* This hints at an internal error, data may be corrupt. */ + if (UNLIKELY(fcu == NULL)) { + return; + } + /* Find function ensures it's never NULL. */ + ChannelDriver *driver = fcu->driver; + fcu->flag &= ~FCURVE_DISABLED; + rna_ChannelDriver_update_data_impl(bmain, scene, ptr->owner_id, driver); BKE_driver_invalidate_expression(driver, false, true); } +static void rna_DriverVariable_update_data(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + DriverVar *dvar = (DriverVar *)ptr->data; + FCurve *fcu = rna_FCurve_find_driver_by_variable(ptr->owner_id, dvar); + BLI_assert(fcu); /* This hints at an internal error, data may be corrupt. */ + if (UNLIKELY(fcu == NULL)) { + return; + } + /* Find function ensures it's never NULL. */ + ChannelDriver *driver = fcu->driver; + fcu->flag &= ~FCURVE_DISABLED; + rna_ChannelDriver_update_data_impl(bmain, scene, ptr->owner_id, driver); +} + /* ----------- */ /* NOTE: this function exists only to avoid id reference-counting. */ @@ -600,7 +666,7 @@ static void rna_FCurve_group_set(PointerRNA *ptr, /* calculate time extents of F-Curve */ static void rna_FCurve_range(FCurve *fcu, float range[2]) { - BKE_fcurve_calc_range(fcu, range, range + 1, false, false); + BKE_fcurve_calc_range(fcu, range, range + 1, false); } static bool rna_FCurve_is_empty_get(PointerRNA *ptr) @@ -1951,14 +2017,14 @@ static void rna_def_drivervar(BlenderRNA *brna) "Name", "Name to use in scripted expressions/functions (no spaces or dots are allowed, " "and must start with a letter)"); - RNA_def_property_update(prop, 0, "rna_DriverTarget_update_name"); /* XXX */ + RNA_def_property_update(prop, 0, "rna_DriverVariable_update_name"); /* Enums */ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_items(prop, prop_type_items); RNA_def_property_enum_funcs(prop, NULL, "rna_DriverVariable_type_set", NULL); RNA_def_property_ui_text(prop, "Type", "Driver variable type"); - RNA_def_property_update(prop, 0, "rna_ChannelDriver_update_data"); /* XXX */ + RNA_def_property_update(prop, 0, "rna_DriverVariable_update_data"); /* Targets */ /* TODO: for nicer api, only expose the relevant props via subclassing, diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c index abb709473e1..c3c77bc07b9 100644 --- a/source/blender/makesrna/intern/rna_gpencil.c +++ b/source/blender/makesrna/intern/rna_gpencil.c @@ -10,7 +10,7 @@ #include "DNA_brush_types.h" #include "DNA_curve_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_meshdata_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" @@ -155,10 +155,10 @@ static const EnumPropertyItem rna_enum_gpencil_caps_modes_items[] = { # include "BKE_action.h" # include "BKE_animsys.h" # include "BKE_deform.h" -# include "BKE_gpencil.h" -# include "BKE_gpencil_curve.h" -# include "BKE_gpencil_geom.h" -# include "BKE_gpencil_update_cache.h" +# include "BKE_gpencil_curve_legacy.h" +# include "BKE_gpencil_geom_legacy.h" +# include "BKE_gpencil_legacy.h" +# include "BKE_gpencil_update_cache_legacy.h" # include "BKE_icons.h" # include "DEG_depsgraph.h" @@ -481,7 +481,7 @@ static PointerRNA rna_GPencil_active_layer_get(PointerRNA *ptr) { bGPdata *gpd = (bGPdata *)ptr->owner_id; - if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */ + if (GS(gpd->id.name) == ID_GD_LEGACY) { /* why would this ever be not GD */ bGPDlayer *gl; for (gl = gpd->layers.first; gl; gl = gl->next) { @@ -513,7 +513,7 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, return; } - if (GS(gpd->id.name) == ID_GD) { /* why would this ever be not GD */ + if (GS(gpd->id.name) == ID_GD_LEGACY) { /* why would this ever be not GD */ bGPDlayer *gl; for (gl = gpd->layers.first; gl; gl = gl->next) { diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 40dbc2ebbd4..09d8dee5d14 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -9,8 +9,8 @@ #include #include "DNA_armature_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_gpencil_modifier_types.h" -#include "DNA_gpencil_types.h" #include "DNA_modifier_types.h" #include "DNA_object_force_types.h" #include "DNA_object_types.h" @@ -276,8 +276,8 @@ static const EnumPropertyItem modifier_noise_random_mode_items[] = { # include "BKE_cachefile.h" # include "BKE_context.h" -# include "BKE_gpencil.h" -# include "BKE_gpencil_modifier.h" +# include "BKE_gpencil_legacy.h" +# include "BKE_gpencil_modifier_legacy.h" # include "BKE_object.h" # include "DEG_depsgraph.h" @@ -2548,7 +2548,7 @@ static void rna_def_modifier_gpencilbuild(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Time Alignment", "How should strokes start to appear/disappear"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); - /* Which time mode to use: Current frames, manual percentage, or drawspeed. */ + /* Which time mode to use: Current frames, manual percentage, or drawspeed. */ prop = RNA_def_property(srna, "time_mode", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "time_mode"); RNA_def_property_enum_items(prop, gpencil_build_time_mode_items); diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index c8736b57863..98dd15e48aa 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -654,11 +654,16 @@ static void rna_Image_pixels_set(PointerRNA *ptr, const float *values) } } + /* NOTE: Do update from the set() because typically pixels.foreach_set() is used to update + * the values, and it does not invoke the update(). */ + ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID | IB_MIPMAP_INVALID; BKE_image_mark_dirty(ima, ibuf); if (!G.background) { BKE_image_free_gputextures(ima); } + + BKE_image_partial_update_mark_full_update(ima); WM_main_add_notifier(NC_IMAGE | ND_DISPLAY, &ima->id); } diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 35678f2f1dd..3a9c1e222f5 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -32,7 +32,7 @@ # include "BKE_curve.h" # include "BKE_curves.h" # include "BKE_displist.h" -# include "BKE_gpencil.h" +# include "BKE_gpencil_legacy.h" # include "BKE_icons.h" # include "BKE_idtype.h" # include "BKE_image.h" @@ -71,7 +71,7 @@ # include "DNA_collection_types.h" # include "DNA_curve_types.h" # include "DNA_curves_types.h" -# include "DNA_gpencil_types.h" +# include "DNA_gpencil_legacy_types.h" # include "DNA_lattice_types.h" # include "DNA_light_types.h" # include "DNA_lightprobe_types.h" @@ -839,7 +839,7 @@ RNA_MAIN_ID_TAG_FUNCS_DEF(armatures, armatures, ID_AR) RNA_MAIN_ID_TAG_FUNCS_DEF(actions, actions, ID_AC) RNA_MAIN_ID_TAG_FUNCS_DEF(particles, particles, ID_PA) RNA_MAIN_ID_TAG_FUNCS_DEF(palettes, palettes, ID_PAL) -RNA_MAIN_ID_TAG_FUNCS_DEF(gpencils, gpencils, ID_GD) +RNA_MAIN_ID_TAG_FUNCS_DEF(gpencils, gpencils, ID_GD_LEGACY) RNA_MAIN_ID_TAG_FUNCS_DEF(movieclips, movieclips, ID_MC) RNA_MAIN_ID_TAG_FUNCS_DEF(masks, masks, ID_MSK) RNA_MAIN_ID_TAG_FUNCS_DEF(linestyle, linestyles, ID_LS) diff --git a/source/blender/makesrna/intern/rna_mask.c b/source/blender/makesrna/intern/rna_mask.c index 5b53c3c8498..8de81b9cc89 100644 --- a/source/blender/makesrna/intern/rna_mask.c +++ b/source/blender/makesrna/intern/rna_mask.c @@ -826,7 +826,7 @@ static void rna_def_mask_splines(BlenderRNA *brna) NULL, NULL); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK); - RNA_def_property_ui_text(prop, "Active Spline", "Active spline of masking layer"); + RNA_def_property_ui_text(prop, "Active Point", "Active point of masking layer"); } static void rna_def_maskSplinePoints(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c index d1b601e6f96..2b0c2a269dd 100644 --- a/source/blender/makesrna/intern/rna_material.c +++ b/source/blender/makesrna/intern/rna_material.c @@ -57,7 +57,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = { # include "MEM_guardedalloc.h" -# include "DNA_gpencil_types.h" +# include "DNA_gpencil_legacy_types.h" # include "DNA_node_types.h" # include "DNA_object_types.h" # include "DNA_screen_types.h" @@ -65,7 +65,7 @@ const EnumPropertyItem rna_enum_ramp_blend_items[] = { # include "BKE_colorband.h" # include "BKE_context.h" -# include "BKE_gpencil.h" +# include "BKE_gpencil_legacy.h" # include "BKE_main.h" # include "BKE_material.h" # include "BKE_node.h" @@ -110,7 +110,7 @@ static void rna_MaterialGpencil_update(Main *bmain, Scene *scene, PointerRNA *pt /* Need set all caches as dirty. */ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = (bGPdata *)ob->data; DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); } diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 79ec8ac73d3..37c02367f05 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -477,7 +477,7 @@ static void rna_MeshVertex_hide_set(PointerRNA *ptr, bool value) return; } hide_vert = (bool *)CustomData_add_layer_named( - &mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totvert, ".hide_vert"); + &mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totvert, ".hide_vert"); } const int index = rna_MeshVertex_index_get(ptr); hide_vert[index] = value; @@ -503,7 +503,7 @@ static void rna_MeshVertex_select_set(PointerRNA *ptr, bool value) return; } select_vert = (bool *)CustomData_add_layer_named( - &mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totvert, ".select_vert"); + &mesh->vdata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totvert, ".select_vert"); } const int index = rna_MeshVertex_index_get(ptr); select_vert[index] = value; @@ -522,7 +522,7 @@ static void rna_MeshVertex_bevel_weight_set(PointerRNA *ptr, float value) Mesh *mesh = rna_mesh(ptr); const int index = rna_MeshVertex_index_get(ptr); float *values = (float *)CustomData_add_layer( - &mesh->vdata, CD_BWEIGHT, CD_SET_DEFAULT, NULL, mesh->totvert); + &mesh->vdata, CD_BWEIGHT, CD_SET_DEFAULT, mesh->totvert); values[index] = clamp_f(value, 0.0f, 1.0f); } @@ -539,7 +539,7 @@ static void rna_MEdge_bevel_weight_set(PointerRNA *ptr, float value) Mesh *mesh = rna_mesh(ptr); const int index = rna_MeshEdge_index_get(ptr); float *values = (float *)CustomData_add_layer( - &mesh->edata, CD_BWEIGHT, CD_SET_DEFAULT, NULL, mesh->totedge); + &mesh->edata, CD_BWEIGHT, CD_SET_DEFAULT, mesh->totedge); values[index] = clamp_f(value, 0.0f, 1.0f); } @@ -556,7 +556,7 @@ static void rna_MEdge_crease_set(PointerRNA *ptr, float value) Mesh *mesh = rna_mesh(ptr); const int index = rna_MeshEdge_index_get(ptr); float *values = (float *)CustomData_add_layer( - &mesh->edata, CD_CREASE, CD_SET_DEFAULT, NULL, mesh->totedge); + &mesh->edata, CD_CREASE, CD_SET_DEFAULT, mesh->totedge); values[index] = clamp_f(value, 0.0f, 1.0f); } @@ -630,7 +630,8 @@ static void rna_MeshPolygon_normal_get(PointerRNA *ptr, float *values) MPoly *poly = (MPoly *)ptr->data; const float(*positions)[3] = BKE_mesh_vert_positions(me); const MLoop *loops = BKE_mesh_loops(me); - BKE_mesh_calc_poly_normal(poly, loops + poly->loopstart, positions, values); + BKE_mesh_calc_poly_normal( + &loops[poly->loopstart], poly->totloop, positions, me->totvert, values); } static bool rna_MeshPolygon_hide_get(PointerRNA *ptr) @@ -653,12 +654,38 @@ static void rna_MeshPolygon_hide_set(PointerRNA *ptr, bool value) return; } hide_poly = (bool *)CustomData_add_layer_named( - &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totpoly, ".hide_poly"); + &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totpoly, ".hide_poly"); } const int index = rna_MeshPolygon_index_get(ptr); hide_poly[index] = value; } +static bool rna_MeshPolygon_use_smooth_get(PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, "sharp_face"); + const int index = rna_MeshPolygon_index_get(ptr); + return !(sharp_faces && sharp_faces[index]); +} + +static void rna_MeshPolygon_use_smooth_set(PointerRNA *ptr, bool value) +{ + Mesh *mesh = rna_mesh(ptr); + bool *sharp_faces = (bool *)CustomData_get_layer_named_for_write( + &mesh->pdata, CD_PROP_BOOL, "sharp_face", mesh->totpoly); + if (!sharp_faces) { + if (!value) { + /* Skip adding layer if the value is the same as the default. */ + return; + } + sharp_faces = (bool *)CustomData_add_layer_named( + &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totpoly, "sharp_face"); + } + const int index = rna_MeshPolygon_index_get(ptr); + sharp_faces[index] = !value; +} + static bool rna_MeshPolygon_select_get(PointerRNA *ptr) { const Mesh *mesh = rna_mesh(ptr); @@ -679,7 +706,7 @@ static void rna_MeshPolygon_select_set(PointerRNA *ptr, bool value) return; } select_poly = (bool *)CustomData_add_layer_named( - &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totpoly, ".select_poly"); + &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totpoly, ".select_poly"); } const int index = rna_MeshPolygon_index_get(ptr); select_poly[index] = value; @@ -707,7 +734,8 @@ static void rna_MeshPolygon_center_get(PointerRNA *ptr, float *values) MPoly *poly = (MPoly *)ptr->data; const float(*positions)[3] = BKE_mesh_vert_positions(me); const MLoop *loops = BKE_mesh_loops(me); - BKE_mesh_calc_poly_center(poly, loops + poly->loopstart, positions, values); + BKE_mesh_calc_poly_center( + &loops[poly->loopstart], poly->totloop, positions, me->totvert, values); } static float rna_MeshPolygon_area_get(PointerRNA *ptr) @@ -716,7 +744,7 @@ static float rna_MeshPolygon_area_get(PointerRNA *ptr) MPoly *poly = (MPoly *)ptr->data; const float(*positions)[3] = BKE_mesh_vert_positions(me); const MLoop *loops = BKE_mesh_loops(me); - return BKE_mesh_calc_poly_area(poly, loops + poly->loopstart, positions); + return BKE_mesh_calc_poly_area(&loops[poly->loopstart], poly->totloop, positions, me->totvert); } static void rna_MeshPolygon_flip(ID *id, MPoly *poly) @@ -926,7 +954,7 @@ static void rna_MEdge_freestyle_edge_mark_set(PointerRNA *ptr, bool value) FreestyleEdge *fed = CustomData_get_layer_for_write(&me->edata, CD_FREESTYLE_EDGE, me->totedge); if (!fed) { - fed = CustomData_add_layer(&me->edata, CD_FREESTYLE_EDGE, CD_SET_DEFAULT, NULL, me->totedge); + fed = CustomData_add_layer(&me->edata, CD_FREESTYLE_EDGE, CD_SET_DEFAULT, me->totedge); } if (value) { fed[index].flag |= FREESTYLE_EDGE_MARK; @@ -952,7 +980,7 @@ static void rna_MPoly_freestyle_face_mark_set(PointerRNA *ptr, bool value) FreestyleFace *ffa = CustomData_get_layer_for_write(&me->pdata, CD_FREESTYLE_FACE, me->totpoly); if (!ffa) { - ffa = CustomData_add_layer(&me->pdata, CD_FREESTYLE_FACE, CD_SET_DEFAULT, NULL, me->totpoly); + ffa = CustomData_add_layer(&me->pdata, CD_FREESTYLE_FACE, CD_SET_DEFAULT, me->totpoly); } if (value) { ffa[index].flag |= FREESTYLE_FACE_MARK; @@ -1004,7 +1032,7 @@ static MBoolProperty *MeshUVLoopLayer_get_bool_layer(Mesh *mesh, char const *nam &mesh->ldata, CD_PROP_BOOL, name, mesh->totloop); if (layer == NULL) { layer = CustomData_add_layer_named( - &mesh->ldata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totloop, name); + &mesh->ldata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totloop, name); } BLI_assert(layer); @@ -1147,14 +1175,8 @@ DEFINE_CUSTOMDATA_LAYER_COLLECTION(vertex_color, ldata, CD_PROP_BYTE_COLOR) static PointerRNA rna_Mesh_vertex_color_active_get(PointerRNA *ptr) { Mesh *mesh = (Mesh *)ptr->data; - - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&mesh->id); - - if (!layer || layer->type != CD_PROP_BYTE_COLOR || - BKE_id_attribute_domain(&mesh->id, layer) != ATTR_DOMAIN_CORNER) { - return PointerRNA_NULL; - } - + CustomDataLayer *layer = BKE_id_attribute_search( + &mesh->id, mesh->active_color_attribute, CD_MASK_PROP_BYTE_COLOR, ATTR_DOMAIN_MASK_CORNER); return rna_pointer_inherit_refine(ptr, &RNA_MeshLoopColorLayer, layer); } @@ -1175,14 +1197,11 @@ static void rna_Mesh_vertex_color_active_set(PointerRNA *ptr, static int rna_Mesh_vertex_color_active_index_get(PointerRNA *ptr) { Mesh *mesh = (Mesh *)ptr->data; - - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&mesh->id); - - if (!layer || layer->type != CD_PROP_BYTE_COLOR || - BKE_id_attribute_domain(&mesh->id, layer) != ATTR_DOMAIN_CORNER) { + CustomDataLayer *layer = BKE_id_attribute_search( + &mesh->id, mesh->active_color_attribute, CD_MASK_PROP_BYTE_COLOR, ATTR_DOMAIN_MASK_CORNER); + if (!layer) { return 0; } - CustomData *ldata = rna_mesh_ldata(ptr); return layer - ldata->layers + CustomData_get_layer_index(ldata, CD_PROP_BYTE_COLOR); } @@ -1259,14 +1278,8 @@ DEFINE_CUSTOMDATA_LAYER_COLLECTION(sculpt_vertex_color, vdata, CD_PROP_COLOR) static PointerRNA rna_Mesh_sculpt_vertex_color_active_get(PointerRNA *ptr) { Mesh *mesh = (Mesh *)ptr->data; - - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&mesh->id); - - if (!layer || layer->type != CD_PROP_COLOR || - BKE_id_attribute_domain(&mesh->id, layer) != ATTR_DOMAIN_POINT) { - return PointerRNA_NULL; - } - + CustomDataLayer *layer = BKE_id_attribute_search( + &mesh->id, mesh->active_color_attribute, CD_MASK_PROP_COLOR, ATTR_DOMAIN_MASK_POINT); return rna_pointer_inherit_refine(ptr, &RNA_MeshVertColorLayer, layer); } @@ -1287,15 +1300,12 @@ static void rna_Mesh_sculpt_vertex_color_active_set(PointerRNA *ptr, static int rna_Mesh_sculpt_vertex_color_active_index_get(PointerRNA *ptr) { Mesh *mesh = (Mesh *)ptr->data; - - CustomDataLayer *layer = BKE_id_attributes_active_color_get(&mesh->id); - CustomData *vdata = rna_mesh_vdata(ptr); - - if (!layer || layer->type != CD_PROP_COLOR || - BKE_id_attribute_domain(&mesh->id, layer) != ATTR_DOMAIN_POINT) { + CustomDataLayer *layer = BKE_id_attribute_search( + &mesh->id, mesh->active_color_attribute, CD_MASK_PROP_COLOR, ATTR_DOMAIN_MASK_POINT); + if (!layer) { return 0; } - + CustomData *vdata = rna_mesh_vdata(ptr); return layer - vdata->layers + CustomData_get_layer_index(vdata, CD_PROP_COLOR); } @@ -1687,7 +1697,7 @@ static void rna_MeshEdge_hide_set(PointerRNA *ptr, bool value) return; } hide_edge = (bool *)CustomData_add_layer_named( - &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totedge, ".hide_edge"); + &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totedge, ".hide_edge"); } const int index = rna_MeshEdge_index_get(ptr); hide_edge[index] = value; @@ -1713,7 +1723,7 @@ static void rna_MeshEdge_select_set(PointerRNA *ptr, bool value) return; } select_edge = (bool *)CustomData_add_layer_named( - &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totedge, ".select_edge"); + &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totedge, ".select_edge"); } const int index = rna_MeshEdge_index_get(ptr); select_edge[index] = value; @@ -1739,7 +1749,7 @@ static void rna_MeshEdge_use_edge_sharp_set(PointerRNA *ptr, bool value) return; } sharp_edge = (bool *)CustomData_add_layer_named( - &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totedge, "sharp_edge"); + &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totedge, "sharp_edge"); } const int index = rna_MeshEdge_index_get(ptr); sharp_edge[index] = value; @@ -1765,7 +1775,7 @@ static void rna_MeshEdge_use_seam_set(PointerRNA *ptr, bool value) return; } seam_edge = (bool *)CustomData_add_layer_named( - &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totedge, ".uv_seam"); + &mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, mesh->totedge, ".uv_seam"); } const int index = rna_MeshEdge_index_get(ptr); seam_edge[index] = value; @@ -1790,8 +1800,9 @@ static bool rna_MeshLoopTriangle_use_smooth_get(PointerRNA *ptr) { const Mesh *me = rna_mesh(ptr); const MLoopTri *ltri = (MLoopTri *)ptr->data; - const MPoly *polys = BKE_mesh_polys(me); - return polys[ltri->poly].flag & ME_SMOOTH; + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &me->pdata, CD_PROP_BOOL, "sharp_face"); + return !(sharp_faces && sharp_faces[ltri->poly]); } /* path construction */ @@ -2474,8 +2485,7 @@ static void rna_Mesh_sculpt_vertex_color_remove(struct Mesh *me, CustomDataLayer *cdl = NULL; \ int index; \ \ - CustomData_add_layer_named( \ - &me->cdata, cd_prop_type, CD_SET_DEFAULT, NULL, me->countvar, name); \ + CustomData_add_layer_named(&me->cdata, cd_prop_type, CD_SET_DEFAULT, me->countvar, name); \ index = CustomData_get_named_layer_index(&me->cdata, cd_prop_type, name); \ \ cdl = (index == -1) ? NULL : &(me->cdata.layers[index]); \ @@ -2960,7 +2970,8 @@ static void rna_def_mpolygon(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Mesh_update_select"); prop = RNA_def_property(srna, "use_smooth", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH); + RNA_def_property_boolean_funcs( + prop, "rna_MeshPolygon_use_smooth_get", "rna_MeshPolygon_use_smooth_set"); RNA_def_property_ui_text(prop, "Smooth", ""); RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 2e2c0f1b694..3699a2ed66d 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -45,7 +45,7 @@ static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, static void rna_Mesh_create_normals_split(Mesh *mesh) { if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { - CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_SET_DEFAULT, NULL, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_SET_DEFAULT, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } } @@ -65,7 +65,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char * } else { r_looptangents = CustomData_add_layer( - &mesh->ldata, CD_MLOOPTANGENT, CD_SET_DEFAULT, NULL, mesh->totloop); + &mesh->ldata, CD_MLOOPTANGENT, CD_SET_DEFAULT, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_MLOOPTANGENT, CD_FLAG_TEMPORARY); } @@ -93,12 +93,15 @@ static void rna_Mesh_calc_smooth_groups( *r_poly_group_len = mesh->totpoly; const bool *sharp_edges = (const bool *)CustomData_get_layer_named( &mesh->edata, CD_PROP_BOOL, "sharp_edge"); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, "sharp_face"); *r_poly_group = BKE_mesh_calc_smoothgroups(mesh->totedge, BKE_mesh_polys(mesh), mesh->totpoly, BKE_mesh_loops(mesh), mesh->totloop, sharp_edges, + sharp_faces, r_group_total, use_bitflags); } @@ -242,7 +245,7 @@ void RNA_api_mesh(StructRNA *srna) func = RNA_def_function(srna, "split_faces", "rna_Mesh_split_faces"); RNA_def_function_ui_description(func, "Split faces based on the edge angle"); /* TODO: This parameter has no effect anymore, since the internal code does not need to - * compute temporary CD_NORMAL loop data. It should be removed for next major release (4.0). */ + * compute temporary CD_NORMAL loop data. It should be removed for next major release (4.0). */ RNA_def_boolean(func, "free_loop_normals", 1, "Free Loop Normals", "Deprecated, has no effect"); func = RNA_def_function(srna, "calc_tangents", "rna_Mesh_calc_tangents"); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index bf1a9963f87..0bba5b68148 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -11,6 +11,8 @@ #include "BLI_math.h" #include "BLI_utildefines.h" +#include "BLF_api.h" + #include "BLT_translation.h" #include "DNA_curves_types.h" @@ -167,7 +169,7 @@ static const EnumPropertyItem rna_enum_vector_rotate_type_items[] = { }; const EnumPropertyItem rna_enum_node_math_items[] = { - RNA_ENUM_ITEM_HEADING(N_("Functions"), NULL), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_NODETREE, "Functions"), NULL), {NODE_MATH_ADD, "ADD", 0, "Add", "A + B"}, {NODE_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"}, {NODE_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "A * B"}, @@ -180,7 +182,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = { {NODE_MATH_INV_SQRT, "INVERSE_SQRT", 0, "Inverse Square Root", "1 / Square root of A"}, {NODE_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Magnitude of A"}, {NODE_MATH_EXPONENT, "EXPONENT", 0, "Exponent", "exp(A)"}, - RNA_ENUM_ITEM_HEADING(N_("Comparison"), NULL), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_NODETREE, "Comparison"), NULL), {NODE_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "The minimum from A and B"}, {NODE_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "The maximum from A and B"}, {NODE_MATH_LESS_THAN, "LESS_THAN", 0, "Less Than", "1 if A < B else 0"}, @@ -197,7 +199,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = { 0, "Smooth Maximum", "The maximum from A and B with smoothing C"}, - RNA_ENUM_ITEM_HEADING(N_("Rounding"), NULL), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_NODETREE, "Rounding"), NULL), {NODE_MATH_ROUND, "ROUND", 0, @@ -216,7 +218,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = { 0, "Ping-Pong", "Wraps a value and reverses every other cycle (A,B)"}, - RNA_ENUM_ITEM_HEADING(N_("Trigonometric"), NULL), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_NODETREE, "Trigonometric"), NULL), {NODE_MATH_SINE, "SINE", 0, "Sine", "sin(A)"}, {NODE_MATH_COSINE, "COSINE", 0, "Cosine", "cos(A)"}, {NODE_MATH_TANGENT, "TANGENT", 0, "Tangent", "tan(A)"}, @@ -229,7 +231,7 @@ const EnumPropertyItem rna_enum_node_math_items[] = { {NODE_MATH_SINH, "SINH", 0, "Hyperbolic Sine", "sinh(A)"}, {NODE_MATH_COSH, "COSH", 0, "Hyperbolic Cosine", "cosh(A)"}, {NODE_MATH_TANH, "TANH", 0, "Hyperbolic Tangent", "tanh(A)"}, - RNA_ENUM_ITEM_HEADING(N_("Conversion"), NULL), + RNA_ENUM_ITEM_HEADING(CTX_N_(BLT_I18NCONTEXT_ID_NODETREE, "Conversion"), NULL), {NODE_MATH_RADIANS, "RADIANS", 0, "To Radians", "Convert from degrees to radians"}, {NODE_MATH_DEGREES, "DEGREES", 0, "To Degrees", "Convert from radians to degrees"}, {0, NULL, 0, NULL, NULL}, @@ -4164,6 +4166,12 @@ static bNodeSocket *rna_NodeOutputFile_slots_new( return sock; } +static void rna_FrameNode_label_size_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + BLF_cache_clear(); + rna_Node_update(bmain, scene, ptr); +} + static void rna_ShaderNodeTexIES_mode_set(PointerRNA *ptr, int value) { bNode *node = (bNode *)ptr->data; @@ -4816,7 +4824,7 @@ static void def_frame(StructRNA *srna) RNA_def_property_int_sdna(prop, NULL, "label_size"); RNA_def_property_range(prop, 8, 64); RNA_def_property_ui_text(prop, "Label Font Size", "Font size to use for displaying the label"); - RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, NULL); + RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_FrameNode_label_size_update"); } static void def_clamp(StructRNA *srna) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 56c66ddca3e..5e340a2039f 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -255,7 +255,7 @@ const EnumPropertyItem rna_enum_object_type_items[] = { {OB_CURVES, "CURVES", ICON_OUTLINER_OB_CURVES, "Hair Curves", ""}, {OB_POINTCLOUD, "POINTCLOUD", ICON_OUTLINER_OB_POINTCLOUD, "Point Cloud", ""}, {OB_VOLUME, "VOLUME", ICON_OUTLINER_OB_VOLUME, "Volume", ""}, - {OB_GPENCIL, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", ""}, + {OB_GPENCIL_LEGACY, "GPENCIL", ICON_OUTLINER_OB_GREASEPENCIL, "Grease Pencil", ""}, RNA_ENUM_ITEM_SEPR, {OB_ARMATURE, "ARMATURE", ICON_OUTLINER_OB_ARMATURE, "Armature", ""}, {OB_LATTICE, "LATTICE", ICON_OUTLINER_OB_LATTICE, "Lattice", ""}, @@ -310,7 +310,7 @@ const EnumPropertyItem rna_enum_object_axis_items[] = { # include "DNA_ID.h" # include "DNA_constraint_types.h" -# include "DNA_gpencil_types.h" +# include "DNA_gpencil_legacy_types.h" # include "DNA_key_types.h" # include "DNA_lattice_types.h" # include "DNA_node_types.h" @@ -323,7 +323,7 @@ const EnumPropertyItem rna_enum_object_axis_items[] = { # include "BKE_deform.h" # include "BKE_effect.h" # include "BKE_global.h" -# include "BKE_gpencil_modifier.h" +# include "BKE_gpencil_modifier_legacy.h" # include "BKE_key.h" # include "BKE_material.h" # include "BKE_mesh.h" @@ -382,7 +382,7 @@ static void rna_Object_duplicator_visibility_flag_update(Main *UNUSED(bmain), static void rna_MaterialIndex_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Object *ob = (Object *)ptr->owner_id; - if (ob && ob->type == OB_GPENCIL) { + if (ob && ob->type == OB_GPENCIL_LEGACY) { /* Notifying material property in top-bar. */ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); } @@ -391,7 +391,7 @@ static void rna_MaterialIndex_update(Main *UNUSED(bmain), Scene *UNUSED(scene), static void rna_GPencil_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { Object *ob = (Object *)ptr->owner_id; - if (ob && ob->type == OB_GPENCIL) { + if (ob && ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = (bGPdata *)ob->data; DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL); @@ -600,7 +600,7 @@ static StructRNA *rna_Object_data_typef(PointerRNA *ptr) return &RNA_Speaker; case OB_LIGHTPROBE: return &RNA_LightProbe; - case OB_GPENCIL: + case OB_GPENCIL_LEGACY: return &RNA_GreasePencil; case OB_CURVES: return &RNA_Curves; @@ -617,7 +617,7 @@ static bool rna_Object_data_poll(PointerRNA *ptr, const PointerRNA value) { Object *ob = (Object *)ptr->data; - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { /* GP Object - Don't allow using "Annotation" GP datablocks here */ bGPdata *gpd = value.data; return (gpd->flag & GP_DATA_ANNOTATIONS) == 0; @@ -1138,7 +1138,7 @@ static void rna_Object_active_material_set(PointerRNA *ptr, BLI_assert(BKE_id_is_in_global_main(value.data)); BKE_object_material_assign(G_MAIN, ob, value.data, ob->actcol, BKE_MAT_ASSIGN_EXISTING); - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { /* notifying material property in topbar */ WM_main_add_notifier(NC_SPACE | ND_SPACE_VIEW3D, NULL); } @@ -1377,7 +1377,7 @@ static bool rna_MaterialSlot_material_poll(PointerRNA *ptr, PointerRNA value) Object *ob = (Object *)ptr->owner_id; Material *ma = (Material *)value.data; - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { /* GP Materials only */ return (ma->gp_style != NULL); } @@ -2237,7 +2237,7 @@ bool rna_Light_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value) bool rna_GPencil_object_poll(PointerRNA *UNUSED(ptr), PointerRNA value) { - return ((Object *)value.owner_id)->type == OB_GPENCIL; + return ((Object *)value.owner_id)->type == OB_GPENCIL_LEGACY; } bool rna_Object_use_dynamic_topology_sculpting_get(PointerRNA *ptr) diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 9c62fd241e0..49209979a9a 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -20,7 +20,7 @@ #include "DNA_modifier_types.h" #include "DNA_object_types.h" -#include "BKE_gpencil_curve.h" +#include "BKE_gpencil_curve_legacy.h" #include "BKE_layer.h" #include "DEG_depsgraph.h" diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index e2e0e2e3b4f..ec83454c26c 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -2775,6 +2775,52 @@ bool rna_property_override_apply_default(Main *bmain, # undef RNA_PROPERTY_GET_SINGLE # undef RNA_PROPERTY_SET_SINGLE +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Primitive Values + * \{ */ + +/* Primitive String. */ + +static void rna_PrimitiveString_value_get(PointerRNA *ptr, char *result) +{ + const PrimitiveStringRNA *data = ptr->data; + strcpy(result, data->value ? data->value : ""); +} + +static int rna_PrimitiveString_value_length(PointerRNA *ptr) +{ + const PrimitiveStringRNA *data = ptr->data; + return data->value ? strlen(data->value) : 0; +} + +/* Primitive Int. */ + +static int rna_PrimitiveInt_value_get(PointerRNA *ptr) +{ + const PrimitiveIntRNA *data = ptr->data; + return data->value; +} + +/* Primitive Float. */ + +static float rna_PrimitiveFloat_value_get(PointerRNA *ptr) +{ + const PrimitiveFloatRNA *data = ptr->data; + return data->value; +} + +/* Primitive Boolean. */ + +static bool rna_PrimitiveBoolean_value_get(PointerRNA *ptr) +{ + const PrimitiveBooleanRNA *data = ptr->data; + return data->value; +} + +/** \} */ + #else static void rna_def_struct(BlenderRNA *brna) @@ -3367,6 +3413,40 @@ static void rna_def_pointer_property(StructRNA *srna, PropertyType type) RNA_def_property_ui_text(prop, "Pointer Type", "Fixed pointer type, empty if variable type"); } +static void rna_def_rna_primitive(BlenderRNA *brna) +{ + /* Primitive Values, use when passing #PointerRNA is used for primitive types. + * For the rare cases we want to pass a value as RNA which wraps a primitive data. */ + + StructRNA *srna; + PropertyRNA *prop; + + srna = RNA_def_struct(brna, "PrimitiveString", NULL); + RNA_def_struct_ui_text(srna, "String Value", "RNA wrapped string"); + prop = RNA_def_property(srna, "value", PROP_STRING, PROP_BYTESTRING); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_string_funcs( + prop, "rna_PrimitiveString_value_get", "rna_PrimitiveString_value_length", NULL); + + srna = RNA_def_struct(brna, "PrimitiveInt", NULL); + RNA_def_struct_ui_text(srna, "Primitive Int", "RNA wrapped int"); + prop = RNA_def_property(srna, "value", PROP_INT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_int_funcs(prop, "rna_PrimitiveInt_value_get", NULL, NULL); + + srna = RNA_def_struct(brna, "PrimitiveFloat", NULL); + RNA_def_struct_ui_text(srna, "Primitive Float", "RNA wrapped float"); + prop = RNA_def_property(srna, "value", PROP_FLOAT, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_float_funcs(prop, "rna_PrimitiveFloat_value_get", NULL, NULL); + + srna = RNA_def_struct(brna, "PrimitiveBoolean", NULL); + RNA_def_struct_ui_text(srna, "Primitive Boolean", "RNA wrapped boolean"); + prop = RNA_def_property(srna, "value", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_PrimitiveBoolean_value_get", NULL); +} + void RNA_def_rna(BlenderRNA *brna) { StructRNA *srna; @@ -3451,6 +3531,8 @@ void RNA_def_rna(BlenderRNA *brna) # endif RNA_def_property_ui_text(prop, "Structs", ""); + + rna_def_rna_primitive(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 2629373f452..c47235f8c36 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -8,7 +8,7 @@ #include "DNA_brush_types.h" #include "DNA_collection_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_layer_types.h" #include "DNA_linestyle_types.h" #include "DNA_modifier_types.h" @@ -667,7 +667,7 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = { # include "BKE_context.h" # include "BKE_freestyle.h" # include "BKE_global.h" -# include "BKE_gpencil.h" +# include "BKE_gpencil_legacy.h" # include "BKE_idprop.h" # include "BKE_image.h" # include "BKE_image_format.h" @@ -724,7 +724,7 @@ static void rna_Gpencil_extend_selection(bContext *C, PointerRNA *UNUSED(ptr)) ViewLayer *view_layer = CTX_data_view_layer(C); BKE_view_layer_synced_ensure(scene, view_layer); Object *ob = BKE_view_layer_active_object_get(view_layer); - if ((ob) && (ob->type == OB_GPENCIL)) { + if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) { bGPdata *gpd = (bGPdata *)ob->data; CTX_DATA_BEGIN (C, bGPDstroke *, gps, editable_gpencil_strokes) { if ((gps->flag & GP_STROKE_SELECT) && (gps->totpoints > 1)) { @@ -1193,7 +1193,9 @@ static char *rna_ImageFormatSettings_path(const PointerRNA *ptr) for (node = ntree->nodes.first; node; node = node->next) { if (node->type == CMP_NODE_OUTPUT_FILE) { if (&((NodeImageMultiFile *)node->storage)->format == imf) { - return BLI_sprintfN("nodes['%s'].format", node->name); + char node_name_esc[sizeof(node->name) * 2]; + BLI_str_escape(node_name_esc, node->name, sizeof(node_name_esc)); + return BLI_sprintfN("nodes[\"%s\"].format", node_name_esc); } else { bNodeSocket *sock; @@ -1201,8 +1203,14 @@ static char *rna_ImageFormatSettings_path(const PointerRNA *ptr) for (sock = node->inputs.first; sock; sock = sock->next) { NodeImageMultiFileSocket *sockdata = sock->storage; if (&sockdata->format == imf) { + char node_name_esc[sizeof(node->name) * 2]; + BLI_str_escape(node_name_esc, node->name, sizeof(node_name_esc)); + + char socketdata_path_esc[sizeof(sockdata->path) * 2]; + BLI_str_escape(socketdata_path_esc, sockdata->path, sizeof(socketdata_path_esc)); + return BLI_sprintfN( - "nodes['%s'].file_slots['%s'].format", node->name, sockdata->path); + "nodes[\"%s\"].file_slots[\"%s\"].format", node_name_esc, socketdata_path_esc); } } } @@ -4286,6 +4294,12 @@ static void rna_def_view_layer_aovs(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "add", "BKE_view_layer_add_aov"); parm = RNA_def_pointer(func, "aov", "AOV", "", "Newly created AOV"); RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "BKE_view_layer_remove_aov"); + parm = RNA_def_pointer(func, "aov", "AOV", "", "AOV to remove"); + RNA_def_function_ui_description(func, "Remove an AOV"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); } static void rna_def_view_layer_aov(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c index aa60339b7b8..1f5418ce2ec 100644 --- a/source/blender/makesrna/intern/rna_sculpt_paint.c +++ b/source/blender/makesrna/intern/rna_sculpt_paint.c @@ -17,7 +17,7 @@ #include "DNA_ID.h" #include "DNA_brush_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -108,7 +108,7 @@ const EnumPropertyItem rna_enum_symmetrize_direction_items[] = { # include "BKE_collection.h" # include "BKE_context.h" -# include "BKE_gpencil.h" +# include "BKE_gpencil_legacy.h" # include "BKE_object.h" # include "BKE_particle.h" # include "BKE_pbvh.h" diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 369cde9cc89..3beaf9c9a45 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -358,7 +358,7 @@ static void rna_Sequence_retiming_handle_frame_set(PointerRNA *ptr, int value) return; } - const int offset = value - SEQ_time_start_frame_get(seq) + handle->strip_frame_index; + const int offset = value - (SEQ_time_start_frame_get(seq) + handle->strip_frame_index); SEQ_retiming_offset_handle(scene, seq, handle, offset); SEQ_relations_invalidate_cache_raw(scene, seq); } diff --git a/source/blender/makesrna/intern/rna_shader_fx.c b/source/blender/makesrna/intern/rna_shader_fx.c index 930d79fb0dc..6a2dff121d9 100644 --- a/source/blender/makesrna/intern/rna_shader_fx.c +++ b/source/blender/makesrna/intern/rna_shader_fx.c @@ -8,7 +8,7 @@ #include #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_shader_fx_types.h" diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 1aea7338283..5fb55eb6f20 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -32,7 +32,7 @@ #include "BLI_uuid.h" #include "DNA_action_types.h" -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_key_types.h" #include "DNA_mask_types.h" #include "DNA_material_types.h" @@ -923,7 +923,7 @@ static void rna_GPencil_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UN bool changed = false; /* need set all caches as dirty to recalculate onion skinning */ for (Object *ob = bmain->objects.first; ob; ob = ob->id.next) { - if (ob->type == OB_GPENCIL) { + if (ob->type == OB_GPENCIL_LEGACY) { bGPdata *gpd = (bGPdata *)ob->data; DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY); changed = true; @@ -2624,8 +2624,8 @@ static void rna_SpaceNodeEditor_cursor_location_from_region(SpaceNode *snode, float cursor_location[2]; UI_view2d_region_to_view(®ion->v2d, x, y, &cursor_location[0], &cursor_location[1]); - cursor_location[0] /= UI_DPI_FAC; - cursor_location[1] /= UI_DPI_FAC; + cursor_location[0] /= UI_SCALE_FAC; + cursor_location[1] /= UI_SCALE_FAC; ED_node_cursor_location_set(snode, cursor_location); } @@ -3394,8 +3394,8 @@ static struct IDFilterEnumPropertyItem rna_enum_space_file_id_filter_categories[ ICON_WORLD_DATA, "Environment", "Show worlds, lights, cameras and speakers"}, - {FILTER_ID_BR | FILTER_ID_GD | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | FILTER_ID_TXT | - FILTER_ID_VF | FILTER_ID_CF | FILTER_ID_WS, + {FILTER_ID_BR | FILTER_ID_GD_LEGACY | FILTER_ID_PA | FILTER_ID_PAL | FILTER_ID_PC | + FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_CF | FILTER_ID_WS, "category_misc", ICON_GREASEPENCIL, "Miscellaneous", @@ -3909,7 +3909,7 @@ static void rna_def_space_outliner(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); prop = RNA_def_property(srna, "use_filter_object_grease_pencil", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_GPENCIL); + RNA_def_property_boolean_negative_sdna(prop, NULL, "filter", SO_FILTER_NO_OB_GPENCIL_LEGACY); RNA_def_property_ui_text(prop, "Show Grease Pencil", "Show grease pencil objects"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL); @@ -6329,27 +6329,12 @@ static void rna_def_space_graph(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show Handles", "Show handles of Bezier control points"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); - prop = RNA_def_property(srna, "use_only_selected_curves_handles", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SELCUVERTSONLY); - RNA_def_property_ui_text(prop, - "Only Selected Curve Keyframes", - "Only keyframes of selected F-Curves are visible and editable"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); - prop = RNA_def_property(srna, "use_only_selected_keyframe_handles", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SELVHANDLESONLY); RNA_def_property_ui_text( prop, "Only Selected Keyframes Handles", "Only show and edit handles of selected keyframes"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); - prop = RNA_def_property(srna, "use_beauty_drawing", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_BEAUTYDRAW_OFF); - RNA_def_property_ui_text(prop, - "Use High Quality Display", - "Display F-Curves using Anti-Aliasing and other fancy effects " - "(disable for better performance)"); - RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); - prop = RNA_def_property(srna, "show_markers", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_SHOW_MARKERS); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index 9790a85e1c8..464aeb0a2b3 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -152,7 +152,7 @@ void rna_def_object_type_visibility_flags_common(StructRNA *srna, {"show_object_viewport_lattice", "show_object_select_lattice"}}, {"Empty", (1 << OB_EMPTY), {"show_object_viewport_empty", "show_object_select_empty"}}, {"Grease Pencil", - (1 << OB_GPENCIL), + (1 << OB_GPENCIL_LEGACY), {"show_object_viewport_grease_pencil", "show_object_select_grease_pencil"}}, {"Camera", (1 << OB_CAMERA), {"show_object_viewport_camera", "show_object_select_camera"}}, {"Light", (1 << OB_LAMP), {"show_object_viewport_light", "show_object_select_light"}}, diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 55da02286a3..364ac8dbdd2 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -2220,7 +2220,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "edge_width", PROP_INT, PROP_PIXEL); - RNA_def_property_range(prop, 1, 5); + RNA_def_property_range(prop, 1, 32); RNA_def_property_ui_text(prop, "Edge Width", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); @@ -3069,7 +3069,7 @@ static void rna_def_userdef_theme_space_image(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); prop = RNA_def_property(srna, "edge_width", PROP_INT, PROP_PIXEL); - RNA_def_property_range(prop, 1, 5); + RNA_def_property_range(prop, 1, 32); RNA_def_property_ui_text(prop, "Edge Width", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); @@ -4794,7 +4794,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) /* mini axis */ static const EnumPropertyItem mini_axis_type_items[] = { {USER_MINI_AXIS_TYPE_NONE, "NONE", 0, "Off", ""}, - {USER_MINI_AXIS_TYPE_MINIMAL, "MINIMAL", 0, "Simple Axis", ""}, + {USER_MINI_AXIS_TYPE_MINIMAL, "MINIMAL", 0, "Simple Axes", ""}, {USER_MINI_AXIS_TYPE_GIZMO, "GIZMO", 0, "Interactive Navigation", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -4804,7 +4804,7 @@ static void rna_def_userdef_view(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Mini Axes Type", - "Show a small rotating 3D axes in the top right corner of the 3D viewport"); + "Show small rotating 3D axes in the top right corner of the 3D viewport"); RNA_def_property_update(prop, 0, "rna_userdef_gizmo_update"); prop = RNA_def_property(srna, "mini_axis_size", PROP_INT, PROP_PIXEL); @@ -5175,6 +5175,23 @@ static void rna_def_userdef_edit(BlenderRNA *brna) "background of the Graph Editor"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); + /* FCurve keyframe visibility. */ + prop = RNA_def_property(srna, "show_only_selected_curve_keyframes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, NULL, "animation_flag", USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS); + RNA_def_property_ui_text(prop, + "Only Show Selected F-Curve Keyframes", + "Only keyframes of selected F-Curves are visible and editable"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); + + /* Graph Editor line drawing quality. */ + prop = RNA_def_property(srna, "use_fcurve_high_quality_drawing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "animation_flag", USER_ANIM_HIGH_QUALITY_DRAWING); + RNA_def_property_ui_text(prop, + "F-Curve High Quality Drawing", + "Draw F-Curves using Anti-Aliasing (disable for better performance)"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); + /* grease pencil */ prop = RNA_def_property(srna, "grease_pencil_manhattan_distance", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "gp_manhattandist"); @@ -5480,7 +5497,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) prop = RNA_def_property(srna, "ui_scale", PROP_FLOAT, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_float_sdna(prop, NULL, "dpi_fac"); + RNA_def_property_float_sdna(prop, NULL, "ui_scale"); RNA_def_property_ui_text( prop, "UI Scale", diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 6140c9ed43a..ace7ca9c136 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -664,6 +664,12 @@ static bool rna_Event_is_repeat_get(PointerRNA *ptr) return (event->flag & WM_EVENT_IS_REPEAT) != 0; } +static bool rna_Event_is_consecutive_get(PointerRNA *ptr) +{ + const wmEvent *event = ptr->data; + return (event->flag & WM_EVENT_IS_CONSECUTIVE) != 0; +} + static float rna_Event_pressure_get(PointerRNA *ptr) { const wmEvent *event = ptr->data; @@ -2154,6 +2160,15 @@ static void rna_def_event(BlenderRNA *brna) RNA_def_property_boolean_funcs(prop, "rna_Event_is_repeat_get", NULL); RNA_def_property_ui_text(prop, "Is Repeat", "The event is generated by holding a key down"); + /* Track-pad & NDOF. */ + prop = RNA_def_property(srna, "is_consecutive", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_Event_is_consecutive_get", NULL); + RNA_def_property_ui_text(prop, + "Is Consecutive", + "Part of a track-pad or NDOF motion, " + "interrupted by cursor motion, button or key press events"); + /* mouse */ prop = RNA_def_property(srna, "mouse_x", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "xy[0]"); diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c index 98adb456b23..abd831a66b9 100644 --- a/source/blender/modifiers/intern/MOD_armature.c +++ b/source/blender/modifiers/intern/MOD_armature.c @@ -99,7 +99,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte /* If not using envelopes, * create relations to individual bones for more rigging flexibility. */ if ((amd->deformflag & ARM_DEF_ENVELOPE) == 0 && (amd->object->pose != NULL) && - ELEM(ctx->object->type, OB_MESH, OB_LATTICE, OB_GPENCIL)) { + ELEM(ctx->object->type, OB_MESH, OB_LATTICE, OB_GPENCIL_LEGACY)) { /* If neither vertex groups nor envelopes are used, the modifier has no bone dependencies. */ if ((amd->deformflag & ARM_DEF_VGROUP) != 0) { /* Enumerate groups that match existing bones. */ diff --git a/source/blender/modifiers/intern/MOD_array.cc b/source/blender/modifiers/intern/MOD_array.cc index 36ce8e861cd..458983c0ca5 100644 --- a/source/blender/modifiers/intern/MOD_array.cc +++ b/source/blender/modifiers/intern/MOD_array.cc @@ -31,7 +31,7 @@ #include "BKE_displist.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_object_deform.h" #include "BKE_screen.h" @@ -372,8 +372,12 @@ static void mesh_merge_transform(Mesh *result, static Mesh *arrayModifier_doArray(ArrayModifierData *amd, const ModifierEvalContext *ctx, - const Mesh *mesh) + Mesh *mesh) { + if (mesh->totvert == 0) { + return mesh; + } + MEdge *edge; MLoop *ml; int i, j, c, count; @@ -572,10 +576,10 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, first_chunk_nverts = chunk_nverts; unit_m4(current_offset); - const float(*src_vert_normals)[3] = nullptr; + blender::Span src_vert_normals; float(*dst_vert_normals)[3] = nullptr; if (!use_recalc_normals) { - src_vert_normals = BKE_mesh_vert_normals_ensure(mesh); + src_vert_normals = mesh->vert_normals(); dst_vert_normals = BKE_mesh_vert_normals_for_write(result); BKE_mesh_vert_normals_clear_dirty(result); } diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index 2be77dc6245..6bc7c045de6 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -32,7 +32,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_boolean_convert.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" diff --git a/source/blender/modifiers/intern/MOD_build.cc b/source/blender/modifiers/intern/MOD_build.cc index 7b77b443d76..e4c28530bc1 100644 --- a/source/blender/modifiers/intern/MOD_build.cc +++ b/source/blender/modifiers/intern/MOD_build.cc @@ -24,7 +24,7 @@ #include "DEG_depsgraph_query.h" #include "BKE_context.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_scene.h" diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index baed03692cb..533dd66676c 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -116,7 +116,7 @@ static void deformVerts(ModifierData *md, if (!(layerorco = CustomData_get_layer_for_write( &mesh_src->vdata, CD_CLOTH_ORCO, mesh_src->totvert))) { layerorco = CustomData_add_layer( - &mesh_src->vdata, CD_CLOTH_ORCO, CD_SET_DEFAULT, NULL, mesh_src->totvert); + &mesh_src->vdata, CD_CLOTH_ORCO, CD_SET_DEFAULT, mesh_src->totvert); } memcpy(layerorco, kb->data, sizeof(float[3]) * verts_num); diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.cc b/source/blender/modifiers/intern/MOD_correctivesmooth.cc index ae1b3eb4a6f..7dfbe03ca84 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.cc +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.cc @@ -26,7 +26,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_screen.h" diff --git a/source/blender/modifiers/intern/MOD_datatransfer.cc b/source/blender/modifiers/intern/MOD_datatransfer.cc index 4bb36d9a791..fbce7ef6da9 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.cc +++ b/source/blender/modifiers/intern/MOD_datatransfer.cc @@ -22,7 +22,7 @@ #include "BKE_data_transfer.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_remap.h" #include "BKE_modifier.h" diff --git a/source/blender/modifiers/intern/MOD_displace.cc b/source/blender/modifiers/intern/MOD_displace.cc index 796bf63e79d..1d6db98d8fd 100644 --- a/source/blender/modifiers/intern/MOD_displace.cc +++ b/source/blender/modifiers/intern/MOD_displace.cc @@ -25,7 +25,7 @@ #include "BKE_image.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -155,7 +155,7 @@ struct DisplaceUserdata { float (*tex_co)[3]; float (*vertexCos)[3]; float local_mat[4][4]; - const float (*vert_normals)[3]; + blender::Span vert_normals; float (*vert_clnors)[3]; }; @@ -336,7 +336,7 @@ static void displaceModifier_do(DisplaceModifierData *dmd, data.vertexCos = vertexCos; copy_m4_m4(data.local_mat, local_mat); if (direction == MOD_DISP_DIR_NOR) { - data.vert_normals = BKE_mesh_vert_normals_ensure(mesh); + data.vert_normals = mesh->vert_normals(); } data.vert_clnors = vert_clnors; if (tex_target != nullptr) { diff --git a/source/blender/modifiers/intern/MOD_explode.cc b/source/blender/modifiers/intern/MOD_explode.cc index 2e6a6847c79..40a8a8c99b1 100644 --- a/source/blender/modifiers/intern/MOD_explode.cc +++ b/source/blender/modifiers/intern/MOD_explode.cc @@ -27,7 +27,7 @@ #include "BKE_deform.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.h" #include "BKE_modifier.h" #include "BKE_particle.h" diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.cc b/source/blender/modifiers/intern/MOD_laplaciandeform.cc index 63947d5fd34..bc329d3e5bc 100644 --- a/source/blender/modifiers/intern/MOD_laplaciandeform.cc +++ b/source/blender/modifiers/intern/MOD_laplaciandeform.cc @@ -24,7 +24,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.cc b/source/blender/modifiers/intern/MOD_laplaciansmooth.cc index 9577e10c0a3..7422f8d09bd 100644 --- a/source/blender/modifiers/intern/MOD_laplaciansmooth.cc +++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.cc @@ -23,7 +23,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index af8739eec12..eddd3b09633 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -29,7 +29,7 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.cc b/source/blender/modifiers/intern/MOD_meshsequencecache.cc index e323c592b44..1a9ab043d43 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.cc +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.cc @@ -26,7 +26,7 @@ #include "BKE_cachefile.h" #include "BKE_context.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_object.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -156,6 +156,10 @@ static Mesh *generate_bounding_box_mesh(const Mesh *org_mesh) } Mesh *result = geometry::create_cuboid_mesh(max - min, 2, 2, 2); + if (org_mesh->mat) { + result->mat = static_cast(MEM_dupallocN(org_mesh->mat)); + result->totcol = org_mesh->totcol; + } BKE_mesh_translate(result, math::midpoint(min, max), false); return result; diff --git a/source/blender/modifiers/intern/MOD_multires.cc b/source/blender/modifiers/intern/MOD_multires.cc index 91a5c5bd102..528c5aee889 100644 --- a/source/blender/modifiers/intern/MOD_multires.cc +++ b/source/blender/modifiers/intern/MOD_multires.cc @@ -21,7 +21,7 @@ #include "BKE_cdderivedmesh.h" #include "BKE_context.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_paint.h" diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index e4474d3b5ea..564c270674b 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -46,7 +46,7 @@ #include "BKE_lib_id.h" #include "BKE_lib_query.h" #include "BKE_main.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_node_runtime.hh" #include "BKE_node_tree_update.h" @@ -1358,13 +1358,13 @@ static void modifyGeometry(ModifierData *md, * #eModifierTypeFlag_SupportsMapping flag is set. If the layers did not exist before, it is * assumed that the output mesh does not have a mapping to the original mesh. */ if (use_orig_index_verts) { - CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->totvert); } if (use_orig_index_edges) { - CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->totedge); } if (use_orig_index_polys) { - CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, mesh->totpoly); } } } diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index e829a2d1183..9cf960af128 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -26,7 +26,7 @@ #include "BKE_deform.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_screen.h" #include "UI_interface.h" @@ -126,12 +126,12 @@ static void mix_normals(const float mix_factor, const short mix_mode, const int verts_num, const blender::Span loops, - float (*nos_old)[3], - float (*nos_new)[3]) + blender::float3 *nos_old, + blender::float3 *nos_new) { /* Mix with org normals... */ float *facs = nullptr, *wfac; - float(*no_new)[3], (*no_old)[3]; + blender::float3 *no_new, *no_old; int i; if (dvert) { @@ -174,7 +174,7 @@ static void mix_normals(const float mix_factor, /* Check poly normals and new loop normals are compatible, otherwise flip polygons * (and invert matching poly normals). */ static bool polygons_check_flip(blender::MutableSpan loops, - float (*nos)[3], + blender::float3 *nos, CustomData *ldata, const blender::Span polys, float (*poly_normals)[3]) @@ -186,11 +186,9 @@ static bool polygons_check_flip(blender::MutableSpan loops, for (const int i : polys.index_range()) { const MPoly &poly = polys[i]; float norsum[3] = {0.0f}; - float(*no)[3]; - int j; - for (j = 0, no = &nos[poly.loopstart]; j < poly.totloop; j++, no++) { - add_v3_v3(norsum, *no); + for (const int64_t j : blender::IndexRange(poly.loopstart, poly.totloop)) { + add_v3_v3(norsum, nos[j]); } if (!normalize_v3(norsum)) { @@ -199,7 +197,8 @@ static bool polygons_check_flip(blender::MutableSpan loops, /* If average of new loop normals is opposed to polygon normal, flip polygon. */ if (dot_v3v3(poly_normals[i], norsum) < 0.0f) { - BKE_mesh_polygon_flip_ex(&poly, loops.data(), ldata, nos, mdisp, true); + BKE_mesh_polygon_flip_ex( + &poly, loops.data(), ldata, reinterpret_cast(nos), mdisp, true); negate_v3(poly_normals[i]); flipped = true; } @@ -213,35 +212,31 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, Object *ob, Mesh *mesh, short (*clnors)[2], - float (*loop_normals)[3], - const float (*poly_normals)[3], + blender::MutableSpan loop_normals, const short mix_mode, const float mix_factor, const float mix_limit, const MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, - const float (*vert_positions)[3], - const int verts_num, + blender::Span vert_positions, const blender::Span edges, - bool *sharp_edges, + blender::MutableSpan sharp_edges, blender::MutableSpan loops, const blender::Span polys) { Object *ob_target = enmd->target; const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; - int i; float(*cos)[3] = static_cast( - MEM_malloc_arrayN(size_t(verts_num), sizeof(*cos), __func__)); - float(*nos)[3] = static_cast( - MEM_malloc_arrayN(size_t(loops.size()), sizeof(*nos), __func__)); + MEM_malloc_arrayN(size_t(vert_positions.size()), sizeof(*cos), __func__)); + blender::Array nos(loops.size()); float size[3]; - BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(verts_num), __func__); + BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(vert_positions.size()), __func__); - generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, verts_num, cos, size); + generate_vert_coordinates(mesh, ob, ob_target, enmd->offset, vert_positions.size(), cos, size); /** * size gives us our spheroid coefficients `(A, B, C)`. @@ -279,12 +274,9 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, const float m2 = (b * b) / (a * a); const float n2 = (c * c) / (a * a); - const MLoop *ml; - float(*no)[3]; - /* We reuse cos to now store the ellipsoid-normal of the verts! */ - for (i = loops.size(), ml = loops.data(), no = nos; i--; ml++, no++) { - const int vidx = ml->v; + for (const int64_t i : loops.index_range()) { + const int vidx = loops[i].v; float *co = cos[vidx]; if (!BLI_BITMAP_TEST(done_verts, vidx)) { @@ -302,46 +294,42 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, BLI_BITMAP_ENABLE(done_verts, vidx); } - copy_v3_v3(*no, co); + nos[i] = co; } } - if (loop_normals) { + if (!loop_normals.is_empty()) { mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup, mix_limit, mix_mode, - verts_num, + vert_positions.size(), loops, - loop_normals, - nos); + loop_normals.data(), + nos.data()); } if (do_polynors_fix && polygons_check_flip( - loops, nos, &mesh->ldata, polys, BKE_mesh_poly_normals_for_write(mesh))) { - /* We need to recompute vertex normals! */ - BKE_mesh_normals_tag_dirty(mesh); + loops, nos.data(), &mesh->ldata, polys, BKE_mesh_poly_normals_for_write(mesh))) { + mesh->runtime->vert_normals_dirty = true; } - - BKE_mesh_normals_loop_custom_set(vert_positions, - BKE_mesh_vert_normals_ensure(mesh), - verts_num, - edges.data(), - edges.size(), - loops.data(), - nos, - loops.size(), - polys.data(), - poly_normals, - polys.size(), - sharp_edges, - clnors); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); + blender::bke::mesh::normals_loop_custom_set(vert_positions, + edges, + polys, + loops, + mesh->vert_normals(), + mesh->poly_normals(), + sharp_faces, + sharp_edges, + nos, + clnors); MEM_freeN(cos); - MEM_freeN(nos); MEM_freeN(done_verts); } @@ -350,18 +338,16 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, Object *ob, Mesh *mesh, short (*clnors)[2], - float (*loop_normals)[3], - const float (*poly_normals)[3], + blender::MutableSpan loop_normals, const short mix_mode, const float mix_factor, const float mix_limit, const MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup, - const float (*positions)[3], - const int verts_num, + const blender::Span positions, const blender::Span edges, - bool *sharp_edges, + blender::MutableSpan sharp_edges, blender::MutableSpan loops, const blender::Span polys) { @@ -370,8 +356,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, const bool do_polynors_fix = (enmd->flag & MOD_NORMALEDIT_NO_POLYNORS_FIX) == 0; const bool use_parallel_normals = (enmd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0; - float(*nos)[3] = static_cast( - MEM_malloc_arrayN(loops.size(), sizeof(*nos), __func__)); + blender::Array nos(loops.size()); float target_co[3]; int i; @@ -395,16 +380,14 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, } else { float(*cos)[3] = static_cast( - MEM_malloc_arrayN(size_t(verts_num), sizeof(*cos), __func__)); - generate_vert_coordinates(mesh, ob, ob_target, nullptr, verts_num, cos, nullptr); + MEM_malloc_arrayN(size_t(positions.size()), sizeof(*cos), __func__)); + generate_vert_coordinates(mesh, ob, ob_target, nullptr, positions.size(), cos, nullptr); - BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(verts_num), __func__); - const MLoop *ml; - float(*no)[3]; + BLI_bitmap *done_verts = BLI_BITMAP_NEW(size_t(positions.size()), __func__); /* We reuse cos to now store the 'to target' normal of the verts! */ - for (i = loops.size(), no = nos, ml = loops.data(); i--; no++, ml++) { - const int vidx = ml->v; + for (const int64_t i : loops.index_range()) { + const int vidx = loops[i].v; float *co = cos[vidx]; if (!BLI_BITMAP_TEST(done_verts, vidx)) { @@ -413,48 +396,43 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, BLI_BITMAP_ENABLE(done_verts, vidx); } - - copy_v3_v3(*no, co); + nos[i] = co; } MEM_freeN(done_verts); MEM_freeN(cos); } - if (loop_normals) { + if (!loop_normals.is_empty()) { mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup, mix_limit, mix_mode, - verts_num, + positions.size(), loops, - loop_normals, - nos); + loop_normals.data(), + nos.data()); } if (do_polynors_fix && polygons_check_flip( - loops, nos, &mesh->ldata, polys, BKE_mesh_poly_normals_for_write(mesh))) { - BKE_mesh_normals_tag_dirty(mesh); + loops, nos.data(), &mesh->ldata, polys, BKE_mesh_poly_normals_for_write(mesh))) { + mesh->runtime->vert_normals_dirty = true; } - - BKE_mesh_normals_loop_custom_set(positions, - BKE_mesh_vert_normals_ensure(mesh), - verts_num, - edges.data(), - edges.size(), - loops.data(), - nos, - loops.size(), - polys.data(), - poly_normals, - polys.size(), - sharp_edges, - clnors); - - MEM_freeN(nos); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); + blender::bke::mesh::normals_loop_custom_set(positions, + edges, + polys, + loops, + mesh->vert_normals(), + mesh->poly_normals(), + sharp_faces, + sharp_edges, + nos, + clnors); } static bool is_valid_target(NormalEditModifierData *enmd) @@ -520,8 +498,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, result = mesh; } - const int verts_num = result->totvert; - const float(*positions)[3] = BKE_mesh_vert_positions(result); + const blender::Span positions = result->vert_positions(); const blender::Span edges = result->edges(); const blender::Span polys = result->polys(); blender::MutableSpan loops = result->loops_for_write(); @@ -529,13 +506,10 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, int defgrp_index; const MDeformVert *dvert; - float(*loop_normals)[3] = nullptr; + blender::Array loop_normals; CustomData *ldata = &result->ldata; - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(result); - const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(result); - bke::MutableAttributeAccessor attributes = result->attributes_for_write(); bke::SpanAttributeWriter sharp_edges = attributes.lookup_or_add_for_write_span( "sharp_edge", ATTR_DOMAIN_EDGE); @@ -545,31 +519,28 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, if (use_current_clnors) { clnors = static_cast( CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, loops.size())); - loop_normals = static_cast( - MEM_malloc_arrayN(loops.size(), sizeof(*loop_normals), __func__)); - - BKE_mesh_normals_loop_split(positions, - vert_normals, - verts_num, - edges.data(), - edges.size(), - loops.data(), - loop_normals, - loops.size(), - polys.data(), - poly_normals, - polys.size(), - true, - result->smoothresh, - sharp_edges.span.data(), - nullptr, - nullptr, - clnors); + loop_normals.reinitialize(loops.size()); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face")); + blender::bke::mesh::normals_calc_loop(positions, + edges, + polys, + loops, + {}, + result->vert_normals(), + result->poly_normals(), + sharp_edges.span.data(), + sharp_faces, + true, + result->smoothresh, + clnors, + nullptr, + loop_normals); } if (clnors == nullptr) { clnors = static_cast( - CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, loops.size())); + CustomData_add_layer(ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, loops.size())); } MOD_get_vgroup(ob, result, enmd->defgrp_name, &dvert, &defgrp_index); @@ -581,7 +552,6 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, result, clnors, loop_normals, - poly_normals, enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, @@ -589,9 +559,8 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, defgrp_index, use_invert_vgroup, positions, - verts_num, edges, - sharp_edges.span.data(), + sharp_edges.span, loops, polys); } @@ -602,7 +571,6 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, result, clnors, loop_normals, - poly_normals, enmd->mix_mode, enmd->mix_factor, enmd->mix_limit, @@ -610,15 +578,12 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, defgrp_index, use_invert_vgroup, positions, - verts_num, edges, - sharp_edges.span.data(), + sharp_edges.span, loops, polys); } - MEM_SAFE_FREE(loop_normals); - result->runtime->is_original_bmesh = false; sharp_edges.finish(); diff --git a/source/blender/modifiers/intern/MOD_ocean.cc b/source/blender/modifiers/intern/MOD_ocean.cc index 792efd2215c..c9fe4aa4167 100644 --- a/source/blender/modifiers/intern/MOD_ocean.cc +++ b/source/blender/modifiers/intern/MOD_ocean.cc @@ -24,7 +24,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_ocean.h" #include "BKE_screen.h" @@ -204,7 +204,6 @@ static void generate_ocean_geometry_polys(void *__restrict userdata, gogd->polys[fi].loopstart = fi * 4; gogd->polys[fi].totloop = 4; - gogd->polys[fi].flag |= ME_SMOOTH; } } @@ -286,7 +285,7 @@ static Mesh *generate_ocean_geometry(OceanModifierData *omd, Mesh *mesh_orig, co /* add uvs */ if (CustomData_number_of_layers(&result->ldata, CD_PROP_FLOAT2) < MAX_MTFACE) { gogd.mloopuvs = static_cast(CustomData_add_layer_named( - &result->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, polys_num * 4, "UVMap")); + &result->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, polys_num * 4, "UVMap")); if (gogd.mloopuvs) { /* unlikely to fail */ gogd.ix = 1.0 / gogd.rx; @@ -367,21 +366,13 @@ static Mesh *doOcean(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mes if (omd->flag & MOD_OCEAN_GENERATE_FOAM) { const blender::Span loops = result->loops(); - MLoopCol *mloopcols = static_cast(CustomData_add_layer_named(&result->ldata, - CD_PROP_BYTE_COLOR, - CD_SET_DEFAULT, - nullptr, - loops.size(), - omd->foamlayername)); + MLoopCol *mloopcols = static_cast(CustomData_add_layer_named( + &result->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, loops.size(), omd->foamlayername)); MLoopCol *mloopcols_spray = nullptr; if (omd->flag & MOD_OCEAN_GENERATE_SPRAY) { - mloopcols_spray = static_cast(CustomData_add_layer_named(&result->ldata, - CD_PROP_BYTE_COLOR, - CD_SET_DEFAULT, - nullptr, - loops.size(), - omd->spraylayername)); + mloopcols_spray = static_cast(CustomData_add_layer_named( + &result->ldata, CD_PROP_BYTE_COLOR, CD_SET_DEFAULT, loops.size(), omd->spraylayername)); } if (mloopcols) { /* unlikely to fail */ diff --git a/source/blender/modifiers/intern/MOD_particleinstance.cc b/source/blender/modifiers/intern/MOD_particleinstance.cc index 3d0b0275651..c1e07497598 100644 --- a/source/blender/modifiers/intern/MOD_particleinstance.cc +++ b/source/blender/modifiers/intern/MOD_particleinstance.cc @@ -25,7 +25,7 @@ #include "BKE_effect.h" #include "BKE_lattice.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_pointcache.h" diff --git a/source/blender/modifiers/intern/MOD_particlesystem.cc b/source/blender/modifiers/intern/MOD_particlesystem.cc index bf19553378f..85ca594d991 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.cc +++ b/source/blender/modifiers/intern/MOD_particlesystem.cc @@ -20,7 +20,7 @@ #include "BKE_context.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_legacy_convert.h" #include "BKE_modifier.h" #include "BKE_particle.h" diff --git a/source/blender/modifiers/intern/MOD_remesh.cc b/source/blender/modifiers/intern/MOD_remesh.cc index eef079e2fa7..9d6ca28759f 100644 --- a/source/blender/modifiers/intern/MOD_remesh.cc +++ b/source/blender/modifiers/intern/MOD_remesh.cc @@ -21,7 +21,7 @@ #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_remesh_voxel.h" #include "BKE_mesh_runtime.h" #include "BKE_screen.h" diff --git a/source/blender/modifiers/intern/MOD_screw.cc b/source/blender/modifiers/intern/MOD_screw.cc index 986e3fba52e..a3ba9056c55 100644 --- a/source/blender/modifiers/intern/MOD_screw.cc +++ b/source/blender/modifiers/intern/MOD_screw.cc @@ -22,10 +22,11 @@ #include "DNA_object_types.h" #include "DNA_screen_types.h" +#include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_screen.h" #include "UI_interface.h" @@ -191,6 +192,7 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result, static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData) { + using namespace blender; const Mesh *mesh = meshData; Mesh *result; ScrewModifierData *ltmd = (ScrewModifierData *)md; @@ -257,7 +259,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * ScrewVertConnect *vc, *vc_tmp, *vert_connect = nullptr; - const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0; + const bool use_flat_shading = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) == 0; /* don't do anything? */ if (!totvert) { @@ -405,9 +407,12 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * blender::MutableSpan edges_new = result->edges_for_write(); blender::MutableSpan polys_new = result->polys_for_write(); blender::MutableSpan loops_new = result->loops_for_write(); + bke::MutableAttributeAccessor attributes = result->attributes_for_write(); + bke::SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span( + "sharp_face", ATTR_DOMAIN_FACE); if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) { - CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, int(maxPolys)); + CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, int(maxPolys)); } int *origindex = static_cast( @@ -877,7 +882,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * else { origindex[mpoly_index] = ORIGINDEX_NONE; dst_material_index[mpoly_index] = mat_nr; - mp_new->flag = mpoly_flag; + sharp_faces.span[i] = use_flat_shading; } mp_new->loopstart = mpoly_index * 4; mp_new->totloop = 4; @@ -1001,6 +1006,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } #endif + sharp_faces.finish(); + if (edge_poly_map) { MEM_freeN(edge_poly_map); } diff --git a/source/blender/modifiers/intern/MOD_skin.cc b/source/blender/modifiers/intern/MOD_skin.cc index 20c6aa7e6a6..f3e8ab01f74 100644 --- a/source/blender/modifiers/intern/MOD_skin.cc +++ b/source/blender/modifiers/intern/MOD_skin.cc @@ -59,7 +59,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_modifier.h" #include "BKE_screen.h" @@ -236,6 +236,8 @@ static bool quad_crosses_symmetry_plane(BMVert *quad[4], const SkinModifierData return false; } +#ifdef WITH_BULLET + /* Returns true if the frame is filled by precisely two faces (and * outputs those faces to fill_faces), otherwise returns false. */ static bool skin_frame_find_contained_faces(const Frame *frame, BMFace *fill_faces[2]) @@ -255,6 +257,8 @@ static bool skin_frame_find_contained_faces(const Frame *frame, BMFace *fill_fac return false; } +#endif + /* Returns true if hull is successfully built, false otherwise */ static bool build_hull(SkinOutput *so, Frame **frames, int totframe) { @@ -370,7 +374,7 @@ static bool build_hull(SkinOutput *so, Frame **frames, int totframe) return true; #else - UNUSED_VARS(so, frames, totframe, skin_frame_find_contained_faces); + UNUSED_VARS(so, frames, totframe); return false; #endif } @@ -833,7 +837,7 @@ static EMat *build_edge_mats(const MVertSkin *vs, static int calc_edge_subdivisions(const float (*vert_positions)[3], const MVertSkin *nodes, const MEdge *edge, - const int *degree) + const blender::Span degree) { /* prevent memory errors #38003. */ #define NUM_SUBDIVISIONS_MAX 128 @@ -901,22 +905,20 @@ static Mesh *subdivide_base(const Mesh *orig) int orig_edge_num = orig->totedge; /* Get degree of all vertices */ - int *degree = MEM_cnew_array(orig_vert_num, __func__); + blender::Array degree(orig_vert_num, 0); for (i = 0; i < orig_edge_num; i++) { degree[orig_edges[i].v1]++; degree[orig_edges[i].v2]++; } /* Per edge, store how many subdivisions are needed */ - int *edge_subd = MEM_cnew_array(orig_edge_num, __func__); + blender::Array edge_subd(orig_edge_num, 0); for (i = 0, subd_num = 0; i < orig_edge_num; i++) { edge_subd[i] += calc_edge_subdivisions(orig_vert_positions, orignode, &orig_edges[i], degree); BLI_assert(edge_subd[i] >= 0); subd_num += edge_subd[i]; } - MEM_freeN(degree); - /* Allocate output mesh */ Mesh *result = BKE_mesh_new_nomain_from_template( orig, orig_vert_num + subd_num, orig_edge_num + subd_num, 0, 0); @@ -1020,8 +1022,6 @@ static Mesh *subdivide_base(const Mesh *orig) result_edge_i++; } - MEM_freeN(edge_subd); - return result; } @@ -1892,7 +1892,7 @@ static BMesh *build_skin(SkinNode *skin_nodes, static void skin_set_orig_indices(Mesh *mesh) { int *orig = static_cast( - CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CONSTRUCT, nullptr, mesh->totpoly)); + CustomData_add_layer(&mesh->pdata, CD_ORIGINDEX, CD_CONSTRUCT, mesh->totpoly)); copy_vn_i(orig, mesh->totpoly, ORIGINDEX_NONE); } diff --git a/source/blender/modifiers/intern/MOD_smooth.cc b/source/blender/modifiers/intern/MOD_smooth.cc index 6dade62048b..6582bcd4f70 100644 --- a/source/blender/modifiers/intern/MOD_smooth.cc +++ b/source/blender/modifiers/intern/MOD_smooth.cc @@ -23,7 +23,7 @@ #include "BKE_deform.h" #include "BKE_editmesh.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_particle.h" #include "BKE_screen.h" diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.cc b/source/blender/modifiers/intern/MOD_solidify_extrude.cc index d43997d5815..6504e3cbc00 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.cc +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.cc @@ -17,7 +17,7 @@ #include "MEM_guardedalloc.h" #include "BKE_deform.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_particle.h" #include "MOD_modifiertypes.h" @@ -50,11 +50,11 @@ BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref) /** * \param mesh: Mesh to calculate normals for. - * \param poly_nors: Precalculated face normals. + * \param poly_normals: Precalculated face normals. * \param r_vert_nors: Return vert normals. */ static void mesh_calc_hq_normal(Mesh *mesh, - const float (*poly_nors)[3], + const blender::Span poly_normals, float (*r_vert_nors)[3], #ifdef USE_NONMANIFOLD_WORKAROUND BLI_bitmap *edge_tmp_tag @@ -115,13 +115,13 @@ static void mesh_calc_hq_normal(Mesh *mesh, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); #else mid_v3_v3v3_angle_weighted( - edge_normal, poly_nors[edge_ref->p1], poly_nors[edge_ref->p2]); + edge_normal, poly_normals[edge_ref->p1], poly_normals[edge_ref->p2]); #endif } else { /* only one face attached to that edge */ /* an edge without another attached- the weight on this is undefined */ - copy_v3_v3(edge_normal, poly_nors[edge_ref->p1]); + copy_v3_v3(edge_normal, poly_normals[edge_ref->p1]); } add_v3_v3(r_vert_nors[edge->v1], edge_normal); add_v3_v3(r_vert_nors[edge->v2], edge_normal); @@ -131,7 +131,7 @@ static void mesh_calc_hq_normal(Mesh *mesh, } /* normalize vertex normals and assign */ - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh); + const blender::Span vert_normals = mesh->vert_normals(); for (int i = 0; i < verts_num; i++) { if (normalize_v3(r_vert_nors[i]) == 0.0f) { copy_v3_v3(r_vert_nors[i], vert_normals[i]); @@ -176,7 +176,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex int *edge_order = nullptr; float(*vert_nors)[3] = nullptr; - const float(*poly_nors)[3] = nullptr; + blender::Span poly_normals; const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) || (smd->flag & MOD_SOLIDIFY_EVEN) || @@ -205,7 +205,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex /* array size is doubled in case of using a shell */ const uint stride = do_shell ? 2 : 1; - const float(*mesh_vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh); + const blender::Span vert_normals = mesh->vert_normals(); MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index); @@ -216,7 +216,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex if (need_poly_normals) { /* calculate only face normals */ - poly_nors = BKE_mesh_poly_normals_ensure(mesh); + poly_normals = mesh->poly_normals(); } STACK_INIT(new_vert_arr, verts_num * 2); @@ -315,7 +315,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) { vert_nors = static_cast(MEM_calloc_arrayN(verts_num, sizeof(float[3]), __func__)); mesh_calc_hq_normal(mesh, - poly_nors, + poly_normals, vert_nors #ifdef USE_NONMANIFOLD_WORKAROUND , @@ -384,8 +384,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex float *result_edge_bweight = nullptr; if (do_bevel_convex) { - result_edge_bweight = static_cast(CustomData_add_layer( - &result->edata, CD_BWEIGHT, CD_SET_DEFAULT, nullptr, result->totedge)); + result_edge_bweight = static_cast( + CustomData_add_layer(&result->edata, CD_BWEIGHT, CD_SET_DEFAULT, result->totedge)); } /* Initializes: (`i_end`, `do_shell_align`, `vert_index`). */ @@ -446,8 +446,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex #endif if (mat_ofs) { - dst_material_index[i] += mat_ofs; - CLAMP(dst_material_index[i], 0, mat_nr_max); + dst_material_index[poly_i] += mat_ofs; + CLAMP(dst_material_index[poly_i], 0, mat_nr_max); } e = ml2[0].e; @@ -540,8 +540,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex for (uint i = 0; i < edges_num; i++, edge++) { if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) && !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) { - const float *n0 = poly_nors[edge_user_pairs[i][0]]; - const float *n1 = poly_nors[edge_user_pairs[i][1]]; + const float *n0 = poly_normals[edge_user_pairs[i][0]]; + const float *n1 = poly_normals[edge_user_pairs[i][1]]; sub_v3_v3v3(e, orig_vert_positions[edge->v1], orig_vert_positions[edge->v2]); normalize_v3(e); const float angle = angle_signed_on_axis_v3v3_v3(n0, n1, e); @@ -606,7 +606,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex madd_v3_v3fl(vert_positions[vert_index], vert_nors[i], ofs_new_vgroup); } else { - madd_v3_v3fl(vert_positions[vert_index], mesh_vert_normals[i], ofs_new_vgroup); + madd_v3_v3fl(vert_positions[vert_index], vert_normals[i], ofs_new_vgroup); } } } @@ -658,7 +658,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex madd_v3_v3fl(vert_positions[vert_index], vert_nors[i], ofs_new_vgroup); } else { - madd_v3_v3fl(vert_positions[vert_index], mesh_vert_normals[i], ofs_new_vgroup); + madd_v3_v3fl(vert_positions[vert_index], vert_normals[i], ofs_new_vgroup); } } } @@ -710,12 +710,12 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex vert_nors = static_cast( MEM_malloc_arrayN(verts_num, sizeof(float[3]), "mod_solid_vno")); for (i = 0; i < verts_num; i++) { - copy_v3_v3(vert_nors[i], mesh_vert_normals[i]); + copy_v3_v3(vert_nors[i], vert_normals[i]); } } for (const int64_t i : blender::IndexRange(polys_num)) { - /* #BKE_mesh_calc_poly_angles logic is inlined here */ + /* #bke::mesh::poly_angles_calc logic is inlined here */ float nor_prev[3]; float nor_next[3]; @@ -746,14 +746,15 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex if ((check_non_manifold == false) || LIKELY(!BLI_BITMAP_TEST(edge_tmp_tag, ml[i_curr].e) && !BLI_BITMAP_TEST(edge_tmp_tag, ml[i_next].e))) { - vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * + vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_normals[i]) * angle; } else { vert_angles[vidx] += angle; } #else - vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle; + vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_normals[i]) * + angle; #endif /* --- end non-angle-calc section --- */ @@ -837,8 +838,8 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex for (i = 0; i < edges_num; i++, edge++) { if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) && !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) { - const float *n0 = poly_nors[edge_user_pairs[i][0]]; - const float *n1 = poly_nors[edge_user_pairs[i][1]]; + const float *n0 = poly_normals[edge_user_pairs[i][0]]; + const float *n1 = poly_normals[edge_user_pairs[i][1]]; if (do_angle_clamp) { const float angle = M_PI - angle_normalized_v3v3(n0, n1); vert_angs[edge->v1] = max_ff(vert_angs[edge->v1], angle); @@ -970,13 +971,13 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex /* must recalculate normals with vgroups since they can displace unevenly #26888. */ if (BKE_mesh_vert_normals_are_dirty(mesh) || do_rim || dvert) { - BKE_mesh_normals_tag_dirty(result); + /* Pass. */ } else if (do_shell) { uint i; /* flip vertex normals for copied verts */ for (i = 0; i < verts_num; i++) { - negate_v3((float *)mesh_vert_normals[i]); + negate_v3((float *)&vert_normals[i].x); } } @@ -1037,7 +1038,7 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex float *result_edge_crease = nullptr; if (crease_rim || crease_outer || crease_inner) { result_edge_crease = (float *)CustomData_add_layer( - &result->edata, CD_CREASE, CD_SET_DEFAULT, nullptr, result->totedge); + &result->edata, CD_CREASE, CD_SET_DEFAULT, result->totedge); } /* add faces & edges */ @@ -1085,7 +1086,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex CustomData_copy_data( &mesh->pdata, &result->pdata, int(pidx), int((polys_num * stride) + i), 1); polys[new_poly_index].loopstart = int(j + (loops_num * stride)); - polys[new_poly_index].flag = polys[pidx].flag; /* notice we use 'polys[new_poly_index].totloop' which is later overwritten, * we could lookup the original face but there's no point since this is a copy @@ -1184,10 +1184,10 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex normalize_v3_v3(nor_cpy, edge_vert_nos[edge_orig.v1]); for (k = 0; k < 2; k++) { /* loop over both verts of the edge */ - copy_v3_v3(nor, mesh_vert_normals[*(&edge.v1 + k)]); + copy_v3_v3(nor, vert_normals[*(&edge.v1 + k)]); add_v3_v3(nor, nor_cpy); normalize_v3(nor); - copy_v3_v3((float *)mesh_vert_normals[*(&edge.v1 + k)], nor); + copy_v3_v3((float *)&vert_normals[*(&edge.v1 + k)].x, nor); } } diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc index e15d7c0b434..5dc456e0e3a 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc @@ -15,7 +15,7 @@ #include "MEM_guardedalloc.h" #include "BKE_deform.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_particle.h" #include "MOD_modifiertypes.h" @@ -207,9 +207,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, #define MOD_SOLIDIFY_EMPTY_TAG uint(-1) /* Calculate only face normals. Copied because they are modified directly below. */ - float(*poly_nors)[3] = static_cast( - MEM_malloc_arrayN(polys_num, sizeof(float[3]), __func__)); - memcpy(poly_nors, BKE_mesh_poly_normals_ensure(mesh), sizeof(float[3]) * polys_num); + blender::Array poly_nors = mesh->poly_normals(); NewFaceRef *face_sides_arr = static_cast( MEM_malloc_arrayN(polys_num * 2, sizeof(*face_sides_arr), __func__)); @@ -2004,8 +2002,8 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, float *result_edge_bweight = static_cast( CustomData_get_layer_for_write(&result->edata, CD_BWEIGHT, result->totedge)); if (bevel_convex != 0.0f || orig_vert_bweight != nullptr) { - result_edge_bweight = static_cast(CustomData_add_layer( - &result->edata, CD_BWEIGHT, CD_SET_DEFAULT, nullptr, result->totedge)); + result_edge_bweight = static_cast( + CustomData_add_layer(&result->edata, CD_BWEIGHT, CD_SET_DEFAULT, result->totedge)); } /* Checks that result has dvert data. */ @@ -2021,7 +2019,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, float *result_edge_crease = nullptr; if (vertex_crease) { result_edge_crease = (float *)CustomData_add_layer( - &result->edata, CD_CREASE, CD_SET_DEFAULT, nullptr, result->totedge); + &result->edata, CD_CREASE, CD_SET_DEFAULT, result->totedge); /* delete all vertex creases in the result if a rim is used. */ if (do_rim) { CustomData_free_layers(&result->vdata, CD_CREASE, result->totvert); @@ -2320,7 +2318,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, dst_material_index[poly_index] = most_mat_nr + (g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim); CLAMP(dst_material_index[poly_index], 0, mat_nr_max); - polys[poly_index].flag = orig_polys[most_mat_nr_face].flag; poly_index++; for (uint k = 0; g2->valid && k < j; g2++) { @@ -2395,7 +2392,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, dst_material_index[poly_index] = (src_material_index ? src_material_index[orig_face_index] : 0) + mat_ofs_rim; CLAMP(dst_material_index[poly_index], 0, mat_nr_max); - polys[poly_index].flag = face->flag; poly_index++; int loop1 = -1; @@ -2588,7 +2584,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, 0) + (fr->reversed != do_flip ? mat_ofs : 0); CLAMP(dst_material_index[poly_index], 0, mat_nr_max); - polys[poly_index].flag = fr->face->flag; if (fr->reversed != do_flip) { for (int l = int(k) - 1; l >= 0; l--) { if (shell_defgrp_index != -1) { @@ -2674,7 +2669,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, MEM_freeN(p->link_edges); } MEM_freeN(face_sides_arr); - MEM_freeN(poly_nors); } #undef MOD_SOLIDIFY_EMPTY_TAG diff --git a/source/blender/modifiers/intern/MOD_subsurf.cc b/source/blender/modifiers/intern/MOD_subsurf.cc index 412db630ee9..6619523bee6 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.cc +++ b/source/blender/modifiers/intern/MOD_subsurf.cc @@ -24,7 +24,7 @@ #include "BKE_context.h" #include "BKE_editmesh.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_scene.h" #include "BKE_screen.h" #include "BKE_subdiv.h" @@ -437,9 +437,6 @@ static void panel_draw(const bContext *C, Panel *panel) if (runtime_data->used_cpu) { uiItemL(layout, "Using both CPU and GPU subdivision", ICON_INFO); } - else { - uiItemL(layout, "Using GPU subdivision", ICON_INFO); - } } } } diff --git a/source/blender/modifiers/intern/MOD_surfacedeform.cc b/source/blender/modifiers/intern/MOD_surfacedeform.cc index 030c1694694..d13a15e724b 100644 --- a/source/blender/modifiers/intern/MOD_surfacedeform.cc +++ b/source/blender/modifiers/intern/MOD_surfacedeform.cc @@ -24,7 +24,7 @@ #include "BKE_editmesh.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" diff --git a/source/blender/modifiers/intern/MOD_triangulate.cc b/source/blender/modifiers/intern/MOD_triangulate.cc index 66ffce98c65..04726f47a5a 100644 --- a/source/blender/modifiers/intern/MOD_triangulate.cc +++ b/source/blender/modifiers/intern/MOD_triangulate.cc @@ -19,7 +19,7 @@ #include "DNA_screen_types.h" #include "BKE_context.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c index f88fb971b9c..17eabfbbd7a 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.c +++ b/source/blender/modifiers/intern/MOD_ui_common.c @@ -44,7 +44,7 @@ static bool modifier_ui_poll(const bContext *C, PanelType *UNUSED(pt)) { Object *ob = ED_object_active_context(C); - return (ob != NULL) && (ob->type != OB_GPENCIL); + return (ob != NULL) && (ob->type != OB_GPENCIL_LEGACY); } /* -------------------------------------------------------------------- */ diff --git a/source/blender/modifiers/intern/MOD_util.cc b/source/blender/modifiers/intern/MOD_util.cc index 4c8663277ab..a5c15420f28 100644 --- a/source/blender/modifiers/intern/MOD_util.cc +++ b/source/blender/modifiers/intern/MOD_util.cc @@ -26,7 +26,7 @@ #include "BKE_image.h" #include "BKE_lattice.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_object.h" diff --git a/source/blender/modifiers/intern/MOD_uvproject.cc b/source/blender/modifiers/intern/MOD_uvproject.cc index 92bd0bd77e6..ffaace78131 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.cc +++ b/source/blender/modifiers/intern/MOD_uvproject.cc @@ -25,7 +25,7 @@ #include "BKE_context.h" #include "BKE_lib_query.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_screen.h" #include "UI_interface.h" @@ -119,7 +119,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, * (e.g. if a preceding modifier could not preserve it). */ if (!CustomData_has_layer(&mesh->ldata, CD_PROP_FLOAT2)) { CustomData_add_layer_named( - &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, mesh->totloop, umd->uvlayer_name); + &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, mesh->totloop, umd->uvlayer_name); } /* make sure we're using an existing layer */ @@ -180,6 +180,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, mul_mat3_m4_v3(projectors[i].ob->object_to_world, projectors[i].normal); } + const blender::Span positions = mesh->vert_positions(); const blender::Span polys = mesh->polys(); const blender::Span loops = mesh->loops(); @@ -225,13 +226,13 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, } else { /* multiple projectors, select the closest to face normal direction */ - float face_no[3]; int j; Projector *best_projector; float best_dot; /* get the untransformed face normal */ - BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], (const float(*)[3])coords, face_no); + const blender::float3 face_no = blender::bke::mesh::poly_normal_calc( + positions, loops.slice(poly.loopstart, poly.totloop)); /* find the projector which the face points at most directly * (projector normal with largest dot product is best) diff --git a/source/blender/modifiers/intern/MOD_uvwarp.cc b/source/blender/modifiers/intern/MOD_uvwarp.cc index 4d664adfc3d..0c4c559c69b 100644 --- a/source/blender/modifiers/intern/MOD_uvwarp.cc +++ b/source/blender/modifiers/intern/MOD_uvwarp.cc @@ -23,7 +23,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc index 2c3eadc3343..abc6b5a5a88 100644 --- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc +++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc @@ -7,7 +7,7 @@ #include #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_volume.h" #include "BKE_volume_to_mesh.hh" @@ -183,9 +183,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } BKE_mesh_copy_parameters_for_eval(mesh, input_mesh); - if (vmmd->flag & VOLUME_TO_MESH_USE_SMOOTH_SHADE) { - BKE_mesh_smooth_flag_set(mesh, true); - } + BKE_mesh_smooth_flag_set(mesh, vmmd->flag & VOLUME_TO_MESH_USE_SMOOTH_SHADE); return mesh; #else UNUSED_VARS(md); diff --git a/source/blender/modifiers/intern/MOD_wave.cc b/source/blender/modifiers/intern/MOD_wave.cc index 360915a022b..a2098e1ef4e 100644 --- a/source/blender/modifiers/intern/MOD_wave.cc +++ b/source/blender/modifiers/intern/MOD_wave.cc @@ -24,7 +24,7 @@ #include "BKE_editmesh_cache.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -144,9 +144,9 @@ static void waveModifier_do(WaveModifierData *md, float falloff_fac = 1.0f; /* when falloff == 0.0f this stays at 1.0f */ const bool invert_group = (wmd->flag & MOD_WAVE_INVERT_VGROUP) != 0; - const float(*vert_normals)[3] = nullptr; + blender::Span vert_normals; if ((wmd->flag & MOD_WAVE_NORM) && (mesh != nullptr)) { - vert_normals = BKE_mesh_vert_normals_ensure(mesh); + vert_normals = mesh->vert_normals(); } if (wmd->objectcenter != nullptr) { @@ -266,7 +266,7 @@ static void waveModifier_do(WaveModifierData *md, /* Apply weight & falloff. */ amplit *= def_weight * falloff_fac; - if (vert_normals) { + if (!vert_normals.is_empty()) { /* move along normals */ if (wmd->flag & MOD_WAVE_NORM_X) { co[0] += (lifefac * amplit) * vert_normals[i][0]; diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index 4db720822a5..7dbf6ba13e8 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -23,7 +23,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_screen.h" @@ -70,10 +70,10 @@ struct WeightedNormalDataAggregateItem { struct WeightedNormalData { int verts_num; - const float (*vert_positions)[3]; - const float (*vert_normals)[3]; + blender::Span vert_positions; + blender::Span vert_normals; blender::Span edges; - bool *sharp_edges; + blender::MutableSpan sharp_edges; blender::Span loops; blender::Span loop_to_poly; @@ -82,7 +82,8 @@ struct WeightedNormalData { float split_angle; blender::Span polys; - const float (*poly_normals)[3]; + blender::Span poly_normals; + const bool *sharp_faces; const int *poly_strength; const MDeformVert *dvert; @@ -130,7 +131,7 @@ static void aggregate_item_normal(WeightedNormalModifierData *wnmd, const float curr_val, const bool use_face_influence) { - const float(*poly_normals)[3] = wn_data->poly_normals; + const blender::Span poly_normals = wn_data->poly_normals; const MDeformVert *dvert = wn_data->dvert; const int defgrp_index = wn_data->defgrp_index; @@ -183,7 +184,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, using namespace blender; const int verts_num = wn_data->verts_num; - const float(*positions)[3] = wn_data->vert_positions; + const blender::Span positions = wn_data->vert_positions; const blender::Span edges = wn_data->edges; const blender::Span polys = wn_data->polys; const blender::Span loops = wn_data->loops; @@ -191,7 +192,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, short(*clnors)[2] = wn_data->clnors; const Span loop_to_poly = wn_data->loop_to_poly; - const float(*poly_normals)[3] = wn_data->poly_normals; + const blender::Span poly_normals = wn_data->poly_normals; const int *poly_strength = wn_data->poly_strength; const MDeformVert *dvert = wn_data->dvert; @@ -208,7 +209,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, poly_strength != nullptr; const bool has_vgroup = dvert != nullptr; - float(*loop_normals)[3] = nullptr; + blender::Array loop_normals; WeightedNormalDataAggregateItem *items_data = nullptr; int items_num = 0; @@ -217,25 +218,21 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, /* This will give us loop normal spaces, * we do not actually care about computed loop_normals for now... */ - loop_normals = static_cast( - MEM_calloc_arrayN(size_t(loops.size()), sizeof(*loop_normals), __func__)); - BKE_mesh_normals_loop_split(positions, - wn_data->vert_normals, - verts_num, - edges.data(), - edges.size(), - loops.data(), - loop_normals, - loops.size(), - polys.data(), - poly_normals, - polys.size(), - true, - split_angle, - wn_data->sharp_edges, - loop_to_poly.data(), - &lnors_spacearr, - has_clnors ? clnors : nullptr); + loop_normals.reinitialize(loops.size()); + bke::mesh::normals_calc_loop(positions, + edges, + polys, + loops, + loop_to_poly, + wn_data->vert_normals, + wn_data->poly_normals, + wn_data->sharp_edges.data(), + wn_data->sharp_faces, + true, + split_angle, + has_clnors ? clnors : nullptr, + &lnors_spacearr, + loop_normals); items_num = lnors_spacearr.spaces_num; items_data = static_cast( @@ -347,19 +344,16 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, } } - BKE_mesh_normals_loop_custom_set(positions, - wn_data->vert_normals, - verts_num, - edges.data(), - edges.size(), - loops.data(), - loop_normals, - loops.size(), - polys.data(), - poly_normals, - polys.size(), - wn_data->sharp_edges, - clnors); + blender::bke::mesh::normals_loop_custom_set(positions, + edges, + polys, + loops, + wn_data->vert_normals, + poly_normals, + wn_data->sharp_faces, + wn_data->sharp_edges, + loop_normals, + clnors); } else { /* TODO: Ideally, we could add an option to `BKE_mesh_normals_loop_custom_[from_verts_]set()` @@ -371,51 +365,40 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, /* NOTE: in theory, we could avoid this extra allocation & copying... * But think we can live with it for now, * and it makes code simpler & cleaner. */ - float(*vert_normals)[3] = static_cast( - MEM_calloc_arrayN(size_t(verts_num), sizeof(*loop_normals), __func__)); + blender::Array vert_normals(verts_num, float3(0)); for (int ml_index = 0; ml_index < loops.size(); ml_index++) { const int mv_index = loops[ml_index].v; copy_v3_v3(vert_normals[mv_index], items_data[mv_index].normal); } - BKE_mesh_normals_loop_custom_from_verts_set(positions, - wn_data->vert_normals, - vert_normals, - verts_num, - edges.data(), - edges.size(), - loops.data(), - loops.size(), - polys.data(), - poly_normals, - polys.size(), - wn_data->sharp_edges, - clnors); - - MEM_freeN(vert_normals); + blender::bke::mesh::normals_loop_custom_set_from_verts(positions, + edges, + polys, + loops, + wn_data->vert_normals, + poly_normals, + wn_data->sharp_faces, + wn_data->sharp_edges, + vert_normals, + clnors); } else { - loop_normals = static_cast( - MEM_calloc_arrayN(size_t(loops.size()), sizeof(*loop_normals), __func__)); - - BKE_mesh_normals_loop_split(positions, - wn_data->vert_normals, - verts_num, - edges.data(), - edges.size(), - loops.data(), - loop_normals, - loops.size(), - polys.data(), - poly_normals, - polys.size(), - true, - split_angle, - wn_data->sharp_edges, - loop_to_poly.data(), - nullptr, - has_clnors ? clnors : nullptr); + loop_normals.reinitialize(loops.size()); + blender::bke::mesh::normals_calc_loop(positions, + edges, + polys, + loops, + loop_to_poly, + wn_data->vert_normals, + poly_normals, + wn_data->sharp_edges.data(), + wn_data->sharp_faces, + true, + split_angle, + has_clnors ? clnors : nullptr, + nullptr, + loop_normals); for (int ml_index = 0; ml_index < loops.size(); ml_index++) { const int item_index = loops[ml_index].v; @@ -423,32 +406,27 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, copy_v3_v3(loop_normals[ml_index], items_data[item_index].normal); } } - - BKE_mesh_normals_loop_custom_set(positions, - wn_data->vert_normals, - verts_num, - edges.data(), - edges.size(), - loops.data(), - loop_normals, - loops.size(), - polys.data(), - poly_normals, - polys.size(), - wn_data->sharp_edges, - clnors); + blender::bke::mesh::normals_loop_custom_set(positions, + edges, + polys, + loops, + wn_data->vert_normals, + poly_normals, + wn_data->sharp_faces, + wn_data->sharp_edges, + loop_normals, + clnors); } } if (keep_sharp) { BKE_lnor_spacearr_free(&lnors_spacearr); } - MEM_SAFE_FREE(loop_normals); } static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) { - const float(*positions)[3] = wn_data->vert_positions; + const blender::Span positions = wn_data->vert_positions; const blender::Span polys = wn_data->polys; const blender::Span loops = wn_data->loops; @@ -457,7 +435,8 @@ static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *w ModePair *f_area = face_area; for (const int i : polys.index_range()) { - f_area[i].val = BKE_mesh_calc_poly_area(&polys[i], &loops[polys[i].loopstart], positions); + f_area[i].val = blender::bke::mesh::poly_area_calc( + positions, loops.slice(polys[i].loopstart, polys[i].totloop)); f_area[i].index = i; } @@ -469,7 +448,7 @@ static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *w static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) { - const float(*positions)[3] = wn_data->vert_positions; + const blender::Span positions = wn_data->vert_positions; const blender::Span polys = wn_data->polys; const blender::Span loops = wn_data->loops; @@ -480,7 +459,8 @@ static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData const MPoly &poly = polys[i]; float *index_angle = static_cast( MEM_malloc_arrayN(poly.totloop, sizeof(*index_angle), __func__)); - BKE_mesh_calc_poly_angles(&poly, &loops[poly.loopstart], positions, index_angle); + blender::bke::mesh::poly_angles_calc( + positions, loops.slice(poly.loopstart, poly.totloop), {index_angle, poly.totloop}); ModePair *c_angl = &corner_angle[poly.loopstart]; float *angl = index_angle; @@ -500,7 +480,7 @@ static void wn_corner_angle(WeightedNormalModifierData *wnmd, WeightedNormalData static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) { - const float(*positions)[3] = wn_data->vert_positions; + const blender::Span positions = wn_data->vert_positions; const blender::Span polys = wn_data->polys; const blender::Span loops = wn_data->loops; @@ -509,10 +489,11 @@ static void wn_face_with_angle(WeightedNormalModifierData *wnmd, WeightedNormalD for (const int i : polys.index_range()) { const MPoly &poly = polys[i]; - float face_area = BKE_mesh_calc_poly_area(&poly, &loops[poly.loopstart], positions); + const blender::Span poly_loops = loops.slice(poly.loopstart, poly.totloop); + const float face_area = blender::bke::mesh::poly_area_calc(positions, poly_loops); float *index_angle = static_cast( MEM_malloc_arrayN(size_t(poly.totloop), sizeof(*index_angle), __func__)); - BKE_mesh_calc_poly_angles(&poly, &loops[poly.loopstart], positions, index_angle); + blender::bke::mesh::poly_angles_calc(positions, poly_loops, {index_angle, poly.totloop}); ModePair *cmbnd = &combined[poly.loopstart]; float *angl = index_angle; @@ -557,7 +538,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * result = (Mesh *)BKE_id_copy_ex(nullptr, &mesh->id, nullptr, LIB_ID_COPY_LOCALIZE); const int verts_num = result->totvert; - const float(*positions)[3] = BKE_mesh_vert_positions(result); + const blender::Span positions = mesh->vert_positions(); const blender::Span edges = mesh->edges(); const blender::Span polys = mesh->polys(); const blender::Span loops = mesh->loops(); @@ -587,8 +568,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * * it helps when generating clnor spaces and default normals. */ const bool has_clnors = clnors != nullptr; if (!clnors) { - clnors = static_cast(CustomData_add_layer( - &result->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, loops.size())); + clnors = static_cast( + CustomData_add_layer(&result->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, loops.size())); } const MDeformVert *dvert; @@ -606,9 +587,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * wn_data.verts_num = verts_num; wn_data.vert_positions = positions; - wn_data.vert_normals = BKE_mesh_vert_normals_ensure(result); + wn_data.vert_normals = result->vert_normals(); wn_data.edges = edges; - wn_data.sharp_edges = sharp_edges.span.data(); + wn_data.sharp_edges = sharp_edges.span; wn_data.loops = loops; wn_data.loop_to_poly = loop_to_poly_map; @@ -617,7 +598,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * wn_data.split_angle = split_angle; wn_data.polys = polys; - wn_data.poly_normals = BKE_mesh_poly_normals_ensure(mesh); + wn_data.poly_normals = mesh->poly_normals(); + wn_data.sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); wn_data.poly_strength = static_cast(CustomData_get_layer_named( &result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID)); diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.cc b/source/blender/modifiers/intern/MOD_weightvgedit.cc index e8a2795aa79..e5b0e830fe9 100644 --- a/source/blender/modifiers/intern/MOD_weightvgedit.cc +++ b/source/blender/modifiers/intern/MOD_weightvgedit.cc @@ -27,7 +27,7 @@ #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_screen.h" #include "BKE_texture.h" /* Texture masking. */ diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.cc b/source/blender/modifiers/intern/MOD_weightvgmix.cc index c766d117db8..370eff8b8de 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.cc +++ b/source/blender/modifiers/intern/MOD_weightvgmix.cc @@ -23,7 +23,7 @@ #include "BKE_customdata.h" #include "BKE_deform.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_modifier.h" #include "BKE_screen.h" #include "BKE_texture.h" /* Texture masking. */ diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.cc b/source/blender/modifiers/intern/MOD_weightvgproximity.cc index 917311f68d1..270283b0f30 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.cc +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.cc @@ -31,7 +31,7 @@ #include "BKE_deform.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" #include "BKE_screen.h" diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h index 7b6244042f8..e904b436281 100644 --- a/source/blender/nodes/NOD_common.h +++ b/source/blender/nodes/NOD_common.h @@ -21,8 +21,6 @@ struct bNodeSocket *node_group_find_output_socket(struct bNode *groupnode, const struct bNodeSocket *node_group_input_find_socket(struct bNode *node, const char *identifier); struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char *identifier); -void node_internal_links_create(struct bNodeTree *ntree, struct bNode *node); - #ifdef __cplusplus } #endif diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 208d51f13d3..baacd1bedbe 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -194,8 +194,6 @@ class GeoNodeExecParams { /** * Returns true when the output has to be computed. - * Nodes that support laziness could use the #lazy_output_is_required variant to possibly avoid - * some computations. */ bool output_is_required(StringRef identifier) const { @@ -203,29 +201,6 @@ class GeoNodeExecParams { return params_.get_output_usage(index) != lf::ValueUsage::Unused; } - /** - * Tell the evaluator that a specific input is required. - * This returns true when the input will only be available in the next execution. - * False is returned if the input is available already. - * This can only be used when the node supports laziness. - */ - bool lazy_require_input(StringRef identifier) - { - const int index = this->get_input_index(identifier); - return params_.try_get_input_data_ptr_or_request(index) == nullptr; - } - - /** - * Asks the evaluator if a specific output is required right now. If this returns false, the - * value might still need to be computed later. - * This can only be used when the node supports laziness. - */ - bool lazy_output_is_required(StringRef identifier) - { - const int index = this->get_output_index(identifier); - return params_.get_output_usage(index) == lf::ValueUsage::Used; - } - /** * Get the node that is currently being executed. */ diff --git a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh index 793798c4974..7401fbfca8c 100644 --- a/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh +++ b/source/blender/nodes/NOD_geometry_nodes_lazy_function.hh @@ -221,6 +221,8 @@ class GeometryNodesLazyFunctionLogger : public fn::lazy_function::GraphExecutor: const lf::Context &context) const override; }; +std::unique_ptr get_switch_node_lazy_function(const bNode &node); + /** * Tells the lazy-function graph evaluator which nodes have side effects based on the current * context. For example, the same viewer node can have side effects in one context, but not in diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index cb97e88ac9f..efccef2bed9 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -337,7 +337,7 @@ DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", Inpu DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS",InputMeshEdgeNeighbors, "Edge Neighbors", "Retrieve the number of faces that use each edge as one of their sides") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "Retrieve topology information relating to each edge of a mesh") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "Calculate the surface area of a mesh's faces") -DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_IS_PLANAR, 0, "MESH_FACE_IS_PLANAR",InputMeshFaceIsPlanar, "Is Face Planar", "Retrieve whether all triangles in a face are on the same plane, i.e. whether have the same normal") +DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_IS_PLANAR, 0, "MESH_FACE_IS_PLANAR", InputMeshFaceIsPlanar, "Is Face Planar", "Retrieve whether all triangles in a face are on the same plane, i.e. whether they have the same normal") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, 0, "MESH_FACE_NEIGHBORS",InputMeshFaceNeighbors, "Face Neighbors", "Retrieve topology information relating to each face of a mesh") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_ISLAND, 0, "MESH_ISLAND", InputMeshIsland, "Mesh Island", "Retrieve information about separate connected regions in a mesh") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, 0, "MESH_VERTEX_NEIGHBORS", InputMeshVertexNeighbors, "Vertex Neighbors", "Retrieve topology information relating to each vertex of a mesh") diff --git a/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc index 35a1261001a..be81362cc60 100644 --- a/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_val_to_rgb.cc @@ -92,6 +92,10 @@ class ColorRampShaderNode : public ShaderNode { GPU_uniform(&color_band->data[0].r), GPU_uniform(&color_band->data[1].r)); return; + case COLBAND_INTERP_B_SPLINE: + case COLBAND_INTERP_CARDINAL: + /* Not optimized yet. Fallback to gradient texture. */ + break; default: BLI_assert_unreachable(); return; diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 516a1994efc..6ba11d3620e 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -6,7 +6,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_pointcloud.h" diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index aa755d229a2..7823bf3ac08 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -66,13 +66,6 @@ Mesh *create_cylinder_or_cone_mesh(float radius_top, GeometryNodeMeshCircleFillType fill_type, ConeAttributeOutputs &attribute_outputs); -/** - * Copies the point domain attributes from `in_component` that are in the mask to `out_component`. - */ -void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, - GeometryComponent &result_component, - Span masks, - bool invert); /** * Returns the parts of the geometry that are on the selection for the given domain. If the domain * is not applicable for the component, e.g. face domain for point cloud, nothing happens to that diff --git a/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc index 77bfa7a2b58..4c2a1336e02 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc @@ -15,7 +15,7 @@ #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_geometry_fields.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "UI_interface.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 33dc6bec641..0866074ebab 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -6,7 +6,7 @@ #include "BKE_curves.hh" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" @@ -43,6 +43,7 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span coords) result = BKE_mesh_new_nomain(verts_num, edges_num, loops_num, faces_num); BKE_id_material_eval_ensure_default_slot(&result->id); } + BKE_mesh_smooth_flag_set(result, false); /* Copy vertices. */ MutableSpan dst_positions = result->vert_positions_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 9bb358f2cd9..c64259a8f00 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -8,7 +8,7 @@ #include "DNA_meshdata_types.h" #include "BKE_curves.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_task.hh" @@ -105,6 +105,7 @@ static Mesh *cdt_to_mesh(const meshintersect::CDT_result &result) /* The delaunay triangulation doesn't seem to return all of the necessary edges, even in * triangulation mode. */ BKE_mesh_calc_edges(mesh, true, false); + BKE_mesh_smooth_flag_set(mesh, false); return mesh; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc index 24c3526087e..f7279cdfe7e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc @@ -4,7 +4,7 @@ #include "BKE_curves.hh" #include "BKE_editmesh.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index a152293259d..f89945f89ee 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -14,7 +14,7 @@ #include "BKE_curves.hh" #include "BKE_customdata.h" #include "BKE_instances.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index 0e459566d47..3ba718f211a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -12,7 +12,7 @@ #include "BKE_attribute_math.hh" #include "BKE_bvhutils.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_sample.hh" #include "BKE_pointcloud.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 11c7f60909f..207e30992ef 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -7,7 +7,7 @@ #include "DNA_meshdata_types.h" #include "BKE_attribute_math.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "node_geometry_util.hh" @@ -140,6 +140,7 @@ static void transfer_attributes( * Remove anonymous attributes that don't need to be propagated. */ Set attribute_ids = src_attributes.all_ids(); attribute_ids.remove("position"); + attribute_ids.remove("sharp_face"); attribute_ids.remove_if([&](const AttributeIDRef &id) { return id.is_anonymous() && !propagation_info.propagate(id.anonymous_id()); }); @@ -677,10 +678,8 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, Vector vert_positions(src_mesh.totpoly); for (const int i : src_polys.index_range()) { const MPoly &poly = src_polys[i]; - BKE_mesh_calc_poly_center(&poly, - &src_loops[poly.loopstart], - reinterpret_cast(src_positions.data()), - vert_positions[i]); + vert_positions[i] = bke::mesh::poly_center_calc(src_positions, + src_loops.slice(poly.loopstart, poly.totloop)); } Array boundary_edge_midpoint_index; @@ -887,6 +886,7 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, } Mesh *mesh_out = BKE_mesh_new_nomain( vert_positions.size(), new_edges.size(), loops.size(), loop_lengths.size()); + BKE_mesh_smooth_flag_set(mesh_out, false); transfer_attributes(vertex_types, keep_boundaries, diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc index 0ceff398174..d2efdbbddcc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc @@ -14,7 +14,7 @@ #include "BKE_attribute_math.hh" #include "BKE_curves.hh" #include "BKE_instances.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "node_geometry_util.hh" @@ -322,7 +322,7 @@ static void duplicate_curves(GeometrySet &geometry_set, int dst_curves_num = 0; int dst_points_num = 0; for (const int i_curve : selection.index_range()) { - const int count = std::max(counts[selection[i_curve]], 0); + const int count = counts[selection[i_curve]]; curve_offset_data[i_curve] = dst_curves_num; point_offset_data[i_curve] = dst_points_num; dst_curves_num += count; @@ -498,7 +498,7 @@ static void duplicate_faces(GeometrySet &geometry_set, int total_loops = 0; Array offset_data(selection.size() + 1); for (const int i_selection : selection.index_range()) { - const int count = std::max(counts[selection[i_selection]], 0); + const int count = counts[selection[i_selection]]; offset_data[i_selection] = total_polys; total_polys += count; total_loops += count * polys[selection[i_selection]].totloop; @@ -1042,7 +1042,13 @@ static void node_geo_exec(GeoNodeExecParams params) const NodeGeometryDuplicateElements &storage = node_storage(params.node()); const eAttrDomain duplicate_domain = eAttrDomain(storage.domain); - Field count_field = params.extract_input>("Amount"); + static auto max_zero_fn = mf::build::SI1_SO( + "max_zero", + [](int value) { return std::max(0, value); }, + mf::build::exec_presets::AllSpanOrSingle()); + Field count_field( + FieldOperation::Create(max_zero_fn, {params.extract_input>("Amount")})); + Field selection_field = params.extract_input>("Selection"); IndexAttributes attribute_outputs; attribute_outputs.duplicate_index = params.get_output_anonymous_attribute_id_if_needed( diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc index d9a9b7fdcfe..dc705914919 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_paths_to_selection.cc @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "BKE_attribute_math.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_map.hh" #include "BLI_set.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_edges_to_face_groups.cc b/source/blender/nodes/geometry/nodes/node_geo_edges_to_face_groups.cc index b89ad0dfd14..cc27c4e9fe3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edges_to_face_groups.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edges_to_face_groups.cc @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BLI_atomic_disjoint_set.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 86a9d2b794d..c1afbf2a0fa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -9,7 +9,7 @@ #include "DNA_meshdata_types.h" #include "BKE_attribute_math.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" @@ -160,7 +160,6 @@ static MPoly new_poly(const int loopstart, const int totloop) MPoly poly; poly.loopstart = loopstart; poly.totloop = totloop; - poly.flag = 0; return poly; } @@ -1089,7 +1088,7 @@ static void extrude_individual_mesh_faces(Mesh &mesh, /* For every selected polygon, change it to use the new extruded vertices and the duplicate * edges, and build the faces that form the sides of the extrusion. Build "original index" * arrays for the new vertices and edges so they can be accessed later. - + * * Filling some of this data like the new edges or polygons could be easily split into * separate loops, which may or may not be faster, but would involve more duplication. */ Array new_vert_indices(extrude_corner_size); diff --git a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc index 9d5e9390d5b..14e2449d80d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_flip_faces.cc @@ -2,7 +2,7 @@ #include "BLI_task.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_attribute_math.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc index c508814caa8..ab31ab3c218 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_instance_rotation.cc @@ -22,7 +22,7 @@ class InstanceRotationFieldInput final : public bke::InstancesFieldInput { GVArray get_varray_for_context(const bke::Instances &instances, IndexMask /*mask*/) const final { auto rotation_fn = [&](const int i) -> float3 { - return float3(math::to_euler(instances.transforms()[i])); + return float3(math::to_euler(math::normalize(instances.transforms()[i]))); }; return VArray::ForFunc(instances.instances_num(), rotation_fn); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc index 9f3a355498c..e2e20237470 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc @@ -6,7 +6,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" @@ -79,15 +79,10 @@ class AngleFieldInput final : public bke::MeshFieldInput { } const MPoly &poly_1 = polys[edge_map[i].face_index_1]; const MPoly &poly_2 = polys[edge_map[i].face_index_2]; - float3 normal_1, normal_2; - BKE_mesh_calc_poly_normal(&poly_1, - &loops[poly_1.loopstart], - reinterpret_cast(positions.data()), - normal_1); - BKE_mesh_calc_poly_normal(&poly_2, - &loops[poly_2.loopstart], - reinterpret_cast(positions.data()), - normal_2); + const float3 normal_1 = bke::mesh::poly_normal_calc( + positions, loops.slice(poly_1.loopstart, poly_1.totloop)); + const float3 normal_2 = bke::mesh::poly_normal_calc( + positions, loops.slice(poly_2.loopstart, poly_2.totloop)); return angle_normalized_v3v3(normal_1, normal_2); }; @@ -138,26 +133,18 @@ class SignedAngleFieldInput final : public bke::MeshFieldInput { const MPoly &poly_2 = polys[edge_map[i].face_index_2]; /* Find the normals of the 2 polys. */ - float3 poly_1_normal, poly_2_normal; - BKE_mesh_calc_poly_normal(&poly_1, - &loops[poly_1.loopstart], - reinterpret_cast(positions.data()), - poly_1_normal); - BKE_mesh_calc_poly_normal(&poly_2, - &loops[poly_2.loopstart], - reinterpret_cast(positions.data()), - poly_2_normal); + const float3 poly_1_normal = bke::mesh::poly_normal_calc( + positions, loops.slice(poly_1.loopstart, poly_1.totloop)); + const float3 poly_2_normal = bke::mesh::poly_normal_calc( + positions, loops.slice(poly_2.loopstart, poly_2.totloop)); /* Find the centerpoint of the axis edge */ const float3 edge_centerpoint = (positions[edges[i].v1] + positions[edges[i].v2]) * 0.5f; /* Get the centerpoint of poly 2 and subtract the edge centerpoint to get a tangent * normal for poly 2. */ - float3 poly_center_2; - BKE_mesh_calc_poly_center(&poly_2, - &loops[poly_2.loopstart], - reinterpret_cast(positions.data()), - poly_center_2); + const float3 poly_center_2 = bke::mesh::poly_center_calc( + positions, loops.slice(poly_2.loopstart, poly_2.totloop)); const float3 poly_2_tangent = math::normalize(poly_center_2 - edge_centerpoint); const float concavity = math::dot(poly_1_normal, poly_2_tangent); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc index 97c950988e7..9fc5b361b5a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc @@ -3,7 +3,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc index 667beeefd2f..01211d32435 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc @@ -3,7 +3,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc index d9f5f4b82a3..d8aeac6df8f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc @@ -3,7 +3,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" @@ -24,8 +24,7 @@ static VArray construct_face_area_varray(const Mesh &mesh, const eAttrDom auto area_fn = [positions, polys, loops](const int i) -> float { const MPoly &poly = polys[i]; - return BKE_mesh_calc_poly_area( - &poly, &loops[poly.loopstart], reinterpret_cast(positions.data())); + return bke::mesh::poly_area_calc(positions, loops.slice(poly.loopstart, poly.totloop)); }; return mesh.attributes().adapt_domain( diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc index 61fad459561..71ab9ab3018 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_is_planar.cc @@ -5,7 +5,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc index f1724ef4a41..a4b71941c23 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc @@ -3,7 +3,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc index d2a66986abd..59c52da20e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc @@ -3,7 +3,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_atomic_disjoint_set.hh" #include "BLI_task.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc index 5b1b32c7b9c..2fb8e4f54fa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc @@ -3,7 +3,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc index 54279719bd4..dd54bf1136e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc @@ -11,8 +11,8 @@ static void node_declare(NodeDeclarationBuilder &b) static void node_geo_exec(GeoNodeExecParams params) { - Field shade_smooth_field = AttributeFieldInput::Create("shade_smooth"); - params.set_output("Smooth", std::move(shade_smooth_field)); + Field shade_smooth_field = AttributeFieldInput::Create("sharp_face"); + params.set_output("Smooth", fn::invert_boolean_field(shade_smooth_field)); } } // namespace blender::nodes::node_geo_input_shade_smooth_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc index 2eb41ea7435..ce3d460540b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_shortest_edge_paths.cc @@ -7,7 +7,7 @@ #include "BLI_set.hh" #include "BLI_task.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_group_boundaries.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_group_boundaries.cc index a2befdb31b2..90f7677f456 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_group_boundaries.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_group_boundaries.cc @@ -3,7 +3,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index 3a871f2291f..d85d153972e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc @@ -4,7 +4,7 @@ #include "DNA_meshdata_types.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "UI_interface.h" #include "UI_resources.h" @@ -112,6 +112,7 @@ static Mesh *create_circle_mesh(const float radius, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); /* Assign vertex coordinates. */ const float angle_delta = 2.0f * (M_PI / float(verts_num)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 15cea9d5db4..3145211d1d8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -4,7 +4,7 @@ #include "DNA_meshdata_types.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "UI_interface.h" #include "UI_resources.h" @@ -692,6 +692,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); calculate_cone_verts(config, positions); calculate_cone_edges(config, edges); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc index 88fb4c72b1a..3af830562d9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc @@ -4,7 +4,7 @@ #include "DNA_meshdata_types.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "GEO_mesh_primitive_cuboid.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc index bc651cdb652..5c6f206f04d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc @@ -4,7 +4,7 @@ #include "DNA_meshdata_types.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 9534160cccd..2d366debda7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -6,7 +6,7 @@ #include "DNA_meshdata_types.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "UI_interface.h" #include "UI_resources.h" @@ -57,6 +57,7 @@ Mesh *create_grid_mesh(const int verts_x, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); { const float dx = edges_x == 0 ? 0.0f : size_x / edges_x; @@ -147,6 +148,9 @@ Mesh *create_grid_mesh(const int verts_x, mesh->loose_edges_tag_none(); + const float3 bounds = float3(size_x * 0.5f, size_y * 0.5f, 0.0f); + mesh->bounds_set_eager({-bounds, bounds}); + return mesh; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc index d1387ca5cdc..dd5def9c706 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc @@ -4,7 +4,7 @@ #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "bmesh.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc index 12cb9f81d12..416076cf486 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc @@ -7,7 +7,7 @@ #include "BLI_task.hh" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index 45aed66e35e..41a48e7bc73 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -6,7 +6,7 @@ #include "DNA_meshdata_types.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "UI_interface.h" #include "UI_resources.h" @@ -315,6 +315,7 @@ static Mesh *create_uv_sphere_mesh(const float radius, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); threading::parallel_invoke( 1024 < segments * rings, diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index c4ef7f8944f..2fbb3438401 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_subdiv.h" #include "BKE_subdiv_mesh.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc index 6c0e7b4fa7e..117971602a4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_volume.cc @@ -4,7 +4,7 @@ #include "node_geometry_util.hh" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" #include "BKE_object.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc index 55c70095236..9d359848bc6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_face.cc @@ -2,7 +2,7 @@ #include "BLI_task.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc index 81608271d5b..2a115560d7e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BLI_task.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc index 833f5f26f6c..ecec64c0950 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BLI_task.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc index 8fd1ffa5148..e4a30e506c9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BLI_task.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc index 4a7b1bbfbdb..c572a52a93d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc index d4e6aa6e4ef..45b21836acc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "BLI_task.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc index 8f631c87311..59ce296b1e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_vertex_of_corner.cc @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BLI_task.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 6a7dc3bb59a..92ac14046ec 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -5,7 +5,7 @@ #include "DNA_pointcloud_types.h" #include "BKE_attribute_math.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc index 04c0afa2f38..ea1c5ddd17d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc @@ -54,11 +54,11 @@ static void rotate_instances(GeoNodeExecParams ¶ms, bke::Instances &instance /* Create rotations around the individual axis. This could be optimized to skip some axis * when the angle is zero. */ const float3x3 rotation_x = from_rotation( - AxisAngle(instance_transform.x_axis(), euler.x)); + AxisAngle(normalize(instance_transform.x_axis()), euler.x)); const float3x3 rotation_y = from_rotation( - AxisAngle(instance_transform.y_axis(), euler.y)); + AxisAngle(normalize(instance_transform.y_axis()), euler.y)); const float3x3 rotation_z = from_rotation( - AxisAngle(instance_transform.z_axis(), euler.z)); + AxisAngle(normalize(instance_transform.z_axis()), euler.z)); /* Combine the previously computed rotations into the final rotation matrix. */ rotation_matrix = float4x4(rotation_z * rotation_y * rotation_x); diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc index abe5be3c182..e8de583d6e6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest.cc @@ -3,7 +3,7 @@ #include "DNA_pointcloud_types.h" #include "BKE_bvhutils.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "UI_interface.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc index 092689b6b3b..65946ee947f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_nearest_surface.cc @@ -5,7 +5,7 @@ #include "BKE_attribute_math.hh" #include "BKE_bvhutils.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_sample.hh" #include "UI_interface.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc index 2da0e088598..41cf26b38c2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_sample_uv_surface.cc @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "BKE_attribute_math.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_type_conversions.hh" #include "UI_interface.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc index cd0342ffedb..819084cb9fa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_elements.cc @@ -13,7 +13,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc index aa2930cfed9..0222515b9a4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc @@ -12,7 +12,7 @@ #include "DNA_volume_types.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" namespace blender::nodes::node_geo_set_material_cc { diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc index 2f13bc1f591..57781534d63 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc @@ -8,7 +8,7 @@ #include "DNA_meshdata_types.h" #include "BKE_curves.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc index 7dd721288ac..af80cf75e2e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc @@ -14,36 +14,63 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output(N_("Geometry")).propagate_all(); } -static void set_smooth(Mesh &mesh, - const Field &selection_field, - const Field &shade_field) +/** + * When the `sharp_face` attribute doesn't exist, all faces are considered smooth. If all faces + * are selected and the sharp value is a constant false value, we can remove the attribute instead + * as an optimization to avoid storing it and propagating it in the future. + */ +static bool try_removing_sharp_attribute(Mesh &mesh, + const Field &selection_field, + const Field &sharp_field) +{ + if (selection_field.node().depends_on_input() || sharp_field.node().depends_on_input()) { + return false; + } + const bool selection = fn::evaluate_constant_field(selection_field); + if (!selection) { + return true; + } + const bool sharp = fn::evaluate_constant_field(sharp_field); + if (sharp) { + return false; + } + mesh.attributes_for_write().remove("sharp_face"); + return true; +} + +static void set_sharp_faces(Mesh &mesh, + const Field &selection_field, + const Field &sharp_field) { if (mesh.totpoly == 0) { return; } + if (try_removing_sharp_attribute(mesh, selection_field, sharp_field)) { + return; + } MutableAttributeAccessor attributes = mesh.attributes_for_write(); - AttributeWriter smooth = attributes.lookup_or_add_for_write("shade_smooth", - ATTR_DOMAIN_FACE); + AttributeWriter sharp_faces = attributes.lookup_or_add_for_write("sharp_face", + ATTR_DOMAIN_FACE); bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE}; fn::FieldEvaluator evaluator{field_context, mesh.totpoly}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(shade_field, smooth.varray); + evaluator.add_with_destination(sharp_field, sharp_faces.varray); evaluator.evaluate(); - smooth.finish(); + sharp_faces.finish(); } static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Geometry"); Field selection_field = params.extract_input>("Selection"); - Field shade_field = params.extract_input>("Shade Smooth"); + Field smooth_field = params.extract_input>("Shade Smooth"); geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { - set_smooth(*mesh, selection_field, shade_field); + set_sharp_faces(*mesh, selection_field, fn::invert_boolean_field(smooth_field)); } }); params.set_output("Geometry", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 69d82f0cb4e..f643fe22489 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -7,7 +7,7 @@ #include "DNA_modifier_types.h" #include "BKE_attribute.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_subdiv.h" #include "BKE_subdiv_mesh.hh" @@ -74,7 +74,7 @@ static void write_vertex_creases(Mesh &mesh, const VArray &crease_varray) } else { crease = static_cast( - CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_CONSTRUCT, nullptr, mesh.totvert)); + CustomData_add_layer(&mesh.vdata, CD_CREASE, CD_CONSTRUCT, mesh.totvert)); } materialize_and_clamp_creases(crease_varray, {crease, mesh.totvert}); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc index 6873c557310..d4d7ecf6ae3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc @@ -5,14 +5,9 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "DNA_mesh_types.h" -#include "DNA_meshdata_types.h" - -#include "BKE_material.h" - #include "NOD_socket_search_link.hh" -#include "FN_multi_function_signature.hh" +#include "FN_field_cpp_type.hh" namespace blender::nodes::node_geo_switch_cc { @@ -149,149 +144,128 @@ static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) } } -template void switch_fields(GeoNodeExecParams ¶ms, const StringRef suffix) -{ - if (params.lazy_require_input("Switch")) { - return; +class LazyFunctionForSwitchNode : public LazyFunction { + public: + LazyFunctionForSwitchNode(const bNode &node) + { + const NodeSwitch &storage = node_storage(node); + const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.input_type); + const bNodeSocketType *socket_type = nullptr; + for (const bNodeSocket *socket : node.output_sockets()) { + if (socket->type == data_type) { + socket_type = socket->typeinfo; + break; + } + } + BLI_assert(socket_type != nullptr); + const CPPType &cpp_type = *socket_type->geometry_nodes_cpp_type; + + inputs_.append_as("Condition", CPPType::get>()); + inputs_.append_as("False", cpp_type, lf::ValueUsage::Maybe); + inputs_.append_as("True", cpp_type, lf::ValueUsage::Maybe); + outputs_.append_as("Value", cpp_type); } - const std::string name_false = "False" + suffix; - const std::string name_true = "True" + suffix; - const std::string name_output = "Output" + suffix; + void execute_impl(lf::Params ¶ms, const lf::Context & /*context*/) const override + { + const ValueOrField condition = params.get_input>(0); + if (condition.is_field()) { + Field condition_field = condition.as_field(); + if (condition_field.node().depends_on_input()) { + this->execute_field(condition.as_field(), params); + return; + } + const bool condition_bool = fn::evaluate_constant_field(condition_field); + this->execute_single(condition_bool, params); + return; + } + this->execute_single(condition.as_value(), params); + } - Field switches_field = params.get_input>("Switch"); - if (switches_field.node().depends_on_input()) { - /* The switch has to be incorporated into the field. Both inputs have to be evaluated. */ - const bool require_false = params.lazy_require_input(name_false); - const bool require_true = params.lazy_require_input(name_true); - if (require_false | require_true) { + static constexpr int false_input_index = 1; + static constexpr int true_input_index = 2; + + void execute_single(const bool condition, lf::Params ¶ms) const + { + const int input_to_forward = condition ? true_input_index : false_input_index; + const int input_to_ignore = condition ? false_input_index : true_input_index; + + params.set_input_unused(input_to_ignore); + void *value_to_forward = params.try_get_input_data_ptr_or_request(input_to_forward); + if (value_to_forward == nullptr) { + /* Try again when the value is available. */ return; } - Field falses_field = params.extract_input>(name_false); - Field trues_field = params.extract_input>(name_true); + const CPPType &type = *outputs_[0].type; + void *output_ptr = params.get_output_data_ptr(0); + type.move_construct(value_to_forward, output_ptr); + params.output_set(0); + } - static auto switch_fn = mf::build::SI3_SO( - "Switch", [](bool condition, const T &false_value, const T &true_value) { - return condition ? true_value : false_value; + void execute_field(Field condition, lf::Params ¶ms) const + { + /* When the condition is a non-constant field, we need both inputs. */ + void *false_value_or_field = params.try_get_input_data_ptr_or_request(false_input_index); + void *true_value_or_field = params.try_get_input_data_ptr_or_request(true_input_index); + if (ELEM(nullptr, false_value_or_field, true_value_or_field)) { + /* Try again when inputs are available. */ + return; + } + + const CPPType &type = *outputs_[0].type; + const fn::ValueOrFieldCPPType &value_or_field_type = *fn::ValueOrFieldCPPType::get_from_self( + type); + const CPPType &value_type = value_or_field_type.value; + const MultiFunction &switch_multi_function = this->get_switch_multi_function(value_type); + + GField false_field = value_or_field_type.as_field(false_value_or_field); + GField true_field = value_or_field_type.as_field(true_value_or_field); + + GField output_field{FieldOperation::Create( + switch_multi_function, + {std::move(condition), std::move(false_field), std::move(true_field)})}; + + void *output_ptr = params.get_output_data_ptr(0); + value_or_field_type.construct_from_field(output_ptr, std::move(output_field)); + params.output_set(0); + } + + const MultiFunction &get_switch_multi_function(const CPPType &type) const + { + const MultiFunction *switch_multi_function = nullptr; + type.to_static_type_tag( + [&](auto type_tag) { + using T = typename decltype(type_tag)::type; + if constexpr (std::is_void_v) { + BLI_assert_unreachable(); + } + else { + static auto switch_fn = mf::build::SI3_SO( + "Switch", [](const bool condition, const T &false_value, const T &true_value) { + return condition ? true_value : false_value; + }); + switch_multi_function = &switch_fn; + } }); - - auto switch_op = std::make_shared(FieldOperation( - std::move(switch_fn), - {std::move(switches_field), std::move(falses_field), std::move(trues_field)})); - - params.set_output(name_output, Field(switch_op, 0)); + BLI_assert(switch_multi_function != nullptr); + return *switch_multi_function; } - else { - /* The switch input is constant, so just evaluate and forward one of the inputs. */ - const bool switch_value = fn::evaluate_constant_field(switches_field); - if (switch_value) { - params.set_input_unused(name_false); - if (params.lazy_require_input(name_true)) { - return; - } - params.set_output(name_output, params.extract_input>(name_true)); - } - else { - params.set_input_unused(name_true); - if (params.lazy_require_input(name_false)) { - return; - } - params.set_output(name_output, params.extract_input>(name_false)); - } - } -} - -template void switch_no_fields(GeoNodeExecParams ¶ms, const StringRef suffix) -{ - if (params.lazy_require_input("Switch_001")) { - return; - } - bool switch_value = params.get_input("Switch_001"); - - const std::string name_false = "False" + suffix; - const std::string name_true = "True" + suffix; - const std::string name_output = "Output" + suffix; - - if (switch_value) { - params.set_input_unused(name_false); - if (params.lazy_require_input(name_true)) { - return; - } - params.set_output(name_output, params.extract_input(name_true)); - } - else { - params.set_input_unused(name_true); - if (params.lazy_require_input(name_false)) { - return; - } - params.set_output(name_output, params.extract_input(name_false)); - } -} - -static void node_geo_exec(GeoNodeExecParams params) -{ - const NodeSwitch &storage = node_storage(params.node()); - const eNodeSocketDatatype data_type = eNodeSocketDatatype(storage.input_type); - - switch (data_type) { - - case SOCK_FLOAT: { - switch_fields(params, ""); - break; - } - case SOCK_INT: { - switch_fields(params, "_001"); - break; - } - case SOCK_BOOLEAN: { - switch_fields(params, "_002"); - break; - } - case SOCK_VECTOR: { - switch_fields(params, "_003"); - break; - } - case SOCK_RGBA: { - switch_fields(params, "_004"); - break; - } - case SOCK_STRING: { - switch_fields(params, "_005"); - break; - } - case SOCK_GEOMETRY: { - switch_no_fields(params, "_006"); - break; - } - case SOCK_OBJECT: { - switch_no_fields(params, "_007"); - break; - } - case SOCK_COLLECTION: { - switch_no_fields(params, "_008"); - break; - } - case SOCK_TEXTURE: { - switch_no_fields(params, "_009"); - break; - } - case SOCK_MATERIAL: { - switch_no_fields(params, "_010"); - break; - } - case SOCK_IMAGE: { - switch_no_fields(params, "_011"); - break; - } - default: - BLI_assert_unreachable(); - break; - } -} +}; } // namespace blender::nodes::node_geo_switch_cc +namespace blender::nodes { + +std::unique_ptr get_switch_node_lazy_function(const bNode &node) +{ + using namespace node_geo_switch_cc; + BLI_assert(node.type == GEO_NODE_SWITCH); + return std::make_unique(node); +} + +} // namespace blender::nodes + void register_node_type_geo_switch() { namespace file_ns = blender::nodes::node_geo_switch_cc; @@ -303,8 +277,6 @@ void register_node_type_geo_switch() ntype.initfunc = file_ns::node_init; ntype.updatefunc = file_ns::node_update; node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = file_ns::node_geo_exec; - ntype.geometry_node_execute_supports_laziness = true; ntype.gather_link_search_ops = file_ns::node_gather_link_searches; ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc index 7704c94b76a..7eac7bc87aa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform_geometry.cc @@ -14,7 +14,7 @@ #include "BKE_curves.hh" #include "BKE_instances.hh" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_pointcloud.h" #include "BKE_volume.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index eb22ebb3045..09ecb34ddbb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "bmesh.h" #include "bmesh_tools.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc index 6b6b0209e82..d6a31c9133e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_uv_pack_islands.cc @@ -5,7 +5,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "node_geometry_util.hh" diff --git a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc index 4e27ce15f47..492decd8eb9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_uv_unwrap.cc @@ -5,7 +5,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "UI_interface.h" #include "UI_resources.h" diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc index d88940edefd..c7a3e7d9651 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_cube.cc @@ -15,7 +15,7 @@ #include "BKE_geometry_set.hh" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_volume.h" namespace blender::nodes::node_geo_volume_cube_cc { diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 776f98e281a..77bf69d187c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -10,7 +10,7 @@ #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_volume.h" #include "BKE_volume_to_mesh.hh" @@ -141,6 +141,7 @@ static Mesh *create_mesh_from_volume_grids(Span gri } BKE_mesh_calc_edges(mesh, false, false); + BKE_mesh_smooth_flag_set(mesh, false); return mesh; } diff --git a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc index 1a7f1520b12..ad272993ea1 100644 --- a/source/blender/nodes/intern/geometry_nodes_lazy_function.cc +++ b/source/blender/nodes/intern/geometry_nodes_lazy_function.cc @@ -73,10 +73,7 @@ static void lazy_function_interface_from_node(const bNode &node, Vector &r_outputs) { const bool is_muted = node.is_muted(); - const bool supports_laziness = node.typeinfo->geometry_node_execute_supports_laziness || - node.is_group(); - const lf::ValueUsage input_usage = supports_laziness ? lf::ValueUsage::Maybe : - lf::ValueUsage::Used; + const lf::ValueUsage input_usage = lf::ValueUsage::Used; for (const bNodeSocket *socket : node.input_sockets()) { if (!socket->is_available()) { continue; @@ -1331,6 +1328,10 @@ struct GeometryNodesLazyFunctionGraphBuilder { this->handle_viewer_node(*bnode); break; } + case GEO_NODE_SWITCH: { + this->handle_switch_node(*bnode); + break; + } default: { if (node_type->geometry_node_execute) { this->handle_geometry_node(*bnode); @@ -1499,6 +1500,8 @@ struct GeometryNodesLazyFunctionGraphBuilder { multi_input_socket_nodes_.add_new(&bsocket, &lf_multi_input_node); for (lf::InputSocket *lf_multi_input_socket : lf_multi_input_node.inputs()) { mapping_->bsockets_by_lf_socket_map.add(lf_multi_input_socket, &bsocket); + const void *default_value = lf_multi_input_socket->type().default_value(); + lf_multi_input_socket->set_default_value(default_value); } } else { @@ -1570,6 +1573,31 @@ struct GeometryNodesLazyFunctionGraphBuilder { mapping_->viewer_node_map.add(&bnode, &lf_node); } + void handle_switch_node(const bNode &bnode) + { + std::unique_ptr lazy_function = get_switch_node_lazy_function(bnode); + lf::FunctionNode &lf_node = lf_graph_->add_function(*lazy_function); + lf_graph_info_->functions.append(std::move(lazy_function)); + + int input_index = 0; + for (const bNodeSocket *bsocket : bnode.input_sockets()) { + if (bsocket->is_available()) { + lf::InputSocket &lf_socket = lf_node.input(input_index); + input_socket_map_.add(bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); + input_index++; + } + } + for (const bNodeSocket *bsocket : bnode.output_sockets()) { + if (bsocket->is_available()) { + lf::OutputSocket &lf_socket = lf_node.output(0); + output_socket_map_.add(bsocket, &lf_socket); + mapping_->bsockets_by_lf_socket_map.add(&lf_socket, bsocket); + break; + } + } + } + void handle_undefined_node(const bNode &bnode) { Vector used_outputs; @@ -2740,7 +2768,8 @@ class UsedSocketVisualizeOptions : public lf::Graph::ToDotOptions { socket_name_suffixes_.add(lf_socket, suffix); } } - else if (lf::OutputSocket *lf_socket = builder_.output_socket_map_.lookup(bsocket)) { + else if (lf::OutputSocket *lf_socket = builder_.output_socket_map_.lookup_default(bsocket, + nullptr)) { socket_font_colors_.add(lf_socket, color_str); socket_name_suffixes_.add(lf_socket, suffix); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index d8fb30396a3..6c2eb108e21 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -77,8 +77,8 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, if (ima->source == IMA_SRC_TILED) { const char *gpu_node_name = use_cubic ? "node_tex_tile_cubic" : "node_tex_tile_linear"; - GPUNodeLink *gpu_image = GPU_image_tiled(mat, ima, iuser, sampler_state); - GPUNodeLink *gpu_image_tile_mapping = GPU_image_tiled_mapping(mat, ima, iuser); + GPUNodeLink *gpu_image, *gpu_image_tile_mapping; + GPU_image_tiled(mat, ima, iuser, sampler_state, &gpu_image, &gpu_image_tile_mapping); /* UDIM tiles needs a `sampler2DArray` and `sampler1DArray` for tile mapping. */ GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image, gpu_image_tile_mapping); } diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index e218c2384f5..c0ce4348821 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -989,7 +989,11 @@ static PyObject *bpy_bmesh_free(BPy_BMesh *self) bm_dealloc_editmode_warn(self); - if ((self->flag & BPY_BMFLAG_IS_WRAPPED) == 0) { + if (self->flag & BPY_BMFLAG_IS_WRAPPED) { + /* Ensure further access doesn't return this invalid object, see: #105715. */ + bm->py_handle = NULL; + } + else { BM_mesh_free(bm); } @@ -3464,8 +3468,8 @@ static Py_hash_t bpy_bm_hash(PyObject *self) return _Py_HashPointer(((BPy_BMesh *)self)->bm); } -/* Type Docstrings - * =============== */ +/* Type Doc-strings + * ================ */ PyDoc_STRVAR(bpy_bmesh_doc, "The BMesh data structure\n"); PyDoc_STRVAR(bpy_bmvert_doc, "The BMesh vertex type\n"); @@ -3690,7 +3694,7 @@ void BPy_BM_init_types(void) BPy_BMFaceSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter; BPy_BMLoopSeq_Type.tp_iter = NULL; /* no mapping */ - /* only 1 iteratir so far */ + /* Only 1 iterator so far. */ BPy_BMIter_Type.tp_iternext = (iternextfunc)bpy_bmiter_next; BPy_BMIter_Type.tp_iter = PyObject_SelfIter; diff --git a/source/blender/python/bmesh/bmesh_py_types_meshdata.c b/source/blender/python/bmesh/bmesh_py_types_meshdata.c index 673adacfdde..98d57eb368a 100644 --- a/source/blender/python/bmesh/bmesh_py_types_meshdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_meshdata.c @@ -131,7 +131,7 @@ static PyObject *bpy_bmloopuv_select_edge_get(BPy_BMLoopUV *self, void *UNUSED(c } static int bpy_bmloopuv_select_edge_set(BPy_BMLoopUV *self, PyObject *value, void *UNUSED(closure)) { - /* TODO: see comment above on bpy_bmloopuv_pin_uv_set(), the same applies here. */ + /* TODO: see comment above on bpy_bmloopuv_pin_uv_set(), the same applies here. */ BLI_assert(self->edge_select); if (self->edge_select) { *self->edge_select = PyC_Long_AsBool(value); diff --git a/source/blender/python/generic/imbuf_py_api.c b/source/blender/python/generic/imbuf_py_api.c index f17a9c07f3c..925e47afaf5 100644 --- a/source/blender/python/generic/imbuf_py_api.c +++ b/source/blender/python/generic/imbuf_py_api.c @@ -480,7 +480,7 @@ static PyObject *M_imbuf_load(PyObject *UNUSED(self), PyObject *args, PyObject * return NULL; } - ImBuf *ibuf = IMB_loadifffile(file, filepath, IB_rect, NULL, filepath); + ImBuf *ibuf = IMB_loadifffile(file, IB_rect, NULL, filepath); close(file); diff --git a/source/blender/python/gpu/gpu_py_state.c b/source/blender/python/gpu/gpu_py_state.c index 870a83eb9a8..2db477bfa9b 100644 --- a/source/blender/python/gpu/gpu_py_state.c +++ b/source/blender/python/gpu/gpu_py_state.c @@ -470,7 +470,7 @@ static struct PyMethodDef pygpu_state__tp_methods[] = { pygpu_state_scissor_get_doc}, {"scissor_test_set", (PyCFunction)pygpu_state_scissor_test_set, - METH_VARARGS, + METH_O, pygpu_state_scissor_test_set_doc}, {"line_width_set", (PyCFunction)pygpu_state_line_width_set, diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c index 296d10fa84b..387f1c73b83 100644 --- a/source/blender/python/intern/bpy_app_handlers.c +++ b/source/blender/python/intern/bpy_app_handlers.c @@ -14,7 +14,9 @@ #include "BKE_callbacks.h" #include "RNA_access.h" +#include "RNA_prototypes.h" #include "RNA_types.h" + #include "bpy_app_handlers.h" #include "bpy_rna.h" @@ -29,6 +31,13 @@ void bpy_app_generic_callback(struct Main *main, static PyTypeObject BlenderAppCbType; +#define FILEPATH_SAVE_ARG \ + "Accepts one argument: " \ + "the file being saved, an empty string for the startup-file." +#define FILEPATH_LOAD_ARG \ + "Accepts one argument: " \ + "the file being loaded, an empty string for the startup-file." + /** * See `BKE_callbacks.h` #eCbEvent declaration for the policy on naming. */ @@ -50,10 +59,15 @@ static PyStructSequence_Field app_cb_info_fields[] = { {"render_init", "on initialization of a render job"}, {"render_complete", "on completion of render job"}, {"render_cancel", "on canceling a render job"}, - {"load_pre", "on loading a new blend file (before)"}, - {"load_post", "on loading a new blend file (after)"}, - {"save_pre", "on saving a blend file (before)"}, - {"save_post", "on saving a blend file (after)"}, + + {"load_pre", "on loading a new blend file (before)." FILEPATH_LOAD_ARG}, + {"load_post", "on loading a new blend file (after). " FILEPATH_LOAD_ARG}, + {"load_post_fail", "on failure to load a new blend file (after). " FILEPATH_LOAD_ARG}, + + {"save_pre", "on saving a blend file (before). " FILEPATH_SAVE_ARG}, + {"save_post", "on saving a blend file (after). " FILEPATH_SAVE_ARG}, + {"save_post_fail", "on failure to save a blend file (after). " FILEPATH_SAVE_ARG}, + {"undo_pre", "on loading an undo step (before)"}, {"undo_post", "on loading an undo step (after)"}, {"redo_pre", "on loading a redo step (before)"}, @@ -344,7 +358,8 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), /* setup arguments */ for (int i = 0; i < pointers_num; ++i) { - PyTuple_SET_ITEM(args_all, i, pyrna_struct_CreatePyObject(pointers[i])); + PyTuple_SET_ITEM( + args_all, i, pyrna_struct_CreatePyObject_with_primitive_support(pointers[i])); } for (int i = pointers_num; i < num_arguments; ++i) { PyTuple_SET_ITEM(args_all, i, Py_INCREF_RET(Py_None)); @@ -354,7 +369,8 @@ void bpy_app_generic_callback(struct Main *UNUSED(main), PyTuple_SET_ITEM(args_single, 0, Py_INCREF_RET(Py_None)); } else { - PyTuple_SET_ITEM(args_single, 0, pyrna_struct_CreatePyObject(pointers[0])); + PyTuple_SET_ITEM( + args_single, 0, pyrna_struct_CreatePyObject_with_primitive_support(pointers[0])); } /* Iterate the list and run the callbacks diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c index 3fa3c5d75b1..b9b1b629eca 100644 --- a/source/blender/python/intern/bpy_app_translations.c +++ b/source/blender/python/intern/bpy_app_translations.c @@ -829,7 +829,7 @@ PyObject *BPY_app_translations_struct(void) { PyObject *ret; - /* Let's finalize our contexts structseq definition! */ + /* Let's finalize our contexts `PyStructSequence` definition! */ { BLT_i18n_contexts_descriptor *ctxt; PyStructSequence_Field *desc; diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 93d22467970..1a4c124da7b 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -7407,6 +7407,27 @@ PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr) return (PyObject *)pyrna; } +PyObject *pyrna_struct_CreatePyObject_with_primitive_support(PointerRNA *ptr) +{ + if (ptr->type == &RNA_PrimitiveString) { + const PrimitiveStringRNA *data = ptr->data; + return PyC_UnicodeFromBytes(data->value); + } + if (ptr->type == &RNA_PrimitiveInt) { + const PrimitiveIntRNA *data = ptr->data; + return PyLong_FromLong(data->value); + } + if (ptr->type == &RNA_PrimitiveFloat) { + const PrimitiveFloatRNA *data = ptr->data; + return PyFloat_FromDouble(data->value); + } + if (ptr->type == &RNA_PrimitiveBoolean) { + const PrimitiveBooleanRNA *data = ptr->data; + return PyBool_FromLong(data->value); + } + return pyrna_struct_CreatePyObject(ptr); +} + PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop) { BPy_PropertyRNA *pyrna; diff --git a/source/blender/python/intern/bpy_rna.h b/source/blender/python/intern/bpy_rna.h index d7778da6213..6b94c48179e 100644 --- a/source/blender/python/intern/bpy_rna.h +++ b/source/blender/python/intern/bpy_rna.h @@ -173,6 +173,7 @@ void BPY_update_rna_module(void); // PyObject *BPY_rna_doc(void); PyObject *BPY_rna_types(void); +PyObject *pyrna_struct_CreatePyObject_with_primitive_support(PointerRNA *ptr); PyObject *pyrna_struct_CreatePyObject(PointerRNA *ptr); PyObject *pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop); diff --git a/source/blender/python/intern/bpy_rna_array.c b/source/blender/python/intern/bpy_rna_array.c index 48ba028edf0..07f63d16deb 100644 --- a/source/blender/python/intern/bpy_rna_array.c +++ b/source/blender/python/intern/bpy_rna_array.c @@ -247,6 +247,7 @@ static int count_items(PyObject *seq, int dim) static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, + const bool prop_is_param_dyn_alloc, int lvalue_dim, int *r_totitem, const char *error_prefix) @@ -266,26 +267,20 @@ static int validate_array_length(PyObject *rvalue, return -1; } if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) { - if (RNA_property_array_length(ptr, prop) != tot) { -#if 0 - /* length is flexible */ - if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) { - /* BLI_snprintf(error_str, error_str_size, - * "%s.%s: array length cannot be changed to %d", - * RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */ + const int tot_expected = RNA_property_array_length(ptr, prop); + if (tot_expected != tot) { + *r_totitem = tot; + if (!prop_is_param_dyn_alloc) { PyErr_Format(PyExc_ValueError, - "%s %s.%s: array length cannot be changed to %d", + "%s %s.%s: array length cannot be changed to %d (expected %d)", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), - tot); + tot, + tot_expected); return -1; } -#else - *r_totitem = tot; return 0; - -#endif } len = tot; @@ -340,6 +335,7 @@ static int validate_array_length(PyObject *rvalue, static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, + const bool prop_is_param_dyn_alloc, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, @@ -410,7 +406,8 @@ static int validate_array(PyObject *rvalue, return -1; } - return validate_array_length(rvalue, ptr, prop, lvalue_dim, r_totitem, error_prefix); + return validate_array_length( + rvalue, ptr, prop, prop_is_param_dyn_alloc, lvalue_dim, r_totitem, error_prefix); } } @@ -527,15 +524,26 @@ static int py_to_array(PyObject *seq, char *data = NULL; // totdim = RNA_property_array_dimension(ptr, prop, dim_size); /* UNUSED */ + const int flag = RNA_property_flag(prop); - if (validate_array(seq, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix) == - -1) { + /* Use #ParameterDynAlloc which defines it's own array length. */ + const bool prop_is_param_dyn_alloc = param_data && (flag & PROP_DYNAMIC); + + if (validate_array(seq, + ptr, + prop, + prop_is_param_dyn_alloc, + 0, + check_item_type, + item_type_str, + &totitem, + error_prefix) == -1) { return -1; } if (totitem) { /* NOTE: this code is confusing. */ - if (param_data && RNA_property_flag(prop) & PROP_DYNAMIC) { + if (prop_is_param_dyn_alloc) { /* not freeing allocated mem, RNA_parameter_list_free() will do this */ ParameterDynAlloc *param_alloc = (ParameterDynAlloc *)param_data; param_alloc->array_tot = (int)totitem; @@ -626,9 +634,16 @@ static int py_to_array_index(PyObject *py, copy_value_single(py, ptr, prop, NULL, 0, &index, convert_item, rna_set_index); } else { - if (validate_array( - py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix) == - -1) { + const bool prop_is_param_dyn_alloc = false; + if (validate_array(py, + ptr, + prop, + prop_is_param_dyn_alloc, + lvalue_dim, + check_item_type, + item_type_str, + &totitem, + error_prefix) == -1) { return -1; } diff --git a/source/blender/python/intern/stubs.c b/source/blender/python/intern/stubs.c index f860bdc36ee..6ac9cd64f33 100644 --- a/source/blender/python/intern/stubs.c +++ b/source/blender/python/intern/stubs.c @@ -12,6 +12,9 @@ #if defined(__GNUC__) || defined(__clang__) # pragma GCC diagnostic error "-Wmissing-prototypes" # pragma GCC diagnostic ignored "-Wunused-parameter" +#elif defined(_MSC_VER) +/* Suppress unreferenced formal parameter warning. */ +# pragma warning(disable : 4100) #endif /* python, will come back */ diff --git a/source/blender/python/mathutils/mathutils_bvhtree.cc b/source/blender/python/mathutils/mathutils_bvhtree.cc index 6bb68802d7d..e9e07a7c248 100644 --- a/source/blender/python/mathutils/mathutils_bvhtree.cc +++ b/source/blender/python/mathutils/mathutils_bvhtree.cc @@ -34,7 +34,7 @@ # include "BKE_customdata.h" # include "BKE_editmesh_bvh.h" # include "BKE_lib_id.h" -# include "BKE_mesh.h" +# include "BKE_mesh.hh" # include "BKE_mesh_runtime.h" # include "DEG_depsgraph_query.h" @@ -803,7 +803,7 @@ static PyObject *C_BVHTree_FromPolygons(PyObject * /*cls*/, PyObject *args, PyOb } *p_plink_prev = nullptr; - /* all ngon's are parsed, now tessellate */ + /* All NGON's are parsed, now tessellate. */ pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__); tris = static_cast(MEM_mallocN(sizeof(*tris) * size_t(tris_len), __func__)); @@ -1161,14 +1161,17 @@ static PyObject *C_BVHTree_FromObject(PyObject * /*cls*/, PyObject *args, PyObje uint i; int *orig_index = nullptr; - float(*orig_normal)[3] = nullptr; + blender::float3 *orig_normal = nullptr; tree = BLI_bvhtree_new(int(tris_len), epsilon, PY_BVH_TREE_TYPE_DEFAULT, PY_BVH_AXIS_DEFAULT); if (tree) { orig_index = static_cast( MEM_mallocN(sizeof(*orig_index) * size_t(tris_len), __func__)); if (!BKE_mesh_poly_normals_are_dirty(mesh)) { - orig_normal = static_cast(MEM_dupallocN(BKE_mesh_poly_normals_ensure(mesh))); + const blender::Span poly_normals = mesh->poly_normals(); + orig_normal = static_cast( + MEM_malloc_arrayN(size_t(mesh->totpoly), sizeof(blender::float3), __func__)); + blender::MutableSpan(orig_normal, poly_normals.size()).copy_from(poly_normals); } for (i = 0; i < tris_len; i++, lt++) { @@ -1193,8 +1196,14 @@ static PyObject *C_BVHTree_FromObject(PyObject * /*cls*/, PyObject *args, PyObje BKE_id_free(nullptr, mesh); } - return bvhtree_CreatePyObject( - tree, epsilon, coords, coords_len, tris, tris_len, orig_index, orig_normal); + return bvhtree_CreatePyObject(tree, + epsilon, + coords, + coords_len, + tris, + tris_len, + orig_index, + reinterpret_cast(orig_normal)); } } #endif /* MATH_STANDALONE */ diff --git a/source/blender/render/intern/bake.cc b/source/blender/render/intern/bake.cc index fb4f81a0367..f114f5cd3b9 100644 --- a/source/blender/render/intern/bake.cc +++ b/source/blender/render/intern/bake.cc @@ -56,11 +56,12 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BKE_attribute.hh" #include "BKE_bvhutils.h" #include "BKE_customdata.h" #include "BKE_image.h" #include "BKE_lib_id.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_runtime.h" #include "BKE_mesh_tangent.h" #include "BKE_node.h" @@ -450,6 +451,7 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData, */ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval) { + using namespace blender; int i; const int tottri = poly_to_tri_count(me->totpoly, me->totloop); @@ -458,32 +460,30 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval /* calculate normal for each polygon only once */ uint mpoly_prev = UINT_MAX; - float no[3]; + blender::float3 no; - const float(*positions)[3] = BKE_mesh_vert_positions(me); + const blender::Span positions = me->vert_positions(); const blender::Span polys = me->polys(); const blender::Span loops = me->loops(); + const bke::AttributeAccessor attributes = me->attributes(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); looptri = static_cast(MEM_mallocN(sizeof(*looptri) * tottri, __func__)); triangles = static_cast(MEM_callocN(sizeof(TriTessFace) * tottri, __func__)); - const float(*precomputed_normals)[3] = BKE_mesh_poly_normals_are_dirty(me) ? - nullptr : - BKE_mesh_poly_normals_ensure(me); - const bool calculate_normal = precomputed_normals ? false : true; + const bool calculate_normal = BKE_mesh_poly_normals_are_dirty(me); + blender::Span precomputed_normals; + if (!calculate_normal) { + precomputed_normals = me->poly_normals(); + } - if (precomputed_normals != nullptr) { - BKE_mesh_recalc_looptri_with_normals(loops.data(), - polys.data(), - positions, - me->totloop, - me->totpoly, - looptri, - precomputed_normals); + if (!precomputed_normals.is_empty()) { + blender::bke::mesh::looptris_calc_with_normals( + positions, polys, loops, precomputed_normals, {looptri, tottri}); } else { - BKE_mesh_recalc_looptri( - loops.data(), polys.data(), positions, me->totloop, me->totpoly, looptri); + blender::bke::mesh::looptris_calc(positions, polys, loops, {looptri, tottri}); } const TSpace *tspace = nullptr; @@ -500,7 +500,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval CustomData_get_layer(&me_eval->ldata, CD_NORMAL)); } - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(me); + const blender::Span vert_normals = me->vert_normals(); for (i = 0; i < tottri; i++) { const MLoopTri *lt = &looptri[i]; const MPoly &poly = polys[lt->poly]; @@ -511,7 +511,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval triangles[i].vert_normals[0] = vert_normals[loops[lt->tri[0]].v]; triangles[i].vert_normals[1] = vert_normals[loops[lt->tri[1]].v]; triangles[i].vert_normals[2] = vert_normals[loops[lt->tri[2]].v]; - triangles[i].is_smooth = (poly.flag & ME_SMOOTH) != 0; + triangles[i].is_smooth = !sharp_faces[lt->poly]; if (tangent) { triangles[i].tspace[0] = &tspace[lt->tri[0]]; @@ -527,7 +527,8 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval if (calculate_normal) { if (lt->poly != mpoly_prev) { - BKE_mesh_calc_poly_normal(&poly, &loops[poly.loopstart], positions, no); + no = blender::bke::mesh::poly_normal_calc(positions, + loops.slice(poly.loopstart, poly.totloop)); mpoly_prev = lt->poly; } copy_v3_v3(triangles[i].normal, no); @@ -750,11 +751,8 @@ void RE_bake_pixels_populate(Mesh *me, const int tottri = poly_to_tri_count(me->totpoly, me->totloop); MLoopTri *looptri = static_cast(MEM_mallocN(sizeof(*looptri) * tottri, __func__)); - const float(*positions)[3] = BKE_mesh_vert_positions(me); - const blender::Span polys = me->polys(); - const blender::Span loops = me->loops(); - BKE_mesh_recalc_looptri( - loops.data(), polys.data(), positions, me->totloop, me->totpoly, looptri); + blender::bke::mesh::looptris_calc( + me->vert_positions(), me->polys(), me->loops(), {looptri, tottri}); const int *material_indices = BKE_mesh_material_indices(me); const int materials_num = targets->materials_num; diff --git a/source/blender/render/intern/multires_bake.cc b/source/blender/render/intern/multires_bake.cc index 5ec2989381e..71fdfd54742 100644 --- a/source/blender/render/intern/multires_bake.cc +++ b/source/blender/render/intern/multires_bake.cc @@ -24,7 +24,7 @@ #include "BKE_image.h" #include "BKE_lib_id.h" #include "BKE_material.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_tangent.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -61,15 +61,17 @@ struct MultiresBakeResult { struct MResolvePixelData { const float (*vert_positions)[3]; - const float (*vert_normals)[3]; + const blender::float3 *vert_normals; + int verts_num; const MPoly *polys; const int *material_indices; + const bool *sharp_faces; MLoop *mloop; float (*mloopuv)[2]; float uv_offset[2]; const MLoopTri *mlooptri; float *pvtangent; - const float (*precomputed_normals)[3]; + const blender::float3 *poly_normals; int w, h; int tri_index; DerivedMesh *lores_dm, *hires_dm; @@ -114,19 +116,22 @@ static void multiresbake_get_normal(const MResolvePixelData *data, { const int poly_index = data->mlooptri[tri_num].poly; const MPoly &poly = data->polys[poly_index]; - const bool smoothnormal = (poly.flag & ME_SMOOTH) != 0; + const bool smoothnormal = !(data->sharp_faces && data->sharp_faces[poly_index]); if (smoothnormal) { const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v; copy_v3_v3(r_normal, data->vert_normals[vi]); } else { - if (data->precomputed_normals) { - copy_v3_v3(r_normal, data->precomputed_normals[poly_index]); + if (data->poly_normals) { + copy_v3_v3(r_normal, data->poly_normals[poly_index]); } else { - BKE_mesh_calc_poly_normal( - &poly, &data->mloop[poly.loopstart], data->vert_positions, r_normal); + copy_v3_v3( + r_normal, + blender::bke::mesh::poly_normal_calc( + {reinterpret_cast(data->vert_positions), data->verts_num}, + {&data->mloop[poly.loopstart], poly.totloop})); } } } @@ -492,8 +497,8 @@ static void do_multires_bake(MultiresBakeRender *bkr, temp_mesh->edges_for_write().copy_from({dm->getEdgeArray(dm), temp_mesh->totedge}); temp_mesh->polys_for_write().copy_from({dm->getPolyArray(dm), temp_mesh->totpoly}); temp_mesh->loops_for_write().copy_from({dm->getLoopArray(dm), temp_mesh->totloop}); - const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(temp_mesh); - const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(temp_mesh); + const blender::Span vert_normals = temp_mesh->vert_normals(); + const blender::Span poly_normals = temp_mesh->poly_normals(); if (require_tangent) { if (CustomData_get_layer_index(&dm->loopData, CD_TANGENT) == -1) { @@ -504,12 +509,14 @@ static void do_multires_bake(MultiresBakeRender *bkr, dm->getLoopArray(dm), dm->getLoopTriArray(dm), dm->getNumLoopTri(dm), + static_cast( + CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")), &dm->loopData, true, nullptr, 0, - vert_normals, - poly_normals, + reinterpret_cast(vert_normals.data()), + reinterpret_cast(poly_normals.data()), (const float(*)[3])dm->getLoopDataArray(dm, CD_NORMAL), (const float(*)[3])dm->getVertDataArray(dm, CD_ORCO), /* May be nullptr. */ /* result */ @@ -550,14 +557,17 @@ static void do_multires_bake(MultiresBakeRender *bkr, handle->data.polys = polys; handle->data.material_indices = static_cast( CustomData_get_layer_named(&dm->polyData, CD_PROP_INT32, "material_index")); + handle->data.sharp_faces = static_cast( + CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")); handle->data.vert_positions = positions; - handle->data.vert_normals = vert_normals; + handle->data.vert_normals = vert_normals.data(); + handle->data.verts_num = dm->getNumVerts(dm); handle->data.mloopuv = mloopuv; BKE_image_get_tile_uv(ima, tile->tile_number, handle->data.uv_offset); handle->data.mlooptri = mlooptri; handle->data.mloop = mloop; handle->data.pvtangent = pvtangent; - handle->data.precomputed_normals = poly_normals; /* don't strictly need this */ + handle->data.poly_normals = poly_normals.data(); /* don't strictly need this */ handle->data.w = ibuf->x; handle->data.h = ibuf->y; handle->data.lores_dm = dm; diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index 09761b16149..f99e895d303 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -13,7 +13,7 @@ #include "BKE_DerivedMesh.h" #include "BKE_customdata.h" -#include "BKE_mesh.h" +#include "BKE_mesh.hh" #include "BKE_mesh_mapping.h" #include "DNA_mesh_types.h" @@ -515,12 +515,8 @@ static void generate_margin(ImBuf *ibuf, tottri = poly_to_tri_count(me->totpoly, me->totloop); looptri_mem = static_cast(MEM_mallocN(sizeof(*looptri) * tottri, __func__)); - BKE_mesh_recalc_looptri(mloop, - polys, - reinterpret_cast(me->vert_positions().data()), - me->totloop, - me->totpoly, - looptri_mem); + bke::mesh::looptris_calc( + me->vert_positions(), me->polys(), me->loops(), {looptri_mem, tottri}); looptri = looptri_mem; } else { diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 65ba8bf48fe..dc55682e8bc 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -529,7 +529,7 @@ static void sequencer_preprocess_transform_crop( break; case SEQ_TRANSFORM_FILTER_NEAREST_3x3: filter = IMB_FILTER_NEAREST; - num_subsamples = context->for_render ? 3 : 1; + num_subsamples = 3; break; } diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 89da6bb1769..1ab81719299 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -176,6 +176,7 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa if (!load_data->effect.seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ + seq->flag |= SEQ_SINGLE_FRAME_CONTENT; SEQ_time_right_handle_frame_set(scene, seq, load_data->effect.end_frame); } @@ -235,6 +236,10 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL Strip *strip = seq->strip; strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem"); + if (seq->len == 1) { + seq->flag |= SEQ_SINGLE_FRAME_CONTENT; + } + /* Multiview settings. */ if (load_data->use_multiview) { seq->flag |= SEQ_USE_VIEWS; diff --git a/source/blender/sequencer/intern/strip_retiming.cc b/source/blender/sequencer/intern/strip_retiming.cc index 3ecf664c63a..35047f8b0f6 100644 --- a/source/blender/sequencer/intern/strip_retiming.cc +++ b/source/blender/sequencer/intern/strip_retiming.cc @@ -99,7 +99,7 @@ void SEQ_retiming_data_ensure(Sequence *seq) seq->retiming_handles = (SeqRetimingHandle *)MEM_calloc_arrayN( 2, sizeof(SeqRetimingHandle), __func__); SeqRetimingHandle *handle = seq->retiming_handles + 1; - handle->strip_frame_index = seq_time_strip_original_content_length_get(seq) - 1; + handle->strip_frame_index = seq->len; handle->retiming_factor = 1.0f; seq->retiming_handle_num = 2; } @@ -232,7 +232,7 @@ float SEQ_retiming_handle_speed_get(const Sequence *seq, const SeqRetimingHandle const SeqRetimingHandle *handle_prev = handle - 1; - const int frame_index_max = seq_time_strip_original_content_length_get(seq) - 1; + const int frame_index_max = seq->len - 1; const int frame_retimed_prev = round_fl_to_int(handle_prev->retiming_factor * frame_index_max); const int frame_index_prev = handle_prev->strip_frame_index; const int frame_retimed = round_fl_to_int(handle->retiming_factor * frame_index_max); diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index 60950c614a1..0d36c172a02 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -53,21 +53,12 @@ float seq_time_media_playback_rate_factor_get(const Scene *scene, const Sequence return seq->media_playback_rate / scene_playback_rate; } -int seq_time_strip_original_content_length_get(const Sequence *seq) -{ - if (seq->type == SEQ_TYPE_SOUND_RAM) { - return seq->len; - } - - return seq->len; -} - float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_frame) { float frame_index; float sta = SEQ_time_start_frame_get(seq); float end = SEQ_time_content_end_frame_get(scene, seq) - 1; - const float length = seq_time_strip_original_content_length_get(seq); + const float length = seq->len; if (seq->type & SEQ_TYPE_EFFECT) { end = SEQ_time_right_handle_frame_get(scene, seq); @@ -77,7 +68,7 @@ float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_fra return -1; } - if (seq->len == 1 && seq->type == SEQ_TYPE_IMAGE) { + if (seq->type == SEQ_TYPE_IMAGE && SEQ_transform_single_image_check(seq)) { return 0; } @@ -94,7 +85,7 @@ float seq_give_frame_index(const Scene *scene, Sequence *seq, float timeline_fra if (SEQ_retiming_is_active(seq)) { const float retiming_factor = seq_retiming_evaluate(seq, frame_index); - frame_index = retiming_factor * (length - 1); + frame_index = retiming_factor * (length); } /* Clamp frame index to strip content frame range. */ frame_index = clamp_f(frame_index, 0, length); @@ -513,8 +504,7 @@ int SEQ_time_strip_length_get(const Scene *scene, const Sequence *seq) SeqRetimingHandle *handle_start = seq->retiming_handles; SeqRetimingHandle *handle_end = seq->retiming_handles + (SEQ_retiming_handles_count(seq) - 1); return handle_end->strip_frame_index / seq_time_media_playback_rate_factor_get(scene, seq) - - (handle_start->strip_frame_index + 1) / - seq_time_media_playback_rate_factor_get(scene, seq); + (handle_start->strip_frame_index) / seq_time_media_playback_rate_factor_get(scene, seq); } return seq->len / seq_time_media_playback_rate_factor_get(scene, seq); diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h index d88a37bab89..d8854eba118 100644 --- a/source/blender/sequencer/intern/strip_time.h +++ b/source/blender/sequencer/intern/strip_time.h @@ -43,7 +43,6 @@ void seq_time_update_effects_strip_range(const struct Scene *scene, struct SeqCo void seq_time_translate_handles(const struct Scene *scene, struct Sequence *seq, const int offset); float seq_time_media_playback_rate_factor_get(const struct Scene *scene, const struct Sequence *seq); -int seq_time_strip_original_content_length_get(const struct Sequence *seq); float seq_retiming_evaluate(const struct Sequence *seq, const int frame_index); #ifdef __cplusplus diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index c81482c878c..c8ee4e58b4a 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -36,9 +36,7 @@ static CLG_LogRef LOG = {"seq.strip_transform"}; bool SEQ_transform_single_image_check(Sequence *seq) { - return ((seq->len == 1) && - (seq->type == SEQ_TYPE_IMAGE || - ((seq->type & SEQ_TYPE_EFFECT) && SEQ_effect_get_num_inputs(seq->type) == 0))); + return (seq->flag & SEQ_SINGLE_FRAME_CONTENT) != 0; } bool SEQ_transform_seqbase_isolated_sel_check(ListBase *seqbase) diff --git a/source/blender/shader_fx/intern/FX_shader_flip.c b/source/blender/shader_fx/intern/FX_shader_flip.c index 7d067bbc6f8..0c8d6624442 100644 --- a/source/blender/shader_fx/intern/FX_shader_flip.c +++ b/source/blender/shader_fx/intern/FX_shader_flip.c @@ -7,7 +7,7 @@ #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/shader_fx/intern/FX_shader_glow.c b/source/blender/shader_fx/intern/FX_shader_glow.c index 9c0e5857f6c..8e24ab70a57 100644 --- a/source/blender/shader_fx/intern/FX_shader_glow.c +++ b/source/blender/shader_fx/intern/FX_shader_glow.c @@ -7,7 +7,7 @@ #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/shader_fx/intern/FX_shader_shadow.c b/source/blender/shader_fx/intern/FX_shader_shadow.c index cbbe182e7fa..d0cf26fcc2d 100644 --- a/source/blender/shader_fx/intern/FX_shader_shadow.c +++ b/source/blender/shader_fx/intern/FX_shader_shadow.c @@ -7,7 +7,7 @@ #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/shader_fx/intern/FX_shader_swirl.c b/source/blender/shader_fx/intern/FX_shader_swirl.c index a02acb59c27..2046d0d8173 100644 --- a/source/blender/shader_fx/intern/FX_shader_swirl.c +++ b/source/blender/shader_fx/intern/FX_shader_swirl.c @@ -7,7 +7,7 @@ #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/shader_fx/intern/FX_shader_wave.c b/source/blender/shader_fx/intern/FX_shader_wave.c index ef5c626241c..6a43f020405 100644 --- a/source/blender/shader_fx/intern/FX_shader_wave.c +++ b/source/blender/shader_fx/intern/FX_shader_wave.c @@ -7,7 +7,7 @@ #include -#include "DNA_gpencil_types.h" +#include "DNA_gpencil_legacy_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c index afbd75cee75..ffb70843016 100644 --- a/source/blender/shader_fx/intern/FX_ui_common.c +++ b/source/blender/shader_fx/intern/FX_ui_common.c @@ -215,7 +215,7 @@ static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt)) { Object *ob = ED_object_active_context(C); - return (ob != NULL) && (ob->type == OB_GPENCIL); + return (ob != NULL) && (ob->type == OB_GPENCIL_LEGACY); } PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index c681049c4b7..712b16f4113 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -187,7 +187,7 @@ int WM_window_pixels_y(const struct wmWindow *win); void WM_window_rect_calc(const struct wmWindow *win, struct rcti *r_rect); /** * Get boundaries usable by screen-layouts, excluding global areas. - * \note Depends on #U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first. + * \note Depends on #UI_SCALE_FAC. Should that be outdated, call #WM_window_set_dpi first. */ void WM_window_screen_rect_calc(const struct wmWindow *win, struct rcti *r_rect); bool WM_window_is_fullscreen(const struct wmWindow *win); @@ -1258,6 +1258,15 @@ bool WM_gesture_is_modal_first(const struct wmGesture *gesture); void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op); void WM_event_fileselect_event(struct wmWindowManager *wm, void *ophandle, int eventval); +/* Event consecutive data. */ + +/** Return a borrowed reference to the custom-data. */ +void *WM_event_consecutive_data_get(wmWindow *win, const char *id); +/** Set the custom-data (and own the pointer), free with #MEM_freeN. */ +void WM_event_consecutive_data_set(wmWindow *win, const char *id, void *custom_data); +/** Clear and free the consecutive custom-data. */ +void WM_event_consecutive_data_free(wmWindow *win); + /** * Sets the active region for this space from the context. * @@ -1650,6 +1659,9 @@ char WM_event_utf8_to_ascii(const struct wmEvent *event) ATTR_NONNULL(1) ATTR_WA */ bool WM_cursor_test_motion_and_update(const int mval[2]) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT; +bool WM_event_consecutive_gesture_test(const wmEvent *event); +bool WM_event_consecutive_gesture_test_break(const wmWindow *win, const wmEvent *event); + int WM_event_drag_threshold(const struct wmEvent *event); bool WM_event_drag_test(const struct wmEvent *event, const int prev_xy[2]); bool WM_event_drag_test_with_delta(const struct wmEvent *event, const int delta[2]); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 6cea9719d2d..3e97abca3be 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -614,11 +614,19 @@ typedef enum eWM_EventFlag { * See #KMI_REPEAT_IGNORE for details on how key-map handling uses this. */ WM_EVENT_IS_REPEAT = (1 << 1), + /** + * Generated for consecutive track-pad or NDOF-motion events, + * the repeat chain is broken by key/button events, + * or cursor motion exceeding #WM_EVENT_CURSOR_MOTION_THRESHOLD. + * + * Changing the type of track-pad or gesture event also breaks the chain. + */ + WM_EVENT_IS_CONSECUTIVE = (1 << 2), /** * Mouse-move events may have this flag set to force creating a click-drag event * even when the threshold has not been met. */ - WM_EVENT_FORCE_DRAG_THRESHOLD = (1 << 2), + WM_EVENT_FORCE_DRAG_THRESHOLD = (1 << 3), } eWM_EventFlag; ENUM_OPERATORS(eWM_EventFlag, WM_EVENT_FORCE_DRAG_THRESHOLD); @@ -767,7 +775,7 @@ typedef struct wmEvent { * * Always check for <= this value since it may be zero. */ -#define WM_EVENT_CURSOR_MOTION_THRESHOLD ((float)U.move_threshold * U.dpi_fac) +#define WM_EVENT_CURSOR_MOTION_THRESHOLD ((float)U.move_threshold * UI_SCALE_FAC) /** Motion progress, for modal handlers. */ typedef enum { diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c index 9d212798f39..f503a089b76 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo.c @@ -453,7 +453,7 @@ void WM_gizmo_modal_set_while_modal(struct wmGizmoMap *gzmap, void wm_gizmo_calculate_scale(wmGizmo *gz, const bContext *C) { const RegionView3D *rv3d = CTX_wm_region_view3d(C); - float scale = UI_DPI_FAC; + float scale = UI_SCALE_FAC; if ((gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_SCALE) == 0) { scale *= U.gizmo_size; diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 671a69003dd..16c36a270bf 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -179,6 +179,8 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id) win->event_queue_check_click = 0; win->event_queue_check_drag = 0; win->event_queue_check_drag_handled = 0; + win->event_queue_consecutive_gesture_type = 0; + win->event_queue_consecutive_gesture_data = NULL; BLO_read_data_address(reader, &win->stereo3d_format); /* Multi-view always fallback to anaglyph at file opening diff --git a/source/blender/windowmanager/intern/wm_dragdrop.cc b/source/blender/windowmanager/intern/wm_dragdrop.cc index aec761da5ff..e9ae895c4da 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.cc +++ b/source/blender/windowmanager/intern/wm_dragdrop.cc @@ -884,13 +884,13 @@ static void wm_drag_draw_icon(bContext * /*C*/, wmWindow * /*win*/, wmDrag *drag col); } else { - int padding = 4 * UI_DPI_FAC; + int padding = 4 * UI_SCALE_FAC; x = xy[0] - 2 * padding; - y = xy[1] - 2 * UI_DPI_FAC; + y = xy[1] - 2 * UI_SCALE_FAC; const uchar text_col[] = {255, 255, 255, 255}; UI_icon_draw_ex( - x, y, drag->icon, U.inv_dpi_fac, 0.8, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); + x, y, drag->icon, UI_INV_SCALE_FAC, 0.8, 0.0f, text_col, false, UI_NO_ICON_OVERLAY_TEXT); } } @@ -903,8 +903,8 @@ static void wm_drag_draw_item_name(wmDrag *drag, const int x, const int y) void WM_drag_draw_item_name_fn(bContext * /*C*/, wmWindow * /*win*/, wmDrag *drag, const int xy[2]) { - int x = xy[0] + 10 * UI_DPI_FAC; - int y = xy[1] + 1 * UI_DPI_FAC; + int x = xy[0] + 10 * UI_SCALE_FAC; + int y = xy[1] + 1 * UI_SCALE_FAC; wm_drag_draw_item_name(drag, x, y); } @@ -915,8 +915,8 @@ static void wm_drag_draw_tooltip(bContext *C, wmWindow *win, wmDrag *drag, const /* Some callbacks require the region. */ return; } - int iconsize = UI_DPI_ICON_SIZE; - int padding = 4 * UI_DPI_FAC; + int iconsize = UI_ICON_SIZE; + int padding = 4 * UI_SCALE_FAC; char *tooltip = nullptr; if (drag->drop_state.active_dropbox) { @@ -973,13 +973,13 @@ static void wm_drag_draw_default(bContext *C, wmWindow *win, wmDrag *drag, const /* Item name. */ if (drag->imb) { - int iconsize = UI_DPI_ICON_SIZE; + int iconsize = UI_ICON_SIZE; xy_tmp[0] = xy[0] - (wm_drag_imbuf_icon_width_get(drag) / 2); xy_tmp[1] = xy[1] - (wm_drag_imbuf_icon_height_get(drag) / 2) - iconsize; } else { - xy_tmp[0] = xy[0] + 10 * UI_DPI_FAC; - xy_tmp[1] = xy[1] + 1 * UI_DPI_FAC; + xy_tmp[0] = xy[0] + 10 * UI_SCALE_FAC; + xy_tmp[1] = xy[1] + 1 * UI_SCALE_FAC; } wm_drag_draw_item_name(drag, UNPACK2(xy_tmp)); diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 15707553e9d..1e0002a4f11 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -291,7 +291,7 @@ static void wm_software_cursor_draw_crosshair(const int event_xy[2]) /* Draw a primitive cross-hair cursor. * NOTE: the `win->cursor` could be used for drawing although it's complicated as some cursors * are set by the operating-system, where the pixel information isn't easily available. */ - const float unit = max_ff(U.dpi_fac, 1.0f); + const float unit = max_ff(UI_SCALE_FAC, 1.0f); uint pos = GPU_vertformat_attr_add( immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c index 2e1afe808ad..18864b35aac 100644 --- a/source/blender/windowmanager/intern/wm_event_query.c +++ b/source/blender/windowmanager/intern/wm_event_query.c @@ -103,6 +103,7 @@ void WM_event_print(const wmEvent *event) struct FlagIdentifierPair flag_data[] = { {"SCROLL_INVERT", WM_EVENT_SCROLL_INVERT}, {"IS_REPEAT", WM_EVENT_IS_REPEAT}, + {"IS_CONSECUTIVE", WM_EVENT_IS_CONSECUTIVE}, {"FORCE_DRAG_THRESHOLD", WM_EVENT_FORCE_DRAG_THRESHOLD}, }; event_ids_from_flag(flag_id, sizeof(flag_id), flag_data, ARRAY_SIZE(flag_data), event->flag); @@ -336,6 +337,51 @@ bool WM_cursor_test_motion_and_update(const int mval[2]) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Event Consecutive Checks + * \{ */ + +/** + * Return true if this event type is a candidate for being flagged as consecutive. + * + * See: #WM_EVENT_IS_CONSECUTIVE doc-string. + */ +bool WM_event_consecutive_gesture_test(const wmEvent *event) +{ + return ISMOUSE_GESTURE(event->type) || (event->type == NDOF_MOTION); +} + +/** + * Return true if this event should break the chain of consecutive gestures. + * Practically all intentional user input should, key presses or button clicks. + */ +bool WM_event_consecutive_gesture_test_break(const wmWindow *win, const wmEvent *event) +{ + /* Cursor motion breaks the chain. */ + if (ISMOUSE_MOTION(event->type)) { + /* Mouse motion is checked because the user may navigate to a new area + * and perform the same gesture - logically it's best to view this as two separate gestures. */ + if (len_manhattan_v2v2_int(event->xy, win->event_queue_consecutive_gesture_xy) > + WM_EVENT_CURSOR_MOTION_THRESHOLD) { + return true; + } + } + else if (ISKEYBOARD_OR_BUTTON(event->type)) { + /* Modifiers are excluded because from a user perspective, + * releasing a modifier (for e.g.) should not begin a new action. */ + if (!ISKEYMODIFIER(event->type)) { + return true; + } + } + else if (event->type == WINDEACTIVATE) { + return true; + } + + return false; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Event Click/Drag Checks * @@ -362,7 +408,7 @@ int WM_event_drag_threshold(const struct wmEvent *event) /* Typically keyboard, could be NDOF button or other less common types. */ drag_threshold = U.drag_threshold; } - return drag_threshold * U.dpi_fac; + return drag_threshold * UI_SCALE_FAC; } bool WM_event_drag_test_with_delta(const wmEvent *event, const int drag_delta[2]) diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index faab3fe4bd1..dcf73332410 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -239,6 +239,11 @@ static void wm_event_free_last_handled(wmWindow *win, wmEvent *event) if (win->event_last_handled) { wm_event_free(win->event_last_handled); } + + /* While not essential, these values are undefined, as the event is no longer in a list + * clear the linked-list pointers to avoid any confusion. */ + event->next = event->prev = nullptr; + /* Don't store custom data in the last handled event as we don't have control how long this event * will be stored and the referenced data may become invalid (also it's not needed currently). */ wm_event_custom_free(event); @@ -2638,8 +2643,8 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C, IFACE_("Blender File View"), WM_window_pixels_x(win) / 2, WM_window_pixels_y(win) / 2, - U.file_space_data.temp_win_sizex * UI_DPI_FAC, - U.file_space_data.temp_win_sizey * UI_DPI_FAC, + U.file_space_data.temp_win_sizex * UI_SCALE_FAC, + U.file_space_data.temp_win_sizey * UI_SCALE_FAC, SPACE_FILE, U.filebrowser_display_type, true))) { @@ -3961,6 +3966,27 @@ void wm_event_do_handlers(bContext *C) } const bool event_queue_check_drag_prev = win->event_queue_check_drag; + { + const bool is_consecutive = WM_event_consecutive_gesture_test(event); + if (win->event_queue_consecutive_gesture_type != 0) { + if (event->type == win->event_queue_consecutive_gesture_type) { + event->flag |= WM_EVENT_IS_CONSECUTIVE; + } + else if (is_consecutive || WM_event_consecutive_gesture_test_break(win, event)) { + CLOG_INFO(WM_LOG_HANDLERS, 1, "consecutive gesture break (%d)", event->type); + win->event_queue_consecutive_gesture_type = 0; + WM_event_consecutive_data_free(win); + } + } + else if (is_consecutive) { + CLOG_INFO(WM_LOG_HANDLERS, 1, "consecutive gesture begin (%d)", event->type); + win->event_queue_consecutive_gesture_type = event->type; + copy_v2_v2_int(win->event_queue_consecutive_gesture_xy, event->xy); + /* While this should not be set, it's harmless to free here. */ + WM_event_consecutive_data_free(win); + } + } + /* Active screen might change during handlers, update pointer. */ screen = WM_window_get_active_screen(win); @@ -4304,6 +4330,56 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Consecutive Event Access + * \{ */ + +using wmEvent_ConsecutiveData = struct wmEvent_ConsecutiveData { + /** Owned custom-data. */ + void *custom_data; + /** Unique identifier per struct type. */ + char id[0]; +}; + +void *WM_event_consecutive_data_get(wmWindow *win, const char *id) +{ + wmEvent_ConsecutiveData *cdata = win->event_queue_consecutive_gesture_data; + if (cdata && STREQ(cdata->id, id)) { + return cdata->custom_data; + } + return nullptr; +} + +void WM_event_consecutive_data_set(wmWindow *win, const char *id, void *custom_data) +{ + if (win->event_queue_consecutive_gesture_data) { + WM_event_consecutive_data_free(win); + } + + const size_t id_size = strlen(id) + 1; + wmEvent_ConsecutiveData *cdata = static_cast( + MEM_mallocN(sizeof(*cdata) + id_size, __func__)); + cdata->custom_data = custom_data; + memcpy((cdata + 1), id, id_size); + win->event_queue_consecutive_gesture_data = cdata; +} + +void WM_event_consecutive_data_free(wmWindow *win) +{ + wmEvent_ConsecutiveData *cdata = win->event_queue_consecutive_gesture_data; + if (cdata == nullptr) { + return; + } + + if (cdata->custom_data) { + MEM_freeN(cdata->custom_data); + } + MEM_freeN(cdata); + win->event_queue_consecutive_gesture_data = nullptr; +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Modal Operator Handling * \{ */ diff --git a/source/blender/windowmanager/intern/wm_files.cc b/source/blender/windowmanager/intern/wm_files.cc index 3de5684e085..c873c511414 100644 --- a/source/blender/windowmanager/intern/wm_files.cc +++ b/source/blender/windowmanager/intern/wm_files.cc @@ -43,6 +43,7 @@ #include "PIL_time.h" +#include "BLO_readfile.h" #include "BLT_translation.h" #include "BLF_api.h" @@ -79,7 +80,6 @@ #include "BKE_undo_system.h" #include "BKE_workspace.h" -#include "BLO_readfile.h" #include "BLO_undofile.h" /* to save from an undo memfile */ #include "BLO_writefile.h" @@ -591,9 +591,9 @@ void WM_file_autoexec_init(const char *filepath) } if (G.f & G_FLAG_SCRIPT_AUTOEXEC) { - char path[FILE_MAX]; - BLI_split_dir_part(filepath, path, sizeof(path)); - if (BKE_autoexec_match(path)) { + char dirpath[FILE_MAX]; + BLI_split_dir_part(filepath, dirpath, sizeof(dirpath)); + if (BKE_autoexec_match(dirpath)) { G.f &= ~G_FLAG_SCRIPT_AUTOEXEC; } } @@ -632,10 +632,9 @@ void wm_file_read_report(bContext *C, Main *bmain) * \note In the case of #WM_file_read the file may fail to load. * Change here shouldn't cause user-visible changes in that case. */ -static void wm_file_read_pre(bContext *C, bool use_data, bool /*use_userdef*/) +static void wm_file_read_pre(bool use_data, bool /*use_userdef*/) { if (use_data) { - BKE_callback_exec_null(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE); BLI_timer_on_file_load(); } @@ -656,6 +655,10 @@ struct wmFileReadPost_Params { uint is_startup_file : 1; uint is_factory_startup : 1; uint reset_app_template : 1; + + /* Used by #wm_homefile_read_post */ + uint success : 1; + uint is_alloc : 1; }; /** @@ -747,7 +750,6 @@ static void wm_file_read_post(bContext *C, const struct wmFileReadPost_Params *p if (use_data) { /* important to do before nullptr'ing the context */ BKE_callback_exec_null(bmain, BKE_CB_EVT_VERSION_UPDATE); - BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_POST); if (is_factory_startup) { BKE_callback_exec_null(bmain, BKE_CB_EVT_LOAD_FACTORY_STARTUP_POST); } @@ -876,8 +878,10 @@ static void file_read_reports_finalize(BlendFileReadReport *bf_reports) for (LinkNode *node_lib = bf_reports->resynced_lib_overrides_libraries; node_lib != nullptr; node_lib = node_lib->next) { Library *library = static_cast(node_lib->link); - BKE_reportf( - bf_reports->reports, RPT_INFO, "Library %s needs overrides resync", library->filepath); + BKE_reportf(bf_reports->reports, + RPT_INFO, + "Library \"%s\" needs overrides resync", + library->filepath); } } @@ -944,6 +948,10 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) const bool use_data = true; const bool use_userdef = false; + /* NOTE: either #BKE_CB_EVT_LOAD_POST or #BKE_CB_EVT_LOAD_POST_FAIL must run. + * Runs at the end of this function, don't return beforehand. */ + BKE_callback_exec_string(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE, filepath); + /* so we can get the error message */ errno = 0; @@ -968,7 +976,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) bf_reports.duration.whole = PIL_check_seconds_timer(); struct BlendFileData *bfd = BKE_blendfile_read(filepath, ¶ms, &bf_reports); if (bfd != nullptr) { - wm_file_read_pre(C, use_data, use_userdef); + wm_file_read_pre(use_data, use_userdef); /* Put aside screens to match with persistent windows later, * also exit screens and editors. */ @@ -1004,6 +1012,8 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) read_file_post_params.is_startup_file = false; read_file_post_params.is_factory_startup = false; read_file_post_params.reset_app_template = false; + read_file_post_params.success = true; + read_file_post_params.is_alloc = false; wm_file_read_post(C, &read_file_post_params); bf_reports.duration.whole = PIL_check_seconds_timer() - bf_reports.duration.whole; @@ -1020,18 +1030,18 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) { BKE_reportf(reports, RPT_ERROR, - "Cannot read file '%s': %s", + "Cannot read file \"%s\": %s", filepath, errno ? strerror(errno) : TIP_("unable to open the file")); } else if (retval == BKE_READ_EXOTIC_FAIL_FORMAT) { - BKE_reportf(reports, RPT_ERROR, "File format is not supported in file '%s'", filepath); + BKE_reportf(reports, RPT_ERROR, "File format is not supported in file \"%s\"", filepath); } else if (retval == BKE_READ_EXOTIC_FAIL_PATH) { - BKE_reportf(reports, RPT_ERROR, "File path '%s' invalid", filepath); + BKE_reportf(reports, RPT_ERROR, "File path \"%s\" invalid", filepath); } else { - BKE_reportf(reports, RPT_ERROR, "Unknown error loading '%s'", filepath); + BKE_reportf(reports, RPT_ERROR, "Unknown error loading \"%s\"", filepath); BLI_assert_msg(0, "invalid 'retval'"); } @@ -1048,7 +1058,11 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports) WM_cursor_wait(false); - BLI_assert(BKE_main_namemap_validate(CTX_data_main(C))); + Main *bmain = CTX_data_main(C); + BKE_callback_exec_string( + bmain, success ? BKE_CB_EVT_LOAD_POST : BKE_CB_EVT_LOAD_POST_FAIL, filepath); + + BLI_assert(BKE_main_namemap_validate(bmain)); return success; } @@ -1178,10 +1192,16 @@ void wm_homefile_read_ex(bContext *C, #endif /* WITH_PYTHON */ } + if (use_data) { + /* NOTE: either #BKE_CB_EVT_LOAD_POST or #BKE_CB_EVT_LOAD_POST_FAIL must run. + * This runs from #wm_homefile_read_post. */ + BKE_callback_exec_string(CTX_data_main(C), BKE_CB_EVT_LOAD_PRE, ""); + } + /* For regular file loading this only runs after the file is successfully read. * In the case of the startup file, the in-memory startup file is used as a fallback * so we know this will work if all else fails. */ - wm_file_read_pre(C, use_data, use_userdef); + wm_file_read_pre(use_data, use_userdef); if (use_data) { /* put aside screens to match with persistent windows later */ @@ -1225,7 +1245,7 @@ void wm_homefile_read_ex(bContext *C, userdef = nullptr; skip_flags |= BLO_READ_SKIP_USERDEF; - printf("Read prefs: %s\n", filepath_userdef); + printf("Read prefs: \"%s\"\n", filepath_userdef); } } } @@ -1234,7 +1254,7 @@ void wm_homefile_read_ex(bContext *C, if (!BKE_appdir_app_template_id_search( app_template, app_template_system, sizeof(app_template_system))) { /* Can safely continue with code below, just warn it's not found. */ - BKE_reportf(reports, RPT_WARNING, "Application Template '%s' not found", app_template); + BKE_reportf(reports, RPT_WARNING, "Application Template \"%s\" not found", app_template); } /* Insert template name into startup file. */ @@ -1294,7 +1314,7 @@ void wm_homefile_read_ex(bContext *C, if (success == false && filepath_startup_override && reports) { /* We can not return from here because wm is already reset */ - BKE_reportf(reports, RPT_ERROR, "Could not read '%s'", filepath_startup_override); + BKE_reportf(reports, RPT_ERROR, "Could not read \"%s\"", filepath_startup_override); } if (success == false) { @@ -1392,10 +1412,14 @@ void wm_homefile_read_ex(bContext *C, params_file_read_post.is_factory_startup = is_factory_startup; params_file_read_post.reset_app_template = reset_app_template; + params_file_read_post.success = success; + params_file_read_post.is_alloc = false; + if (r_params_file_read_post == nullptr) { - wm_file_read_post(C, ¶ms_file_read_post); + wm_homefile_read_post(C, ¶ms_file_read_post); } else { + params_file_read_post.is_alloc = true; *r_params_file_read_post = static_cast( MEM_mallocN(sizeof(wmFileReadPost_Params), __func__)); **r_params_file_read_post = params_file_read_post; @@ -1417,7 +1441,17 @@ void wm_homefile_read_post(struct bContext *C, const struct wmFileReadPost_Params *params_file_read_post) { wm_file_read_post(C, params_file_read_post); - MEM_freeN((void *)params_file_read_post); + + if (params_file_read_post->use_data) { + BKE_callback_exec_string(CTX_data_main(C), + params_file_read_post->success ? BKE_CB_EVT_LOAD_POST : + BKE_CB_EVT_LOAD_POST_FAIL, + ""); + } + + if (params_file_read_post->is_alloc) { + MEM_freeN((void *)params_file_read_post); + } } /** \} */ @@ -1747,17 +1781,14 @@ static ImBuf *blend_file_thumb_from_camera(const bContext *C, bool write_crash_blend(void) { - char path[FILE_MAX]; + char filepath[FILE_MAX]; - BLI_strncpy(path, BKE_main_blendfile_path_from_global(), sizeof(path)); - BLI_path_extension_replace(path, sizeof(path), "_crash.blend"); + BLI_strncpy(filepath, BKE_main_blendfile_path_from_global(), sizeof(filepath)); + BLI_path_extension_replace(filepath, sizeof(filepath), "_crash.blend"); BlendFileWriteParams params{}; - if (BLO_write_file(G_MAIN, path, G.fileflags, ¶ms, nullptr)) { - printf("written: %s\n", path); - return 1; - } - printf("failed: %s\n", path); - return 0; + const bool success = BLO_write_file(G_MAIN, filepath, G.fileflags, ¶ms, nullptr); + printf("%s: \"%s\"\n", success ? "written" : "failed", filepath); + return success; } /** @@ -1781,7 +1812,8 @@ static bool wm_file_write_check_with_report_on_failure(Main *bmain, /* Check if file write permission is ok */ if (BLI_exists(filepath) && !BLI_file_is_writable(filepath)) { - BKE_reportf(reports, RPT_ERROR, "Cannot save blend file, path '%s' is not writable", filepath); + BKE_reportf( + reports, RPT_ERROR, "Cannot save blend file, path \"%s\" is not writable", filepath); return false; } @@ -1806,7 +1838,6 @@ static bool wm_file_write(bContext *C, ReportList *reports) { Main *bmain = CTX_data_main(C); - int ok = false; BlendThumbnail *thumb = nullptr, *main_thumb = nullptr; ImBuf *ibuf_thumb = nullptr; @@ -1815,12 +1846,15 @@ static bool wm_file_write(bContext *C, * its handy for scripts to save to a predefined name without blender editing it */ if (!wm_file_write_check_with_report_on_failure(bmain, filepath, reports)) { - return ok; + return false; } /* Call pre-save callbacks before writing preview, * that way you can generate custom file thumbnail. */ - BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE); + + /* NOTE: either #BKE_CB_EVT_SAVE_POST or #BKE_CB_EVT_SAVE_POST_FAIL must run. + * Runs at the end of this function, don't return beforehand. */ + BKE_callback_exec_string(bmain, BKE_CB_EVT_SAVE_PRE, filepath); ED_assets_pre_save(bmain); /* Enforce full override check/generation on file save. */ @@ -1891,7 +1925,10 @@ static bool wm_file_write(bContext *C, blend_write_params.use_save_versions = true; blend_write_params.use_save_as_copy = use_save_as_copy; blend_write_params.thumb = thumb; - if (BLO_write_file(bmain, filepath, fileflags, &blend_write_params, reports)) { + + const bool success = BLO_write_file(bmain, filepath, fileflags, &blend_write_params, reports); + + if (success) { const bool do_history_file_update = (G.background == false) && (CTX_wm_manager(C)->op_undo_depth == 0); @@ -1906,8 +1943,6 @@ static bool wm_file_write(bContext *C, wm_history_file_update(); } - BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST); - /* run this function after because the file can't be written before the blend is */ if (ibuf_thumb) { IMB_thumb_delete(filepath, THB_FAIL); /* without this a failed thumb overrides */ @@ -1916,11 +1951,11 @@ static bool wm_file_write(bContext *C, /* Without this there is no feedback the file was saved. */ BKE_reportf(reports, RPT_INFO, "Saved \"%s\"", BLI_path_basename(filepath)); - - /* Success. */ - ok = true; } + BKE_callback_exec_string( + bmain, success ? BKE_CB_EVT_SAVE_POST : BKE_CB_EVT_SAVE_POST_FAIL, filepath); + if (ibuf_thumb) { IMB_freeImBuf(ibuf_thumb); } @@ -1930,7 +1965,7 @@ static bool wm_file_write(bContext *C, WM_cursor_wait(false); - return ok; + return success; } /** \} */ @@ -1942,7 +1977,7 @@ static bool wm_file_write(bContext *C, static void wm_autosave_location(char filepath[FILE_MAX]) { const int pid = abs(getpid()); - char path[1024]; + char filename[1024]; /* Normally there is no need to check for this to be nullptr, * however this runs on exit when it may be cleared. */ @@ -1952,10 +1987,10 @@ static void wm_autosave_location(char filepath[FILE_MAX]) if (blendfile_path && (blendfile_path[0] != '\0')) { const char *basename = BLI_path_basename(blendfile_path); int len = strlen(basename) - 6; - BLI_snprintf(path, sizeof(path), "%.*s_%d_autosave.blend", len, basename, pid); + BLI_snprintf(filename, sizeof(filename), "%.*s_%d_autosave.blend", len, basename, pid); } else { - BLI_snprintf(path, sizeof(path), "%d_autosave.blend", pid); + BLI_snprintf(filename, sizeof(filename), "%d_autosave.blend", pid); } const char *tempdir_base = BKE_tempdir_base(); @@ -1972,7 +2007,7 @@ static void wm_autosave_location(char filepath[FILE_MAX]) } #endif - BLI_path_join(filepath, FILE_MAX, tempdir_base, path); + BLI_path_join(filepath, FILE_MAX, tempdir_base, filename); } static void wm_autosave_write(Main *bmain, wmWindowManager *wm) @@ -2154,7 +2189,9 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_PRE); + /* NOTE: either #BKE_CB_EVT_SAVE_POST or #BKE_CB_EVT_SAVE_POST_FAIL must run. + * Runs at the end of this function, don't return beforehand. */ + BKE_callback_exec_string(bmain, BKE_CB_EVT_SAVE_PRE, ""); ED_assets_pre_save(bmain); /* check current window and close it if temp */ @@ -2167,7 +2204,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE); - printf("Writing homefile: '%s' ", filepath); + printf("Writing homefile: \"%s\" ", filepath); ED_editors_flush_edits(bmain); @@ -2181,17 +2218,19 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op) blend_write_params.remap_mode = BLO_WRITE_PATH_REMAP_ABSOLUTE; /* Don't apply any path changes to the current blend file. */ blend_write_params.use_save_as_copy = true; - if (BLO_write_file(bmain, filepath, fileflags, &blend_write_params, op->reports) == 0) { - printf("fail\n"); - return OPERATOR_CANCELLED; + + const bool success = BLO_write_file( + bmain, filepath, fileflags, &blend_write_params, op->reports); + + BKE_callback_exec_string(bmain, success ? BKE_CB_EVT_SAVE_POST : BKE_CB_EVT_SAVE_POST_FAIL, ""); + + if (success) { + printf("ok\n"); + BKE_report(op->reports, RPT_INFO, "Startup file saved"); + return OPERATOR_FINISHED; } - - printf("ok\n"); - BKE_report(op->reports, RPT_INFO, "Startup file saved"); - - BKE_callback_exec_null(bmain, BKE_CB_EVT_SAVE_POST); - - return OPERATOR_FINISHED; + printf("fail\n"); + return OPERATOR_CANCELLED; } void WM_OT_save_homefile(wmOperatorType *ot) @@ -2218,9 +2257,9 @@ static int wm_userpref_write_exec(bContext *C, wmOperator *op) /* Update keymaps in user preferences. */ WM_keyconfig_update(wm); - const bool ok = BKE_blendfile_userdef_write_all(op->reports); + const bool success = BKE_blendfile_userdef_write_all(op->reports); - return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + return success ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } void WM_OT_save_userpref(wmOperatorType *ot) @@ -2434,7 +2473,7 @@ static int wm_homefile_read_exec(bContext *C, wmOperator *op) filepath = filepath_buf; if (BLI_access(filepath, R_OK)) { BKE_reportf( - op->reports, RPT_ERROR, "Can't read alternative start-up file: '%s'", filepath); + op->reports, RPT_ERROR, "Can't read alternative start-up file: \"%s\"", filepath); return OPERATOR_CANCELLED; } } @@ -2595,8 +2634,6 @@ void WM_OT_read_factory_settings(wmOperatorType *ot) */ static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports) { - bool success; - /* XXX wm in context is not set correctly after WM_file_read -> crash */ /* do it before for now, but is this correct with multiple windows? */ WM_event_add_notifier(C, NC_WINDOW, nullptr); @@ -2606,7 +2643,7 @@ static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *r WM_file_autoexec_init(filepath); } - success = WM_file_read(C, filepath, reports); + const bool success = WM_file_read(C, filepath, reports); return success; } @@ -2773,13 +2810,12 @@ static char *wm_open_mainfile_description(struct bContext * /*C*/, return nullptr; } - /* Filepath. */ - char path[FILE_MAX]; - RNA_string_get(params, "filepath", path); + char filepath[FILE_MAX]; + RNA_string_get(params, "filepath", filepath); BLI_stat_t stats; - if (BLI_stat(path, &stats) == -1) { - return BLI_sprintfN("%s\n\n%s", path, TIP_("File Not Found")); + if (BLI_stat(filepath, &stats) == -1) { + return BLI_sprintfN("%s\n\n%s", filepath, TIP_("File Not Found")); } /* Date. */ @@ -2796,8 +2832,13 @@ static char *wm_open_mainfile_description(struct bContext * /*C*/, char size_str[FILELIST_DIRENTRY_SIZE_LEN]; BLI_filelist_entry_size_to_string(nullptr, uint64_t(stats.st_size), false, size_str); - return BLI_sprintfN( - "%s\n\n%s: %s %s\n%s: %s", path, TIP_("Modified"), date_st, time_st, TIP_("Size"), size_str); + return BLI_sprintfN("%s\n\n%s: %s %s\n%s: %s", + filepath, + TIP_("Modified"), + date_st, + time_st, + TIP_("Size"), + size_str); } /* currently fits in a pointer */ @@ -2812,19 +2853,19 @@ static bool wm_open_mainfile_check(bContext * /*C*/, wmOperator *op) struct FileRuntime *file_info = (struct FileRuntime *)&op->customdata; PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_scripts"); bool is_untrusted = false; - char path[FILE_MAX]; + char filepath[FILE_MAX]; char *lslash; - RNA_string_get(op->ptr, "filepath", path); + RNA_string_get(op->ptr, "filepath", filepath); /* get the dir */ - lslash = (char *)BLI_path_slash_rfind(path); + lslash = (char *)BLI_path_slash_rfind(filepath); if (lslash) { *(lslash + 1) = '\0'; } if ((U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0) { - if (BKE_autoexec_match(path) == true) { + if (BKE_autoexec_match(filepath) == true) { RNA_property_boolean_set(op->ptr, prop, false); is_untrusted = true; } @@ -3143,11 +3184,11 @@ static int wm_save_as_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_RUNNING_MODAL; } -/* function used for WM_OT_save_mainfile too */ +/* Function used for #WM_OT_save_mainfile too. */ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); - char path[FILE_MAX]; + char filepath[FILE_MAX]; const bool is_save_as = (op->type->invoke == wm_save_as_mainfile_invoke); const bool use_save_as_copy = is_save_as && RNA_boolean_get(op->ptr, "copy"); @@ -3161,13 +3202,13 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) const bool is_filepath_set = RNA_struct_property_is_set(op->ptr, "filepath"); if (is_filepath_set) { - RNA_string_get(op->ptr, "filepath", path); + RNA_string_get(op->ptr, "filepath", filepath); } else { - STRNCPY(path, BKE_main_blendfile_path(bmain)); + STRNCPY(filepath, BKE_main_blendfile_path(bmain)); } - if (path[0] == '\0') { + if (filepath[0] == '\0') { BKE_report(op->reports, RPT_ERROR, "Unable to save an unsaved file with an empty or unset \"filepath\" property"); @@ -3179,11 +3220,11 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) * Even though this should never happen, there may be some corner case where a malformed * path is stored in `G.main->filepath`: when the file path is initialized from recovering * a blend file - for example, so in this case failing to save isn't ideal. */ - if (is_filepath_set && !BLI_path_is_abs_from_cwd(path)) { + if (is_filepath_set && !BLI_path_is_abs_from_cwd(filepath)) { BKE_reportf(op->reports, RPT_ERROR, "The \"filepath\" property was not an absolute path: \"%s\"", - path); + filepath); return OPERATOR_CANCELLED; } @@ -3193,7 +3234,8 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) /* set compression flag */ SET_FLAG_FROM_TEST(fileflags, RNA_boolean_get(op->ptr, "compress"), G_FILE_COMPRESS); - const bool ok = wm_file_write(C, path, fileflags, remap_mode, use_save_as_copy, op->reports); + const bool success = wm_file_write( + C, filepath, fileflags, remap_mode, use_save_as_copy, op->reports); if ((op->flag & OP_IS_INVOKE) == 0) { /* OP_IS_INVOKE is set when the operator is called from the GUI. @@ -3202,7 +3244,7 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) G.fileflags = fileflags_orig; } - if (ok == false) { + if (success == false) { return OPERATOR_CANCELLED; } @@ -3215,12 +3257,11 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -/* function used for WM_OT_save_mainfile too */ -static bool blend_save_check(bContext * /*C*/, wmOperator *op) +static bool wm_save_mainfile_check(bContext * /*C*/, wmOperator *op) { char filepath[FILE_MAX]; RNA_string_get(op->ptr, "filepath", filepath); - if (!BLO_has_bfile_extension(filepath)) { + if (!BKE_blendfile_extension_check(filepath)) { /* some users would prefer BLI_path_extension_replace(), * we keep getting nitpicking bug reports about this - campbell */ BLI_path_extension_ensure(filepath, FILE_MAX, ".blend"); @@ -3261,7 +3302,7 @@ void WM_OT_save_as_mainfile(wmOperatorType *ot) ot->exec = wm_save_as_mainfile_exec; ot->get_name = wm_save_as_mainfile_get_name; ot->get_description = wm_save_as_mainfile_get_description; - ot->check = blend_save_check; + ot->check = wm_save_mainfile_check; /* omit window poll so this can work in background mode */ WM_operator_properties_filesel(ot, @@ -3310,9 +3351,6 @@ static int wm_save_mainfile_invoke(bContext *C, wmOperator *op, const wmEvent * } if (blendfile_path[0] != '\0') { - char path[FILE_MAX]; - - RNA_string_get(op->ptr, "filepath", path); ret = wm_save_as_mainfile_exec(C, op); } else { @@ -3331,8 +3369,8 @@ void WM_OT_save_mainfile(wmOperatorType *ot) ot->invoke = wm_save_mainfile_invoke; ot->exec = wm_save_as_mainfile_exec; - ot->check = blend_save_check; - /* omit window poll so this can work in background mode */ + ot->check = wm_save_mainfile_check; + /* Omit window poll so this can work in background mode. */ PropertyRNA *prop; WM_operator_properties_filesel(ot, @@ -3515,7 +3553,7 @@ static uiBlock *block_create_autorun_warning(struct bContext *C, UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); - UI_block_bounds_set_centered(block, 14 * U.dpi_fac); + UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC); return block; } @@ -3854,7 +3892,7 @@ static uiBlock *block_create__close_file_dialog(struct bContext *C, wm_block_file_close_save_button(block, post_action); } - UI_block_bounds_set_centered(block, 14 * U.dpi_fac); + UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC); return block; } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 3af7d2f26f0..ee2b7455a0d 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -37,6 +37,7 @@ #include "BLO_readfile.h" #include "BKE_armature.h" +#include "BKE_blendfile.h" #include "BKE_blendfile_link_append.h" #include "BKE_context.h" #include "BKE_global.h" @@ -216,7 +217,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_path_join(path, sizeof(path), root, relname); /* test if we have a valid data */ - if (!BLO_library_path_explode(path, libname, &group, &name)) { + if (!BKE_blendfile_library_path_explode(path, libname, &group, &name)) { BKE_reportf(op->reports, RPT_ERROR, "'%s': not a library", path); return OPERATOR_CANCELLED; } @@ -289,7 +290,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_path_join(path, sizeof(path), root, relname); - if (BLO_library_path_explode(path, libname, &group, &name)) { + if (BKE_blendfile_library_path_explode(path, libname, &group, &name)) { if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) { continue; } @@ -308,7 +309,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_path_join(path, sizeof(path), root, relname); - if (BLO_library_path_explode(path, libname, &group, &name)) { + if (BKE_blendfile_library_path_explode(path, libname, &group, &name)) { BlendfileLinkAppendContextItem *item; if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) { @@ -610,7 +611,7 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) { - if (!BLO_has_bfile_extension(lib->filepath_abs)) { + if (!BKE_blendfile_extension_check(lib->filepath_abs)) { BKE_reportf(reports, RPT_ERROR, "'%s' is not a valid library filepath", lib->filepath_abs); return; } @@ -687,7 +688,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) RNA_string_get(op->ptr, "directory", root); RNA_string_get(op->ptr, "filename", libname); - if (!BLO_has_bfile_extension(libname)) { + if (!BKE_blendfile_extension_check(libname)) { BKE_report(op->reports, RPT_ERROR, "Not a library"); return OPERATOR_CANCELLED; } @@ -750,7 +751,8 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) BLI_path_join(path, sizeof(path), root, relname); - if (BLI_path_cmp(path, lib->filepath_abs) == 0 || !BLO_has_bfile_extension(relname)) { + if (BLI_path_cmp(path, lib->filepath_abs) == 0 || + !BKE_blendfile_extension_check(relname)) { continue; } diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c index 83ecad59012..c6918f302ab 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.c +++ b/source/blender/windowmanager/intern/wm_gesture_ops.c @@ -580,7 +580,7 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* Make a simple distance check to get a smoother lasso * add only when at least 2 pixels between this and previous location. */ - else if ((x * x + y * y) > pow2f(2.0f * UI_DPI_FAC)) { + else if ((x * x + y * y) > pow2f(2.0f * UI_SCALE_FAC)) { lasso[gesture->points][0] = event->xy[0] - gesture->winrct.xmin; lasso[gesture->points][1] = event->xy[1] - gesture->winrct.ymin; gesture->points++; diff --git a/source/blender/windowmanager/intern/wm_init_exit.cc b/source/blender/windowmanager/intern/wm_init_exit.cc index 243480c84e6..683e3ec0dd7 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.cc +++ b/source/blender/windowmanager/intern/wm_init_exit.cc @@ -457,7 +457,7 @@ void WM_exit_ex(bContext *C, const bool do_python) if ((has_edited && BLO_write_file(bmain, filepath, fileflags, &blend_file_write_params, nullptr)) || BLO_memfile_write_file(undo_memfile, filepath)) { - printf("Saved session recovery to '%s'\n", filepath); + printf("Saved session recovery to \"%s\"\n", filepath); } } } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index df1555dfdd7..39d0f0cf843 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1411,7 +1411,7 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *region, void *arg_op) uiTemplateOperatorPropertyButs( C, col, op, UI_BUT_LABEL_ALIGN_NONE, UI_TEMPLATE_OP_PROPS_SHOW_TITLE); - UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL); + UI_block_bounds_set_popup(block, 6 * UI_SCALE_FAC, NULL); return block; } @@ -1486,7 +1486,7 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *region, void *userD /* center around the mouse */ UI_block_bounds_set_popup( - block, 6 * U.dpi_fac, (const int[2]){data->width / -2, data->height / 2}); + block, 6 * UI_SCALE_FAC, (const int[2]){data->width / -2, data->height / 2}); return block; } @@ -1510,7 +1510,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *region, void *userDa UI_block_func_set(block, NULL, NULL, NULL); - UI_block_bounds_set_popup(block, 6 * U.dpi_fac, NULL); + UI_block_bounds_set_popup(block, 6 * UI_SCALE_FAC, NULL); return block; } @@ -1549,7 +1549,7 @@ int WM_operator_ui_popup(bContext *C, wmOperator *op, int width) { wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_ui_popup"); data->op = op; - data->width = width * U.dpi_fac; + data->width = width * UI_SCALE_FAC; /* Actual used height depends on the content. */ data->height = 0; data->free_op = true; /* if this runs and gets registered we may want not to free it */ @@ -1619,7 +1619,7 @@ int WM_operator_props_dialog_popup(bContext *C, wmOperator *op, int width) wmOpPopUp *data = MEM_callocN(sizeof(wmOpPopUp), "WM_operator_props_dialog_popup"); data->op = op; - data->width = width * U.dpi_fac; + data->width = width * UI_SCALE_FAC; /* Actual height depends on the content. */ data->height = 0; data->free_op = true; /* if this runs and gets registered we may want not to free it */ @@ -2173,8 +2173,8 @@ void WM_paint_cursor_remove_by_type(wmWindowManager *wm, void *draw_fn, void (*f /** \name Radial Control Operator * \{ */ -#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * UI_DPI_FAC) -#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * UI_DPI_FAC) +#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * UI_SCALE_FAC) +#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * UI_SCALE_FAC) #define WM_RADIAL_CONTROL_DISPLAY_WIDTH \ (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) #define WM_RADIAL_MAX_STR 10 @@ -2558,7 +2558,7 @@ static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void immUnbindProgram(); - BLF_size(fontid, 1.75f * fstyle_points * U.dpi_fac); + BLF_size(fontid, 1.75f * fstyle_points * UI_SCALE_FAC); UI_GetThemeColor4fv(TH_TEXT_HI, text_color); BLF_color4fv(fontid, text_color); diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 1bcd51ed9c7..abe8161f798 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -83,7 +83,7 @@ static void wm_block_splash_image_roundcorners_add(ImBuf *ibuf) } bTheme *btheme = UI_GetTheme(); - const float roundness = btheme->tui.wcol_menu_back.roundness * U.dpi_fac; + const float roundness = btheme->tui.wcol_menu_back.roundness * UI_SCALE_FAC; const int size = roundness * 20; if (size < ibuf->x && size < ibuf->y) { @@ -184,7 +184,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); - int splash_width = text_points_max * 45 * U.dpi_fac; + int splash_width = text_points_max * 45 * UI_SCALE_FAC; CLAMP_MAX(splash_width, CTX_wm_window(C)->sizex * 0.7f); int splash_height; @@ -199,17 +199,17 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void *UNUSE wm_block_splash_add_label(block, BKE_blender_version_string(), - splash_width - 8.0 * U.dpi_fac, - splash_height - 13.0 * U.dpi_fac); + splash_width - 8.0 * UI_SCALE_FAC, + splash_height - 13.0 * UI_SCALE_FAC); - const int layout_margin_x = U.dpi_fac * 26; + const int layout_margin_x = UI_SCALE_FAC * 26; uiLayout *layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, layout_margin_x, 0, splash_width - (layout_margin_x * 2), - U.dpi_fac * 110, + UI_SCALE_FAC * 110, 0, style); @@ -263,7 +263,7 @@ static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED { const uiStyle *style = UI_style_get_dpi(); const int text_points_max = MAX2(style->widget.points, style->widgetlabel.points); - const int dialog_width = text_points_max * 42 * U.dpi_fac; + const int dialog_width = text_points_max * 42 * UI_SCALE_FAC; uiBlock *block = UI_block_begin(C, region, "about", UI_EMBOSS); @@ -317,7 +317,7 @@ static uiBlock *wm_block_create_about(bContext *C, ARegion *region, void *UNUSED UI_menutype_draw(C, mt, col); } - UI_block_bounds_set_centered(block, 22 * U.dpi_fac); + UI_block_bounds_set_centered(block, 22 * UI_SCALE_FAC); return block; } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index ad146c0e393..3fd7bc603fb 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -256,6 +256,9 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win) if (win->event_last_handled) { MEM_freeN(win->event_last_handled); } + if (win->event_queue_consecutive_gesture_data) { + WM_event_consecutive_data_free(win); + } if (win->cursor_keymap_status) { MEM_freeN(win->cursor_keymap_status); @@ -518,12 +521,12 @@ void WM_window_set_dpi(const wmWindow *win) /* Set user preferences globals for drawing, and for forward compatibility. */ U.pixelsize = pixelsize; U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE; - U.dpi_fac = U.dpi / 72.0f; - U.inv_dpi_fac = 1.0f / U.dpi_fac; + U.scale_factor = U.dpi / 72.0f; + U.inv_scale_factor = 1.0f / U.scale_factor; /* Widget unit is 20 pixels at 1X scale. This consists of 18 user-scaled units plus * left and right borders of line-width (pixel-size). */ - U.widget_unit = (int)roundf(18.0f * U.dpi_fac) + (2 * pixelsize); + U.widget_unit = (int)roundf(18.0f * U.scale_factor) + (2 * pixelsize); } /** @@ -1778,7 +1781,7 @@ static uiBlock *block_create_opengl_usage_warning(struct bContext *C, uiItemS(layout); - UI_block_bounds_set_centered(block, 14 * U.dpi_fac); + UI_block_bounds_set_centered(block, 14 * UI_SCALE_FAC); return block; } diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h index c7678223ce4..e17e1ae512e 100644 --- a/source/blender/windowmanager/wm_event_types.h +++ b/source/blender/windowmanager/wm_event_types.h @@ -60,7 +60,7 @@ enum { /* More mouse buttons - can't use 9 and 10 here (wheel) */ BUTTON6MOUSE = 0x0012, BUTTON7MOUSE = 0x0013, - /* Extra track-pad gestures. */ + /* Extra track-pad gestures (check #WM_EVENT_IS_CONSECUTIVE to detect motion events). */ MOUSEPAN = 0x000e, MOUSEZOOM = 0x000f, MOUSEROTATE = 0x0010, @@ -247,6 +247,10 @@ enum { * These must be kept in sync with `GHOST_NDOFManager.h`. * Ordering matters, exact values do not. */ + /** + * Motion from 3D input (translation & rotation). + * Check #WM_EVENT_IS_CONSECUTIVE to detect motion events. + */ NDOF_MOTION = 0x0190, /* 400 */ #define _NDOF_MIN NDOF_MOTION diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index ee09ce3374e..9edd16c5cac 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -6,7 +6,6 @@ set(INC ../../intern/guardedalloc ../blender/blenkernel ../blender/blenlib - ../blender/blenloader ../blender/depsgraph ../blender/editors/include ../blender/gpu @@ -1217,6 +1216,16 @@ elseif(WIN32) ALL ) + windows_install_shared_manifest( + FILES ${LIBDIR}/shaderc/bin/shaderc_shared.dll + RELEASE + ) + + windows_install_shared_manifest( + FILES ${LIBDIR}/shaderc/bin/shaderc_shared_d.dll + DEBUG + ) + windows_install_shared_manifest( FILES ${LIBDIR}/openal/lib/OpenAL32.dll diff --git a/source/creator/blender_launcher_win32.c b/source/creator/blender_launcher_win32.c index 993efafb53d..49acc591487 100644 --- a/source/creator/blender_launcher_win32.c +++ b/source/creator/blender_launcher_win32.c @@ -55,6 +55,11 @@ BOOL LaunchedFromSteam() int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow) { + /* Silence unreferenced formal parameter warning. */ + (void)hInstance; + (void)hPrevInstance; + (void)nCmdShow; + STARTUPINFO siStartInfo = {0}; PROCESS_INFORMATION procInfo; wchar_t path[MAX_PATH]; diff --git a/source/creator/creator.c b/source/creator/creator.c index fe6d501164a..6d55cb57b1b 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -39,7 +39,7 @@ #include "BKE_context.h" #include "BKE_cpp_types.h" #include "BKE_global.h" -#include "BKE_gpencil_modifier.h" +#include "BKE_gpencil_modifier_legacy.h" #include "BKE_idtype.h" #include "BKE_main.h" #include "BKE_material.h" @@ -239,12 +239,12 @@ void *gmp_alloc(size_t size) { return scalable_malloc(size); } -void *gmp_realloc(void *ptr, size_t old_size, size_t new_size) +void *gmp_realloc(void *ptr, size_t UNUSED(old_size), size_t new_size) { return scalable_realloc(ptr, new_size); } -void gmp_free(void *ptr, size_t size) +void gmp_free(void *ptr, size_t UNUSED(size)) { scalable_free(ptr); } diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 41708cc81a8..8b11aa07b03 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -29,9 +29,8 @@ # include "BLI_threads.h" # include "BLI_utildefines.h" -# include "BLO_readfile.h" /* only for BLO_has_bfile_extension */ - # include "BKE_blender_version.h" +# include "BKE_blendfile.h" # include "BKE_context.h" # include "BKE_global.h" @@ -2071,7 +2070,7 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data) return -1; } - if (BLO_has_bfile_extension(filepath)) { + if (BKE_blendfile_extension_check(filepath)) { /* Just pretend a file was loaded, so the user can press Save and it'll * save at the filepath from the CLI. */ STRNCPY(G_MAIN->filepath, filepath); diff --git a/tests/python/bl_pyapi_prop_array.py b/tests/python/bl_pyapi_prop_array.py index 1132914b14c..5595325d60d 100644 --- a/tests/python/bl_pyapi_prop_array.py +++ b/tests/python/bl_pyapi_prop_array.py @@ -195,6 +195,76 @@ class TestPropArrayMultiDimensional(unittest.TestCase): del id_type.temp +class TestPropArrayDynamicAssign(unittest.TestCase): + """ + Pixels are dynamic in the sense the size can change however the assignment does not define the size. + """ + + dims = 12 + + def setUp(self): + self.image = bpy.data.images.new("", self.dims, self.dims) + + def tearDown(self): + bpy.data.images.remove(self.image) + self.image = None + + def test_assign_fixed_under_1px(self): + image = self.image + with self.assertRaises(ValueError): + image.pixels = [1.0, 1.0, 1.0, 1.0] + + def test_assign_fixed_under_0px(self): + image = self.image + with self.assertRaises(ValueError): + image.pixels = [] + + def test_assign_fixed_over_by_1px(self): + image = self.image + with self.assertRaises(ValueError): + image.pixels = ([1.0, 1.0, 1.0, 1.0] * (self.dims * self.dims)) + [1.0] + + def test_assign_fixed(self): + # Valid assignment, ensure it works as intended. + image = self.image + values = [1.0, 0.0, 1.0, 0.0] * (self.dims * self.dims) + image.pixels = values + self.assertEqual(tuple(values), tuple(image.pixels)) + + +class TestPropArrayDynamicArg(unittest.TestCase): + """ + Index array, a dynamic array argument which defines it's own length. + """ + + dims = 8 + + def setUp(self): + self.me = bpy.data.meshes.new("") + self.me.vertices.add(self.dims) + self.ob = bpy.data.objects.new("", self.me) + + def tearDown(self): + bpy.data.objects.remove(self.ob) + bpy.data.meshes.remove(self.me) + self.me = None + self.ob = None + + def test_param_dynamic(self): + ob = self.ob + vg = ob.vertex_groups.new(name="") + + # Add none. + vg.add(index=(), weight=1.0, type='REPLACE') + for i in range(self.dims): + with self.assertRaises(RuntimeError): + vg.weight(i) + + # Add all. + vg.add(index=range(self.dims), weight=1.0, type='REPLACE') + self.assertEqual(tuple([1.0] * self.dims), tuple([vg.weight(i) for i in range(self.dims)])) + + if __name__ == '__main__': import sys sys.argv = [__file__] + (sys.argv[sys.argv.index("--") + 1:] if "--" in sys.argv else []) diff --git a/tools/check_source/check_spelling_c_config.py b/tools/check_source/check_spelling_c_config.py index 077d8468ceb..edc22deb96f 100644 --- a/tools/check_source/check_spelling_c_config.py +++ b/tools/check_source/check_spelling_c_config.py @@ -141,6 +141,7 @@ dict_custom = { "instantiable", "instantiation", "instantiations", + "interdependencies", "interferences", "interocular", "invariant",